From f1807034732f3b1dae15d8bce5cc2dd1b219ac2d Mon Sep 17 00:00:00 2001 From: Mike Kell Date: Mon, 29 Dec 2025 15:38:18 -0500 Subject: [PATCH] Implemented multiple type of products and UI changes --- backend/debug.log | 1 + .../typing_extensions.cpython-312.pyc | Bin 0 -> 163643 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 254 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 1902 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 18623 bytes .../__pycache__/test_cases.cpython-312.pyc | Bin 0 -> 13236 bytes .../site-packages/annotated_types/py.typed | 0 .../annotated_types/test_cases.py | 151 + .../anyio-4.12.0.dist-info/INSTALLER | 1 + .../anyio-4.12.0.dist-info/METADATA | 96 + .../anyio-4.12.0.dist-info/RECORD | 92 + .../anyio-4.12.0.dist-info/WHEEL | 5 + .../anyio-4.12.0.dist-info/entry_points.txt | 2 + .../anyio-4.12.0.dist-info/licenses/LICENSE | 20 + .../anyio-4.12.0.dist-info/top_level.txt | 1 + .../venv/Lib/site-packages/anyio/__init__.py | 111 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4626 bytes .../__pycache__/from_thread.cpython-312.pyc | Bin 0 -> 25799 bytes .../__pycache__/functools.cpython-312.pyc | Bin 0 -> 13726 bytes .../__pycache__/lowlevel.cpython-312.pyc | Bin 0 -> 7887 bytes .../__pycache__/pytest_plugin.cpython-312.pyc | Bin 0 -> 14285 bytes .../to_interpreter.cpython-312.pyc | Bin 0 -> 10329 bytes .../__pycache__/to_process.cpython-312.pyc | Bin 0 -> 11832 bytes .../__pycache__/to_thread.cpython-312.pyc | Bin 0 -> 2975 bytes .../site-packages/anyio/_backends/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 192 bytes .../__pycache__/_asyncio.cpython-312.pyc | Bin 0 -> 139826 bytes .../__pycache__/_trio.cpython-312.pyc | Bin 0 -> 73273 bytes .../site-packages/anyio/_backends/_asyncio.py | 3007 ++++++ .../site-packages/anyio/_backends/_trio.py | 1384 +++ .../Lib/site-packages/anyio/_core/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 188 bytes .../_asyncio_selector_thread.cpython-312.pyc | Bin 0 -> 8403 bytes .../_contextmanagers.cpython-312.pyc | Bin 0 -> 8998 bytes .../__pycache__/_eventloop.cpython-312.pyc | Bin 0 -> 8307 bytes .../__pycache__/_exceptions.cpython-312.pyc | Bin 0 -> 7265 bytes .../_core/__pycache__/_fileio.cpython-312.pyc | Bin 0 -> 43370 bytes .../__pycache__/_resources.cpython-312.pyc | Bin 0 -> 930 bytes .../__pycache__/_signals.cpython-312.pyc | Bin 0 -> 1273 bytes .../__pycache__/_sockets.cpython-312.pyc | Bin 0 -> 39928 bytes .../__pycache__/_streams.cpython-312.pyc | Bin 0 -> 2337 bytes .../__pycache__/_subprocesses.cpython-312.pyc | Bin 0 -> 9628 bytes .../_synchronization.cpython-312.pyc | Bin 0 -> 32943 bytes .../_core/__pycache__/_tasks.cpython-312.pyc | Bin 0 -> 7129 bytes .../__pycache__/_tempfile.cpython-312.pyc | Bin 0 -> 28132 bytes .../__pycache__/_testing.cpython-312.pyc | Bin 0 -> 3568 bytes .../__pycache__/_typedattr.cpython-312.pyc | Bin 0 -> 3833 bytes .../anyio/_core/_asyncio_selector_thread.py | 167 + .../anyio/_core/_contextmanagers.py | 200 + .../site-packages/anyio/_core/_eventloop.py | 229 + .../site-packages/anyio/_core/_exceptions.py | 153 + .../Lib/site-packages/anyio/_core/_fileio.py | 797 ++ .../site-packages/anyio/_core/_resources.py | 18 + .../Lib/site-packages/anyio/_core/_signals.py | 27 + .../Lib/site-packages/anyio/_core/_sockets.py | 991 ++ .../Lib/site-packages/anyio/_core/_streams.py | 52 + .../anyio/_core/_subprocesses.py | 202 + .../anyio/_core/_synchronization.py | 753 ++ .../Lib/site-packages/anyio/_core/_tasks.py | 163 + .../site-packages/anyio/_core/_tempfile.py | 616 ++ .../Lib/site-packages/anyio/_core/_testing.py | 78 + .../site-packages/anyio/_core/_typedattr.py | 81 + .../Lib/site-packages/anyio/abc/__init__.py | 58 + .../abc/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2363 bytes .../__pycache__/_eventloop.cpython-312.pyc | Bin 0 -> 16890 bytes .../__pycache__/_resources.cpython-312.pyc | Bin 0 -> 1635 bytes .../abc/__pycache__/_sockets.cpython-312.pyc | Bin 0 -> 18428 bytes .../abc/__pycache__/_streams.cpython-312.pyc | Bin 0 -> 9889 bytes .../__pycache__/_subprocesses.cpython-312.pyc | Bin 0 -> 3243 bytes .../abc/__pycache__/_tasks.cpython-312.pyc | Bin 0 -> 5142 bytes .../abc/__pycache__/_testing.cpython-312.pyc | Bin 0 -> 2838 bytes .../Lib/site-packages/anyio/abc/_eventloop.py | 420 + .../Lib/site-packages/anyio/abc/_resources.py | 33 + .../Lib/site-packages/anyio/abc/_sockets.py | 405 + .../Lib/site-packages/anyio/abc/_streams.py | 239 + .../site-packages/anyio/abc/_subprocesses.py | 79 + .../Lib/site-packages/anyio/abc/_tasks.py | 117 + .../Lib/site-packages/anyio/abc/_testing.py | 65 + .../Lib/site-packages/anyio/from_thread.py | 570 ++ .../venv/Lib/site-packages/anyio/functools.py | 347 + .../venv/Lib/site-packages/anyio/lowlevel.py | 195 + backend/venv/Lib/site-packages/anyio/py.typed | 0 .../Lib/site-packages/anyio/pytest_plugin.py | 302 + .../site-packages/anyio/streams/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../__pycache__/buffered.cpython-312.pyc | Bin 0 -> 9069 bytes .../streams/__pycache__/file.cpython-312.pyc | Bin 0 -> 7564 bytes .../__pycache__/memory.cpython-312.pyc | Bin 0 -> 15011 bytes .../__pycache__/stapled.cpython-312.pyc | Bin 0 -> 7540 bytes .../streams/__pycache__/text.cpython-312.pyc | Bin 0 -> 9336 bytes .../streams/__pycache__/tls.cpython-312.pyc | Bin 0 -> 20221 bytes .../site-packages/anyio/streams/buffered.py | 188 + .../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 | 424 + .../Lib/site-packages/anyio/to_interpreter.py | 246 + .../Lib/site-packages/anyio/to_process.py | 264 + .../venv/Lib/site-packages/anyio/to_thread.py | 74 + .../certifi-2025.11.12.dist-info/INSTALLER | 1 + .../certifi-2025.11.12.dist-info/METADATA | 78 + .../certifi-2025.11.12.dist-info/RECORD | 14 + .../certifi-2025.11.12.dist-info/WHEEL | 5 + .../licenses/LICENSE | 20 + .../top_level.txt | 1 + .../Lib/site-packages/certifi/__init__.py | 4 + .../Lib/site-packages/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 311 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 626 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 2058 bytes .../venv/Lib/site-packages/certifi/cacert.pem | 4678 +++++++++ .../venv/Lib/site-packages/certifi/core.py | 83 + .../venv/Lib/site-packages/certifi/py.typed | 0 .../INSTALLER | 1 + .../METADATA | 764 ++ .../charset_normalizer-3.4.4.dist-info/RECORD | 35 + .../charset_normalizer-3.4.4.dist-info/WHEEL | 5 + .../entry_points.txt | 2 + .../licenses/LICENSE | 21 + .../top_level.txt | 1 + .../charset_normalizer/__init__.py | 48 + .../charset_normalizer/__main__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1777 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 352 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 18160 bytes .../__pycache__/cd.cpython-312.pyc | Bin 0 -> 13239 bytes .../__pycache__/constant.cpython-312.pyc | Bin 0 -> 40807 bytes .../__pycache__/legacy.cpython-312.pyc | Bin 0 -> 3007 bytes .../__pycache__/md.cpython-312.pyc | Bin 0 -> 24333 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 17120 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 13707 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 379 bytes .../site-packages/charset_normalizer/api.py | 669 ++ .../site-packages/charset_normalizer/cd.py | 395 + .../charset_normalizer/cli/__init__.py | 8 + .../charset_normalizer/cli/__main__.py | 381 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 340 bytes .../cli/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 14390 bytes .../charset_normalizer/constant.py | 2015 ++++ .../charset_normalizer/legacy.py | 80 + .../charset_normalizer/md.cp312-win_amd64.pyd | Bin 0 -> 10752 bytes .../site-packages/charset_normalizer/md.py | 635 ++ .../md__mypyc.cp312-win_amd64.pyd | Bin 0 -> 126976 bytes .../charset_normalizer/models.py | 360 + .../site-packages/charset_normalizer/py.typed | 0 .../site-packages/charset_normalizer/utils.py | 414 + .../charset_normalizer/version.py | 8 + .../click-8.3.1.dist-info/INSTALLER | 1 + .../click-8.3.1.dist-info/METADATA | 84 + .../click-8.3.1.dist-info/RECORD | 40 + .../site-packages/click-8.3.1.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + .../venv/Lib/site-packages/click/__init__.py | 123 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4068 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 24187 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 31556 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2416 bytes .../click/__pycache__/_utils.cpython-312.pyc | Bin 0 -> 1196 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11761 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 134392 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 22133 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14773 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 13594 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 2961 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 20420 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 23295 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 34648 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 27390 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 50060 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 24865 bytes .../venv/Lib/site-packages/click/_compat.py | 622 ++ .../Lib/site-packages/click/_termui_impl.py | 852 ++ .../venv/Lib/site-packages/click/_textwrap.py | 51 + .../venv/Lib/site-packages/click/_utils.py | 36 + .../Lib/site-packages/click/_winconsole.py | 296 + backend/venv/Lib/site-packages/click/core.py | 3415 +++++++ .../Lib/site-packages/click/decorators.py | 551 + .../Lib/site-packages/click/exceptions.py | 308 + .../Lib/site-packages/click/formatting.py | 301 + .../venv/Lib/site-packages/click/globals.py | 67 + .../venv/Lib/site-packages/click/parser.py | 532 + backend/venv/Lib/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 667 ++ .../venv/Lib/site-packages/click/termui.py | 883 ++ .../venv/Lib/site-packages/click/testing.py | 577 ++ backend/venv/Lib/site-packages/click/types.py | 1209 +++ backend/venv/Lib/site-packages/click/utils.py | 627 ++ .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 485 bytes .../colorama/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 3938 bytes .../__pycache__/ansitowin32.cpython-312.pyc | Bin 0 -> 16405 bytes .../__pycache__/initialise.cpython-312.pyc | Bin 0 -> 3543 bytes .../__pycache__/win32.cpython-312.pyc | Bin 0 -> 8128 bytes .../__pycache__/winterm.cpython-312.pyc | Bin 0 -> 9081 bytes .../venv/Lib/site-packages/colorama/ansi.py | 102 + .../Lib/site-packages/colorama/ansitowin32.py | 277 + .../Lib/site-packages/colorama/initialise.py | 121 + .../site-packages/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 191 bytes .../__pycache__/ansi_test.cpython-312.pyc | Bin 0 -> 5460 bytes .../ansitowin32_test.cpython-312.pyc | Bin 0 -> 17999 bytes .../initialise_test.cpython-312.pyc | Bin 0 -> 11647 bytes .../__pycache__/isatty_test.cpython-312.pyc | Bin 0 -> 4774 bytes .../tests/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2463 bytes .../__pycache__/winterm_test.cpython-312.pyc | Bin 0 -> 6605 bytes .../site-packages/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../colorama/tests/initialise_test.py | 189 + .../colorama/tests/isatty_test.py | 57 + .../Lib/site-packages/colorama/tests/utils.py | 49 + .../colorama/tests/winterm_test.py | 131 + .../venv/Lib/site-packages/colorama/win32.py | 180 + .../Lib/site-packages/colorama/winterm.py | 195 + .../venv/Lib/site-packages/dotenv/__init__.py | 51 + .../venv/Lib/site-packages/dotenv/__main__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1688 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 356 bytes .../dotenv/__pycache__/cli.cpython-312.pyc | Bin 0 -> 10282 bytes .../__pycache__/ipython.cpython-312.pyc | Bin 0 -> 1972 bytes .../dotenv/__pycache__/main.cpython-312.pyc | Bin 0 -> 18132 bytes .../dotenv/__pycache__/parser.cpython-312.pyc | Bin 0 -> 9982 bytes .../__pycache__/variables.cpython-312.pyc | Bin 0 -> 5024 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 208 bytes backend/venv/Lib/site-packages/dotenv/cli.py | 218 + .../venv/Lib/site-packages/dotenv/ipython.py | 50 + backend/venv/Lib/site-packages/dotenv/main.py | 435 + .../venv/Lib/site-packages/dotenv/parser.py | 182 + .../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.128.0.dist-info/INSTALLER | 1 + .../fastapi-0.128.0.dist-info/METADATA | 645 ++ .../fastapi-0.128.0.dist-info/RECORD | 103 + .../fastapi-0.128.0.dist-info/REQUESTED | 0 .../fastapi-0.128.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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1099 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 246 bytes .../__pycache__/applications.cpython-312.pyc | Bin 0 -> 86656 bytes .../__pycache__/background.cpython-312.pyc | Bin 0 -> 2400 bytes .../fastapi/__pycache__/cli.cpython-312.pyc | Bin 0 -> 660 bytes .../__pycache__/concurrency.cpython-312.pyc | Bin 0 -> 1721 bytes .../datastructures.cpython-312.pyc | Bin 0 -> 7211 bytes .../__pycache__/encoders.cpython-312.pyc | Bin 0 -> 11059 bytes .../exception_handlers.cpython-312.pyc | Bin 0 -> 2026 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 9970 bytes .../__pycache__/logger.cpython-312.pyc | Bin 0 -> 286 bytes .../param_functions.cpython-312.pyc | Bin 0 -> 36380 bytes .../__pycache__/params.cpython-312.pyc | Bin 0 -> 24339 bytes .../__pycache__/requests.cpython-312.pyc | Bin 0 -> 275 bytes .../__pycache__/responses.cpython-312.pyc | Bin 0 -> 2403 bytes .../__pycache__/routing.cpython-312.pyc | Bin 0 -> 86419 bytes .../__pycache__/staticfiles.cpython-312.pyc | Bin 0 -> 247 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 249 bytes .../__pycache__/testclient.cpython-312.pyc | Bin 0 -> 244 bytes .../fastapi/__pycache__/types.cpython-312.pyc | Bin 0 -> 853 bytes .../fastapi/__pycache__/utils.cpython-312.pyc | Bin 0 -> 6429 bytes .../__pycache__/websockets.cpython-312.pyc | Bin 0 -> 324 bytes .../site-packages/fastapi/_compat/__init__.py | 41 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1764 bytes .../__pycache__/shared.cpython-312.pyc | Bin 0 -> 9391 bytes .../_compat/__pycache__/v2.cpython-312.pyc | Bin 0 -> 23009 bytes .../site-packages/fastapi/_compat/shared.py | 206 + .../Lib/site-packages/fastapi/_compat/v2.py | 568 ++ .../Lib/site-packages/fastapi/applications.py | 4669 +++++++++ .../Lib/site-packages/fastapi/background.py | 60 + backend/venv/Lib/site-packages/fastapi/cli.py | 13 + .../Lib/site-packages/fastapi/concurrency.py | 41 + .../site-packages/fastapi/datastructures.py | 183 + .../fastapi/dependencies/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 197 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 9214 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 39922 bytes .../fastapi/dependencies/models.py | 193 + .../fastapi/dependencies/utils.py | 1021 ++ .../Lib/site-packages/fastapi/encoders.py | 346 + .../fastapi/exception_handlers.py | 34 + .../Lib/site-packages/fastapi/exceptions.py | 246 + .../venv/Lib/site-packages/fastapi/logger.py | 3 + .../fastapi/middleware/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 253 bytes .../asyncexitstack.cpython-312.pyc | Bin 0 -> 1488 bytes .../__pycache__/cors.cpython-312.pyc | Bin 0 -> 258 bytes .../__pycache__/gzip.cpython-312.pyc | Bin 0 -> 258 bytes .../__pycache__/httpsredirect.cpython-312.pyc | Bin 0 -> 287 bytes .../__pycache__/trustedhost.cpython-312.pyc | Bin 0 -> 281 bytes .../__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 258 bytes .../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 | 1 + .../site-packages/fastapi/openapi/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 192 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 362 bytes .../openapi/__pycache__/docs.cpython-312.pyc | Bin 0 -> 10796 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 22799 bytes .../openapi/__pycache__/utils.cpython-312.pyc | Bin 0 -> 21165 bytes .../fastapi/openapi/constants.py | 3 + .../Lib/site-packages/fastapi/openapi/docs.py | 344 + .../site-packages/fastapi/openapi/models.py | 438 + .../site-packages/fastapi/openapi/utils.py | 567 ++ .../site-packages/fastapi/param_functions.py | 2369 +++++ .../venv/Lib/site-packages/fastapi/params.py | 755 ++ .../venv/Lib/site-packages/fastapi/py.typed | 0 .../Lib/site-packages/fastapi/requests.py | 2 + .../Lib/site-packages/fastapi/responses.py | 48 + .../venv/Lib/site-packages/fastapi/routing.py | 4508 +++++++++ .../fastapi/security/__init__.py | 15 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 849 bytes .../__pycache__/api_key.cpython-312.pyc | Bin 0 -> 10486 bytes .../security/__pycache__/base.cpython-312.pyc | Bin 0 -> 511 bytes .../security/__pycache__/http.cpython-312.pyc | Bin 0 -> 14539 bytes .../__pycache__/oauth2.cpython-312.pyc | Bin 0 -> 19252 bytes .../open_id_connect_url.cpython-312.pyc | Bin 0 -> 3765 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 595 bytes .../site-packages/fastapi/security/api_key.py | 318 + .../site-packages/fastapi/security/base.py | 6 + .../site-packages/fastapi/security/http.py | 423 + .../site-packages/fastapi/security/oauth2.py | 663 ++ .../fastapi/security/open_id_connect_url.py | 94 + .../site-packages/fastapi/security/utils.py | 10 + .../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 | 11 + .../venv/Lib/site-packages/fastapi/utils.py | 164 + .../Lib/site-packages/fastapi/websockets.py | 3 + .../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 + .../venv/Lib/site-packages/h11/__init__.py | 62 + .../h11/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1071 bytes .../h11/__pycache__/_abnf.cpython-312.pyc | Bin 0 -> 1777 bytes .../__pycache__/_connection.cpython-312.pyc | Bin 0 -> 23127 bytes .../h11/__pycache__/_events.cpython-312.pyc | Bin 0 -> 13217 bytes .../h11/__pycache__/_headers.cpython-312.pyc | Bin 0 -> 7979 bytes .../h11/__pycache__/_readers.cpython-312.pyc | Bin 0 -> 9644 bytes .../_receivebuffer.cpython-312.pyc | Bin 0 -> 4695 bytes .../h11/__pycache__/_state.cpython-312.pyc | Bin 0 -> 8459 bytes .../h11/__pycache__/_util.cpython-312.pyc | Bin 0 -> 4715 bytes .../h11/__pycache__/_version.cpython-312.pyc | Bin 0 -> 209 bytes .../h11/__pycache__/_writers.cpython-312.pyc | Bin 0 -> 6281 bytes backend/venv/Lib/site-packages/h11/_abnf.py | 132 + .../venv/Lib/site-packages/h11/_connection.py | 659 ++ backend/venv/Lib/site-packages/h11/_events.py | 369 + .../venv/Lib/site-packages/h11/_headers.py | 282 + .../venv/Lib/site-packages/h11/_readers.py | 250 + .../Lib/site-packages/h11/_receivebuffer.py | 153 + backend/venv/Lib/site-packages/h11/_state.py | 365 + backend/venv/Lib/site-packages/h11/_util.py | 135 + .../venv/Lib/site-packages/h11/_version.py | 16 + .../venv/Lib/site-packages/h11/_writers.py | 145 + backend/venv/Lib/site-packages/h11/py.typed | 1 + .../idna-3.11.dist-info/INSTALLER | 1 + .../idna-3.11.dist-info/METADATA | 209 + .../site-packages/idna-3.11.dist-info/RECORD | 22 + .../site-packages/idna-3.11.dist-info/WHEEL | 4 + .../idna-3.11.dist-info/licenses/LICENSE.md | 31 + .../venv/Lib/site-packages/idna/__init__.py | 45 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 879 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4969 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 883 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16136 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 100908 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2626 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 210 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 161838 bytes backend/venv/Lib/site-packages/idna/codec.py | 122 + backend/venv/Lib/site-packages/idna/compat.py | 15 + backend/venv/Lib/site-packages/idna/core.py | 437 + .../venv/Lib/site-packages/idna/idnadata.py | 4309 ++++++++ .../venv/Lib/site-packages/idna/intranges.py | 57 + .../Lib/site-packages/idna/package_data.py | 1 + backend/venv/Lib/site-packages/idna/py.typed | 0 .../venv/Lib/site-packages/idna/uts46data.py | 8841 +++++++++++++++++ .../Lib/site-packages/multipart/__init__.py | 24 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1426 bytes .../__pycache__/decoders.cpython-312.pyc | Bin 0 -> 233 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 237 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 235 bytes .../Lib/site-packages/multipart/decoders.py | 1 + .../Lib/site-packages/multipart/exceptions.py | 1 + .../Lib/site-packages/multipart/multipart.py | 1 + .../pip-25.0.1.dist-info/AUTHORS.txt | 806 ++ .../pip-25.0.1.dist-info/INSTALLER | 1 + .../pip-25.0.1.dist-info/LICENSE.txt | 20 + .../pip-25.0.1.dist-info/METADATA | 90 + .../site-packages/pip-25.0.1.dist-info/RECORD | 854 ++ .../pip-25.0.1.dist-info/REQUESTED | 0 .../site-packages/pip-25.0.1.dist-info/WHEEL | 5 + .../pip-25.0.1.dist-info/entry_points.txt | 3 + .../pip-25.0.1.dist-info/top_level.txt | 1 + .../venv/Lib/site-packages/pip/__init__.py | 13 + .../venv/Lib/site-packages/pip/__main__.py | 24 + .../Lib/site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 691 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 845 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2209 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 791 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14775 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12671 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17635 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 36849 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 674 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 5122 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10407 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13619 bytes .../site-packages/pip/_internal/build_env.py | 322 + .../Lib/site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 282 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8610 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10512 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30405 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1778 bytes .../__pycache__/index_command.cpython-312.pyc | Bin 0 -> 7185 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2304 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4910 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15044 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 3856 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 12245 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7837 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 379 bytes .../pip/_internal/cli/autocompletion.py | 176 + .../pip/_internal/cli/base_command.py | 240 + .../pip/_internal/cli/cmdoptions.py | 1075 ++ .../pip/_internal/cli/command_context.py | 27 + .../pip/_internal/cli/index_command.py | 171 + .../site-packages/pip/_internal/cli/main.py | 80 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 94 + .../pip/_internal/cli/req_command.py | 329 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4006 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9932 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2596 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5197 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13167 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10072 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7507 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4389 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2972 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1677 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6675 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3984 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 29096 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15761 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7522 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 10941 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4713 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8869 bytes .../pip/_internal/commands/cache.py | 228 + .../pip/_internal/commands/check.py | 67 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 146 + .../pip/_internal/commands/freeze.py | 109 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 784 ++ .../pip/_internal/commands/list.py | 375 + .../pip/_internal/commands/search.py | 172 + .../pip/_internal/commands/show.py | 224 + .../pip/_internal/commands/uninstall.py | 114 + .../pip/_internal/commands/wheel.py | 182 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 945 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2897 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1704 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8431 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2285 bytes .../pip/_internal/distributions/base.py | 53 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 158 + .../pip/_internal/distributions/wheel.py | 42 + .../site-packages/pip/_internal/exceptions.py | 809 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 236 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21621 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 41369 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12528 bytes .../pip/_internal/index/collector.py | 494 + .../pip/_internal/index/package_finder.py | 1029 ++ .../pip/_internal/index/sources.py | 284 + .../pip/_internal/locations/__init__.py | 456 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16444 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6795 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8032 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3785 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 214 + .../pip/_internal/locations/base.py | 81 + .../Lib/site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 128 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5871 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2971 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35202 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 16088 bytes .../pip/_internal/metadata/_json.py | 86 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 362 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 4495 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 12883 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11083 bytes .../_internal/metadata/importlib/_compat.py | 85 + .../_internal/metadata/importlib/_dists.py | 228 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 301 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 270 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1608 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 10848 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4227 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1698 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2281 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26987 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1027 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 4991 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1855 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4957 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 6556 bytes .../pip/_internal/models/candidate.py | 25 + .../pip/_internal/models/direct_url.py | 224 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 604 ++ .../pip/_internal/models/scheme.py | 25 + .../pip/_internal/models/search_scope.py | 127 + .../pip/_internal/models/selection_prefs.py | 53 + .../pip/_internal/models/target_python.py | 121 + .../pip/_internal/models/wheel.py | 118 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 258 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 22103 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 7050 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8483 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11611 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18910 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2259 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2953 bytes .../pip/_internal/network/auth.py | 566 ++ .../pip/_internal/network/cache.py | 118 + .../pip/_internal/network/download.py | 187 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 523 + .../pip/_internal/network/utils.py | 98 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 201 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7108 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10252 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25776 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 207 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7671 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1861 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1915 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3015 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1681 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2020 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3850 bytes .../operations/build/build_tracker.py | 138 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 42 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 181 + .../pip/_internal/operations/freeze.py | 256 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 270 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1802 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 34107 bytes .../operations/install/editable_legacy.py | 47 + .../pip/_internal/operations/install/wheel.py | 741 ++ .../pip/_internal/operations/prepare.py | 732 ++ .../site-packages/pip/_internal/pyproject.py | 185 + .../pip/_internal/req/__init__.py | 90 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3449 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21259 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 24242 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38474 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 5487 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 32098 bytes .../pip/_internal/req/constructors.py | 560 ++ .../pip/_internal/req/req_file.py | 623 ++ .../pip/_internal/req/req_install.py | 934 ++ .../pip/_internal/req/req_set.py | 82 + .../pip/_internal/req/req_uninstall.py | 633 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 201 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1189 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 208 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22583 bytes .../_internal/resolution/legacy/resolver.py | 597 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 212 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8153 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 29412 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32490 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6797 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10527 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 5044 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 15360 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12318 bytes .../_internal/resolution/resolvelib/base.py | 139 + .../resolution/resolvelib/candidates.py | 574 ++ .../resolution/resolvelib/factory.py | 823 ++ .../resolution/resolvelib/found_candidates.py | 174 + .../resolution/resolvelib/provider.py | 258 + .../resolution/resolvelib/reporter.py | 81 + .../resolution/resolvelib/requirements.py | 245 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 252 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4531 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1867 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2411 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2908 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 6351 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 685 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4192 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3537 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3207 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 3994 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7330 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1165 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2420 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7604 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13892 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 33227 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2661 bytes .../utils/__pycache__/retry.cpython-312.pyc | Bin 0 -> 2109 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4551 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8640 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12025 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 13499 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2078 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4467 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5904 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 79 + .../pip/_internal/utils/compatibility_tags.py | 188 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 124 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 149 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 101 + .../pip/_internal/utils/hashes.py | 147 + .../pip/_internal/utils/logging.py | 354 + .../site-packages/pip/_internal/utils/misc.py | 773 ++ .../pip/_internal/utils/packaging.py | 58 + .../pip/_internal/utils/retry.py | 42 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 245 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 337 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 535 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5056 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19021 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7609 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12528 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29001 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 527 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 688 ++ .../pip/_internal/wheel_builder.py | 354 + .../Lib/site-packages/pip/_vendor/__init__.py | 116 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4554 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 139456 bytes .../pip/_vendor/cachecontrol/__init__.py | 29 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 907 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2651 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6469 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3792 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16229 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4352 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6702 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 5266 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1679 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 161 + .../pip/_vendor/cachecontrol/cache.py | 75 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 440 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7749 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2738 bytes .../_vendor/cachecontrol/caches/file_cache.py | 182 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 500 + .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 323 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 650 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3216 bytes .../pip/_vendor/certifi/cacert.pem | 4929 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 114 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1274 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45531 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 65586 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24321 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 59866 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15081 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7659 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41565 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17317 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19758 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88040 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30349 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 52550 bytes .../pip/_vendor/distlib/compat.py | 1137 +++ .../pip/_vendor/distlib/database.py | 1329 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1295 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 162 + .../pip/_vendor/distlib/metadata.py | 1031 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 447 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 97792 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 0 -> 182784 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 108032 bytes .../site-packages/pip/_vendor/distlib/util.py | 1984 ++++ .../pip/_vendor/distlib/version.py | 750 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 91648 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 0 -> 168448 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 101888 bytes .../pip/_vendor/distlib/wheel.py | 1100 ++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 965 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 297 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53797 bytes .../pip/_vendor/distro/distro.py | 1403 +++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 45 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 891 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4981 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 895 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16126 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99481 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2638 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 222 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158851 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1744 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2030 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8298 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 41495 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 563 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 5028 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9716 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4559 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 13990 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3246 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7920 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 11379 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 27217 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4415 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 39047 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 23010 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 6640 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 20491 bytes .../pip/_vendor/packaging/_elffile.py | 110 + .../pip/_vendor/packaging/_manylinux.py | 263 + .../pip/_vendor/packaging/_musllinux.py | 85 + .../pip/_vendor/packaging/_parser.py | 354 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/_tokenizer.py | 194 + .../_vendor/packaging/licenses/__init__.py | 145 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4125 bytes .../__pycache__/_spdx.cpython-312.pyc | Bin 0 -> 47369 bytes .../pip/_vendor/packaging/licenses/_spdx.py | 759 ++ .../pip/_vendor/packaging/markers.py | 331 + .../pip/_vendor/packaging/metadata.py | 863 ++ .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 91 + .../pip/_vendor/packaging/specifiers.py | 1020 ++ .../pip/_vendor/packaging/tags.py | 617 ++ .../pip/_vendor/packaging/utils.py | 163 + .../pip/_vendor/packaging/version.py | 582 ++ .../pip/_vendor/pkg_resources/__init__.py | 3676 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161266 bytes .../pip/_vendor/platformdirs/__init__.py | 631 ++ .../pip/_vendor/platformdirs/__main__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 19852 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1953 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 10702 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 13309 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 8829 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 14695 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 602 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13679 bytes .../pip/_vendor/platformdirs/android.py | 249 + .../pip/_vendor/platformdirs/api.py | 298 + .../pip/_vendor/platformdirs/macos.py | 144 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 269 + .../pip/_vendor/platformdirs/version.py | 16 + .../pip/_vendor/platformdirs/windows.py | 272 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3494 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 740 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26590 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2634 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3227 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4726 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38367 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1565 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 2614 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4083 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4762 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 12104 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6699 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8195 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 32978 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 14075 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 70 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37917 bytes .../pip/_vendor/pygments/formatter.py | 129 + .../_vendor/pygments/formatters/__init__.py | 157 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6908 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4221 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4228 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7299 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 41032 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 28554 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6061 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 20131 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6883 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2964 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 13779 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9145 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5825 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15124 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 987 ++ .../pip/_vendor/pygments/formatters/img.py | 685 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 518 + .../pip/_vendor/pygments/formatters/other.py | 160 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 349 + .../pip/_vendor/pygments/formatters/svg.py | 185 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 963 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14627 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 68269 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42973 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 589 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2670 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 3654 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 753 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 18052 bytes .../pip/_vendor/pyproject_hooks/_impl.py | 410 + .../pyproject_hooks/_in_process/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1082 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 15320 bytes .../_in_process/_in_process.py | 389 + .../pip/_vendor/pyproject_hooks/py.typed | 0 .../pip/_vendor/requests/__init__.py | 179 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5259 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 590 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2030 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28437 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7197 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13927 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 684 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1683 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25204 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7604 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4234 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1057 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35434 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1272 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27852 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6029 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5629 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36372 bytes .../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 | 78 + .../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 | 1037 ++ .../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 | 1096 ++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 640 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6857 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2660 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25886 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10506 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 206 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 426 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 + .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 273 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7021 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10298 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7878 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205982 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1735 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2355 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 543 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 861 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12028 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4153 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1876 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3635 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5166 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 727 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6576 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13185 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 971 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 871 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28817 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2496 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3569 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 3332 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1614 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12397 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9087 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4278 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11844 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5566 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26558 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1707 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8590 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 114551 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2264 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9216 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10947 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10444 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1494 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4218 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1851 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3577 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3053 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9894 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6041 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5214 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20164 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19014 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4895 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 14070 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9573 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6384 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 6939 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1817 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5303 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12776 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40617 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 75740 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10383 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 16011 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1798 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 573 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6619 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6574 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3831 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2485 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28543 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6096 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6067 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33482 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2145 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 40190 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43889 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3354 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 61216 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6333 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 320 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 32898 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11799 bytes .../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 | 159 + .../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 | 312 + .../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 | 480 + .../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 | 2661 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 191 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 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 | 375 + .../pip/_vendor/rich/live_render.py | 112 + .../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 | 318 + .../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 | 138 + .../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 | 966 ++ .../site-packages/pip/_vendor/rich/table.py | 1007 ++ .../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 | 797 ++ .../site-packages/pip/_vendor/rich/tree.py | 257 + .../pip/_vendor/tomli/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 344 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 29358 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 4045 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 372 bytes .../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/truststore/__init__.py | 36 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1350 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 16779 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 18993 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2211 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1105 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15771 bytes .../pip/_vendor/truststore/_api.py | 316 + .../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/typing_extensions.py | 3641 +++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3411 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 16370 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 224 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20409 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36544 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13499 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10408 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4018 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20435 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7300 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33949 bytes .../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 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 204 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1854 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11570 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5720 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24454 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35507 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7517 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 221 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17433 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14769 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 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 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41261 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 215 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1831 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7342 bytes .../urllib3/packages/backports/makefile.py | 51 + .../packages/backports/weakref_finalize.py | 155 + .../pip/_vendor/urllib3/packages/six.py | 1076 ++ .../pip/_vendor/urllib3/poolmanager.py | 540 + .../pip/_vendor/urllib3/request.py | 191 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1152 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4753 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1558 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1358 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4189 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2998 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21728 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15370 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5057 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10759 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11145 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15791 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4409 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 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 | 18 + backend/venv/Lib/site-packages/pip/py.typed | 4 + .../pydantic-2.12.5.dist-info/INSTALLER | 1 + .../pydantic-2.12.5.dist-info/METADATA | 1029 ++ .../pydantic-2.12.5.dist-info/RECORD | 217 + .../pydantic-2.12.5.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../Lib/site-packages/pydantic/__init__.py | 456 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14425 bytes .../__pycache__/_migration.cpython-312.pyc | Bin 0 -> 11032 bytes .../alias_generators.cpython-312.pyc | Bin 0 -> 3282 bytes .../__pycache__/aliases.cpython-312.pyc | Bin 0 -> 6562 bytes .../annotated_handlers.cpython-312.pyc | Bin 0 -> 5496 bytes .../class_validators.cpython-312.pyc | Bin 0 -> 370 bytes .../__pycache__/color.cpython-312.pyc | Bin 0 -> 30176 bytes .../__pycache__/config.cpython-312.pyc | Bin 0 -> 7502 bytes .../__pycache__/dataclasses.cpython-312.pyc | Bin 0 -> 17329 bytes .../datetime_parse.cpython-312.pyc | Bin 0 -> 370 bytes .../__pycache__/decorator.cpython-312.pyc | Bin 0 -> 360 bytes .../__pycache__/env_settings.cpython-312.pyc | Bin 0 -> 366 bytes .../error_wrappers.cpython-312.pyc | Bin 0 -> 370 bytes .../__pycache__/errors.cpython-312.pyc | Bin 0 -> 7631 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 72927 bytes .../functional_serializers.cpython-312.pyc | Bin 0 -> 17933 bytes .../functional_validators.cpython-312.pyc | Bin 0 -> 34744 bytes .../__pycache__/generics.cpython-312.pyc | Bin 0 -> 358 bytes .../pydantic/__pycache__/json.cpython-312.pyc | Bin 0 -> 350 bytes .../__pycache__/json_schema.cpython-312.pyc | Bin 0 -> 120013 bytes .../pydantic/__pycache__/main.cpython-312.pyc | Bin 0 -> 77304 bytes .../pydantic/__pycache__/mypy.cpython-312.pyc | Bin 0 -> 61639 bytes .../__pycache__/networks.cpython-312.pyc | Bin 0 -> 50219 bytes .../__pycache__/parse.cpython-312.pyc | Bin 0 -> 352 bytes .../__pycache__/root_model.cpython-312.pyc | Bin 0 -> 7813 bytes .../__pycache__/schema.cpython-312.pyc | Bin 0 -> 354 bytes .../__pycache__/tools.cpython-312.pyc | Bin 0 -> 352 bytes .../__pycache__/type_adapter.cpython-312.pyc | Bin 0 -> 35549 bytes .../__pycache__/types.cpython-312.pyc | Bin 0 -> 96770 bytes .../__pycache__/typing.cpython-312.pyc | Bin 0 -> 350 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 352 bytes .../validate_call_decorator.cpython-312.pyc | Bin 0 -> 5448 bytes .../__pycache__/validators.cpython-312.pyc | Bin 0 -> 362 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 4798 bytes .../__pycache__/warnings.cpython-312.pyc | Bin 0 -> 7214 bytes .../pydantic/_internal/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../__pycache__/_config.cpython-312.pyc | Bin 0 -> 15674 bytes .../_core_metadata.cpython-312.pyc | Bin 0 -> 4615 bytes .../__pycache__/_core_utils.cpython-312.pyc | Bin 0 -> 7712 bytes .../__pycache__/_dataclasses.cpython-312.pyc | Bin 0 -> 13403 bytes .../__pycache__/_decorators.cpython-312.pyc | Bin 0 -> 36758 bytes .../_decorators_v1.cpython-312.pyc | Bin 0 -> 8615 bytes .../_discriminated_union.cpython-312.pyc | Bin 0 -> 20846 bytes .../_docs_extraction.cpython-312.pyc | Bin 0 -> 5308 bytes .../__pycache__/_fields.cpython-312.pyc | Bin 0 -> 24290 bytes .../__pycache__/_forward_ref.cpython-312.pyc | Bin 0 -> 1304 bytes .../_generate_schema.cpython-312.pyc | Bin 0 -> 130331 bytes .../__pycache__/_generics.cpython-312.pyc | Bin 0 -> 24331 bytes .../__pycache__/_git.cpython-312.pyc | Bin 0 -> 1510 bytes .../__pycache__/_import_utils.cpython-312.pyc | Bin 0 -> 823 bytes .../_internal_dataclass.cpython-312.pyc | Bin 0 -> 344 bytes .../_known_annotated_metadata.cpython-312.pyc | Bin 0 -> 14226 bytes .../__pycache__/_mock_val_ser.cpython-312.pyc | Bin 0 -> 11093 bytes .../_model_construction.cpython-312.pyc | Bin 0 -> 35105 bytes .../_namespace_utils.cpython-312.pyc | Bin 0 -> 12313 bytes .../__pycache__/_repr.cpython-312.pyc | Bin 0 -> 7853 bytes .../_schema_gather.cpython-312.pyc | Bin 0 -> 7640 bytes .../_schema_generation_shared.cpython-312.pyc | Bin 0 -> 6221 bytes .../__pycache__/_serializers.cpython-312.pyc | Bin 0 -> 2111 bytes .../__pycache__/_signature.cpython-312.pyc | Bin 0 -> 6761 bytes .../__pycache__/_typing_extra.cpython-312.pyc | Bin 0 -> 28180 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 19768 bytes .../_validate_call.cpython-312.pyc | Bin 0 -> 6982 bytes .../__pycache__/_validators.cpython-312.pyc | Bin 0 -> 22961 bytes .../pydantic/_internal/_config.py | 383 + .../pydantic/_internal/_core_metadata.py | 97 + .../pydantic/_internal/_core_utils.py | 174 + .../pydantic/_internal/_dataclasses.py | 315 + .../pydantic/_internal/_decorators.py | 858 ++ .../pydantic/_internal/_decorators_v1.py | 174 + .../_internal/_discriminated_union.py | 479 + .../pydantic/_internal/_docs_extraction.py | 113 + .../pydantic/_internal/_fields.py | 635 ++ .../pydantic/_internal/_forward_ref.py | 23 + .../pydantic/_internal/_generate_schema.py | 2867 ++++++ .../pydantic/_internal/_generics.py | 543 + .../site-packages/pydantic/_internal/_git.py | 27 + .../pydantic/_internal/_import_utils.py | 20 + .../pydantic/_internal/_internal_dataclass.py | 7 + .../_internal/_known_annotated_metadata.py | 401 + .../pydantic/_internal/_mock_val_ser.py | 228 + .../pydantic/_internal/_model_construction.py | 848 ++ .../pydantic/_internal/_namespace_utils.py | 293 + .../site-packages/pydantic/_internal/_repr.py | 124 + .../pydantic/_internal/_schema_gather.py | 209 + .../_internal/_schema_generation_shared.py | 125 + .../pydantic/_internal/_serializers.py | 53 + .../pydantic/_internal/_signature.py | 188 + .../pydantic/_internal/_typing_extra.py | 760 ++ .../pydantic/_internal/_utils.py | 446 + .../pydantic/_internal/_validate_call.py | 140 + .../pydantic/_internal/_validators.py | 533 + .../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 | 1288 +++ .../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 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../class_validators.cpython-312.pyc | Bin 0 -> 11754 bytes .../__pycache__/config.cpython-312.pyc | Bin 0 -> 4073 bytes .../copy_internals.cpython-312.pyc | Bin 0 -> 8660 bytes .../__pycache__/decorator.cpython-312.pyc | Bin 0 -> 14024 bytes .../__pycache__/json.cpython-312.pyc | Bin 0 -> 6172 bytes .../__pycache__/parse.cpython-312.pyc | Bin 0 -> 3402 bytes .../__pycache__/tools.cpython-312.pyc | Bin 0 -> 3538 bytes .../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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 310 bytes .../arguments_schema.cpython-312.pyc | Bin 0 -> 2402 bytes .../missing_sentinel.cpython-312.pyc | Bin 0 -> 351 bytes .../__pycache__/pipeline.cpython-312.pyc | Bin 0 -> 34459 bytes .../pydantic/experimental/arguments_schema.py | 44 + .../pydantic/experimental/missing_sentinel.py | 5 + .../pydantic/experimental/pipeline.py | 654 ++ .../venv/Lib/site-packages/pydantic/fields.py | 1834 ++++ .../pydantic/functional_serializers.py | 451 + .../pydantic/functional_validators.py | 893 ++ .../Lib/site-packages/pydantic/generics.py | 5 + .../venv/Lib/site-packages/pydantic/json.py | 5 + .../Lib/site-packages/pydantic/json_schema.py | 2854 ++++++ .../venv/Lib/site-packages/pydantic/main.py | 1819 ++++ .../venv/Lib/site-packages/pydantic/mypy.py | 1374 +++ .../Lib/site-packages/pydantic/networks.py | 1331 +++ .../venv/Lib/site-packages/pydantic/parse.py | 5 + .../site-packages/pydantic/plugin/__init__.py | 193 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 8938 bytes .../__pycache__/_loader.cpython-312.pyc | Bin 0 -> 2428 bytes .../_schema_validator.cpython-312.pyc | Bin 0 -> 6916 bytes .../site-packages/pydantic/plugin/_loader.py | 58 + .../pydantic/plugin/_schema_validator.py | 140 + .../venv/Lib/site-packages/pydantic/py.typed | 0 .../Lib/site-packages/pydantic/root_model.py | 155 + .../venv/Lib/site-packages/pydantic/schema.py | 5 + .../venv/Lib/site-packages/pydantic/tools.py | 5 + .../site-packages/pydantic/type_adapter.py | 795 ++ .../venv/Lib/site-packages/pydantic/types.py | 3295 ++++++ .../venv/Lib/site-packages/pydantic/typing.py | 5 + .../venv/Lib/site-packages/pydantic/utils.py | 5 + .../Lib/site-packages/pydantic/v1/__init__.py | 142 + .../v1/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2517 bytes .../_hypothesis_plugin.cpython-312.pyc | Bin 0 -> 20504 bytes .../annotated_types.cpython-312.pyc | Bin 0 -> 3883 bytes .../class_validators.cpython-312.pyc | Bin 0 -> 19643 bytes .../v1/__pycache__/color.cpython-312.pyc | Bin 0 -> 25849 bytes .../v1/__pycache__/config.cpython-312.pyc | Bin 0 -> 8398 bytes .../__pycache__/dataclasses.cpython-312.pyc | Bin 0 -> 22743 bytes .../datetime_parse.cpython-312.pyc | Bin 0 -> 10351 bytes .../v1/__pycache__/decorator.cpython-312.pyc | Bin 0 -> 13916 bytes .../__pycache__/env_settings.cpython-312.pyc | Bin 0 -> 17718 bytes .../error_wrappers.cpython-312.pyc | Bin 0 -> 8926 bytes .../v1/__pycache__/errors.cpython-312.pyc | Bin 0 -> 29601 bytes .../v1/__pycache__/fields.cpython-312.pyc | Bin 0 -> 57441 bytes .../v1/__pycache__/generics.cpython-312.pyc | Bin 0 -> 16991 bytes .../v1/__pycache__/json.cpython-312.pyc | Bin 0 -> 5209 bytes .../v1/__pycache__/main.cpython-312.pyc | Bin 0 -> 48215 bytes .../v1/__pycache__/mypy.cpython-312.pyc | Bin 0 -> 46357 bytes .../v1/__pycache__/networks.cpython-312.pyc | Bin 0 -> 29548 bytes .../v1/__pycache__/parse.cpython-312.pyc | Bin 0 -> 2746 bytes .../v1/__pycache__/schema.cpython-312.pyc | Bin 0 -> 48474 bytes .../v1/__pycache__/tools.cpython-312.pyc | Bin 0 -> 3879 bytes .../v1/__pycache__/types.cpython-312.pyc | Bin 0 -> 48486 bytes .../v1/__pycache__/typing.cpython-312.pyc | Bin 0 -> 22629 bytes .../v1/__pycache__/utils.cpython-312.pyc | Bin 0 -> 35236 bytes .../v1/__pycache__/validators.cpython-312.pyc | Bin 0 -> 30894 bytes .../v1/__pycache__/version.cpython-312.pyc | Bin 0 -> 1957 bytes .../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 | 1113 +++ .../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 | 614 ++ .../Lib/site-packages/pydantic/v1/utils.py | 806 ++ .../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.41.5.dist-info/INSTALLER | 1 + .../pydantic_core-2.41.5.dist-info/METADATA | 180 + .../pydantic_core-2.41.5.dist-info/RECORD | 12 + .../pydantic_core-2.41.5.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../site-packages/pydantic_core/__init__.py | 171 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3151 bytes .../__pycache__/core_schema.cpython-312.pyc | Bin 0 -> 155157 bytes .../_pydantic_core.cp312-win_amd64.pyd | Bin 0 -> 5436928 bytes .../pydantic_core/_pydantic_core.pyi | 1046 ++ .../pydantic_core/core_schema.py | 4435 +++++++++ .../Lib/site-packages/pydantic_core/py.typed | 0 .../python_dotenv-1.2.1.dist-info/INSTALLER | 1 + .../python_dotenv-1.2.1.dist-info/METADATA | 749 ++ .../python_dotenv-1.2.1.dist-info/RECORD | 26 + .../python_dotenv-1.2.1.dist-info/REQUESTED | 0 .../python_dotenv-1.2.1.dist-info/WHEEL | 5 + .../entry_points.txt | 2 + .../licenses/LICENSE | 27 + .../top_level.txt | 1 + .../INSTALLER | 1 + .../METADATA | 40 + .../python_multipart-0.0.21.dist-info/RECORD | 23 + .../REQUESTED | 0 .../python_multipart-0.0.21.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 14 + .../python_multipart/__init__.py | 25 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 585 bytes .../__pycache__/decoders.cpython-312.pyc | Bin 0 -> 8363 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 1754 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 67719 bytes .../python_multipart/decoders.py | 185 + .../python_multipart/exceptions.py | 34 + .../python_multipart/multipart.py | 1872 ++++ .../site-packages/python_multipart/py.typed | 0 .../requests-2.32.5.dist-info/INSTALLER | 1 + .../requests-2.32.5.dist-info/METADATA | 133 + .../requests-2.32.5.dist-info/RECORD | 43 + .../requests-2.32.5.dist-info/REQUESTED | 0 .../requests-2.32.5.dist-info/WHEEL | 5 + .../licenses/LICENSE | 175 + .../requests-2.32.5.dist-info/top_level.txt | 1 + .../Lib/site-packages/requests/__init__.py | 184 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5414 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 578 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2018 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 27799 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7185 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13915 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 660 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 2369 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25192 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7579 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4321 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1045 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35445 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1112 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27848 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6017 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5617 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36096 bytes .../Lib/site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 50 + .../Lib/site-packages/requests/adapters.py | 696 ++ .../venv/Lib/site-packages/requests/api.py | 157 + .../venv/Lib/site-packages/requests/auth.py | 314 + .../venv/Lib/site-packages/requests/certs.py | 17 + .../venv/Lib/site-packages/requests/compat.py | 106 + .../Lib/site-packages/requests/cookies.py | 561 ++ .../Lib/site-packages/requests/exceptions.py | 151 + .../venv/Lib/site-packages/requests/help.py | 134 + .../venv/Lib/site-packages/requests/hooks.py | 33 + .../venv/Lib/site-packages/requests/models.py | 1039 ++ .../Lib/site-packages/requests/packages.py | 23 + .../Lib/site-packages/requests/sessions.py | 831 ++ .../site-packages/requests/status_codes.py | 128 + .../Lib/site-packages/requests/structures.py | 99 + .../venv/Lib/site-packages/requests/utils.py | 1086 ++ .../starlette-0.50.0.dist-info/INSTALLER | 1 + .../starlette-0.50.0.dist-info/METADATA | 177 + .../starlette-0.50.0.dist-info/RECORD | 74 + .../starlette-0.50.0.dist-info/WHEEL | 4 + .../licenses/LICENSE.md | 27 + .../Lib/site-packages/starlette/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 213 bytes .../_exception_handler.cpython-312.pyc | Bin 0 -> 3072 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 5119 bytes .../__pycache__/applications.cpython-312.pyc | Bin 0 -> 12883 bytes .../authentication.cpython-312.pyc | Bin 0 -> 7714 bytes .../__pycache__/background.cpython-312.pyc | Bin 0 -> 2534 bytes .../__pycache__/concurrency.cpython-312.pyc | Bin 0 -> 3174 bytes .../__pycache__/config.cpython-312.pyc | Bin 0 -> 7512 bytes .../__pycache__/convertors.cpython-312.pyc | Bin 0 -> 4765 bytes .../datastructures.cpython-312.pyc | Bin 0 -> 39499 bytes .../__pycache__/endpoints.cpython-312.pyc | Bin 0 -> 7954 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2397 bytes .../__pycache__/formparsers.cpython-312.pyc | Bin 0 -> 14269 bytes .../__pycache__/requests.cpython-312.pyc | Bin 0 -> 16338 bytes .../__pycache__/responses.cpython-312.pyc | Bin 0 -> 30230 bytes .../__pycache__/routing.cpython-312.pyc | Bin 0 -> 43924 bytes .../__pycache__/schemas.cpython-312.pyc | Bin 0 -> 7064 bytes .../__pycache__/staticfiles.cpython-312.pyc | Bin 0 -> 11540 bytes .../__pycache__/status.cpython-312.pyc | Bin 0 -> 5183 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9985 bytes .../__pycache__/testclient.cpython-312.pyc | Bin 0 -> 33134 bytes .../__pycache__/types.cpython-312.pyc | Bin 0 -> 1318 bytes .../__pycache__/websockets.cpython-312.pyc | Bin 0 -> 11822 bytes .../starlette/_exception_handler.py | 65 + .../Lib/site-packages/starlette/_utils.py | 103 + .../site-packages/starlette/applications.py | 244 + .../site-packages/starlette/authentication.py | 142 + .../Lib/site-packages/starlette/background.py | 36 + .../site-packages/starlette/concurrency.py | 57 + .../Lib/site-packages/starlette/config.py | 140 + .../Lib/site-packages/starlette/convertors.py | 89 + .../site-packages/starlette/datastructures.py | 691 ++ .../Lib/site-packages/starlette/endpoints.py | 123 + .../Lib/site-packages/starlette/exceptions.py | 33 + .../site-packages/starlette/formparsers.py | 276 + .../starlette/middleware/__init__.py | 37 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2537 bytes .../authentication.cpython-312.pyc | Bin 0 -> 2897 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 11800 bytes .../__pycache__/cors.cpython-312.pyc | Bin 0 -> 7458 bytes .../__pycache__/errors.cpython-312.pyc | Bin 0 -> 9937 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 4103 bytes .../__pycache__/gzip.cpython-312.pyc | Bin 0 -> 8792 bytes .../__pycache__/httpsredirect.cpython-312.pyc | Bin 0 -> 1772 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 4665 bytes .../__pycache__/trustedhost.cpython-312.pyc | Bin 0 -> 3138 bytes .../__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 8536 bytes .../starlette/middleware/authentication.py | 52 + .../starlette/middleware/base.py | 244 + .../starlette/middleware/cors.py | 172 + .../starlette/middleware/errors.py | 259 + .../starlette/middleware/exceptions.py | 73 + .../starlette/middleware/gzip.py | 145 + .../starlette/middleware/httpsredirect.py | 19 + .../starlette/middleware/sessions.py | 85 + .../starlette/middleware/trustedhost.py | 60 + .../starlette/middleware/wsgi.py | 153 + .../venv/Lib/site-packages/starlette/py.typed | 0 .../Lib/site-packages/starlette/requests.py | 324 + .../Lib/site-packages/starlette/responses.py | 566 ++ .../Lib/site-packages/starlette/routing.py | 876 ++ .../Lib/site-packages/starlette/schemas.py | 148 + .../site-packages/starlette/staticfiles.py | 217 + .../Lib/site-packages/starlette/status.py | 209 + .../Lib/site-packages/starlette/templating.py | 217 + .../Lib/site-packages/starlette/testclient.py | 739 ++ .../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 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 194 bytes .../__pycache__/introspection.cpython-312.pyc | Bin 0 -> 17791 bytes .../typing_objects.cpython-312.pyc | Bin 0 -> 17370 bytes .../typing_inspection/introspection.py | 587 ++ .../site-packages/typing_inspection/py.typed | 0 .../typing_inspection/typing_objects.py | 607 ++ .../typing_inspection/typing_objects.pyi | 417 + .../urllib3-2.6.2.dist-info/INSTALLER | 1 + .../urllib3-2.6.2.dist-info/METADATA | 156 + .../urllib3-2.6.2.dist-info/RECORD | 79 + .../urllib3-2.6.2.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 21 + .../Lib/site-packages/urllib3/__init__.py | 211 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7309 bytes .../_base_connection.cpython-312.pyc | Bin 0 -> 6859 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 22890 bytes .../_request_methods.cpython-312.pyc | Bin 0 -> 10601 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 792 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 38900 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 39729 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 16610 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 12003 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 3478 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 24294 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 57414 bytes .../site-packages/urllib3/_base_connection.py | 165 + .../Lib/site-packages/urllib3/_collections.py | 487 + .../site-packages/urllib3/_request_methods.py | 278 + .../Lib/site-packages/urllib3/_version.py | 34 + .../Lib/site-packages/urllib3/connection.py | 1099 ++ .../site-packages/urllib3/connectionpool.py | 1178 +++ .../site-packages/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 192 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 28216 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 8170 bytes .../urllib3/contrib/emscripten/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 900 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 10306 bytes .../__pycache__/fetch.cpython-312.pyc | Bin 0 -> 28638 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 1420 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 12208 bytes .../urllib3/contrib/emscripten/connection.py | 259 + .../emscripten/emscripten_fetch_worker.js | 110 + .../urllib3/contrib/emscripten/fetch.py | 726 ++ .../urllib3/contrib/emscripten/request.py | 22 + .../urllib3/contrib/emscripten/response.py | 277 + .../urllib3/contrib/pyopenssl.py | 564 ++ .../site-packages/urllib3/contrib/socks.py | 228 + .../Lib/site-packages/urllib3/exceptions.py | 335 + .../venv/Lib/site-packages/urllib3/fields.py | 341 + .../Lib/site-packages/urllib3/filepost.py | 89 + .../site-packages/urllib3/http2/__init__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1745 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 16966 bytes .../http2/__pycache__/probe.cpython-312.pyc | Bin 0 -> 3656 bytes .../site-packages/urllib3/http2/connection.py | 356 + .../Lib/site-packages/urllib3/http2/probe.py | 87 + .../Lib/site-packages/urllib3/poolmanager.py | 651 ++ .../venv/Lib/site-packages/urllib3/py.typed | 2 + .../Lib/site-packages/urllib3/response.py | 1476 +++ .../site-packages/urllib3/util/__init__.py | 42 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1005 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4686 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1217 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 8341 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2876 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 20291 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 17305 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5537 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 13305 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11689 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 16220 bytes .../util/__pycache__/util.cpython-312.pyc | Bin 0 -> 1994 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 3440 bytes .../site-packages/urllib3/util/connection.py | 137 + .../Lib/site-packages/urllib3/util/proxy.py | 43 + .../Lib/site-packages/urllib3/util/request.py | 263 + .../site-packages/urllib3/util/response.py | 101 + .../Lib/site-packages/urllib3/util/retry.py | 533 + .../Lib/site-packages/urllib3/util/ssl_.py | 527 + .../urllib3/util/ssl_match_hostname.py | 159 + .../urllib3/util/ssltransport.py | 271 + .../Lib/site-packages/urllib3/util/timeout.py | 275 + .../Lib/site-packages/urllib3/util/url.py | 469 + .../Lib/site-packages/urllib3/util/util.py | 42 + .../Lib/site-packages/urllib3/util/wait.py | 124 + .../uvicorn-0.40.0.dist-info/INSTALLER | 1 + .../uvicorn-0.40.0.dist-info/METADATA | 191 + .../uvicorn-0.40.0.dist-info/RECORD | 89 + .../uvicorn-0.40.0.dist-info/REQUESTED | 0 .../uvicorn-0.40.0.dist-info/WHEEL | 4 + .../uvicorn-0.40.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 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 382 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 302 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 4000 bytes .../__pycache__/_subprocess.cpython-312.pyc | Bin 0 -> 2945 bytes .../__pycache__/_types.cpython-312.pyc | Bin 0 -> 11413 bytes .../__pycache__/config.cpython-312.pyc | Bin 0 -> 25902 bytes .../__pycache__/importer.cpython-312.pyc | Bin 0 -> 1775 bytes .../__pycache__/logging.cpython-312.pyc | Bin 0 -> 7784 bytes .../uvicorn/__pycache__/main.cpython-312.pyc | Bin 0 -> 20995 bytes .../__pycache__/server.cpython-312.pyc | Bin 0 -> 16706 bytes .../__pycache__/workers.cpython-312.pyc | Bin 0 -> 6563 bytes .../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 | 549 + .../Lib/site-packages/uvicorn/importer.py | 34 + .../uvicorn/lifespan/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 193 bytes .../lifespan/__pycache__/off.cpython-312.pyc | Bin 0 -> 982 bytes .../lifespan/__pycache__/on.cpython-312.pyc | Bin 0 -> 7941 bytes .../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 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../loops/__pycache__/asyncio.cpython-312.pyc | Bin 0 -> 722 bytes .../loops/__pycache__/auto.cpython-312.pyc | Bin 0 -> 822 bytes .../loops/__pycache__/uvloop.cpython-312.pyc | Bin 0 -> 579 bytes .../site-packages/uvicorn/loops/asyncio.py | 11 + .../Lib/site-packages/uvicorn/loops/auto.py | 17 + .../Lib/site-packages/uvicorn/loops/uvloop.py | 10 + .../venv/Lib/site-packages/uvicorn/main.py | 618 ++ .../uvicorn/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../__pycache__/asgi2.cpython-312.pyc | Bin 0 -> 1005 bytes .../message_logger.cpython-312.pyc | Bin 0 -> 4396 bytes .../__pycache__/proxy_headers.cpython-312.pyc | Bin 0 -> 5815 bytes .../__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 9936 bytes .../site-packages/uvicorn/middleware/asgi2.py | 15 + .../uvicorn/middleware/message_logger.py | 87 + .../uvicorn/middleware/proxy_headers.py | 142 + .../site-packages/uvicorn/middleware/wsgi.py | 199 + .../uvicorn/protocols/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 194 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 2965 bytes .../uvicorn/protocols/http/__init__.py | 0 .../http/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 199 bytes .../http/__pycache__/auto.cpython-312.pyc | Bin 0 -> 610 bytes .../__pycache__/flow_control.cpython-312.pyc | Bin 0 -> 3040 bytes .../http/__pycache__/h11_impl.cpython-312.pyc | Bin 0 -> 27181 bytes .../httptools_impl.cpython-312.pyc | Bin 0 -> 29184 bytes .../uvicorn/protocols/http/auto.py | 15 + .../uvicorn/protocols/http/flow_control.py | 54 + .../uvicorn/protocols/http/h11_impl.py | 550 + .../uvicorn/protocols/http/httptools_impl.py | 577 ++ .../site-packages/uvicorn/protocols/utils.py | 56 + .../uvicorn/protocols/websockets/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/auto.cpython-312.pyc | Bin 0 -> 814 bytes .../websockets_impl.cpython-312.pyc | Bin 0 -> 20304 bytes .../websockets_sansio_impl.cpython-312.pyc | Bin 0 -> 24383 bytes .../__pycache__/wsproto_impl.cpython-312.pyc | Bin 0 -> 20876 bytes .../uvicorn/protocols/websockets/auto.py | 21 + .../protocols/websockets/websockets_impl.py | 384 + .../websockets/websockets_sansio_impl.py | 415 + .../protocols/websockets/wsproto_impl.py | 375 + .../venv/Lib/site-packages/uvicorn/py.typed | 1 + .../venv/Lib/site-packages/uvicorn/server.py | 338 + .../uvicorn/supervisors/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 759 bytes .../__pycache__/basereload.cpython-312.pyc | Bin 0 -> 7031 bytes .../__pycache__/multiprocess.cpython-312.pyc | Bin 0 -> 13450 bytes .../__pycache__/statreload.cpython-312.pyc | Bin 0 -> 2825 bytes .../watchfilesreload.cpython-312.pyc | Bin 0 -> 4245 bytes .../uvicorn/supervisors/basereload.py | 125 + .../uvicorn/supervisors/multiprocess.py | 223 + .../uvicorn/supervisors/statreload.py | 52 + .../uvicorn/supervisors/watchfilesreload.py | 85 + .../venv/Lib/site-packages/uvicorn/workers.py | 111 + backend/venv/Scripts/Activate.ps1 | 528 + backend/venv/Scripts/activate | 76 + backend/venv/Scripts/activate.bat | 34 + backend/venv/Scripts/deactivate.bat | 22 + backend/venv/Scripts/dotenv.exe | Bin 0 -> 108416 bytes backend/venv/Scripts/fastapi.exe | Bin 0 -> 108414 bytes backend/venv/Scripts/normalizer.exe | Bin 0 -> 108437 bytes backend/venv/Scripts/pip.exe | Bin 0 -> 108425 bytes backend/venv/Scripts/pip3.12.exe | Bin 0 -> 108425 bytes backend/venv/Scripts/pip3.exe | Bin 0 -> 108425 bytes backend/venv/Scripts/python.exe | Bin 0 -> 274424 bytes backend/venv/Scripts/pythonw.exe | Bin 0 -> 263400 bytes backend/venv/Scripts/uvicorn.exe | Bin 0 -> 108415 bytes backend/venv/pyvenv.cfg | 5 + mobile_app/analysis.txt | 24 + mobile_app/analysis_2.txt | 19 + mobile_app/analysis_3.txt | 18 + mobile_app/analysis_errors.txt | 22 + mobile_app/analysis_errors_2.txt | 32 + mobile_app/analysis_final.txt | 21 + mobile_app/analysis_final_2.txt | 21 + mobile_app/analysis_results.txt | 49 + mobile_app/analysis_results_2.txt | 19 + mobile_app/android/gradle.properties | 4 +- mobile_app/emulators.txt | 12 + mobile_app/lib/api_service.dart | 134 +- mobile_app/lib/main.dart | 9 +- mobile_app/lib/models/channel.dart | 94 + mobile_app/lib/models/product.dart | 415 + mobile_app/lib/models/store.dart | 29 + mobile_app/lib/profile_manager.dart | 106 +- .../lib/screens/product_editor_screen.dart | 341 +- .../lib/screens/product_list_screen.dart | 385 +- mobile_app/lib/screens/profile_screen.dart | 114 + ...creen.dart => store_dashboard_screen.dart} | 39 +- ...e_screen.dart => store_editor_screen.dart} | 63 +- .../lib/screens/variation_editor_screen.dart | 344 + mobile_app/lib/services/platform_service.dart | 10 + mobile_app/lib/services/square_service.dart | 70 + mobile_app/lib/utils/metadata_helper.dart | 83 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + mobile_app/pubspec.lock | 32 + mobile_app/pubspec.yaml | 1 + .../woocommerce_variation_response.json | 1509 +++ 1862 files changed, 313812 insertions(+), 244 deletions(-) create mode 100644 backend/debug.log create mode 100644 backend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/annotated_doc/__init__.py create mode 100644 backend/venv/Lib/site-packages/annotated_doc/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/annotated_doc/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/annotated_doc/main.py create mode 100644 backend/venv/Lib/site-packages/annotated_doc/py.typed create mode 100644 backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/annotated_types/__init__.py create mode 100644 backend/venv/Lib/site-packages/annotated_types/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/annotated_types/__pycache__/test_cases.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/annotated_types/py.typed create mode 100644 backend/venv/Lib/site-packages/annotated_types/test_cases.py create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/anyio/__init__.py create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/from_thread.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/functools.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/lowlevel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/pytest_plugin.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/to_interpreter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/to_process.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/__pycache__/to_thread.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/__init__.py create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/__pycache__/_trio.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/_asyncio.py create mode 100644 backend/venv/Lib/site-packages/anyio/_backends/_trio.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__init__.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_contextmanagers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_eventloop.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_fileio.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_resources.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_signals.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_sockets.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_streams.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_synchronization.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_tasks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_tempfile.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_testing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/__pycache__/_typedattr.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_contextmanagers.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_eventloop.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_exceptions.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_fileio.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_resources.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_signals.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_sockets.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_streams.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_subprocesses.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_synchronization.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_tasks.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_tempfile.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_testing.py create mode 100644 backend/venv/Lib/site-packages/anyio/_core/_typedattr.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__init__.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_eventloop.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_resources.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_sockets.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_streams.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_tasks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/__pycache__/_testing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_eventloop.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_resources.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_sockets.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_streams.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_subprocesses.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_tasks.py create mode 100644 backend/venv/Lib/site-packages/anyio/abc/_testing.py create mode 100644 backend/venv/Lib/site-packages/anyio/from_thread.py create mode 100644 backend/venv/Lib/site-packages/anyio/functools.py create mode 100644 backend/venv/Lib/site-packages/anyio/lowlevel.py create mode 100644 backend/venv/Lib/site-packages/anyio/py.typed create mode 100644 backend/venv/Lib/site-packages/anyio/pytest_plugin.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__init__.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/buffered.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/file.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/memory.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/stapled.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/text.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/__pycache__/tls.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/anyio/streams/buffered.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/file.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/memory.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/stapled.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/text.py create mode 100644 backend/venv/Lib/site-packages/anyio/streams/tls.py create mode 100644 backend/venv/Lib/site-packages/anyio/to_interpreter.py create mode 100644 backend/venv/Lib/site-packages/anyio/to_process.py create mode 100644 backend/venv/Lib/site-packages/anyio/to_thread.py create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/certifi/__init__.py create mode 100644 backend/venv/Lib/site-packages/certifi/__main__.py create mode 100644 backend/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/certifi/__pycache__/core.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/certifi/cacert.pem create mode 100644 backend/venv/Lib/site-packages/certifi/core.py create mode 100644 backend/venv/Lib/site-packages/certifi/py.typed create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__init__.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__main__.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/api.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/cd.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/cli/__init__.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/cli/__main__.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/constant.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/legacy.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/md.cp312-win_amd64.pyd create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/md.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/md__mypyc.cp312-win_amd64.pyd create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/models.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/py.typed create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/utils.py create mode 100644 backend/venv/Lib/site-packages/charset_normalizer/version.py create mode 100644 backend/venv/Lib/site-packages/click-8.3.1.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/click-8.3.1.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/click-8.3.1.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/click/__init__.py create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/decorators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/globals.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/click/_compat.py create mode 100644 backend/venv/Lib/site-packages/click/_termui_impl.py create mode 100644 backend/venv/Lib/site-packages/click/_textwrap.py create mode 100644 backend/venv/Lib/site-packages/click/_utils.py create mode 100644 backend/venv/Lib/site-packages/click/_winconsole.py create mode 100644 backend/venv/Lib/site-packages/click/core.py create mode 100644 backend/venv/Lib/site-packages/click/decorators.py create mode 100644 backend/venv/Lib/site-packages/click/exceptions.py create mode 100644 backend/venv/Lib/site-packages/click/formatting.py create mode 100644 backend/venv/Lib/site-packages/click/globals.py create mode 100644 backend/venv/Lib/site-packages/click/parser.py create mode 100644 backend/venv/Lib/site-packages/click/py.typed create mode 100644 backend/venv/Lib/site-packages/click/shell_completion.py create mode 100644 backend/venv/Lib/site-packages/click/termui.py create mode 100644 backend/venv/Lib/site-packages/click/testing.py create mode 100644 backend/venv/Lib/site-packages/click/types.py create mode 100644 backend/venv/Lib/site-packages/click/utils.py create mode 100644 backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/colorama/__init__.py create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/ansi.py create mode 100644 backend/venv/Lib/site-packages/colorama/ansitowin32.py create mode 100644 backend/venv/Lib/site-packages/colorama/initialise.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__init__.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/colorama/tests/ansi_test.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/ansitowin32_test.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/initialise_test.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/isatty_test.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/utils.py create mode 100644 backend/venv/Lib/site-packages/colorama/tests/winterm_test.py create mode 100644 backend/venv/Lib/site-packages/colorama/win32.py create mode 100644 backend/venv/Lib/site-packages/colorama/winterm.py create mode 100644 backend/venv/Lib/site-packages/dotenv/__init__.py create mode 100644 backend/venv/Lib/site-packages/dotenv/__main__.py create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/cli.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/ipython.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/variables.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/dotenv/cli.py create mode 100644 backend/venv/Lib/site-packages/dotenv/ipython.py create mode 100644 backend/venv/Lib/site-packages/dotenv/main.py create mode 100644 backend/venv/Lib/site-packages/dotenv/parser.py create mode 100644 backend/venv/Lib/site-packages/dotenv/py.typed create mode 100644 backend/venv/Lib/site-packages/dotenv/variables.py create mode 100644 backend/venv/Lib/site-packages/dotenv/version.py create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/fastapi/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/__main__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/applications.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/background.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/cli.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/concurrency.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/logger.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/params.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/requests.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/responses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/routing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/staticfiles.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/templating.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/__pycache__/websockets.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/shared.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/v2.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/shared.py create mode 100644 backend/venv/Lib/site-packages/fastapi/_compat/v2.py create mode 100644 backend/venv/Lib/site-packages/fastapi/applications.py create mode 100644 backend/venv/Lib/site-packages/fastapi/background.py create mode 100644 backend/venv/Lib/site-packages/fastapi/cli.py create mode 100644 backend/venv/Lib/site-packages/fastapi/concurrency.py create mode 100644 backend/venv/Lib/site-packages/fastapi/datastructures.py create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/models.py create mode 100644 backend/venv/Lib/site-packages/fastapi/dependencies/utils.py create mode 100644 backend/venv/Lib/site-packages/fastapi/encoders.py create mode 100644 backend/venv/Lib/site-packages/fastapi/exception_handlers.py create mode 100644 backend/venv/Lib/site-packages/fastapi/exceptions.py create mode 100644 backend/venv/Lib/site-packages/fastapi/logger.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/asyncexitstack.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/cors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/gzip.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/wsgi.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/asyncexitstack.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/cors.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/gzip.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/trustedhost.py create mode 100644 backend/venv/Lib/site-packages/fastapi/middleware/wsgi.py create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/constants.py create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/docs.py create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/models.py create mode 100644 backend/venv/Lib/site-packages/fastapi/openapi/utils.py create mode 100644 backend/venv/Lib/site-packages/fastapi/param_functions.py create mode 100644 backend/venv/Lib/site-packages/fastapi/params.py create mode 100644 backend/venv/Lib/site-packages/fastapi/py.typed create mode 100644 backend/venv/Lib/site-packages/fastapi/requests.py create mode 100644 backend/venv/Lib/site-packages/fastapi/responses.py create mode 100644 backend/venv/Lib/site-packages/fastapi/routing.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__init__.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/api_key.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/http.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/oauth2.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/fastapi/security/api_key.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/base.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/http.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/oauth2.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py create mode 100644 backend/venv/Lib/site-packages/fastapi/security/utils.py create mode 100644 backend/venv/Lib/site-packages/fastapi/staticfiles.py create mode 100644 backend/venv/Lib/site-packages/fastapi/templating.py create mode 100644 backend/venv/Lib/site-packages/fastapi/testclient.py create mode 100644 backend/venv/Lib/site-packages/fastapi/types.py create mode 100644 backend/venv/Lib/site-packages/fastapi/utils.py create mode 100644 backend/venv/Lib/site-packages/fastapi/websockets.py create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/h11-0.16.0.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/h11/__init__.py create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_abnf.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_events.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_headers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_readers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_receivebuffer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_state.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_util.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/__pycache__/_writers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/h11/_abnf.py create mode 100644 backend/venv/Lib/site-packages/h11/_connection.py create mode 100644 backend/venv/Lib/site-packages/h11/_events.py create mode 100644 backend/venv/Lib/site-packages/h11/_headers.py create mode 100644 backend/venv/Lib/site-packages/h11/_readers.py create mode 100644 backend/venv/Lib/site-packages/h11/_receivebuffer.py create mode 100644 backend/venv/Lib/site-packages/h11/_state.py create mode 100644 backend/venv/Lib/site-packages/h11/_util.py create mode 100644 backend/venv/Lib/site-packages/h11/_version.py create mode 100644 backend/venv/Lib/site-packages/h11/_writers.py create mode 100644 backend/venv/Lib/site-packages/h11/py.typed create mode 100644 backend/venv/Lib/site-packages/idna-3.11.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/idna-3.11.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/idna-3.11.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/idna-3.11.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/idna-3.11.dist-info/licenses/LICENSE.md create mode 100644 backend/venv/Lib/site-packages/idna/__init__.py create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/codec.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/core.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/idna/codec.py create mode 100644 backend/venv/Lib/site-packages/idna/compat.py create mode 100644 backend/venv/Lib/site-packages/idna/core.py create mode 100644 backend/venv/Lib/site-packages/idna/idnadata.py create mode 100644 backend/venv/Lib/site-packages/idna/intranges.py create mode 100644 backend/venv/Lib/site-packages/idna/package_data.py create mode 100644 backend/venv/Lib/site-packages/idna/py.typed create mode 100644 backend/venv/Lib/site-packages/idna/uts46data.py create mode 100644 backend/venv/Lib/site-packages/multipart/__init__.py create mode 100644 backend/venv/Lib/site-packages/multipart/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/multipart/__pycache__/decoders.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/multipart/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/multipart/__pycache__/multipart.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/multipart/decoders.py create mode 100644 backend/venv/Lib/site-packages/multipart/exceptions.py create mode 100644 backend/venv/Lib/site-packages/multipart/multipart.py create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/AUTHORS.txt create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/pip-25.0.1.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/pip/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/__pip-runner__.py create mode 100644 backend/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/build_env.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/base_command.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/command_context.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/index_command.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/main.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/main_parser.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/parser.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/req_command.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/spinners.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/cli/status_codes.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/check.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/completion.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/configuration.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/debug.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/download.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/freeze.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/hash.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/help.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/index.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/inspect.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/install.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/list.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/search.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/show.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/uninstall.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/commands/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/configuration.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/base.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/installed.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/sdist.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/distributions/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/exceptions.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/collector.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/package_finder.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/index/sources.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/_distutils.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/locations/base.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/main.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/_json.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/base.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/candidate.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/direct_url.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/format_control.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/index.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/installation_report.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/link.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/scheme.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/search_scope.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/target_python.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/models/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/auth.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/download.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/session.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/utils.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/check.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/freeze.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/operations/prepare.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/pyproject.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/constructors.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/req_file.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/req_install.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/req_set.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/base.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/self_outdated_check.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/_log.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/appdirs.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/compat.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/datetime.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/deprecation.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/egg_link.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/filesystem.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/filetypes.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/glibc.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/hashes.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/logging.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/misc.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/packaging.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/retry.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/subprocess.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/unpacking.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/urls.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/utils/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/git.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/subversion.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 backend/venv/Lib/site-packages/pip/_internal/wheel_builder.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/core.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/certifi/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/compat.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/database.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/index.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/locators.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/markers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/resources.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/util.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/version.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/distro.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/distro/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/codec.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/compat.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/core.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/intranges.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/package_data.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_elffile.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_parser.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/_tokenizer.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__pycache__/_spdx.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/_spdx.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/markers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/metadata.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/tags.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/utils.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/packaging/version.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/console.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/filter.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/style.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/styles/_mapping.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/token.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pygments/util.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/__version__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/adapters.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/api.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/auth.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/certs.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/compat.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/cookies.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/help.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/hooks.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/models.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/packages.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/sessions.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/structures.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/requests/utils.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__main__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_extension.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_loop.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_pick.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_stack.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_timer.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_windows.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/abc.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/align.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/ansi.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/bar.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/box.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/cells.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/color.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/columns.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/console.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/constrain.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/containers.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/control.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/emoji.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/errors.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/filesize.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/json.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/layout.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/live.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/live_render.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/logging.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/markup.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/measure.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/padding.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/pager.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/palette.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/panel.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/pretty.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/progress.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/prompt.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/protocol.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/region.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/repr.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/rule.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/scope.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/screen.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/segment.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/spinner.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/status.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/style.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/styled.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/syntax.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/table.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/text.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/theme.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/themes.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/traceback.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/rich/tree.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/_re.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/_types.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/tomli/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/_api.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/_macos.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/_openssl.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/_ssl_constants.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/_windows.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/truststore/py.typed create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/typing_extensions.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/request.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/response.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 backend/venv/Lib/site-packages/pip/_vendor/vendor.txt create mode 100644 backend/venv/Lib/site-packages/pip/py.typed create mode 100644 backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/pydantic/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/_migration.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/alias_generators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/aliases.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/annotated_handlers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/class_validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/color.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/dataclasses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/datetime_parse.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/decorator.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/env_settings.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/error_wrappers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/errors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/fields.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/functional_serializers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/functional_validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/generics.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/json.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/json_schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/mypy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/networks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/parse.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/root_model.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/tools.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/type_adapter.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/typing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/validate_call_decorator.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/__pycache__/warnings.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_core_metadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_core_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_dataclasses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators_v1.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_discriminated_union.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_docs_extraction.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_fields.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_forward_ref.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_generate_schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_generics.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_git.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_import_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_internal_dataclass.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_known_annotated_metadata.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_mock_val_ser.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_model_construction.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_namespace_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_repr.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_gather.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_generation_shared.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_serializers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_signature.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_typing_extra.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_validate_call.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_config.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_core_metadata.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_core_utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_dataclasses.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_decorators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_decorators_v1.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_discriminated_union.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_docs_extraction.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_fields.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_forward_ref.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_generate_schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_generics.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_git.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_import_utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_internal_dataclass.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_known_annotated_metadata.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_mock_val_ser.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_model_construction.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_namespace_utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_repr.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_schema_gather.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_schema_generation_shared.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_serializers.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_signature.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_typing_extra.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_validate_call.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_internal/_validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/_migration.py create mode 100644 backend/venv/Lib/site-packages/pydantic/alias_generators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/aliases.py create mode 100644 backend/venv/Lib/site-packages/pydantic/annotated_handlers.py create mode 100644 backend/venv/Lib/site-packages/pydantic/class_validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/color.py create mode 100644 backend/venv/Lib/site-packages/pydantic/config.py create mode 100644 backend/venv/Lib/site-packages/pydantic/dataclasses.py create mode 100644 backend/venv/Lib/site-packages/pydantic/datetime_parse.py create mode 100644 backend/venv/Lib/site-packages/pydantic/decorator.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/class_validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/copy_internals.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/decorator.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/json.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/parse.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/tools.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/class_validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/config.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/copy_internals.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/decorator.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/json.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/parse.py create mode 100644 backend/venv/Lib/site-packages/pydantic/deprecated/tools.py create mode 100644 backend/venv/Lib/site-packages/pydantic/env_settings.py create mode 100644 backend/venv/Lib/site-packages/pydantic/error_wrappers.py create mode 100644 backend/venv/Lib/site-packages/pydantic/errors.py create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/arguments_schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/missing_sentinel.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/pipeline.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/arguments_schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/missing_sentinel.py create mode 100644 backend/venv/Lib/site-packages/pydantic/experimental/pipeline.py create mode 100644 backend/venv/Lib/site-packages/pydantic/fields.py create mode 100644 backend/venv/Lib/site-packages/pydantic/functional_serializers.py create mode 100644 backend/venv/Lib/site-packages/pydantic/functional_validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/generics.py create mode 100644 backend/venv/Lib/site-packages/pydantic/json.py create mode 100644 backend/venv/Lib/site-packages/pydantic/json_schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic/main.py create mode 100644 backend/venv/Lib/site-packages/pydantic/mypy.py create mode 100644 backend/venv/Lib/site-packages/pydantic/networks.py create mode 100644 backend/venv/Lib/site-packages/pydantic/parse.py create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/_loader.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/_schema_validator.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/_loader.py create mode 100644 backend/venv/Lib/site-packages/pydantic/plugin/_schema_validator.py create mode 100644 backend/venv/Lib/site-packages/pydantic/py.typed create mode 100644 backend/venv/Lib/site-packages/pydantic/root_model.py create mode 100644 backend/venv/Lib/site-packages/pydantic/schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic/tools.py create mode 100644 backend/venv/Lib/site-packages/pydantic/type_adapter.py create mode 100644 backend/venv/Lib/site-packages/pydantic/types.py create mode 100644 backend/venv/Lib/site-packages/pydantic/typing.py create mode 100644 backend/venv/Lib/site-packages/pydantic/utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/_hypothesis_plugin.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/annotated_types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/class_validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/color.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/dataclasses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/datetime_parse.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/decorator.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/env_settings.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/error_wrappers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/errors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/fields.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/generics.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/json.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/mypy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/networks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/parse.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/tools.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/typing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/validators.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/__pycache__/version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/_hypothesis_plugin.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/annotated_types.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/class_validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/color.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/config.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/dataclasses.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/datetime_parse.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/decorator.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/env_settings.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/error_wrappers.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/errors.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/fields.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/generics.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/json.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/main.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/mypy.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/networks.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/parse.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/py.typed create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/tools.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/types.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/typing.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/utils.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/v1/version.py create mode 100644 backend/venv/Lib/site-packages/pydantic/validate_call_decorator.py create mode 100644 backend/venv/Lib/site-packages/pydantic/validators.py create mode 100644 backend/venv/Lib/site-packages/pydantic/version.py create mode 100644 backend/venv/Lib/site-packages/pydantic/warnings.py create mode 100644 backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/pydantic_core/__init__.py create mode 100644 backend/venv/Lib/site-packages/pydantic_core/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic_core/__pycache__/core_schema.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/pydantic_core/_pydantic_core.cp312-win_amd64.pyd create mode 100644 backend/venv/Lib/site-packages/pydantic_core/_pydantic_core.pyi create mode 100644 backend/venv/Lib/site-packages/pydantic_core/core_schema.py create mode 100644 backend/venv/Lib/site-packages/pydantic_core/py.typed create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/python_dotenv-1.2.1.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/python_multipart-0.0.21.dist-info/licenses/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/python_multipart/__init__.py create mode 100644 backend/venv/Lib/site-packages/python_multipart/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/python_multipart/__pycache__/decoders.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/python_multipart/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/python_multipart/__pycache__/multipart.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/python_multipart/decoders.py create mode 100644 backend/venv/Lib/site-packages/python_multipart/exceptions.py create mode 100644 backend/venv/Lib/site-packages/python_multipart/multipart.py create mode 100644 backend/venv/Lib/site-packages/python_multipart/py.typed create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/requests-2.32.5.dist-info/top_level.txt create mode 100644 backend/venv/Lib/site-packages/requests/__init__.py create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/api.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/auth.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/certs.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/help.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/models.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/packages.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/structures.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/requests/__version__.py create mode 100644 backend/venv/Lib/site-packages/requests/_internal_utils.py create mode 100644 backend/venv/Lib/site-packages/requests/adapters.py create mode 100644 backend/venv/Lib/site-packages/requests/api.py create mode 100644 backend/venv/Lib/site-packages/requests/auth.py create mode 100644 backend/venv/Lib/site-packages/requests/certs.py create mode 100644 backend/venv/Lib/site-packages/requests/compat.py create mode 100644 backend/venv/Lib/site-packages/requests/cookies.py create mode 100644 backend/venv/Lib/site-packages/requests/exceptions.py create mode 100644 backend/venv/Lib/site-packages/requests/help.py create mode 100644 backend/venv/Lib/site-packages/requests/hooks.py create mode 100644 backend/venv/Lib/site-packages/requests/models.py create mode 100644 backend/venv/Lib/site-packages/requests/packages.py create mode 100644 backend/venv/Lib/site-packages/requests/sessions.py create mode 100644 backend/venv/Lib/site-packages/requests/status_codes.py create mode 100644 backend/venv/Lib/site-packages/requests/structures.py create mode 100644 backend/venv/Lib/site-packages/requests/utils.py create mode 100644 backend/venv/Lib/site-packages/starlette-0.50.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/starlette-0.50.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/starlette-0.50.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/starlette-0.50.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/starlette-0.50.0.dist-info/licenses/LICENSE.md create mode 100644 backend/venv/Lib/site-packages/starlette/__init__.py create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/_exception_handler.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/_utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/applications.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/authentication.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/background.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/concurrency.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/convertors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/datastructures.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/endpoints.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/formparsers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/requests.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/responses.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/routing.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/schemas.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/staticfiles.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/status.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/templating.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/testclient.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/__pycache__/websockets.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/_exception_handler.py create mode 100644 backend/venv/Lib/site-packages/starlette/_utils.py create mode 100644 backend/venv/Lib/site-packages/starlette/applications.py create mode 100644 backend/venv/Lib/site-packages/starlette/authentication.py create mode 100644 backend/venv/Lib/site-packages/starlette/background.py create mode 100644 backend/venv/Lib/site-packages/starlette/concurrency.py create mode 100644 backend/venv/Lib/site-packages/starlette/config.py create mode 100644 backend/venv/Lib/site-packages/starlette/convertors.py create mode 100644 backend/venv/Lib/site-packages/starlette/datastructures.py create mode 100644 backend/venv/Lib/site-packages/starlette/endpoints.py create mode 100644 backend/venv/Lib/site-packages/starlette/exceptions.py create mode 100644 backend/venv/Lib/site-packages/starlette/formparsers.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__init__.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/authentication.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/base.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/cors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/errors.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/gzip.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/httpsredirect.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/sessions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/trustedhost.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/__pycache__/wsgi.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/authentication.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/base.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/cors.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/errors.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/exceptions.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/gzip.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/httpsredirect.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/sessions.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/trustedhost.py create mode 100644 backend/venv/Lib/site-packages/starlette/middleware/wsgi.py create mode 100644 backend/venv/Lib/site-packages/starlette/py.typed create mode 100644 backend/venv/Lib/site-packages/starlette/requests.py create mode 100644 backend/venv/Lib/site-packages/starlette/responses.py create mode 100644 backend/venv/Lib/site-packages/starlette/routing.py create mode 100644 backend/venv/Lib/site-packages/starlette/schemas.py create mode 100644 backend/venv/Lib/site-packages/starlette/staticfiles.py create mode 100644 backend/venv/Lib/site-packages/starlette/status.py create mode 100644 backend/venv/Lib/site-packages/starlette/templating.py create mode 100644 backend/venv/Lib/site-packages/starlette/testclient.py create mode 100644 backend/venv/Lib/site-packages/starlette/types.py create mode 100644 backend/venv/Lib/site-packages/starlette/websockets.py create mode 100644 backend/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/typing_extensions.py create mode 100644 backend/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/typing_inspection-0.4.2.dist-info/licenses/LICENSE create mode 100644 backend/venv/Lib/site-packages/typing_inspection/__init__.py create mode 100644 backend/venv/Lib/site-packages/typing_inspection/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/typing_inspection/__pycache__/introspection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/typing_inspection/__pycache__/typing_objects.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/typing_inspection/introspection.py create mode 100644 backend/venv/Lib/site-packages/typing_inspection/py.typed create mode 100644 backend/venv/Lib/site-packages/typing_inspection/typing_objects.py create mode 100644 backend/venv/Lib/site-packages/typing_inspection/typing_objects.pyi create mode 100644 backend/venv/Lib/site-packages/urllib3-2.6.2.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/urllib3-2.6.2.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/urllib3-2.6.2.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/urllib3-2.6.2.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/urllib3-2.6.2.dist-info/licenses/LICENSE.txt create mode 100644 backend/venv/Lib/site-packages/urllib3/__init__.py create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/_base_connection.py create mode 100644 backend/venv/Lib/site-packages/urllib3/_collections.py create mode 100644 backend/venv/Lib/site-packages/urllib3/_request_methods.py create mode 100644 backend/venv/Lib/site-packages/urllib3/_version.py create mode 100644 backend/venv/Lib/site-packages/urllib3/connection.py create mode 100644 backend/venv/Lib/site-packages/urllib3/connectionpool.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/__init__.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__init__.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/connection.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/fetch.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/request.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/emscripten/response.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 backend/venv/Lib/site-packages/urllib3/contrib/socks.py create mode 100644 backend/venv/Lib/site-packages/urllib3/exceptions.py create mode 100644 backend/venv/Lib/site-packages/urllib3/fields.py create mode 100644 backend/venv/Lib/site-packages/urllib3/filepost.py create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/__init__.py create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/connection.py create mode 100644 backend/venv/Lib/site-packages/urllib3/http2/probe.py create mode 100644 backend/venv/Lib/site-packages/urllib3/poolmanager.py create mode 100644 backend/venv/Lib/site-packages/urllib3/py.typed create mode 100644 backend/venv/Lib/site-packages/urllib3/response.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__init__.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/urllib3/util/connection.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/proxy.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/request.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/response.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/retry.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/ssl_.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/ssl_match_hostname.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/ssltransport.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/timeout.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/url.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/util.py create mode 100644 backend/venv/Lib/site-packages/urllib3/util/wait.py create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/INSTALLER create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/METADATA create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/RECORD create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/REQUESTED create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/WHEEL create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/entry_points.txt create mode 100644 backend/venv/Lib/site-packages/uvicorn-0.40.0.dist-info/licenses/LICENSE.md create mode 100644 backend/venv/Lib/site-packages/uvicorn/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/__main__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/__main__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/_compat.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/_subprocess.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/_types.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/config.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/importer.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/logging.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/main.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/server.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/__pycache__/workers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/_compat.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/_subprocess.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/_types.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/config.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/importer.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/__pycache__/off.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/__pycache__/on.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/off.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/lifespan/on.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/logging.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/__pycache__/auto.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/asyncio.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/auto.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/loops/uvloop.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/main.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/asgi2.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/message_logger.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/proxy_headers.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/middleware/wsgi.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/__pycache__/utils.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/auto.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/flow_control.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/h11_impl.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/http/httptools_impl.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/utils.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_sansio_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/auto.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/websockets_impl.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/websockets_sansio_impl.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/protocols/websockets/wsproto_impl.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/py.typed create mode 100644 backend/venv/Lib/site-packages/uvicorn/server.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__init__.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-312.pyc create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/basereload.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/multiprocess.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/statreload.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/supervisors/watchfilesreload.py create mode 100644 backend/venv/Lib/site-packages/uvicorn/workers.py create mode 100644 backend/venv/Scripts/Activate.ps1 create mode 100644 backend/venv/Scripts/activate create mode 100644 backend/venv/Scripts/activate.bat create mode 100644 backend/venv/Scripts/deactivate.bat create mode 100644 backend/venv/Scripts/dotenv.exe create mode 100644 backend/venv/Scripts/fastapi.exe create mode 100644 backend/venv/Scripts/normalizer.exe create mode 100644 backend/venv/Scripts/pip.exe create mode 100644 backend/venv/Scripts/pip3.12.exe create mode 100644 backend/venv/Scripts/pip3.exe create mode 100644 backend/venv/Scripts/python.exe create mode 100644 backend/venv/Scripts/pythonw.exe create mode 100644 backend/venv/Scripts/uvicorn.exe create mode 100644 backend/venv/pyvenv.cfg create mode 100644 mobile_app/analysis.txt create mode 100644 mobile_app/analysis_2.txt create mode 100644 mobile_app/analysis_3.txt create mode 100644 mobile_app/analysis_errors.txt create mode 100644 mobile_app/analysis_errors_2.txt create mode 100644 mobile_app/analysis_final.txt create mode 100644 mobile_app/analysis_final_2.txt create mode 100644 mobile_app/analysis_results.txt create mode 100644 mobile_app/analysis_results_2.txt create mode 100644 mobile_app/emulators.txt create mode 100644 mobile_app/lib/models/channel.dart create mode 100644 mobile_app/lib/models/product.dart create mode 100644 mobile_app/lib/models/store.dart create mode 100644 mobile_app/lib/screens/profile_screen.dart rename mobile_app/lib/screens/{site_selection_screen.dart => store_dashboard_screen.dart} (71%) rename mobile_app/lib/screens/{add_site_screen.dart => store_editor_screen.dart} (68%) create mode 100644 mobile_app/lib/screens/variation_editor_screen.dart create mode 100644 mobile_app/lib/services/platform_service.dart create mode 100644 mobile_app/lib/services/square_service.dart create mode 100644 mobile_app/lib/utils/metadata_helper.dart create mode 100644 mobile_app/woocommerce_variation_response.json diff --git a/backend/debug.log b/backend/debug.log new file mode 100644 index 0000000..9dfb1cb --- /dev/null +++ b/backend/debug.log @@ -0,0 +1 @@ +2025-12-29 11:37:57,833 - asyncio - DEBUG - Using proactor: IocpProactor diff --git a/backend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc b/backend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..758b1a8816486ede79b156ba7fab7a29d6c12080 GIT binary patch literal 163643 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%0DB;G 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

qPBAq6}odI(R!wLr+ywlRqkffkO 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 +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/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD new file mode 100644 index 0000000..06bbc8d --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD @@ -0,0 +1,11 @@ +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-312.pyc,, +annotated_doc/__pycache__/main.cpython-312.pyc,, +annotated_doc/main.py,sha256=5Zfvxv80SwwLqpRW73AZyZyiM4bWma9QWRbp_cgD20s,1075 +annotated_doc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL new file mode 100644 index 0000000..045c8ac --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: pdm-backend (2.4.5) +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt new file mode 100644 index 0000000..c3ad472 --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] + +[gui_scripts] + diff --git a/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE new file mode 100644 index 0000000..7a25446 --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +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/backend/venv/Lib/site-packages/annotated_doc/__init__.py b/backend/venv/Lib/site-packages/annotated_doc/__init__.py new file mode 100644 index 0000000..a0152a7 --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc/__init__.py @@ -0,0 +1,3 @@ +from .main import Doc as Doc + +__version__ = "0.0.4" diff --git a/backend/venv/Lib/site-packages/annotated_doc/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/annotated_doc/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bec063525e25ca4e130c13f8dbcc4d5ac1e45611 GIT binary patch literal 254 zcmX@j%ge<81cB>4yGA1c8IXg8kB?ibZi}A@!iYd-4 zN!2X?iYBI~7RMy!<>i+omZYY{r{pK=#{)HHmc+;F6;$5hu*uC&Da}c>E8+y&26ACB YFOc}a%*e=imqF$MpJ*d@5j#)>0H}jT`v3p{ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/annotated_doc/__pycache__/main.cpython-312.pyc b/backend/venv/Lib/site-packages/annotated_doc/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57c944bbb3486acc1330501c67094f60ff6a6529 GIT binary patch literal 1902 zcmZux-ESL35a0W-Kp%nAxKC(F|+5h8`RNhcV=gH<~K7t_sjfz znE-wC)5rdsHX(nYkQ2z7&R&4+fSBYx!pT12#zQkxY>|QKSY9S%>*UTYeMgWjgOe?j z8(S7Ph0QH)cWhqRx3>!15_ZSrMc|9T&j3FIe2JIDEXZZBn+5s8z;?>1wIMy0K->+{ z@k2qAuAp3c{hkODmiRKHvO^h729cmF4CVN+AN%1pZM~hH2;QpGMAEh>(=qj9!Koio zFJN&@S&}Hf-A_bZr=5Q2X~!(&v?r3Tfl}P$3q`NHWgZacETJJLDvvwfj z)v`YS1i)%L8h2$s-~a%yMl$v>01H-R7z}6(u>ox0gMStvP8J06E}TPx9>_9?wY$LI z5mazLkqRI~yz_O;3(bhQxt#P!QUonido)w|hYJE6>Duz0Tj*>m>7G~`CBB>HOY0}hS+)2S* z2$0)tNH6oqMTd6%S_my!pWglg;MXY_)s{Z%N-Sf{24Dx=lJliQS8mXT3;|XC1R^MV zQtK?;^6T_#boNbk$wUw+IT+7^-Yt;Np4Tsb&)6d_a2XBAvC%j- z6pn{urgkiXjuv9PPU*j&zq8(ql-!2*)q|Qe?@9@M>Ivlu*AI80SyBy}ZRYKWkT*fz zZGPaloA83fN(85DTg1(C<$Arx{BSiIq$L+T_=)S@n}e#X<`NEdjKhDQJbLA|Z|&bp zFP(uzJOkG;VM02oC14I<^!Lc^T=&HOoypDbtxe)sje9nhJ~bRw0s}~S7Pc6DQiahF zjuMfY!pWqU(F`#GoaZh+;HQ^rCzoo&i`Ra9V^~=kmR8gpD4!0l4w?g!On?K(yepu| z>ET$vNz@FSVH>(E?&>zE3Y`28B`T*VGwD?{TY%+0d0bg|uyMM0^FEMLU(RIZgNWPrC804#Hc4=*FXihM2OYonr7xPJKVh`@G~{Eb@{0Snl0j4TKi iVj4Ity_KbOL*b0*==hjMmSGtGn3s*~e-T*ph5rC3d*3bq literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/annotated_doc/main.py b/backend/venv/Lib/site-packages/annotated_doc/main.py new file mode 100644 index 0000000..7063c59 --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_doc/main.py @@ -0,0 +1,36 @@ +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/backend/venv/Lib/site-packages/annotated_doc/py.typed b/backend/venv/Lib/site-packages/annotated_doc/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA new file mode 100644 index 0000000..3ac05cf --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA @@ -0,0 +1,295 @@ +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/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD new file mode 100644 index 0000000..7045729 --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD @@ -0,0 +1,10 @@ +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-312.pyc,, +annotated_types/__pycache__/test_cases.cpython-312.pyc,, +annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +annotated_types/test_cases.py,sha256=zHFX6EpcMbGJ8FzBYDbO56bPwx_DYIVSKbZM-4B3_lg,6421 diff --git a/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL new file mode 100644 index 0000000..516596c --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.24.2 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..d99323a --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +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/backend/venv/Lib/site-packages/annotated_types/__init__.py b/backend/venv/Lib/site-packages/annotated_types/__init__.py new file mode 100644 index 0000000..74e0dee --- /dev/null +++ b/backend/venv/Lib/site-packages/annotated_types/__init__.py @@ -0,0 +1,432 @@ +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/backend/venv/Lib/site-packages/annotated_types/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/annotated_types/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8a1b946091ba4344a15443eb7e5dca9ce5dc415 GIT binary patch literal 18623 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/annotated_types/__pycache__/test_cases.cpython-312.pyc b/backend/venv/Lib/site-packages/annotated_types/__pycache__/test_cases.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d175cddb83dea86d6cf661f77ca3c42bbe438fb9 GIT binary patch literal 13236 zcmc&*e^3-xp6~AIftf}eK~#vSh(?)+$S)BUL4Jr55k)|8#Eb*oGYrlT>}mW#jGNlc zRmH2_imBVXz=f(nq{^Y>;v{8NCaJAjE|sbyySdvp)6}`wo4f2)?#`v^{%}vPYIpy+ z`@Zh!>6xLyF_qlCs(JnT{rG%;zaRADm)Y420jcwY)9!Tz1n~`iQIj!Ncrp)#cLGkX~uVc~{w1 zd9!WV-qp6%UW?7*U1M8A5*#^HtdiB9tnm^>5PT*eW_WVFYi(;u!j~bxnUpsulb$@= zI*K?-u$gZVtchEF&!8aK*0W|Vi(3z35l)I_-k@z8u9McRMcmwBr6rnm2%KcXx#0G4 zk{RbL=Mfx|2^UBGKF&%?nJwIa+w1UHO_HI}cU_`e+yjDSY7;o#(eD8Oxg_{`iEeiX z1c~Wz08IDDFti!EI6*SXWh=Fa8Cx_%2B_vnpU*D9F66IcSFiMjo+^utr-&C>Q{?pXMHd|^ zdAo3ZmpV**mP+n4a#Va=3GcDoNGwc91eZuk1x5f3h} zvfD3@I6SeIOuL=+57_Oz37C>BcDn{2fLiQ(GsF|fi9b1-5A+T5ei!fXdfh%(-&MbV z!0+{P`~YVM+MEwGe7&#VF>s0Vv3>ARV@ZMO7j+Zjk(h$~3N@B@-vC&Qn+n1$SgX+(J zMZQCl`si{DV<=%|bUFpy$Y!L0zDi|sWpp81?Z;-aCf1}PC(}&nWmbEo)H77{L1XF4gzYP*6=h29rOA|BpD0suizbs+|NY676PIbVY8&;bc%7j2 zu&6Bwb!*f*u#MI;j+IcCqxDR~CVDZFtMaNnm&8aeyEYAUy%^C$PmPg0c3m3idj6z? zp5U|JSB$JrjJ*VU&+kuq_P|qUN?Kx%wQO!08q>3f9(t-h*0FhMpzGN~2R%VQ>DePm ziwUEX>X*z}+KiAqM<&b&X~?8!kM$|WfY&AVFtAh_=z8|hLr=9w25U?MUC$mm=m{E4 z&mKv=5=Q@j*&|=i94Cz_y1s#uIW{Xlh zVk=v$Qd(ixqGvBXe0mA~HgoEod&iP?70V9 zmo1OmIh`1PHaA5&nq4CMcg9a#CkdXe#{t9cNzr}t$ zA)S=4OGUjGE3l?P5?c2`YdTz&s^c{cv9;e)NBh|WX;?>Z{Vr3v(4H)jydo^Oy1K~J z7NJ~48LCuE+H>~cz1VE-im${gtdHq(Te~v1>GPB-jjGY_lG~NJ`MxDdl~AZqtt0GJ zOKjcjA(apHnP9neX4P~pSFhs7ygqriX42(umpX>6pKVa*s099&_@rvZ|0CJ;c6BwX zZnY7O^%g^7ME>5eowdb;2=tzpGJd4jX{6bF`S|rD#=^2sS znHtIR&QFWHXK7KVJ&Q>41sx5n5Pg~idUH{?rg62zo=#aO|;%9QyM+-SwwOE|+Df2$$J#y>UirMPl8WbS_e;_x|` zatVvrKLHDGt0c-JKrv2CrH;1+3SpUjnIZ*)IT*mjq?U>Cc$03WTzzkS_TMFaU#mL$ zeM5`@zaO`gQkHkbBe>yHwcYQ8@o}Z__`?oVU>JT6&SXhxrN>TOftwz|57HknY&8^k zyf=Vhcq=c_pt)*^xfV}WgG5MVg+x_U&Ll!(E6mUdv~Y#0+6G)c1eukRj2Lk*kC%9v z5s7q2#{L18!@M7XT8ZqJ$N@!fN98dxD?AQf(4mZV7|MJjWKxCS>SicYIY5W~sBE7gc;&ZD$;ZhuZ&0)|9wbwgJSC>_KC4-}X zK+16X{rwIesA6FyvQeU&{C;R`Y-)z93rAW{T4_ZOSYLc6?qq1}Z&n9Tj(&-DRPez-7sL{pbey0zz4x z$3Nik1nQxnH2es<1#sBDPJ}wcIUn|f9Us}`&-EaS46ONW%-dwY!a?Qw;OM`O=6&#_ zL7!`ks&IX&Mdp|4P!KVz{CUU{SmiIk`?6gA1a~$;_Bt`wIiK@ckIdnysje#SNI>v=kMjPJ zVU9h)2@bgL;^2#5V3O>ZbQS#MizlfU8HTVrQxZ#R%cOGnh)wEL#}Z)K74ZC!csl}C zi0?O=mxH!Vw?MwaYFM*2y zp8j4ZX4eHT-^+h!t&3Re7OeG(b3w=fBj!^)$GQg~0B~#uIFB>ICGg!C1%7nTbMo_3 zOdWq2`yKIz*NLxk^WG_ayEL+;Ud(L}S2g@GKtt0HUnm5fWb*h!3XffY#~%UsESzyT zbK-0eXR^b}S6Jkz+OV8IT!hYl0lxr-dxLmPk>Y~ z3w}5qcD!zu@#wp|Ez#Rq^ycDtQLc1GLbC<|;N9k_p@|7v)rzI0j?;ROGGF=j^4&{Uz z#o`*Va39Lu7ctd-WzM<1eT*Ed5Y3w=t_A6!Ba|a!7BE{lLv9Jo|Rz)yQ_M7bO#@m-gbHPOQBt7W}=7<}2Ayes+ zmi}O|xN$c!m90QwXK-gS`kLGMqWOi1qmxJ8?LekoUzyk3-hfH%o2+`b4w*_4uvP)L zIx0ohgW=BtWQTmML7FknS!9eKpLeYLyus>os z5I!+~P-M9YxbaeVyvY;C9|yfxe@?rQk_*nBtY>PBbIiY>hhh38Q2xroWOJpaqL zBuJLvB;Ijvm|WO=02LgFSPq8I&6`E$bd)}=F`Ye?9p1K3RF4YkBbEl#*onF>h|DWd z`jw|9O+)T+caVJ7qs}6&^A?fmjnciEhMeQh$f=7sx??~rwtYCj#$b*D)_X0zG8kGI(7Ps5>(!W&h(=5eaLnJU36d|JBNCl zBIAnEE^X3G5+~S)4t9vl$tZm?MI24!C4F=y3N?k-hF#&+zp$XHUesqt=dmo2^DJ@= zA?GFJ8;&@Kk?pd`@KKuA5lU0e^Fe8n$!5^_M!O-R`bB0SN)IeATyN;6$h1c3Rs{!S zo30ug9N#>fdw>1R`VbkaxL1e@_C_o<;m)~=PYT1U=X2*BsPptZ7|n+47ZK+~mpqXk zFFNKE8Gn@atHip-^QSBC)=bp|w+1`!)WssKF?2ap^XYz6dE`sOFOBF_=X@aAeGwgX zh)jQ!?pFq{n+Qxck6jzzGFyCq$IK4AI^8Q(!Vm3lM;$S%%5JKzGZ0-tS}fd+a(72e zWe@Vh+vmu+3bEn{DsTNVADupfde4D-EO6e3+~o*&d7+I*#{y3b6kfC_ShO+{7A*{B z5DQCDZfV4{`++H(7rs2V^~+?CYmFbqRG9%5>#9j-P1KtiYqzdV7;pVxI`3}&RQ@Cr?0!)F zaqWk-sI*RG4n^rhN-vG}?DqR5GbLzSl|npZ6Pd$N`moaNwOg-E^h7M%rrEoLQ-hPX z2ird``LHD1f+`xdRg-^c*%GmAnKni&J7)9l=g;Jas!>Vp&#Hf3`$=v1C1npFdoc)& z5zkGJ%=X{+%y>R&5X+9EoyQ}a+9Q?|3#Ymtp6ZR9>YX25xZrqrfs24E_i@N|X~BE> zp?4(W9YN=>h|JX}eN}-|wwrif zzAL-=Ojh}44CVZg0sp%I|0^K>cY$&iz-MITAcW5eJpL<%d_GW)2CLwY6#@9y20Q-S zi 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/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/INSTALLER b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/METADATA b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/METADATA new file mode 100644 index 0000000..0552dea --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/METADATA @@ -0,0 +1,96 @@ +Metadata-Version: 2.4 +Name: anyio +Version: 4.12.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.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 +Requires-Python: >=3.9 +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; python_version >= "3.10" and extra == "trio" +Requires-Dist: trio>=0.31.0; python_version < "3.10" and 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 + +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 version of the functools_ module + +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 +.. _Hypothesis: https://hypothesis.works/ diff --git a/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/RECORD b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/RECORD new file mode 100644 index 0000000..c203c32 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/RECORD @@ -0,0 +1,92 @@ +anyio-4.12.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +anyio-4.12.0.dist-info/METADATA,sha256=rte2_C2hYKP9_iVMFYogSzBxdHBzwY45S1TrLiBsxdk,4277 +anyio-4.12.0.dist-info/RECORD,, +anyio-4.12.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +anyio-4.12.0.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 +anyio-4.12.0.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 +anyio-4.12.0.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 +anyio/__init__.py,sha256=7iDVqMUprUuKNY91FuoKqayAhR-OY136YDPI6P78HHk,6170 +anyio/__pycache__/__init__.cpython-312.pyc,, +anyio/__pycache__/from_thread.cpython-312.pyc,, +anyio/__pycache__/functools.cpython-312.pyc,, +anyio/__pycache__/lowlevel.cpython-312.pyc,, +anyio/__pycache__/pytest_plugin.cpython-312.pyc,, +anyio/__pycache__/to_interpreter.cpython-312.pyc,, +anyio/__pycache__/to_process.cpython-312.pyc,, +anyio/__pycache__/to_thread.cpython-312.pyc,, +anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_backends/__pycache__/__init__.cpython-312.pyc,, +anyio/_backends/__pycache__/_asyncio.cpython-312.pyc,, +anyio/_backends/__pycache__/_trio.cpython-312.pyc,, +anyio/_backends/_asyncio.py,sha256=w6gCSMs_2D1doKVtzi32bOloBl1df-IHubl8-Vks908,99656 +anyio/_backends/_trio.py,sha256=ScNVMQB0iiuJMAon1epQCVOVbIbf-Lxnfb5OxujzMok,42398 +anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_core/__pycache__/__init__.cpython-312.pyc,, +anyio/_core/__pycache__/_asyncio_selector_thread.cpython-312.pyc,, +anyio/_core/__pycache__/_contextmanagers.cpython-312.pyc,, +anyio/_core/__pycache__/_eventloop.cpython-312.pyc,, +anyio/_core/__pycache__/_exceptions.cpython-312.pyc,, +anyio/_core/__pycache__/_fileio.cpython-312.pyc,, +anyio/_core/__pycache__/_resources.cpython-312.pyc,, +anyio/_core/__pycache__/_signals.cpython-312.pyc,, +anyio/_core/__pycache__/_sockets.cpython-312.pyc,, +anyio/_core/__pycache__/_streams.cpython-312.pyc,, +anyio/_core/__pycache__/_subprocesses.cpython-312.pyc,, +anyio/_core/__pycache__/_synchronization.cpython-312.pyc,, +anyio/_core/__pycache__/_tasks.cpython-312.pyc,, +anyio/_core/__pycache__/_tempfile.cpython-312.pyc,, +anyio/_core/__pycache__/_testing.cpython-312.pyc,, +anyio/_core/__pycache__/_typedattr.cpython-312.pyc,, +anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626 +anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215 +anyio/_core/_eventloop.py,sha256=xsoYgHIddNYusTqAFDVmcvpjHKJFmdgtDcAjpN3JEWQ,6261 +anyio/_core/_exceptions.py,sha256=fR2SvRUBYVHvolNKbzWSLt8FC_5NFB2OAzGD738fD8Q,4257 +anyio/_core/_fileio.py,sha256=uc7t10Vb-If7GbdWM_zFf-ajUe6uek63fSt7IBLlZW0,25731 +anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435 +anyio/_core/_signals.py,sha256=vulT1M1xdLYtAR-eY5TamIgaf1WTlOwOrMGwswlTTr8,905 +anyio/_core/_sockets.py,sha256=aTbgMr0qPmBPfrapxLykyajsmS7IAerhW9_Qk5r5E18,34311 +anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806 +anyio/_core/_subprocesses.py,sha256=EXm5igL7dj55iYkPlbYVAqtbqxJxjU-6OndSTIx9SRg,8047 +anyio/_core/_synchronization.py,sha256=SY3nsr1ZZyDrjamsOVoYcvj-x6d_AR13Cu5lZecG0gY,20894 +anyio/_core/_tasks.py,sha256=km6hVE1fsuIenya3MDud8KP6-J_bNzlgYC10wUxI7iA,4880 +anyio/_core/_tempfile.py,sha256=lHb7CW4FyIlpkf5ADAf4VmLHCKwEHF9nxqNyBCFFUiA,19697 +anyio/_core/_testing.py,sha256=YUGwA5cgFFbUTv4WFd7cv_BSVr4ryTtPp8owQA3JdWE,2118 +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-312.pyc,, +anyio/abc/__pycache__/_eventloop.cpython-312.pyc,, +anyio/abc/__pycache__/_resources.cpython-312.pyc,, +anyio/abc/__pycache__/_sockets.cpython-312.pyc,, +anyio/abc/__pycache__/_streams.cpython-312.pyc,, +anyio/abc/__pycache__/_subprocesses.cpython-312.pyc,, +anyio/abc/__pycache__/_tasks.cpython-312.pyc,, +anyio/abc/__pycache__/_testing.cpython-312.pyc,, +anyio/abc/_eventloop.py,sha256=GTZbdItBHcj_b-8K2XylET2-bBYLZ3XjW4snY7vK7LE,10900 +anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783 +anyio/abc/_sockets.py,sha256=ECTY0jLEF18gryANHR3vFzXzGdZ-xPwELq1QdgOb0Jo,13258 +anyio/abc/_streams.py,sha256=005GKSCXGprxnhucILboSqc2JFovECZk9m3p-qqxXVc,7640 +anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067 +anyio/abc/_tasks.py,sha256=KC7wrciE48AINOI-AhPutnFhe1ewfP7QnamFlDzqesQ,3721 +anyio/abc/_testing.py,sha256=tBJUzkSfOXJw23fe8qSJ03kJlShOYjjaEyFB6k6MYT8,1821 +anyio/from_thread.py,sha256=-YZOTpu9WVHtAsMxQGIOaHMjaDRNeKQilx6Nn2qDU-o,19017 +anyio/functools.py,sha256=tIWQ90cuLMxfJIpdBfFY3W3CC1zqFCRAyR3DxKc0Xlo,10061 +anyio/lowlevel.py,sha256=NnPYQ6tWDzLRwpalX2CvsbkXkTeasbJcL52gPopWdYg,5048 +anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/pytest_plugin.py,sha256=3jAFQn0jv_pyoWE2GBBlHaj9sqXj4e8vob0_hgrsXE8,10244 +anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/streams/__pycache__/__init__.cpython-312.pyc,, +anyio/streams/__pycache__/buffered.cpython-312.pyc,, +anyio/streams/__pycache__/file.cpython-312.pyc,, +anyio/streams/__pycache__/memory.cpython-312.pyc,, +anyio/streams/__pycache__/stapled.cpython-312.pyc,, +anyio/streams/__pycache__/text.cpython-312.pyc,, +anyio/streams/__pycache__/tls.cpython-312.pyc,, +anyio/streams/buffered.py,sha256=2R3PeJhe4EXrdYqz44Y6-Eg9R6DrmlsYrP36Ir43-po,6263 +anyio/streams/file.py,sha256=4WZ7XGz5WNu39FQHvqbe__TQ0HDP9OOhgO1mk9iVpVU,4470 +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=Jpxy0Mfbcp1BxHCwE-YjSSFaLnIBbnnwur-excYThs4,15368 +anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100 +anyio/to_process.py,sha256=cEyYUgb8LJVRJCfs6rK3aEM_T3k2gEmhl0nBjEvflOk,9687 +anyio/to_thread.py,sha256=tXQPvHohvQ2Vrw2pBtdzkRPNV7u3H2_UDbvwL2u_R7k,2465 diff --git a/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/WHEEL b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/entry_points.txt b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/entry_points.txt new file mode 100644 index 0000000..44dd9bd --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[pytest11] +anyio = anyio.pytest_plugin diff --git a/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..104eebf --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/licenses/LICENSE @@ -0,0 +1,20 @@ +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/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/top_level.txt b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/top_level.txt new file mode 100644 index 0000000..c77c069 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio-4.12.0.dist-info/top_level.txt @@ -0,0 +1 @@ +anyio diff --git a/backend/venv/Lib/site-packages/anyio/__init__.py b/backend/venv/Lib/site-packages/anyio/__init__.py new file mode 100644 index 0000000..d23c5a5 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/__init__.py @@ -0,0 +1,111 @@ +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 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 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/backend/venv/Lib/site-packages/anyio/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f93499e1c842ca168efe762e80688ac0738c5d6 GIT binary patch literal 4626 zcmZ{n+fQ8A6~_0#zzp}RxjEPq+ZbbGe8cw}cZ`hzGhoOz?#W@!297zG(LQIuptP#0 zKBQ8lD(XWbRh9D4mnv1&KOwJGAL=$rn@&4Yq_z)vbCu+!PyN=KIbd8D;g8>5d+p2F zm$kNkUsqQx@RR<{yxr9y#6PGI{Ztkq_DvWU;v-=RE9M9{CSx&Sm09IZnOiQ)nd9KN zj5Aj_6>g=hWUd4!WP&*XPRb;65?m##n5)3mvYNRXTqA3kYrwU#mbn&OC+nE&oO-uG zHZa$N8)YMN1Gq^xF*kynWixXVxJ9-wH-lScD{~9@kUYfP3T~5a%!k13vYojN+#x%d z+rgc(leq)jCA*kA!H4Bx<}T+gw_A2I9|j+hN0{FNAC*U$yTK`$Vm{)$?H-fIn2$Qg z-4pTzbIR#)Ps)?bZ-aYfFY__*DS3+dIJi&tF`odRmZzC}z-Qzc=9A!l+0WbyJ}b{M zp8^la0p>pNIeCuxH2Azc&wK`aL0(|)2VayIna_eR$xF-w;6XXad=7kBUS>WIz9O$M zUjSc~SD7z5*WBy!I`bvxhI>=qWF7?HlDC*IJGb3C@(%MA@LhSA`6_rw4l!Q?56fZZ z>);VN!h8cfDo2@bg2&_-^DXeW9A~}_o{$sFcfgZ!lKC$9p1j9AVIBw1%30# zh^(ckT@d@ATWu(1*iqdFJ#q0wS<+hmaa=yzd8hBm*HqOP%h#Bm=Z9u!`(E%hjSE}H zaIoWLMtv_-&%=kNXRa&#(0*=vsB3w%xi*v2T6v)n+OC3I@rn6c>_gfUJ=Cq$tJaE%UF4%d!o0d_> z50v$~xe<%vsSGXR1U^q$=(cH0IkszKj2SwXMx;RA@3Y^o_K_8MT&koE^BgvU^~!d!}P( zl~Hza@#_~x=StsBdkW8n#hIz)gQj{jFfzpjDmm4Zibj~BJ*|z3InREM^5G2DCsa`* zoQRy2H3EE&3Q^tjztw1GSY~LhYt!9#Y$-Wn6vMHDPs;^764YgM|(5Pi$IQ_s#FAOg%rj4n|nc4aAF?iREax6(_@bM@{8y=d$rm?R5938r@ zC}OF#HM+W6%CN94j_pyC>NVVB!(1zdh&tCtweRg2nrE=d)`D`gzBctv>2kHEv%Zhp z|GK?-&oE}=@`TtY3{kgdEj6#k;R(^DWpiBHFRj8m;ci+~Swx&=#^eG%X{vbkIOIkj zMV|`SCUjz8$32`rgKQj!`N&alW{a^(fr4XJ+rg-UV7O&l#XEDbCe0VIA*3K=m{AnU zR~v@wTR8-GBQJIf8c2QsB>#<_@IzQ|#*Z*~D6iTCjG-8?0PKF04}@%`9)v1g?m z$NnX;;`CB3{#X^iu8i_vOoXMkG+x>wtlINQg#7xZ^3Thx5w5>L1%y9fU}m4lwZ%AW$oJEYma={-tjUas@lF4 z@v7=?t3_k)i{#0FR(E`S^_SN^>3=aW^jYg?$rqhdpI6_15x@TpIukQ}alMMa`Emrp zd?iwSPJ6rEbY7plzHg;nc-pr~=XWg!SFDPrQ_o#}_vA$38fMlBFA;}EMEM)IHLxqg$t?N0e zc|Ebb@^4mg(eFkWUx}Q$A6;VjMH6i9w~8U=j{X6P6s-gNr%b#okHumIaqM4Wxgcf=;zmJ?Fw7Oi zseu5m$t{24Jf&k-pu^_G%#D#+BWd)2C#650)hxH2g^Z2{6 zvRK)7l_EBYVKLNW_Ch6oF%-r}Bm4qTb-N&L7R1C}BNQ;ni!c?$c^(2?z!gReH&_ru z1u@SKm~(NeP_(+t(>qrX_(emwq2YAYaOmHaqOtYEiJ#s3X!gU|&s%%`+;H-TlYdRr zzrX!)?I)|BC;I-982n>m@VCofB<_6K-Sd9pi)7c!3IwT_)uN*I+sfM5gBUONe*q@I BYcBu* literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/__pycache__/from_thread.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/__pycache__/from_thread.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9dab6eb2c630d36b808743210ac9a9cc3773cbf GIT binary patch literal 25799 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 wFp#WIM| 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 NrH7Prb4K9vzX9#@I^X~R literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/__pycache__/to_process.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/__pycache__/to_process.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..731fc97b75b94bf8a08aed98cab326da6c2d8abf GIT binary patch literal 11832 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 W^i{Ir8fE<*1t>nED*2aTn*Ile@V{FC literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/__pycache__/to_thread.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/__pycache__/to_thread.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97046fee001b51ea485a54e35ee484e3a859d2f9 GIT binary patch literal 2975 zcmZuzO>7&-6`uVex#Utmq#Qd=9C=zBu9-MWQWP=3)OKAL0fMA%VJitj%UBL~N77o$ z8De%Rg{lgujnVedLoTg*NDny%PJ2&Jz4s#52dj$;P0BnGiBzNhn3!FjGhMg%=NmpU(PyrMO7EfG@Islz7Rq z;wGsa8odtlSGWjZaOw){ zF+WTOZ)D0E=B@?HcU|0Lrqx{6e7_g*wD_ig#Ve^Z?_J}`DvMI*$1=XGmg4zW8&+Cl z9VP-PJoxjO@OhNFS*uM;OS!>*?mmJi72*Gvgcy6bL3o`Q0Q`pevm+bkPmN@>4&YBr znAT5VeQe*wo$weWDP$5McXQ!ZX*9CmZjcRo!`QGsF5JyY_8ySyC!poG<{j%7g#x)w z&XZr;f3Vh!Mv*;$i3)`Wy-Jg1PM5+}F6d%k_y`YO3zOvo<4i5}y8uv3LqQo`lWK)4 zm`9Z6Dq7QPi+X*#eZV2@HkCcCFN`S{2wyU&Wku`ibr;p7fQVfMK80v!I@d0aYxFd7$<3cYUsH zYh=ngoQ6w6Dn7bUv&R(cYL_(O&VJ56y*Zx)x5Q1_lQCRE3Kr3QKjDSYuaDh!m_<$6 zZqKVe2Y)4!<|I3K-LnyAtLUdN!4+_2Z3ZF;h%Iv#MwtTrRcLC=j2 z0!B1xzfbyV``6c5kFbx6>qXL5kbhCsGLLLRNKKpB=)@So^%;s@;b^X10K%jlV!x!3g zg%1D|@NXW-c%?Q(L@4JHnWx*iQ9f=XV-A24hmh*%Wifc|NAx>$FU`I9iuTH*2*E+2 zh!aQ(yO_-&`&Qxv@@d3ZdDJjf9R}4AoUxSyO2l?B&P3=hm)j!>VEC?gWAP=wTs(M^;f~xne%@>Hnd3n z(jGDE#V?6jEe?rUz*n{SRXhpWe}4WlF+MRa+J7p5;KRuHK_5dRH}<{_!X2_-O~#c1 zW)DB3x$6MW`foJ%pwwZi%+l522tWqrOr@Ox&_Y+}uZM)_cRNrIqkpXr#%`E$$~-DFLP+2^50)5!u5VDEz3=1N!xS=*36jwMiaMlj<|~-Ps53g?sLW z`|hPJ`;s~dQ;n*63YzsZSMtn#<3?89Z;VR%&70@wsLyau zE{b%6UX_AtF0UUw^o5a6rp4^KY8s6()iRAI)8JI{jPG~J+WHa^HWN5QtgUZf%Y*1aWRPTk(rT^v4|PS F0sxEkHDmw) literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76c01ef062d1deaf25645682b1142b61969b1856 GIT binary patch literal 139826 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 Mw%6sKmewi%4{-<%fdBvi literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_backends/_asyncio.py b/backend/venv/Lib/site-packages/anyio/_backends/_asyncio.py new file mode 100644 index 0000000..2a4dacc --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_backends/_asyncio.py @@ -0,0 +1,3007 @@ +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, suppress +from contextvars import Context, copy_context +from dataclasses import dataclass, field +from functools import partial, wraps +from inspect import ( + CORO_RUNNING, + CORO_SUSPENDED, + getcoroutinestate, + iscoroutine, +) +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, + Optional, + 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, + iterate_exceptions, +) +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 ..abc import ( + AsyncBackend, + IPSockAddrType, + SocketListener, + UDPPacketType, + UNIXDatagramPacketType, +) +from ..abc._eventloop import StrOrBytesPath +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, 10): + from typing import ParamSpec +else: + from typing_extensions import ParamSpec + +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_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 + + +def get_callable_name(func: Callable) -> str: + module = getattr(func, "__module__", None) + qualname = getattr(func, "__qualname__", None) + return ".".join([x for x in (module, qualname) if x]) + + +# +# 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 + try: + return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) + except AttributeError: + # task coro is async_genenerator_asend https://bugs.python.org/issue37771 + raise Exception(f"Cannot determine if task {task} has started or not") from None + + +# +# 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): + 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 + cannot_swallow_exc_val = False + if exc_val is not None: + for exc in iterate_exceptions(exc_val): + if isinstance(exc, CancelledError) and is_anyio_cancellation( + exc + ): + self._cancelled_caught = True + else: + cannot_swallow_exc_val = True + + return self._cancelled_caught and not cannot_swallow_exc_val + 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._active = 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: + self.cancel_scope.__enter__() + self._active = True + 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() + + self._active = False + 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, + func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], + args: tuple[Unpack[PosArgsT]], + name: object, + task_status_future: asyncio.Future | None = None, + ) -> asyncio.Task: + 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 not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + kwargs = {} + if task_status_future: + parent_id = id(current_task()) + kwargs["task_status"] = _AsyncioTaskStatus( + task_status_future, id(self.cancel_scope._host_task) + ) + else: + parent_id = id(self.cancel_scope._host_task) + + coro = func(*args, **kwargs) + if not iscoroutine(coro): + 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" + ) + + name = get_callable_name(func) if name is None else str(name) + loop = asyncio.get_running_loop() + 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(coro, loop=loop, name=name) + else: + task = create_task(coro, name=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 task + + def start_soon( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], + *args: Unpack[PosArgsT], + name: object = None, + ) -> None: + self._spawn(func, args, name) + + async def start( + self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None + ) -> Any: + future: asyncio.Future = asyncio.Future() + task = self._spawn(func, args, 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: + return await future + except CancelledError: + # Cancel the task and wait for it to exit before returning + task.cancel() + with CancelScope(shield=True), suppress(CancelledError): + await task + + raise + + +# +# Threads +# + +_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]] + + +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") + + +class BlockingPortal(abc.BlockingPortal): + def __new__(cls) -> BlockingPortal: + return object.__new__(cls) + + def __init__(self) -> None: + super().__init__() + self._loop = get_running_loop() + + 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: + AsyncIOBackend.run_sync_from_thread( + partial(self._task_group.start_soon, name=name), + (self._call_func, func, args, kwargs, future), + self._loop, + ) + + +# +# 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 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 = BrokenResourceError() + self.exception.__cause__ = 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 + 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.write_event.set() + + def connection_lost(self, exc: Exception | None) -> None: + self.read_event.set() + self.write_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 self._protocol.exception from None + 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 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() + + 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() + + 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): + 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): + 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: + self._waiters.remove(item) + if self._owner_task is task: + self.release() + + raise + + self._waiters.remove(item) + + 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") + + for task, fut in self._waiters: + if not fut.cancelled(): + 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): + 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: + try: + self._waiters.remove(fut) + except ValueError: + 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") + + for fut in self._waiters: + if not fut.cancelled(): + fut.set_result(None) + self._waiters.remove(fut) + 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): + _total_tokens: float = 0 + + def __new__(cls, total_tokens: float) -> CapacityLimiter: + return object.__new__(cls) + + def __init__(self, total_tokens: float): + 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 _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) + + 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 by cancel scope {id(scope):x}") + + if scope.shield: + return + + scope = scope._parent_scope + + @classmethod + def run_async_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + async def task_wrapper() -> T_Retval: + __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_Retval] = 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 + def create_blocking_portal(cls) -> abc.BlockingPortal: + return BlockingPortal() + + @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: + 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/backend/venv/Lib/site-packages/anyio/_backends/_trio.py b/backend/venv/Lib/site-packages/anyio/_backends/_trio.py new file mode 100644 index 0000000..36941f0 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_backends/_trio.py @@ -0,0 +1,1384 @@ +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 concurrent.futures import Future +from contextlib import AbstractContextManager +from dataclasses import dataclass +from functools import partial +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, + NoReturn, + 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 ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType +from ..abc._eventloop import AsyncBackend, StrOrBytesPath +from ..streams.memory import MemoryObjectSendStream + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike + +if sys.version_info >= (3, 10): + from typing import ParamSpec +else: + from typing_extensions import ParamSpec + +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_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) +PosArgsT = TypeVarTuple("PosArgsT") +P = ParamSpec("P") + + +# +# Event loop +# + +RunVar = trio.lowlevel.RunVar + + +# +# Timeouts and cancellation +# + + +class CancelScope(BaseCancelScope): + 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 +# + + +class TaskGroup(abc.TaskGroup): + def __init__(self) -> None: + 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: + 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 start_soon( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], + *args: Unpack[PosArgsT], + name: object = None, + ) -> None: + if not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + self._nursery.start_soon(func, *args, name=name) + + async def start( + self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None + ) -> Any: + if not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + return await self._nursery.start(func, *args, name=name) + + +# +# Threads +# + + +class BlockingPortal(abc.BlockingPortal): + def __new__(cls) -> BlockingPortal: + return object.__new__(cls) + + def __init__(self) -> None: + super().__init__() + self._token = trio.lowlevel.current_trio_token() + + 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: + trio.from_thread.run_sync( + partial(self._task_group.start_soon, name=name), + self._call_func, + func, + args, + kwargs, + future, + trio_token=self._token, + ) + + +# +# 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): + 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): + 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): + 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): + 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 | 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()() + + async def _run_tests_and_fixtures(self) -> None: + self._send_stream, receive_stream = create_memory_object_stream(1) + with receive_stream: + async for coro, outcome_holder in receive_stream: + try: + retval = await coro + 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: + return trio.run(func, *args) + + @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]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + 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 + def create_blocking_portal(cls) -> abc.BlockingPortal: + return BlockingPortal() + + @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: + 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/backend/venv/Lib/site-packages/anyio/_core/__init__.py b/backend/venv/Lib/site-packages/anyio/_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e5a065d85e80fa2f8d2f364d240df2909068aa5 GIT binary patch literal 188 zcmX@j%ge<81i|ZqGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!igvb&DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_pgd6k*@`tiy6MXCDnKy8^N@$q^EmA5!-a`RJ4b5iY!Sb=si0&y{j@sXL4k+Fyw G$N~VF$1~0V literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_asyncio_selector_thread.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7158b6a8af8d481cb5746edfa38a079fc98a98e1 GIT binary patch literal 8403 zcmeHMYit|Yb-ptkQbTeiN}}Emnvx}3wB&~tS{WF?L=u@q<`{HjfBQ< z|MZ+0%?vG5+q{16C3x?h`#AU9JLi1o+%x}HUhX20#(sD_@w}FhU*m(3IK9HG{v%Z8 z$q5oCaVAC5OqgM?&ZgKftChB}O)I%D2c<1#Pdma6Z48$xOY>nq?F>89uCPmMv!~o? zAuOcJ!{rPS1?qq~j#Ne36ZSBKB_fyf8!TAm`|H(kRh*4h$IC=-oc{{6vE+3UcfL*H zuJ>7eNVq00#NBUm;o2MH&1AB2R8C|wQV5>;p=c@v0*pJBI4{n4j9LC!e<+&~RcAz6rxVjT)$?_>nbmQ4o+ly+GjRe3>y9(9 z2^*9wlpK^cDD6;kP�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 YH<5!J7x|iC`HjIJhM!vmOD4d70ng?Zz5oCK literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_eventloop.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_eventloop.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87a335e6a851c736b7180c902ee1dbb6010e39d6 GIT binary patch literal 8307 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_exceptions.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcc08905b775238ba0c6bdc876849191f3854b95 GIT binary patch literal 7265 zcmcIpTW}lI89u9(WLcKwYkWzZcp-*FO)68`8NkCWb}o~WIy9lB7*lzzJ+e1h?TWLj z*fI{o(9k9=Or0quVHgJ5hn7sHZFqvmGSj!dB#=&0O)`@i`cU2+EG7(3{rwpWHn?XV-bb%z>)UKmdkG=d^EtA2xEr^E1GQ@Yf@N% z?PEsd1Tz|W?7ZsZjx|eY6wsy`Xk0>LfHv1aTO>3NXiE*WRYF?BiKARQ0_&c+mjf$_?i ziUX*{j$z>(<@O=&I(d=idxUVr+#691?T~J|+|XvGxvhDkVA@lf=V*DCYq}=N_?kDZ zd)l<_YLgsjg4+fcSd_Q(u0CmT&B$|F#b-S(Y~7L@r*&-NYTJ2oDv7;ZEYe(0a6OBU zIoLnPxsaP0rki$bo2NZ)B$9IR=(%7ql1kZnmZwt1XeyO;jJ!qTSSs~wUbo6K4XKpj zq*JMLY>5c)#ZO0u#&g1%5_&d^tBlV$PTI+4IWCoDd? zM;ztiap9!7>&_joWz1wj8_IHTdT8Q#d9I}Aq;Nw*Op3gnatn5PLNhbq5!YtqK3aKR z12;eg-2)r+Ns-TaRzY)w+}#1Xm;vjxtm#hjY5f>?%cK`{H_=9&yi^B`x+Mab|Zs#$kRG-I=3$j#@tAPqNd(}PwwfGeh*aT38|(B)P}^aD-w5pH8Dm9})( zO{H8q9!%B?LJHv){F>9&5tn3TYYkYgiSF|k*p2vxEAjqI@&1$QKU>!epJ1%wY z_^@l}oteKpcka0b^b#W-f}YdN=#}^x=bK^m@%>wQe^&y0f|f_ zn`dhY&04~8T=B|2o`L0FmDHyKU0-G`b4*BO88TYTDDv>Q$p#L#we9 z4U+N2C>H`=A!q3YL6;Ys(G_9r;XoiQA-v37v9anA6ROY%Z6kGepmRw}tCBK+A9MZd zON!ieCoRjPgP<%1nj7O+d-~pry&k*LGkB?I@Z|ndgmrFQ3@97guC;ZY?mpfBQQMst zTemK<;6U4Agtc#4Xj)`SU)y3+xUKV6jBVI>de3k6Eww~C7hWlG~+ z*E)Jm-*@_vk2(fEj14TRfPCSSz5Q9&t`Pem)V-@;{a}lNJ`wO0fta2M6vMEDd0`h- z92le`RT6RPTBsx6FGwi_-M83W)|)i9EI3HTrwfVYqrU$15Gr*WVh2OZ2qz0Crp*ZWYzjK0(MFt5jaKA-2q@Bdfk*{D&-ZI}Mx2C7 zY9w);G}6P{Z&I%?Pv(_$>P_{0)!4zjLGpWcA&i6jl!t^D(R7QBR?z0+I1PSR;-+%} zDY%j;Wf3ig^)$tBYe=cIXB$@$sA|bZa6XrK1p&QQwmTO$efPrN3-`bO@WtNm|0D94 z5%>L2{G%fc@j;2ug>h|GriPI-oF}T}5Gr@1`%&jASXbPU~ z)lG{Vb1$tDSY0c}uRzks<7IQ6mH{?GDv6v-Y7iMdG^9O2@*({hEFxsc^ju%0hu{H+ zCJr8!vH64s->FfUI-?5%3!H2YdBdb>nO<3(*S`Dra6LiYV|d(3d>X98r!-UNnSuap zB^`cIu2B%Ld1Wrb%`>kWyqqtO#9i=Qv}#4$&7MJE0AEGllx<$A=*=EvqR**}y%snV z_<1PA6!vm=kQK21Yswi#!RS8ra_mnk{E9LPBM~)S({?@GPIJ+Sz2FWiF`HX#huR}& z;x&OeEMsF8qo`u&(rGo#w{!PnET}t-$0fP`H>pr5%p&aziOZV@FE`wCwWIG!$F|EI z+fI&L>rTA0^`q|Om00ppEO}F9o!b|~tfl8yEsG)6Jotqh!wxSdA5ktS4~5@tenhDg zCtQ=-?HR@0+%mItuTjU_>*Q@??!8(WGx7qtjD*yu0&oLJr`+UZK9iw@EIC{r3>Q3p zh^M)Ej31UbN#XxW2gf?Ouje?^N z@_NdDR+-la2}s>Dcw9=aquuJ@3+YkTF3_v z!QtwtTd~@Uev^vAXW^)=!bBxu{y%75jnj}$fqWxW3Z@@{4d^cTvw7|!eV1OxW8zznOO^Qb9Ru+T01HlqF$lPQN3tlO2 z(SfCVBBmHp{}A3wxnI+QR>!IuH7_4 zT@KH(a)qE=@p|PVq&jJ=kYc^arS}OWu*NPAdB8!rAGaMK0*P6{}s70B%{Xep@wEVFpC*IZ+Y4=-9q85T9=cX ze3_2!CjwFTJPjzg^KA`*Zi^hzCyDjLmXkg@cYis4!__Ayev-1C8Qt_I5W(ba8R@!I zoWjiZ1b{QX$k4)dqBja$1a&XrsYY+Z{y_K15|Y6O9-{Z_Qz z$PrQ^C?3G8*j)Dy1Zha;2CDylc)D(Or$+IM-#?SsLe=+79(4y)-vx;n$`1v%*phZE z3l&wQJZ@5-Op72*MLbxx8KLK7*`^qVMT1%hs$Udi$GC8Tj+$S_DaNZ2`xN~cf}cZYrNbQAU)7 YUfO;H+hb;7zC6>274x4lyrfpF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_fileio.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_fileio.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82cd0c24b08a95c649e1e5079b4807f0fe604bea GIT binary patch literal 43370 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_resources.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_resources.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57943ccd113dfaf091481e49273b9dd97f646fae GIT binary patch literal 930 zcmY*XO=#3W7@gT{vgvNKpwfCO8~i!sV5;>@xOJcL<2C)<}$V5|+)6O74v+Hsvo8+q2+*0I3D9j=XH@@nP&wAsximIod zjD6D^hXeRmSYUrxYZ>_IxfWL5;_KSGGJp?5Kz+o3wz1l(R<^YY5K~r}*TBH#jmb1l z;)K(zJjE!nDp}QW<`ZCu<8XQ9GR2+q22v+>#gfR6HE;bT+6M*VhScd-BjzU|xyDCf dDQ~ej1+QNU#&{Q<`GFd{sBxgxu*pY&{|Cyc?dJdh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_signals.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_signals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..927f263a03b78c7338dc6027c3ecc7d92ce4d654 GIT binary patch literal 1273 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

    TN6Y6)}>1p4~25Uswx0P0g3M)(wp3nl`f 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

    QSs8o}zE%`0An6595Q+ouxq{yJE_hE<-D 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da898eac53ab95deda26fe5914ebc9de8dcb7247 GIT binary patch literal 9628 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 vO9*N#1T`RwS&?i-jr@S91p!55dA z#60cFl}tHP$(FM)mn_-MRr2LLB`GpZtjsN9W$&jVj%CH_v2wSha>44g@-X&TeU<`a zZ@r)uzd|C7h6Tg({J;nt-{V>;%)hc`IDxU~+F^d$_H1SZK7;l2D_%X6OoIns(dgij zWjoLfUiVCW(J-&uo@GY&MlcqFw%&mGCb3DGTBMw^XgO`A%2J*j{8@P`4Wh}GVo5M& ztb!%On1v@~V9dc2vM}cBIjt|uy=Cz0Gv1PK%z!Y83f~pG%4}|X0ap!A6=JP0-}7r+ z4S=|$2&!|=O@pb97pRVPP7PLUwdOfDYBo&asI%nQO!b$<2A=9TQ#BY+=V(?=Uqhd#*SvEJBBS<@iQcp+RwT^>7 zGkw>!O<}~6v1pbq`pmBdj%TYTU=csWqBVbU6^J{T3SOEV$~xX3rW`BGCjy6(Sd@@~ zDR&q-4LJO1>$b3QkZipzugj~k2PBJtdiKe)#u}AnTPq!`8S-!dF}-E(^ZHeW7+2O;5d#yse`iZNjjt%o@scsPNs zH;%O3ztmnj4l?kI05-^jKGLt=miA5#-z|PnY@Rs1MYqOw&z#>rbH1s))EvBUTY6X7 zJ23=9cJIj&41Ig*7!3KnmoMIy-pjXu4KX{7hh`9FUI1j11egHCw@!nEuAOz*&^kHH z!0Ys|)$6ArE0Q2F<{Y_4XEiBQ9PW5LFg(*{1-MJ-KkS?JgPBUzwJV@X+tN}DA0Em+ zL^9(jimI}cxRlX#`v$10*r6(17=umzB!CU_=fdFo_HTatMPYpJ*on=lJ5#^5@2-5X zvVCm4*)#rSaip0WVc!5sGkGpd&_9JLCIC603UZjg-;dAE5jG45AdgBb244}cxkrWc z97$rS!Nj=TW#VY*43KejNszpF?EP0ar|(Sv^6h4B_;Ddon?lH_qJTYMq5C^bToIm! zTJOV@1tGYa*y#~B*hznsnIoDs+mKE>)`doPLL{*ZA=SW=d0jVMgL4QucwQWCBGN>V zeH%D+senN$?@~du^fc0z0Bn%GqsKQ(cS^fQwe6!?^T?U4v8~{fwR>w@*MEQF(}6z@ z{bA_S-p_u}EM9KrE#$} z3bs%U)kME^T~RdEDpWoQ(Fr(k$#6NI5dOI4a62wL$o0}a!nz-O64>eSdA*Zq<6DW} z{x6beKy;32Z-eYBq<>Jna#qVlk&=eWB2rmH!D_dz&iYWxQR58-t4zFr{?yQtI)4?4 z{Dj&D*MKVN25{?|Cb4hAi7*otkTAo9szPbe_g#p_N!Vm)r5F#>a94XB1=bV>0Z-Tf zf0Sdve*dZ;|o%24@D z`XD3AkzU1BCR~twm~4a#JqJih*WQC@p^YC3hl`yJ9V{+Y2l|yr!RJ&% z#Sjn;PULlQm(qDAYH>i_s19}vL6^eB8iE($&oOt3deJkoQ#iF-nA|Q*?i8MFO3y|S z1KY`mwO2g%5+I$=wP=t$wEeu*q*5p6NqetdCO`$LhS#YALv-*JqPxnYiZ3ZG#9q13$$WeKunumQzaJ3y;*R(Xl022BNMLQectRn;7 zt-UFvMeu$2a}0z?d;QIR^^4K(?2Nv!J375RI=wSGvr~AjDZTc%8c|j6V8iq#Ag>d8 zK$UG3{Xfrn2O6lK0+(NKhMW1k6+r%scyOO6gz7=s(FbeZ`d}bM Irv$hE0@w6EkN^Mx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_typedattr.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/_core/__pycache__/_typedattr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ba318e89d2dc74e5fa5f273819f4b4e4f42d3fa GIT binary patch literal 3833 zcma)9U1%KF6~6Pc|0}J2qK%XkdmJl@*Og>7sohpIZCxp;T{~*9>_XNOli8WO+OcP6 zHg{$v?XnKSh*rTVghElEO)z~Z34+qszLY!`+6TEJL>^q~(w34pISSb1sps68+11J+ z^uk{5y>ssQyXQOS>|c6%(geo*?=P8uO%d`h+(bhT7Q+5-VX;XJVh9$g3PnM{wP=Y| zsVG(DqRjV_6|2UJ@oJ)&s3wcaYO0umbJ>Vl>1w8!5r{}=!iaAP0oP)d?-T8P5A1ul zLfOTf(Q72v#<2b3R@eU$gb;>`3y zjX6t9t5(6lg%!uqoobabovNn2Ol{9$jfIk?U#GUQ0Q=>Ii)LxTH9a~}gHvsZx(k}! zFr8DX?l5{v=s3LEDM~6uRfXP7iKC{zwRntMe`I2Puoyx^^#@k9bYO=IsD?*O9AVO=E8fR!Ad8N zCOJR7{fb~s9DZP)u>U(){7N|Z#w~z~Nwz}cZwOwvBBVv4fS)Cc&k=G%Y>C%mz~Im@ z#E6awZx6M^mar_i!rM=IiHOjUTH>!oLw-++C~pcf@siQ^x1<*N#ZV{S1kxad*qonJ z)s9)Ns``T3Ok*VT2v?d%71LF!rt3l&DW(VB>-Iz;?kAQgpbKJOGEC;DT~A}4yJC73 z00R&Q_=vgqT7JI@@n?E!O`YBcA{#R8O6AwK18XJHGI|5Vl z_+v3K`55C7AaoaCdbCFFjZJ)@Z@)16QE6xF{6^;9@YC$XsCxc^m2FGr@ z9}j;056O=*f1A2+FMo75uiPHKo!uV4u>HiveMx+BV2_CX1A8$ta_sXgN%g*!xRX5g zaq>71aY!n0#*ypGbB;~HCrMRBGr*r|RjoQk-NJQNRo|#U@`I6NLa(v^_bQHr#smNICKpJjj)f%+axBz6snzvV-8Nt5N9D_ z@(ho-_9|34%n@bkVL1p@2_BMDL*`@DtvR*4qPF<Hf@>3l* z;yq9l;o!%(u;$mkN|kQ{p^F)IjqE;uI*^U2=ium)%}&9mK)S@Gvne?66Gl+wUA&C0 z;>qb7u=#5F-vWwA{-rCA%SV&B{3a|mNeW8DHCP=UEdkTp4M`*|DFWa;IZnK`A4drr z5lBn)Lhut(CoFrQUWZwxt96>2BaCC#tks0<-|6HD#Ko zk?Ggp?0$1-5?(I=xZ8n`YFW^(VW-eO3?+r81abm}d5aLh5fRu%oLN?ECo~G`V%Y)n zgXZG^$WT_>QypPUGhN7cZ}PTkvRmH+o#eCvLeO&B3$nLJrv|P0KY4*Rg4&#FKO)P(7a%~C@i=EMAZZ*byhmA7 ziU03lpN7lsMVQve-jR6f=_pT^GMgef;D<2<9B z#4S$9&iye=>*TKd%Kcc+XJR@wurHB#?;fu9hGFH)r}@dQd>SZx`AWFEazB>dJ@fs2 zl8+7JQRaaNt3V7gk6g&mp28qDE#*4=6@jKDXv}g4yJ@YYGt4Rs^Qa&98u%xQUuD>j z2F9RmenzFMI<4_0oX1w+b?#d3Fm5vbd*DqAH}sGP{N#6o{^@({MWDl+<(`9SPZ9*- z@8p^Pl8JwisU0%)AM*S^Q+@9Y@1&kui{H%-zH?zGtE{E&W(RJaTTAW7Md68u>6`$K Q5=;+ACj^K$n79-E2g4fbGXMYp literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py b/backend/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py new file mode 100644 index 0000000..9f35bae --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py @@ -0,0 +1,167 @@ +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/backend/venv/Lib/site-packages/anyio/_core/_contextmanagers.py b/backend/venv/Lib/site-packages/anyio/_core/_contextmanagers.py new file mode 100644 index 0000000..302f32b --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_contextmanagers.py @@ -0,0 +1,200 @@ +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/backend/venv/Lib/site-packages/anyio/_core/_eventloop.py b/backend/venv/Lib/site-packages/anyio/_core/_eventloop.py new file mode 100644 index 0000000..46d9f46 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_eventloop.py @@ -0,0 +1,229 @@ +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 + +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: + 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) + + """ + 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.""" + 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 + + +class NoCurrentAsyncBackend(Exception): + def __init__(self) -> None: + super().__init__( + f"Not currently running on any asynchronous event loop" + f"Available async backends: {', '.join(get_all_backends())}" + ) + + +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 NoCurrentAsyncBackend + + # 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/backend/venv/Lib/site-packages/anyio/_core/_exceptions.py b/backend/venv/Lib/site-packages/anyio/_core/_exceptions.py new file mode 100644 index 0000000..5f123d7 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_exceptions.py @@ -0,0 +1,153 @@ +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 :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" + ) diff --git a/backend/venv/Lib/site-packages/anyio/_core/_fileio.py b/backend/venv/Lib/site-packages/anyio/_core/_fileio.py new file mode 100644 index 0000000..061f0d7 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_fileio.py @@ -0,0 +1,797 @@ +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, + overload, +) + +from .. import to_thread +from ..abc import AsyncResource + +if TYPE_CHECKING: + from types import ModuleType + + from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer +else: + ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object + + +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]) -> None: + self._fp: Any = fp + + def __getattr__(self, name: str) -> object: + return getattr(self._fp, name) + + @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) + + async def read(self, size: int = -1) -> AnyStr: + return await to_thread.run_sync(self._fp.read, size) + + async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes: + return await to_thread.run_sync(self._fp.read1, size) + + async def readline(self) -> AnyStr: + return await to_thread.run_sync(self._fp.readline) + + async def readlines(self) -> list[AnyStr]: + return await to_thread.run_sync(self._fp.readlines) + + async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int: + return await to_thread.run_sync(self._fp.readinto, b) + + async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int: + return await to_thread.run_sync(self._fp.readinto1, b) + + @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) + + @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) + + async def truncate(self, size: int | None = None) -> int: + return await to_thread.run_sync(self._fp.truncate, size) + + async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: + return await to_thread.run_sync(self._fp.seek, offset, whence) + + async def tell(self) -> int: + return await to_thread.run_sync(self._fp.tell) + + async def flush(self) -> None: + return await to_thread.run_sync(self._fp.flush) + + +@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 = ..., +) -> 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 = ..., +) -> 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, +) -> AsyncFile[Any]: + """ + Open a file asynchronously. + + The arguments are exactly the same as for the builtin :func:`open`. + + :return: an asynchronous file object + + """ + fp = await to_thread.run_sync( + open, file, mode, buffering, encoding, errors, newline, closefd, opener + ) + return AsyncFile(fp) + + +def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]: + """ + Wrap an existing file as an asynchronous file. + + :param file: an existing file-like object + :return: an asynchronous file object + + """ + return AsyncFile(file) + + +@dataclass(eq=False) +class _PathIterator(AsyncIterator["Path"]): + iterator: Iterator[PathLike[str]] + + async def __anext__(self) -> Path: + nextval = await to_thread.run_sync( + next, self.iterator, None, abandon_on_cancel=True + ) + if nextval is None: + raise StopAsyncIteration from None + + return Path(nextval) + + +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` + """ + + __slots__ = "_path", "__weakref__" + + __weakref__: Any + + def __init__(self, *args: str | PathLike[str]) -> None: + self._path: Final[pathlib.Path] = pathlib.Path(*args) + + def __fspath__(self) -> str: + return self._path.__fspath__() + + 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]) -> Path: + return Path(self._path / other) + + def __rtruediv__(self, other: str | PathLike[str]) -> Path: + return Path(other) / self + + @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[Path]: + return tuple(Path(p) for p in self._path.parents) + + @property + def parent(self) -> Path: + return Path(self._path.parent) + + @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) -> Path: + path = await to_thread.run_sync(self._path.absolute) + return Path(path) + + 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) -> Path: + return Path(pathlib.Path.from_uri(uri)) + + 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) -> Any: # TODO: add return type annotation when Typeshed gets it + return self._path.info + + async def copy( + self, + target: str | os.PathLike[str], + *, + follow_symlinks: bool = True, + preserve_metadata: bool = False, + ) -> Path: + func = partial( + self._path.copy, + follow_symlinks=follow_symlinks, + preserve_metadata=preserve_metadata, + ) + return Path(await to_thread.run_sync(func, pathlib.Path(target))) + + async def copy_into( + self, + target_dir: str | os.PathLike[str], + *, + follow_symlinks: bool = True, + preserve_metadata: bool = False, + ) -> Path: + func = partial( + self._path.copy_into, + follow_symlinks=follow_symlinks, + preserve_metadata=preserve_metadata, + ) + return Path(await to_thread.run_sync(func, pathlib.Path(target_dir))) + + async def move(self, target: str | os.PathLike[str]) -> Path: + # Upstream does not handle anyio.Path properly as a PathLike + target = pathlib.Path(target) + return Path(await to_thread.run_sync(self._path.move, target)) + + async def move_into( + self, + target_dir: str | os.PathLike[str], + ) -> Path: + return Path(await to_thread.run_sync(self._path.move_into, target_dir)) + + 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) + + @classmethod + async def cwd(cls) -> Path: + path = await to_thread.run_sync(pathlib.Path.cwd) + return cls(path) + + async def exists(self) -> bool: + return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True) + + async def expanduser(self) -> Path: + return Path( + await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True) + ) + + if sys.version_info < (3, 12): + # Python 3.11 and earlier + def glob(self, pattern: str) -> AsyncIterator[Path]: + gen = self._path.glob(pattern) + return _PathIterator(gen) + 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[Path]: + gen = self._path.glob(pattern, case_sensitive=case_sensitive) + return _PathIterator(gen) + 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[Path]: + gen = self._path.glob( + pattern, # type: ignore[arg-type] + case_sensitive=case_sensitive, + recurse_symlinks=recurse_symlinks, + ) + return _PathIterator(gen) + + async def group(self) -> str: + return await to_thread.run_sync(self._path.group, abandon_on_cancel=True) + + 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) + + @classmethod + async def home(cls) -> Path: + home_path = await to_thread.run_sync(pathlib.Path.home) + return cls(home_path) + + 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 + ) + + async def is_char_device(self) -> bool: + return await to_thread.run_sync( + self._path.is_char_device, abandon_on_cancel=True + ) + + async def is_dir(self) -> bool: + return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True) + + async def is_fifo(self) -> bool: + return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True) + + async def is_file(self) -> bool: + return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True) + + if sys.version_info >= (3, 12): + + async def is_junction(self) -> bool: + return await to_thread.run_sync(self._path.is_junction) + + async def is_mount(self) -> bool: + return await to_thread.run_sync( + os.path.ismount, self._path, abandon_on_cancel=True + ) + + 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) + + async def is_symlink(self) -> bool: + return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True) + + async def iterdir(self) -> AsyncIterator[Path]: + gen = ( + self._path.iterdir() + if sys.version_info < (3, 13) + else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True) + ) + async for path in _PathIterator(gen): + yield path + + def joinpath(self, *args: str | PathLike[str]) -> Path: + return Path(self._path.joinpath(*args)) + + async def lchmod(self, mode: int) -> None: + await to_thread.run_sync(self._path.lchmod, mode) + + async def lstat(self) -> os.stat_result: + return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True) + + 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) + + @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 + ) + return AsyncFile(fp) + + async def owner(self) -> str: + return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True) + + async def read_bytes(self) -> bytes: + return await to_thread.run_sync(self._path.read_bytes) + + 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) + + if sys.version_info >= (3, 12): + + def relative_to( + self, *other: str | PathLike[str], walk_up: bool = False + ) -> Path: + # relative_to() should work with any PathLike but it doesn't + others = [pathlib.Path(other) for other in other] + return Path(self._path.relative_to(*others, walk_up=walk_up)) + + else: + + def relative_to(self, *other: str | PathLike[str]) -> Path: + return Path(self._path.relative_to(*other)) + + async def readlink(self) -> Path: + target = await to_thread.run_sync(os.readlink, self._path) + return Path(target) + + async def rename(self, target: str | pathlib.PurePath | Path) -> Path: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.rename, target) + return Path(target) + + async def replace(self, target: str | pathlib.PurePath | Path) -> Path: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.replace, target) + return Path(target) + + async def resolve(self, strict: bool = False) -> Path: + func = partial(self._path.resolve, strict=strict) + return Path(await to_thread.run_sync(func, abandon_on_cancel=True)) + + if sys.version_info < (3, 12): + # Pre Python 3.12 + def rglob(self, pattern: str) -> AsyncIterator[Path]: + gen = self._path.rglob(pattern) + return _PathIterator(gen) + 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[Path]: + gen = self._path.rglob(pattern, case_sensitive=case_sensitive) + return _PathIterator(gen) + 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[Path]: + gen = self._path.rglob( + pattern, # type: ignore[arg-type] + case_sensitive=case_sensitive, + recurse_symlinks=recurse_symlinks, + ) + return _PathIterator(gen) + + async def rmdir(self) -> None: + await to_thread.run_sync(self._path.rmdir) + + 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 + ) + + 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) + + 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) + + async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: + await to_thread.run_sync(self._path.touch, mode, exist_ok) + + async def unlink(self, missing_ok: bool = False) -> None: + try: + await to_thread.run_sync(self._path.unlink) + 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[Path, 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) + if value is None: + return + + root, dirs, paths = value + yield Path(root), dirs, paths + + def with_name(self, name: str) -> Path: + return Path(self._path.with_name(name)) + + def with_stem(self, stem: str) -> Path: + return Path(self._path.with_name(stem + self._path.suffix)) + + def with_suffix(self, suffix: str) -> Path: + return Path(self._path.with_suffix(suffix)) + + def with_segments(self, *pathsegments: str | PathLike[str]) -> Path: + return Path(*pathsegments) + + async def write_bytes(self, data: bytes) -> int: + return await to_thread.run_sync(self._path.write_bytes, data) + + async def write_text( + self, + data: str, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + ) -> int: + # Path.write_text() does not support the "newline" parameter before Python 3.10 + def sync_write_text() -> int: + with self._path.open( + "w", encoding=encoding, errors=errors, newline=newline + ) as fp: + return fp.write(data) + + return await to_thread.run_sync(sync_write_text) + + +PathLike.register(Path) diff --git a/backend/venv/Lib/site-packages/anyio/_core/_resources.py b/backend/venv/Lib/site-packages/anyio/_core/_resources.py new file mode 100644 index 0000000..b9a5344 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_resources.py @@ -0,0 +1,18 @@ +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/backend/venv/Lib/site-packages/anyio/_core/_signals.py b/backend/venv/Lib/site-packages/anyio/_core/_signals.py new file mode 100644 index 0000000..f3451d3 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_signals.py @@ -0,0 +1,27 @@ +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 + + .. 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/backend/venv/Lib/site-packages/anyio/_core/_sockets.py b/backend/venv/Lib/site-packages/anyio/_core/_sockets.py new file mode 100644 index 0000000..c65508f --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_sockets.py @@ -0,0 +1,991 @@ +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 = ..., + 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 = ..., + 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 = ..., + 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 = ..., + 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 = ..., + happy_eyeballs_delay: float = ..., +) -> SocketStream: ... + + +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | 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 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), None) + 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) + + .. 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 + + """ + 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 + + """ + 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 + + """ + 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 + + .. 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 + + """ + 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/backend/venv/Lib/site-packages/anyio/_core/_streams.py b/backend/venv/Lib/site-packages/anyio/_core/_streams.py new file mode 100644 index 0000000..2b9c7df --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_streams.py @@ -0,0 +1,52 @@ +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/backend/venv/Lib/site-packages/anyio/_core/_subprocesses.py b/backend/venv/Lib/site-packages/anyio/_core/_subprocesses.py new file mode 100644 index 0000000..36d9b30 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_subprocesses.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +import sys +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, Union, cast + +from ..abc import Process +from ._eventloop import get_async_backend +from ._tasks import create_task_group + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +StrOrBytesPath: TypeAlias = Union[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/backend/venv/Lib/site-packages/anyio/_core/_synchronization.py b/backend/venv/Lib/site-packages/anyio/_core/_synchronization.py new file mode 100644 index 0000000..eab87d4 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_synchronization.py @@ -0,0 +1,753 @@ +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 NoCurrentAsyncBackend, get_async_backend +from ._exceptions import BusyResourceError +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: + def __new__(cls) -> Event: + try: + return get_async_backend().create_event() + except NoCurrentAsyncBackend: + 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): + _internal_event: Event | None = None + _is_set: bool = False + + def __new__(cls) -> EventAdapter: + return object.__new__(cls) + + @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: + def __new__(cls, *, fast_acquire: bool = False) -> Lock: + try: + return get_async_backend().create_lock(fast_acquire=fast_acquire) + except NoCurrentAsyncBackend: + 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): + _internal_lock: Lock | None = None + + def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter: + return object.__new__(cls) + + def __init__(self, *, fast_acquire: bool = False): + 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: + _owner_task: TaskInfo | None = None + + def __init__(self, lock: Lock | 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) + + 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: + 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 NoCurrentAsyncBackend: + 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): + _internal_semaphore: Semaphore | None = None + + 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._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: + def __new__(cls, total_tokens: float) -> CapacityLimiter: + try: + return get_async_backend().create_capacity_limiter(total_tokens) + except NoCurrentAsyncBackend: + 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): + _internal_limiter: CapacityLimiter | None = None + + def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter: + return object.__new__(cls) + + def __init__(self, total_tokens: float) -> 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__ = "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/backend/venv/Lib/site-packages/anyio/_core/_tasks.py b/backend/venv/Lib/site-packages/anyio/_core/_tasks.py new file mode 100644 index 0000000..d37efe3 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_tasks.py @@ -0,0 +1,163 @@ +from __future__ import annotations + +import math +from collections.abc import Generator +from contextlib import contextmanager +from types import TracebackType + +from ..abc._tasks import TaskGroup, TaskStatus +from ._eventloop import get_async_backend + + +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 + """ + + 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`\\] + + """ + 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 + + """ + 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 + + """ + return get_async_backend().current_effective_deadline() + + +def create_task_group() -> TaskGroup: + """ + Create a task group. + + :return: a task group + + """ + return get_async_backend().create_task_group() diff --git a/backend/venv/Lib/site-packages/anyio/_core/_tempfile.py b/backend/venv/Lib/site-packages/anyio/_core/_tempfile.py new file mode 100644 index 0000000..fbb6b14 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_tempfile.py @@ -0,0 +1,616 @@ +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 + (Python 3.10+). + :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, + } + if sys.version_info >= (3, 10): + params["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/backend/venv/Lib/site-packages/anyio/_core/_testing.py b/backend/venv/Lib/site-packages/anyio/_core/_testing.py new file mode 100644 index 0000000..9e28b22 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_testing.py @@ -0,0 +1,78 @@ +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 + + """ + 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 + + """ + 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/backend/venv/Lib/site-packages/anyio/_core/_typedattr.py b/backend/venv/Lib/site-packages/anyio/_core/_typedattr.py new file mode 100644 index 0000000..f358a44 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/_core/_typedattr.py @@ -0,0 +1,81 @@ +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/backend/venv/Lib/site-packages/anyio/abc/__init__.py b/backend/venv/Lib/site-packages/anyio/abc/__init__.py new file mode 100644 index 0000000..d560ce3 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/__init__.py @@ -0,0 +1,58 @@ +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/backend/venv/Lib/site-packages/anyio/abc/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/abc/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8cb55e22c8ecdb97adb33d901d2c0419d47682d4 GIT binary patch literal 2363 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_resources.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_resources.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73bd53ec2c2393e8d64a5af3436f7376afed5e11 GIT binary patch literal 1635 zcmZux&u<$=6rR~%UfXffG=@N0wW~-JSt{ufDME-e0)!|zq!CD4qs@4C5}WMqgqd{` zn;t?Fp(2pDHT(-vfPaGnH!h%+B7rzSZ!SiN_SE-gZ50c~^6dBKy?OKA_ukA8wOWP1 zxc%LFXT~JtHx$OhE&v^F0yrTNiD*m`>Qjo?h>gVb&BXF8Et|2OIKHE?6_*m%cPTLl zcO(0Z7M}dFLEa{jb4;QVH@|Vu;6xmLrB`lL9wKbeyvov4WGw55R5gsev~qLxJ)W_A znzd9WS(qg}Yl{dhYa1Z)77KSadb=DJO89-B$((M4=xsbk=g{F>uyR5;@o7YSBci?; z8NL;jBJD%9nq#X zJLqIf+Uk^qqk8Fd4VaGzp~Gna?-C09-6gllx8^=QrE9VZtEV)#@HmD0yeD^7mz%p% zY)h6TopigoFGMJkgab)IC*6a9gzPo3Y&?ycAn!GAby`i;$@nX~unM`UCQExAaf7wO z8^JSvc6)gx2$)VO2>LHf6kzF@rVeo^jO-8c&msAFX6}CVv9dtEXWBGGFdo<$I=eRj zjI;ab-}#R$$F)C#-v0!4Juptp&ukm`=#f{+mp1YtYhVm*=oGv*EI9)Uxyuj2AcM}# zONjPZoI84{rDMXbkr&Xgj2S>3Ahr4brluA1V5e}>nGL4M%-mNypYME;{N!Hx(Y^FU zO@Z!S{R(|RFIy+h75e|RM5`j(9>vHTMt^P#4)K2)(X|m5(gj`a6fLWThAXjJ{RJfG&P}*9Zytnv7jOTE-d%4^q+C9S z2K5QuSoOSCO}qnR)r)wPg$^2qL_sdV)F|g}5Tq>OL4eJah^QMQo(h7GyDT1QN+3{}3cnFoTb�mdu9j0UQ$gpj9FimFX4&NDC)UFR4 z$G-f_#p?qbz5|C`yf!Eya>?vVgEFEDsZ0;6h%OMP{-;6h#i0r45hCeYJi*~6KDo)TX>AqGF x^t!wTCU`Ftf`LgXJtvF5lb6rQ)pN4&t5vH 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_streams.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_streams.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0649ed8680d4c0058f34de5452f589b753d18f8a GIT binary patch literal 9889 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 Hb@qP%w_gH8 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10095d09e701085d55164bfd29eda2f27de13508 GIT binary patch literal 3243 zcmcIn-ESL35Z|@${B5^sS^*WRRuvVsXs;?#1+ow{g(^f1X_N#NSys>IyG?THeVE;I zf-PPOec(Un-%wTX#DBpPZ*Wot5>%pZrUnUkV&?9AIj8AIgt&+C?9A-W%x`CB*WcCa z6$0P-H*5BMiI87#F#Xh+p_4W+cZo$T>JXQ7=i735{3<<#nG5Hx3Xb-^+0gL4I3z0=bjah z&De2FmH3BFeg)<(;iOG1(#~15o#%>GvvPNo`-y#91xek?XC#G4qGTjRkTfhcBPsE6 zv{GSDmabTdbVmS_)Jv+XM!KU`=>T0V(#=`r19bI7S2;k}7*?Cd!s4p%O)ll=(t^hf z#BW>po>y>-t z9t{=AolS`$v43v9-|E2HTf%T%+uQ2w`o8JAE{Dp{ZEuHrfiH%go?+gCV(7qlr?YJL zI?@jK`94UEEiOBTH?;i=M$f#U@8!;=)*pt-F61$)CGcrDs)J)$0P-98>o)mYVm*D4 zQ|JsxAR|!jbb?w02*8=7d2Db2(Ha4l*)-2FNWoYxN&vuqi&Z4 zem05tHoM)HlM5$Etsa&O+Bv&giADl#5*RA0vnc7)6v`%+f;M{EGAfG zx5)%3c`mTur|z!V2uG%LGAaCT*j-y%UjEP6-Ga!U3!8#gd)0^|1^|iUNDwv?VatB| zYw+6?D(sHTU@~g1(~aLN{|s<1wD(v`dc0USbG-WooXo^Ye8>}r-oWi~!On7ROJgm| z2n;BwC>9OM@xzZ-yUjGzxQLoLaRgEe3$dBRR2hrwshV*=nx9rwM)(F8XJE?qGlXkD zOs6(7J!|QMef>y#N>%6kwl%6wy~E(r;k@pq8Ke8SGal3rHMTUeZ}{9wmm#0ok|=5HssNqedni7%v_!p0}SB4;KRP zI&@SpZ6+!hFV94^0&k~6yq{s-_5wIyXTTs-us)iKcm=KTJs63_>%b)@qY9X_&sk&` z&l;VWeRA#7zWl@+ZEA2NEa|#uxLnu6imto9HE@ux>H4Pw!$~wnUAKHw*9G3EVh+hX zl9!O21QM3|0v;ZX>b_xkYavI5NNTRC<+ho)g1(s#B6Fi4KP2 z+Eho?%XD_)Wx6+$stfzH3p3iqjP`eMx=5poBFcNESwqM-2k-;~$OUvk66WC@6r-H( zKNyMRxh+KzjY@ialBIzE4@8uaL~zbR9G2dR_w!wG5lpb_O5BNYo>KaNoPJ17Js>9^ Xk~2S%xBe(xrF4;g<^D+`CJOUkFKa4v literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_tasks.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/abc/__pycache__/_tasks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebe7ede4c942ceebdf862fe824abb65693b71d8d GIT binary patch literal 5142 zcmb_g-H#N<5ue$e{ocFdKKL+T+%~e!!g;X;vBC;D#t1oxe3phHJQ{Z*wdwnbgJ#Dri*^9Q*YNh6YYu4WP7qR)t)j9k^6uR zw;cVtrOQi(Axqey45{h%v}puI-J3~zPm!x=xe8`hAvfEe?aa03AY0a)nGr|SWzns< zb$@4PS9_Of1*%S{YiJq&3(4x(|pR^1MaLloy~eKXS{2;GuI7wR!oXL z&tY0Ncds6s!`Mz?eYPv(@9XCpyYJJ24KuFsAP6HKd10Uy8o9W1>YdZy77>pp`HG4p zccPAn)i138#zgw`!!~*nk@%^BS zjqc|Xnc8U{IKsc+gk9*gXul_-D;!%a+D;fi`9&-+k&suo^mq`(C0DHSo*zM@P@R%% zYSF=3*_Zm++-iaKks*w>=^E{v$h!sCyl#D(PHbD?6y4l7$1S;K*ScP4Tm5{a5?2?w zx_kki?I|Zc)A3!*ElcmvH*T5>H_^nF68@^9sqA0hJKb99%5Y8cPR9$@mNr88uG10H z5w;gx5kVBn{u23I1nv_0SC+oztt=@o60ebi_?l2lJm`DjQNH3FwIk@Fn%#a}QW2Mt za5ra0>NQi|er&A@Xs#Kz-#ESn!f?pZ;~)Gp(p)}|A$b7J&75TTi3@OlPbiXNOumR8 z`4XBZ?e+rr!`)s#CJ&;!@XYPZMsD+Jm8IVWZ!O?Hi`IFBMliCFt#idvW17`$YOBlP zN2XP4v2f)B;Y6&5%!OeciNMtmvQHaa79q^8@ z?YL^&ozU(1MAvQm2R-g5BeG5_l75Lv%}bBicgtUb4z2hN|;r5%VQZ?7KQOuiFPO4%Giub-)c<86*`l5W!UR-fUu#@Tz3&n z0$_zOoN?&p3vlsKvDHvA0SJ&uR;&WV zL+J^{JjH;9%5#N;4hZ`dkwy67!{TZe+I0Xf+&_G{$<7AI5*c|;&*yTUtm!j13|^%T zd_UaK_VpAZ3x4VVTs=oo@&sZdTb0sMVHM<43uGGG|fxWB@fp^wJm}0-*Rl3}kCwAgpDa9Fm*_ z^o!PU2pX)`DB}JTrdE4_(}Iu_Vm$H!!H7fkIa@acG>+=kV%-p^k5P(Jxz?lOqu@jY zA-)J1hvM1;kFP;SwHUQS_mgh(I)q5L+mqM;p@VbvP*OuhKF4Kkn0K;5qhlodbVoOf|yK7_n1+%!cz?!Ga*f!r>9u5QF3m`B51yCS@trQ}*N)Ay^;y|T{-Ljx#7I(^63=GN+-~W3WQ@#`+#@V_k5Z!} z&PW-`7V}2eCAR7Xo?6EgLR-L>P6)z>WdEey=F)8&Wz!IAN(k<&5C8(LS6j;o7-0R# zC`j5-tm$F`H|f%noN}sbdb5qo;;Lg) z=EfzW5M6OmvsNDSdWE#cwlHOO=a511O1?hIjUF(1f{dW5c1h_0YCA^>B!`h^>_{^cz)q1RXg~ z&1=Li*|r-xxa?2ClcOiSZA*I5$v3I_IyH3dmZzwphg))ee~~ECT{raPP+y|?iSZy; zE0hO&joAaYtmp3)W(QSc&;AFM$wK|!WNT2s@1SVxV1p7-Wn*gRfW|PZI{B~$ik=E{ zgBc%!mOPJn1TO05Xa;%HH18NMePvYd8n50pj@~g|xNDraWt_N|FaAD1`$c~C#>Q{+ z2mWXs_>07&J`tt#S+aDz)_38knfZrd*6&=WJy-px7{_VVTBzH4XxN63D?vRpZ8L1x4T;EvH9Yl^lz+jVk;x6>)%J;}vFgwIqe>w^F_4?a zU-;6LvO0~TIHjo{N6Bha&T3b$t$e{!n$6Hol5*;%AxpPnuUXAzt|o)Xy}=^JX&UoP zTcJTfI|0k|m6*r<)Q?!E-Aq9ZLhx0&8V$1A+Mvh2q&$*O0RelPFOk=yQlS0j8HRQHwkf}n{NpKS8fS(qI@ZDWMg%Dc(3b%zahV(wY+)(-*V#7g75fR6J5#glFw zy5bDNiIy=`$f4Mp*1%_hhjoeb0m44ZMa;7{c^nGyk#$WRu8MR#tmNr1i{*+{WojOA zf;a*~c_QXu6F9;ffaDbRdka%ZInLlsa50jBd`Dg@H+u(@2uq3izor9`&r?$*Al`g+ zP2{+9#HEaH9pM|pdiDsch5TKZ#VsVSQ|Eg>9gk%Sdwo)@FBdqfr>eVTJ#koUhSw|Y zl8bU(=WsNOGSnyE=5M_OkcI%ELFptI3qLMFgFQ~o^TKC9)71Dm820Az$XUNe6Lx*q zWj)-j8`fQGHHM@A4K$c5>Bg$_letN24Z0=6gB3g8*x(Wx)H`t;6q2UOFQDwwxO=X* zTCF9k+*{Y3H4sIEjSaEf7c-vkrt8p;b14^I&2g&*>y7_#J88`8;7v?kvcNib%NHRK z;ftHVfs3~>vc+;_$GJER?a)V7MX;Jira4Xo-OO<^!*Rmc>j%i2j`MAw28E{PI9}{J z4##tv_kKC%*yNC(q=HqKynmnH#D^og2!EGXLb% z(olgBB&RM7YshJ2_PwEwoI#8;&+EXADr5WMjNs~u`Q+@Cp#me!oLv~!kkg29_PGvR zVUM!;SKFJ%+iQyX`245C3XY$BCB`RuJ=3n_IsAlw0CsrENS1&ME0QGrK`uTe<^fqeAUA&}HxJ0dpNe^Z?fZ>;^55!* OlKJCD{}33&n*Ig3sqpmx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/abc/_eventloop.py b/backend/venv/Lib/site-packages/anyio/abc/_eventloop.py new file mode 100644 index 0000000..a99a7ee --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_eventloop.py @@ -0,0 +1,420 @@ +from __future__ import annotations + +import math +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import AsyncIterator, Awaitable, Callable, 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, + TypeVar, + Union, + overload, +) + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +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 ..from_thread import BlockingPortal + 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") +PosArgsT = TypeVarTuple("PosArgsT") +StrOrBytesPath: TypeAlias = Union[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]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + 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 + def create_blocking_portal(cls) -> BlockingPortal: + 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/backend/venv/Lib/site-packages/anyio/abc/_resources.py b/backend/venv/Lib/site-packages/anyio/abc/_resources.py new file mode 100644 index 0000000..10df115 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_resources.py @@ -0,0 +1,33 @@ +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/backend/venv/Lib/site-packages/anyio/abc/_sockets.py b/backend/venv/Lib/site-packages/anyio/abc/_sockets.py new file mode 100644 index 0000000..3ff60d4 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_sockets.py @@ -0,0 +1,405 @@ +from __future__ import annotations + +import errno +import socket +import sys +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, TypeVar, Union + +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 + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +IPAddressType: TypeAlias = Union[str, IPv4Address, IPv6Address] +IPSockAddrType: TypeAlias = tuple[str, int] +SockAddrType: TypeAlias = Union[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/backend/venv/Lib/site-packages/anyio/abc/_streams.py b/backend/venv/Lib/site-packages/anyio/abc/_streams.py new file mode 100644 index 0000000..369df3f --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_streams.py @@ -0,0 +1,239 @@ +from __future__ import annotations + +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import Callable +from typing import Any, Generic, TypeVar, Union + +from .._core._exceptions import EndOfStream +from .._core._typedattr import TypedAttributeProvider +from ._resources import AsyncResource +from ._tasks import TaskGroup + +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +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 = Union[ + UnreliableObjectReceiveStream[bytes], ByteReceiveStream +] +#: Type alias for all unreliable bytes-oriented send streams. +AnyUnreliableByteSendStream: TypeAlias = Union[ + UnreliableObjectSendStream[bytes], ByteSendStream +] +#: Type alias for all unreliable bytes-oriented streams. +AnyUnreliableByteStream: TypeAlias = Union[UnreliableObjectStream[bytes], ByteStream] +#: Type alias for all bytes-oriented receive streams. +AnyByteReceiveStream: TypeAlias = Union[ObjectReceiveStream[bytes], ByteReceiveStream] +#: Type alias for all bytes-oriented send streams. +AnyByteSendStream: TypeAlias = Union[ObjectSendStream[bytes], ByteSendStream] +#: Type alias for all bytes-oriented streams. +AnyByteStream: TypeAlias = Union[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 = Union[ + ObjectStreamConnectable[bytes], ByteStreamConnectable +] diff --git a/backend/venv/Lib/site-packages/anyio/abc/_subprocesses.py b/backend/venv/Lib/site-packages/anyio/abc/_subprocesses.py new file mode 100644 index 0000000..ce0564c --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_subprocesses.py @@ -0,0 +1,79 @@ +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/backend/venv/Lib/site-packages/anyio/abc/_tasks.py b/backend/venv/Lib/site-packages/anyio/abc/_tasks.py new file mode 100644 index 0000000..516b3ec --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_tasks.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import Awaitable, Callable +from types import TracebackType +from typing import TYPE_CHECKING, Any, Protocol, 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 + +T_Retval = TypeVar("T_Retval") +T_contra = TypeVar("T_contra", contravariant=True, default=None) +PosArgsT = TypeVarTuple("PosArgsT") + + +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 + + @abstractmethod + def start_soon( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], + *args: Unpack[PosArgsT], + name: object = None, + ) -> None: + """ + 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 + + .. versionadded:: 3.0 + """ + + @abstractmethod + async def start( + self, + func: Callable[..., Awaitable[Any]], + *args: object, + name: object = None, + ) -> 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 + :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/backend/venv/Lib/site-packages/anyio/abc/_testing.py b/backend/venv/Lib/site-packages/anyio/abc/_testing.py new file mode 100644 index 0000000..7c50ed7 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/abc/_testing.py @@ -0,0 +1,65 @@ +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 + """ diff --git a/backend/venv/Lib/site-packages/anyio/from_thread.py b/backend/venv/Lib/site-packages/anyio/from_thread.py new file mode 100644 index 0000000..f8fb99e --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/from_thread.py @@ -0,0 +1,570 @@ +from __future__ import annotations + +__all__ = ( + "BlockingPortal", + "BlockingPortalProvider", + "check_cancelled", + "run", + "run_sync", + "start_blocking_portal", +) + +import sys +from collections.abc import Awaitable, Callable, Generator +from concurrent.futures import Future +from contextlib import ( + AbstractAsyncContextManager, + AbstractContextManager, + contextmanager, +) +from dataclasses import dataclass, field +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_async_backend, + 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 + +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]], Awaitable[T_Retval]], + *args: Unpack[PosArgsT], + token: EventLoopToken | None = None, +) -> T_Retval: + """ + 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.""" + + def __new__(cls) -> BlockingPortal: + return get_async_backend().create_blocking_portal() + + def __init__(self) -> None: + self._event_loop_thread_id: int | None = get_ident() + self._stop_event = Event() + self._task_group = create_task_group() + self._cancelled_exc_class = get_cancelled_exc_class() + + 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: + def callback(f: Future[T_Retval]) -> None: + if f.cancelled(): + if self._event_loop_thread_id == get_ident(): + scope.cancel("the future was cancelled") + elif self._event_loop_thread_id is not None: + self.call(scope.cancel, "the future was cancelled") + + 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 self._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. + + Implementers must ensure that the future is resolved when the task finishes. + + :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 + + """ + raise NotImplementedError + + @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/backend/venv/Lib/site-packages/anyio/functools.py b/backend/venv/Lib/site-packages/anyio/functools.py new file mode 100644 index 0000000..41cc723 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/functools.py @@ -0,0 +1,347 @@ +from __future__ import annotations + +__all__ = ( + "AsyncCacheInfo", + "AsyncCacheParameters", + "AsyncLRUCacheWrapper", + "cache", + "lru_cache", + "reduce", +) + +import functools +import sys +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, + TypedDict, + TypeVar, + cast, + final, + overload, +) +from weakref import WeakKeyDictionary + +from ._core._synchronization import Lock +from .lowlevel import RunVar, checkpoint + +if sys.version_info >= (3, 11): + from typing import ParamSpec +else: + from typing_extensions import ParamSpec + +T = TypeVar("T") +S = TypeVar("S") +P = ParamSpec("P") +lru_cache_items: RunVar[ + WeakKeyDictionary[ + AsyncLRUCacheWrapper[Any, Any], + OrderedDict[Hashable, tuple[_InitialMissingType, Lock] | tuple[Any, None]], + ] +] = RunVar("lru_cache_items") + + +class _InitialMissingType: + pass + + +initial_missing: _InitialMissingType = _InitialMissingType() + + +class AsyncCacheInfo(NamedTuple): + hits: int + misses: int + maxsize: int | None + currsize: int + + +class AsyncCacheParameters(TypedDict): + maxsize: int | None + typed: bool + always_checkpoint: bool + + +@final +class AsyncLRUCacheWrapper(Generic[P, T]): + def __init__( + self, + func: Callable[..., Awaitable[T]], + maxsize: int | None, + typed: bool, + always_checkpoint: bool, + ): + 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 + update_wrapper(self, func) + + def cache_info(self) -> AsyncCacheInfo: + return AsyncCacheInfo(self._hits, self._misses, self._maxsize, self._currsize) + + def cache_parameters(self) -> AsyncCacheParameters: + return { + "maxsize": self._maxsize, + "typed": self._typed, + "always_checkpoint": self._always_checkpoint, + } + + 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 = cache_entry[key] + except KeyError: + # We're the first task to call this function + cached_value, lock = ( + initial_missing, + Lock(fast_acquire=not self._always_checkpoint), + ) + cache_entry[key] = cached_value, lock + + if lock is None: + # 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) + cache_entry[key] = value, None + 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 + + +class _LRUCacheWrapper(Generic[T]): + def __init__(self, maxsize: int | None, typed: bool, always_checkpoint: bool): + self._maxsize = maxsize + self._typed = typed + self._always_checkpoint = always_checkpoint + + @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 + ) + + 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[..., T] | Callable[P, Coroutine[Any, Any, T]], / +) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: + """ + 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 = ... +) -> _LRUCacheWrapper[Any]: ... + + +@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[P, Coroutine[Any, Any, T]] | Callable[..., T] | None = None, + /, + *, + maxsize: int | None = 128, + typed: bool = False, + always_checkpoint: bool = False, +) -> ( + AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T] | _LRUCacheWrapper[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 + + .. note:: Caches and locks are managed on a per-event loop basis. + + """ + if func is None: + return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint) + + if not callable(func): + raise TypeError("the first argument must be callable") + + return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint)(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/backend/venv/Lib/site-packages/anyio/lowlevel.py b/backend/venv/Lib/site-packages/anyio/lowlevel.py new file mode 100644 index 0000000..06d23c9 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/lowlevel.py @@ -0,0 +1,195 @@ +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. + + .. 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]): + __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: + 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]: + 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: + 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/backend/venv/Lib/site-packages/anyio/py.typed b/backend/venv/Lib/site-packages/anyio/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/anyio/pytest_plugin.py b/backend/venv/Lib/site-packages/anyio/pytest_plugin.py new file mode 100644 index 0000000..4222816 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/pytest_plugin.py @@ -0,0 +1,302 @@ +from __future__ import annotations + +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 SubRequest +from _pytest.outcomes import Exit + +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: + 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) + + +@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/backend/venv/Lib/site-packages/anyio/streams/__init__.py b/backend/venv/Lib/site-packages/anyio/streams/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7d5fae27d46c8c03418bf1b964416b63529d8a4 GIT binary patch literal 190 zcmX@j%ge<81i|ZqGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!igmV%DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_pgd6k*@`o$$hsfoG8`td-GnI-Y@dIgoYIBatBQ%ZAE?TT1|wlM;6F^KVznURsP Ih#ANN02_KV#{d8T literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/buffered.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/buffered.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e8d71de6acc09a17e0cb19b1396da1bc6c7eaa3 GIT binary patch literal 9069 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 OV4-ctuL%6I^Y}k0uu3if literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/file.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/file.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af080502e9b20616f1a2d1f12931f7b3c9b225f2 GIT binary patch literal 7564 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/memory.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/memory.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1bd97416835671e9e8534fc8ca1300314f021d57 GIT binary patch literal 15011 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%0Dy8f94ak(^G-)u0g_cy@h>n!-4@zOO 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 YOK#l#enV>GGg$@;X@dtQ%+gi+9}kz*`2YX_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/stapled.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/stapled.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64255f21806c63cb50b90e035a258f86a83b0188 GIT binary patch literal 7540 zcmd5>YitzP6~43c*x85IYkLj0F=mY8#~Q~bkd_1}i9-@nHE~iPs9Efe#yf+(WM|jh z85_Jc5(=cE5|N111|lH^qNWO>t@5+KTKRYXcw?eZ@0(eWR` z8B$5de{^xqIHu9he7GXnX~D@38%ZOzP?|Hs<~K6Bw}xQVdgStA+uSA94vl*2tPBoU zuiOb7)vVVK(d_)3BOO)0Ya6B`A64CXo`;3|j8jQh_ipYTB3Den`xRo41gDdP?^Q6u z1h4xHLFe~Fi!MM(WTmj)q)QjT6!nPizaS(ey;+yx>4#?kp0W|pqk8ayP&SOo{ie}q1H9c>Gz|*NT^fQz>nq5fghOV5TSyP$L+Owr8MxYP8*|UZMlJQ); z7ADXg2eY#d3tD;}gr+h|QnL&tdjgi0%w|rcQ%T!f!QMHIYNk?qriuk8q`G_B%Oqh1 zO0C)~o3Cnk%~6-uRwKk+ZzC}@3i@?IRnyXDtciGA^u#35DoY6u|2!dF@hB9&M>sHm zC33RVTJ=1MJ?qjEcgyn|=fNNS2ztEZyTboi6v+{?hg=eV#h>PGauYXwv>Qe`es3Ld zpCedC`h*iOwKFOz!?JKqigJJQ;ND5l{tRf-ge^{<&SsNY(==$(P*a%&0}O*MPEKpd z*Flw&@V+qlVrqKQO4-Jvb5N_z7}lhgSxjZeJY#|<``$ zgY0kQi*sbHy|d6hly4s@wC~Kf@BFB9wS8ZqdEbh>Z>4$PeJc$8-q<$8-QWg<_r)Qu zu~v^kuWwGP99cxYil|rG1EN8*Ti}7}%;@ma%U(bkrl(Mf+o1!Hx-a)^Yyp+EK|( z)LYR5_bY+p&05Ayj_ugOg(z&Rj?Apz$eze`HQuiZZI40!BI>Vx&;9vG|7v8gAP;^l z4|+T98RD+P8Q+lLj2rIw8VLG#&-lSRhOf_yj3Bn08hw2amcguK5G=)Cu@s(J3Vjqr zvagZi!B=UHwd6WBD$P~(+K1cC%1j0-s(qVzapyf99b9mXprg3{nWh4tZw<{mnwJt*4I^hGsB8(#waV`aVAaQ|ihgXM(IO#~#u;*#U5t$!_rXgse z-@y!HwIfVqGX}T@e4z&*^UAqx9;i7E&}Bp^VV&d0r$!X0nVPy8a%5G_Xr`g6PEb|N ztUjN{a#&SQ&1-3|#jmP*HVM_us#*oSRF!#K=6dKD&W)Dm$l%=P3~Db@RL4z1_hJ)s zQV0$hLgaijq&JA0_1U_PQ-&ckuub2-T-x?R08qZH24b^ z;A@~xmch&t5_ve-spXGDh}I;8N!Rk3%>>}-;_;p7zh6o zP=W5oP1Gv@-FF#N)ts6O5YV4e3~%&XkkxD-4UpOVFiB?fjs!jef|DZw5eUyX&n}*BXSu8`+%6DX?oG5wRp+vn4YWndR@K~= z8iO9KX`F{~7CKO19Y%Lv46Jo@zZba{x%k2#n>()#{rsid&AZm3orS29k1E$Y3cb7Y zy}NHmA76`g7h(hX*ueXz^0D}xN{>&X!|Nf^Ik+AnU40jYw<4}1OO}rVrb5M^M|bg8 zD7Z06=X4*^&S!a~g_rnJ$b6if2S%`(-Z?8Yjy-Vj0Bz2SOG3kg6;FCZH%wVha1g!{ zk<5`xy#i9(@K-XE^FV)B&+U-{2l0B_M;;@r9gOQ89;v52M1))IX&*;k15?4iXZY91 zX$~*KaejhEU|!%rTav*1+J8#*K>W{bj}+Pl zZnq75xP7f#d2iy{#ASIc+Ipqw?WU`VY!RLyjvO{^)GMd z#{0v|eSRzt`=P$Z1K>BzjAj}N4+An_2wh+Z9DIw_MhBxXl?-bm-*c&3a5=6Da{=KO zPlVkcp^W&~)p9kaWauPTt6>+H`~>=2h(TS@T>7%sTDz`{y*;+t+E)no<->hFi#D(g~}gW84;%Ht!z*)Wro z=I7ui2ZP<5JqP3jtJn!&GFu=5rSun@7HBX_oJy%;R}p0)6%LU?OF zy!GmAp=VFNXU`|$C&1{yt4Ji;wIX-A2!}x*!hE`0U!|Zv?kWQueHMu<2AuQo0>k$_!mpN`73Kl8`xr7jK z30)*QvMTH-3IVZiy@MR)j&bX}Up&aIZQkh>4otX(JAtO6h)u;-pZJK!F^FQ9$1y<3 z)c{U55#NFw$%%R3Vt^x|cnl6uBY<&`8mRylYgC&~Qgpr)eIdn2<%G&VB^eeCVvPhL z9iRdYVIL%3X%klSI2bv7M)lJcEVW|RhFJ`=cFZ4?igTD54thoC;gqrFOgVzV% s9s6+qZ>0Q=rykaKlm;e9( literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/text.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/text.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb97da8f34826578d3405544a824420bf7d54738 GIT binary patch literal 9336 zcmeHNYit}>6}~e&vpZgUXZ_msBZ)n6+}P{KI*yY*+){8}El^UaDFrqT>+#Mw-ee!< z&N%6sw6dClj07SGL_h+RAQci)P=E5bKM@l0W`oulUX>6M{pYYnt^A8~?wx%)Zc~Vm zkQiz2ocq4_oO93l?wS2V$$Z9S3FEz6M?l4i<)HF#z+xpzfekK%L!eI#d_^;5RFr8Tn#%0+xp z-F4a89dtZDe-3t2KVT~_tQoJxE#bp;)#hqOi-_-{NZ)PY+*7g_OiGi6c>=Z}nqNsk zapiGkFO*(|qN~ItF~J})@$;bNpwpr$8J?%0#*kvNAw$l~a=w_CStpe!+zKz zX=z3_W4i69nUtsJUd2%pR`k=E1U1uU#@17;he_wOi;Ky`qDD=7nPx0a&*a#EiEMf) zW!h#c2USe-3~f1+#BsF5qE7XMZBl4%X;wCy!8fcer$IMUOJ>|vO)o*iv}RL1V=ZN= z9f#e3_DI%{R`$e(4))E2UoGY%QBjdR0>xu7qn zY>N$xjE8P>bIbO^_~UbPk-Et!%~ESxThuc~3J0?ii@>h>2|(GPkyaU&4~KF}*mHAF zYL;mtFDkRmao%g`tg)OjK{|!?0|9} z(IDul)7mJuEt&CbtHre=r(w@$9HlHF$IE%(csYko+!P!s2_|Qy$DMAw_Bl$NYdlT3 zClzKU1ZnsQrOyCymDsLrC*&MjsD|f~aLcWK#UqkSo=f7Jm6A&&Ug?n|5%FY1pnIV| zSVJ#gloL8@+R5s%aF;^|v6bXVmYG_h{g7e(oPb*&X9vrYpaL~&>q|$cXP0R9EU0@L z6leBgHVYz6n>1m@lNmU$c9!O5=k>&Su-UVazcBk;a(>oI+UEEYlc1~u^?Y5H$twbkfqZIs&bh#&wzx)=;w6#7?-cpwk;lk42Y>0gDBKiIMkKl$IygSp zCNVKNUM`e~hYn+?>*Pgi>3~zMxT~Rli zNU&q0^NB4B&(UlBGm3CsnDI(KeFUicvwRI2a+d$+3>Q#n56JMc&;*hrz~+8rGesO$ zX0#V@Le?@lpJi%VrhQXjY_?E$T&5lZa;1AaQ+em3P-{&=Qs!w<-IrJQ71fcvI#N)_ zipto!GPa?#d^_-sKvCJ1S9bkg*|X^(P2(;L`({MpnlMA8>l#pXEW}lSfQ1sS`sz;l zS}_99$bC)`w$Ym+*Qi!FZB&ozHrVm`WpKXqQD|7Z$tNJcGO&G?cT zj$&{y9~>+O59fo2*OkL`3@T3E^fHs;c;KuvyFyX#94~jmj&u?{I4tZFP{?Y^^wUt_ z(kuNgusaQ)YfLNSz0;@9jA>AE=1fEd;~LNCX)_*o{P8$+t1gR9T3r3%vE#;$#XTJivO4=Fw+&X#~*<-s!#&%c5D6u@>(C=Q1E{BJgwy$j&J z7N`qgos0LHT)gM!XpiB(u+dhB``RO2)C*no{tE5`7XYxy1$F>N5Y=%MXt)Rn@e~I# zAA$Q^lmrq-z+Q#Y4}iHWSjK$-7p$uSus#ZOm0f@BX4tYTP^1AR-4ArJ2|omQRVH}= z;8mFyS^7T+yjnp~m_4FE7emUjYh{bdl?Y>X~zFCz~J^7 z0B3Q=J%Ay#77z~yvzdq$9voiPgDLJNJaj*d;rIbWxieA3Y!Q+92)1?$r!Ko+G$1Rx z(TG-cwI09BK?{qUPljJ2`R>S#;X?Nmq84`A>-K_Eq16sG`>ik#u*em78vEi*rH3 zgw`t^4NSw%38=8p^m5PI9=!ub(fpAAD;v-+p+_2Qa4Wa)2qW*Ne_(CDgzG z4ld3@6@$AwgNxhB*j5RB*lT^m03-HG*S*6J7er7zNZVG;00V>THM-u277$+3X-pV0 z04-sc4R+L-|7Sj5qR(TK`cnESESrHOqS7NsAH@XGD?N_M2}~+?7w*QH4l*~6TE*Fo zh=qA@`Ycko5bng$Z!zcf91s;J-V9E>mvjvmq@fxo-rfsN{AfYyy*v5nuaDoEJc3R< zT9A&EBtbq@@{01ok|N0Co8FzAIL?L|U3om55=y@S;^7Bxwgq;Yi~u-z6}fDLSs=%6 zbYU1L)@*d6TaUFEJw`jc1Mu#Ew`vBBUZbHkdO--*th^4I7ooDXb#+{%W*`qS{2D^7n7-!Hg9Tx z)-FJt%+MBSHm%KP?L~Jf))=&b9D2?2q%cuA6vO*rJOmqD&{NB>kYq+nK_*2eUO2n9CjZ*#Z-Iq1@0A{of@(1iGU76_?*$+pmXAJ# zApxlx5)dh40=xb-UXHPFrJZ?bzGGMXSD@TN<>2l))Kd&a@}WpEG?@=g7D7|S;MBS@ zwH}<>vbcvH0uTL&bX^`2>R?`FgSdo`yTNK$>BE3p8HS*IDLTh8h(*_12Vxl>V_#`p z@uF6L7h7qNRDno;UhOZcgL!rE+KUBsq^OMCRz}>7_D3KnG$j4h8>xpPm5u&4(3YdH z^Jr!lwt<&f*olidxj@S;zmNOGi%E5#Jeo6>SH}u!w5UXHE72{AnphX9sqE}WQ1fv` zcnkXAvt58Y;B}m>;n{f%hDC=!+kI7S_ppP`0TR>uMwMrvlzp0WwSWWCAHuBGCn2fw zhwH)qyt==j4i}Z-b!C`A@`1cMP*fv%HBwMVi^^zT8O5kqyu*ZO8!F!H5H z*Y^VTwkXW_rMEp^r2PV6F-VQ=gdrNuEDo;L(Hb_Q0E9To(- z+%`1wh(X|8HD;j^{{9%cTFA*&vMG65{fsZ1UkCE)flUvTy@S^m&a0`sI<+Z7*(UKc z`8i~!PvZ2*af)ZA1{JqGFe+vOW_w}Kn3*_+kMS6M1V~1Q!vJ3v2n!R8bOiw<50I`w zh-%e<`A|vn%KlO-1I~gxTJj3= z1VZRBHv}d@Ef0YK#Q{4mBLTn4>)G41Si^{0#e`Ljkq&lifq;HoF<0>JALD=rSId zMIauQNqR-F5zVlt>Uo$m4c3|$+?V5XH_Q~s-7))+2H3lH)6{_0D_wY!YWM5*{v}je zYk?)!)bWIl9CfB@w4EFqBe<8ScUD*p(ru|^q;~oS9b3nS@ zdJsOZh!j^vQPe=Q`zPuZ=*1B%KZ?mQOy)7^!2}o9cyE-j43jtDXYGRIby5;#d1zB* zmp@S+aMc$muD;kh(vN}ag=P2>4MA&)(s3X@4S!{T9BMHH%yX6#Ok`6jewnhO`h0>a zP(_=tzPa+x1_(i!Xyld(*l1m zu;A(j$_1aAao0{8A1n^?z;Cwj#|?ftN6B-T$jky`ME#}OQJ&(V_@^n_3ITrB?;zRq z2!ik@GO#Jh&El%Bq!K~>1M&ZbjQ@p9=E>xrNcerJNf6&Bkd!dl3=_#$^mODs9ak>i z_VoQ(>i?TGa?eY|<~8$<(D|M?Bs{v_J$mD4zWYFlKn9pDhBmSI-it!DSwA!jJ#sCP z4~>)vWZY&z-8)v(?4aPkvik>#eA_^Y0PVH{>b-M9voNq89>0;uhY$XfK!yqRUt+$G A)c^nh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/__pycache__/tls.cpython-312.pyc b/backend/venv/Lib/site-packages/anyio/streams/__pycache__/tls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d575901edeee74a212409e5c357913570a99f9db GIT binary patch literal 20221 zcmd6Pd2k!onP)f9xIqBCz(YKmB1ID7AyJfQiMmWl)NM*7(RM=1fgpBMB8`LT1}&4J z9F43b^h|amO_Gr^aVBz2W+IoIiL#sBBwIU`$Vn=x*?-uA63`eWk!zFM^*>v%sg#do zs`mH2ZZtp$vNM~^)HbEpuiyLL_wMg~*TerPD|2&rj{n24N#{0>`=9iYdmMU%U;dbd z(&rjKv*MTg*4+V{vEH9}A2HV&!Ay_;yL|Xhp1YtTI+LRu!urtBwW7 zg0Y&h8kXmY*2e0_>SFa{_3YalT@`B>YltYETt`<@{sc7 zX1x_C-!ax<)LVgi*_VZr%caU2yx!KaPJFMCs?6_@ycU05a@T~V4j@vs{vPX=f^v^k zgX!du-)*M%vh-R?w{ZJ7sqP{t)ys7^tOovd!0(Y(z1ongfk8C_s!49jLEX@Sxv}*n zp_>6M%A&lUTJ%7fK8CRcFstR}T<+M0S!<~EO~M=EGoDC1o=8TLlZm(*5;ES=!^ek` zNoDfXOj6GH@U=S;kIUo9$f>BD@!{9F0G1 zT}t8^Ietu56En)VJgg`QCF2>6OGhU3Dl_H4n^5KOL<0E}Gtua5rslMq439_R<8m}A zOJVuB@i419<4PvN$unrFg!;;Ii>LHw8%3r{eYp-r;LcFC$Q>VkBKBp}`PK)O@1 zBi->px=V5*-St4aTXG}a^FX>s@*=(Lfpo9rL%RQg^fD=c^zsMNeGE^<1L=OL67W@& zK3g3MDgq*Nn`oIvCgZ9&szl=IbV5mrha8=iMX68i$tg6;b|q2OpGU@8QUo=Dm7C-eg^waj)qT7#wF~Pa5AcfXX29|pONRP zk~G&(0Y|sUg2{OD>5P4Ra{7#{%&jG?KrT&=Cruc9=cY9ueL54EmSrV8E-T5&iOF#^ zbI!}E&$X?lIG>smQD!s3sRY{UQDp@yE39H^&9y|a@1H8ww5N0EeCnBqf_qkyafq-P(_zWlXc%_<*#HEM=;6!X1)Q6~x6}`=PXe3ap3W78e3Shm4z`lcsbb$oRwI0>Xx@9?I&aU>ybPDcC?k zKLwj87@%M?f>*d@gxvcd**$myGk02v#A2AF6K4~c!&poP#R*TwpOxdugfe^L6n3N> zmrmgO*%OB+Pn}RFlX4I3)5vLAJrRk|PA1l&Yao>BI`po0dX}v&77U^u^-Bmo#l0@< ze9O+YtWSx3=O4Q?m=gNl=zJvAxn)skx@JoWTi$5hkZRp{e($1JObHtSx|e^PPYpk@ zC{!&5ccp|U-ss+%>fXL6th#z4C2W7Awj)&=I)CU=RZ0i}ddq%3wfVsLk;SS_DdE5y z;ySA5;H5IuldE=7sJRO0zBg*xQ#G9^T6st4RCc0utgU-Ns4ViwR}c<6GV$=sKSfwf zI6x`{om7B02s&{9IS_Pm00JQB1c1fdwDn}0Wg^-=bQC}niS&2 zB6T2!ZV}HAZA8qUNJrQ-wtwSoGi;-0CRLH0OyZe{D#jDy^vtQ~WpOYjC(jI?q*_lR z7YA=d>eX9>Dsg@)s4jPEsp5o^h>3#?^We$n3s3TsB6g;z&P)>tlYxUF8GJUPh$~Ju z5g2tk7uI_`h_1>;wH+<3BVK1Z~Hk$5gwCc*fzTk9Lc!C zbS8u7B(S;9f}F|}9~lh^Y-?tmXA)|X_BcopXvetDGce@i#3;~1blQpkFVG_VEK(0~ zJQm`-<-B#?>gCQ^<^}bW^A@E(Nzm+>%9YI};5|inik^7ghmRMbErzs;MXmpSeC4r? z307ijM?}UB^q70Nph?LD+x2GC4I~9D!Jv5Zm&_JTIr(`)U;y8a6%>o{?pqM}dm9vwo9O@MxS3#>2@#rk!9tU|!$}12@K-woF zGtngVh$I;C>=~eCb2<$gKAF$ZX?t>Iy*l-#o*M(2YviCvF_EZUZp>&JMe2J#XZ(yj z{tV3$Mp}~9Nw8ZXvwgWK%9Bc+dgsM0QD?uXZ*;s6ZU}z`gA&28g0WrM=Uk6-Bd-rj ziHaZO=>}QUV9o{`UyeB+-WG}=s;w&?MW3%L@IAl|HBV9in_fTw@g1rd9=vvW+ zjN|BxG7YgdAJadA`tXO1S;?J>83)!I@d6n~f(?bL z90cNwD}USyB<3n~pk$oHQqW>0osExYf)JpiQ985rr4l9%Bq3$IQX*{5 zRmhXEjz?9!H;jqi2Q12d3W$l$IHrwm*ii*o<&1;giJ2s0v@;HajZ*0Vq`@>E? zI&KF#{`>ClANt;*^tR*Lw&PhVS5|f3&aG-n*KgG7H{N_QRlj}V5K;m)Ur-kt2JZMD zSqiL52U>3jT3@xMJNIavdlozPXn{RH3$*^ayy{Bh<;Kr9FWB!^RA1@2-1GT$3y%9v z&KtPoNqHK+X8pSFWuNBhU8-wK*Y#+1JxhV$Rmb(Ge%gtO>wA|uOTF*KgD4<|(#?HZ zb04d#O$)REa4ArO&!s@^QlM(N%pv;T;T-k8g@bQZaFxNO#-1gyf2nr$Qm|pErs=-N zUg=(NWPO}JnD%vRzV7Q|>7G4W&z_WTIPDx>bPg~1gA2ZFD^R?f6*<>l{(ZF#19xGM zV_4vScAJVKM90z5~@;%A7VN+PB+RK#WD_~hp;|B*Xq zo#&IEt<8D7Lq9Nv3h7 za;2E5HtrIy*m?BsA+?ua7L{%PZhgYY{gpuM%OjW+^s4k&`X4?*Y-CnoIVS*12}W?r zWb5+S@(dnyrPCNoleuf-lt$K`QkY6Gdbt_nxsP)3L&@4)9l-PGIom^8^nrL#CWoZp zU5d%f*PS%k$$8ra=+n>Hp0}Ol&vMUMKgyluKZ>;w-%+q$8VV2_QM7mGL+9a7zou#C ztoixJ*!`b^_LX2x|9=?If)l42bq5>j+HAezkej|g5?6J*2)!l$@1B6Gr_?!l4)4URfM11f8g+N z_}K8!o&zKMLe-3Kz)1_$6SyRH7H0%#A*75zQnhjzt;htx`#l+nCyyaTSE4%%jRfO8 zNGA`eTPY`4mo9B_aY zE7va7gF9HK)vq&ngwgMWzZFhzI-qSjklJ)8Rev~Lb$GGr@V%PGOJ!LbSN$0O-u(kW zQIoFh&?-BYIbYejtfj1c-MyMsS3Y_9lj)k?+cmvQO{>#Q{aRChx@oi4wE4SL-*5h2 zb9&2T+Lp&sTaKifj;3pmYPCo2wX8|E3}`I_>6RT@%Z^mbqv=(TF0Oj?(w=O9tFF5; za(N_O)u~l=Ua$IDRqwm^{akJ9+Zd~rt?o_S2Ti;&4f1N>63J{|1Rf?et0dM&vA zX4Q9^ztx=X8`k=UQ+@kV!TssL{#0Q9-O6CPvR$ieN2O)`U}3KKF8k7fPA$-RC$N^j z{g?geKu8OO?gYB-21D1?#lVK&q1csem$$vmdCI^5eMq6o#;fCB>;L-Bmv`Q&>|d&? zxpMd~4==9S{R8zU^S9=;HODdD>6&%7Yu4Ru>bt2f)(-x|Z>~DnZ@sl~$h*g8`60*ew%UKl zucmk_zq{T3!!{emLk$4>k*#%jgY8G17K*QRQhdYK;U3$Mdu)jRc!L$`Ki*^o(jRXg za^mAB9KX+M{|RrSxSbmD6K4g*>$mQ&w*Is_i1<&tc3BVhTK}n+fc~l92B2|MmxQ)M zk)Uh28jxyexwxr92msInQdELzDaC{puum&ACG3DRv?w}GJ)HUgR*aP~S*?7j4=qzd z!-XD{s{I4loCynK_dcc*&$)}Hh_}ZO0+}?I6Ddtercg_w$jKQcJ_xl6vvQCW-l+>J z64R3y%9?InX(C4Di6nHgOgtrmE1sH}n2?oFfruD#GIFKt!DwXcGjYPE%Y3Ji!U(u7 zLyhC}6<$f;rP73oI<0#a(YZjL*6A32K~PZyI&FhEP?`3HG+*d?TYBxFwstVRc1T-0 zl=AILJ9jNQcP%-+pYy%wOFKo)Dc*6erf>g?{t9R z-=ei|NwsfX^lx2sZp}J4*KWuWbP`+$?eg+B_+4({)uCoYS1eC(D*Ez#9}#nTB3}F` zb&S`hI0UnlG${z4aBF`mFt_{ns zL@foIg!=@_7V={kxE${Y-2JrpUg1YVc3s4$>C2Suim3ANbB2CGsX&^3R@-$0wsICJ zg_HgXd>2l-4o2pBHHLsq`jW?=_O#yiv}P>=XlSth$}^Xr`Fso_>|&rb>t-vWRr9r` zeQPz}+LW(5?d;Z^-B}M;-uB+zO7U&ZQWm@$?6@wZJGX0{+f%_E>A(&xuwyAuowXtF z{j8I7^}Mg{MvWKBhPLvTDu>FrzvYKK!q)`Et~Vm>mW?0UBHXguDDL5re5mJ5$?1G8^A^>fG^xo22(XM&_-L|} zSu_FG24X7ME>&nJGIl6rW!o|1ibb9aGc~EAB2T4d3w}i3pfWz@%JUo4;H}7dsBT4| zPgZqZx_Z4C9qrTg}3eS3fEN>v|A`;RRMulpD39gsIP;dNGPI`XflbF)-MRONmayg^pW{`y zWJso+<(vTJi*;U@ut>IN&>zK@G*3mzKF@!d`-)lH1->B9k;8a_XJ@2yWUd+u_u0-9 zQdg*R=irH677OisliI2fQia9~Q~PHWC+o=ER+_#rB!tco93MVD1N}415J{Yc5$LW7 zU0-kiRuLLxg(>f4mCX30YgWa%M+yq(bmOy7;xoPcWDGtJF%*LO9o7wYTI&`_HRR0L zn5k2@nv;P(V^QRcEfz_RpUGI^9+9z~Ca0QAC z*wix2-pazjNqYhkn5S=aJhR z_x&J}TEG9&riEb;-%B$K&tJ3O_P2vs&RY1Iwxzap*S2S^eD#K9tF@*g3+}$+J_!8k zCGYUE)#7(&Ig88v9ut!;>PLG8I)tP_`9NB@|SwM*9k=5^AD{jFp(LEf2B9zHmj@B~B7fy!%ZlKN9vEm1atO4Rk-e{2bOzZ2_dPOsk-t)&D>~0k z+Kh8sG!i={MRv?}=eH%J3VF9ZwRc-I0hNTh0}&m%8a1h;MTF7d=EijYZmoZJy8npQ ze`N9K<9GU>V9qW7Mjabf{sSs5?uqg_B>w9<5u{F#MI4>@Zd-crpf-3gJ@|w+_ynZq z`&P?V--F$t5oYtV9+3~2pAy^tIH$8k`n2dyQYMqCPsjg5C&-sZB|Q^5aa~IH?$CO7 zqyKeitU?JKtkYfsuYJEpjeaAr1Hw5pM6Cb`I_~6)>6Waic51&}0 zKM*R(AonNe1(f~VGRa%$#Z4(aFmiifvG*j&9^aYMcS{uwP|m==4~fgZnM_8 zIo)|g>pXIolKV9;Y30%ZQ45Iaz(y^wk%2dB-sWpn>6SjNr7zvGS!>zMz(blhlGlDweIVVwLu=phRx4VZ4$?1%=$E3kwzI%|tr;#?-o^wlo>M7lK`l*~_^wUpwi#d1crGKQNXZuBZkyZQUb;G z)W1Q@C_mS1IM6?ZTDrx22hd=oJpFXYuWX@$bo44DW-8k#*p49MVcvhb(O&r&B|k|4 zsUj58EGRMsrzrSy1Q{nBV&D{zoMo#~*+Ci1;qy_7k!FMiPavZH9Kol!w*;rnnXTe# z+EPO6Qe9(8Xk039N(oI%{)Uv$uoR$_d$s`75N(}H&8i~6{x)mc^uI&gR8+vSwHY~}3bSqlR=Z0WW&EmaL> zt@PdvGe6$rcV3k$ z;nr${t7;W< zBq5ZMwh_`99DLy3l+Ppg)W}RS(G!Sw8~xUFvnJRx602#feYOS_-2`&WV*)<>q-v1 zlt)!WoQOtFi_^GOLnCwslJ9Bw{UvhV!ubP*R=~+ZeEE^4dBQBA#fYE-@UCNW_XB=U ztT-*T&Rm74h)i}EzX-Xu_mX2&I5Gh<;z`{XZLTagGDN|i&Ny=;GUr=K!Wms3&3g>L zNrFnoHW5ukl9}=c8oNS^Nc`Ljv^Rf`h^_(4`>#SnLwph*=mU!^8%e94Lv|8!Z_%IJ zF3af=)wLh21^uW51oe^8Y7-%rNAu?y|`EbKhJ35^l4c!;ZX50*`PwyKocqX37Ykuf`+~z z3xw-oZOM;;u|a`Q-}EMCvu<+>!#EVvfr`h+gdLfyXS%A~46T?Q+`4cAJ>2Lf60j&S z3j(Qq6^KZ1wWBU$d@?TZs2F8*pK%8nm)WF@YuFr2i;|>Lc4OFRW#%+rLE3N+lH6zSerQnm%b^gWBje^qL!(TC!>94_8SXQDF}ZlrBo~rpfrkRc z0`-qKM-t9iAyOJ!7zoU#lt>BHtm(jCY>FsUqlc^`D~xA!s(+rS*$Ir~7cF`NC0?@7 z_1|+mxu=oy-HWyl(p+yM3PYIKQ_Ai-&jCXT{TxzD=;c7UjA1mp!d%hdNl#ai@t31q zJX-gn@JUniY{IWJzBRUTeXw<%g+}|MXe-Zswn2Bi0xheAVa}w8FwCvNu-m3cVNmp7 zh|PLgJ(%7?7rBp;Q;qd`>#Xt4yLai-a)jx&=^ASO-~x9~B8Kjm;>vK!x9IEdDPSxx zW28+8WsWlb0Rg0pZ%~}TGd{yuY}}mDH=0A=FmQVTi0RC7-q33Kja*!QVfTvW))wwH z=02R)X%)eqq&@f7!1^xRbieVg$qMeW-q)*}uL)^!KobXkR{hA`u8rT^@yd>++9vSe z>9&np+s38t_37?CTK67UcDo0cIiWlF4kxq+FO9ro<${~xd0NwSHJ%Fgqys%#peI|7 zymwjFV)Y~MXDhh!-uLc1xT+R%71_x=Mf$X0-_6#W&+2Bxp9gmQ4jSvSoxfLS(7YEM zySn+ms2JMHeP#VnkM&j=Kh$Nvq$ci`wEH*JrvSeb{-=Hb5>3Q%{ z{uV*T#)cPw%sTLGN^&Q0JvYou3Ce##f=ZMFr;4b{>;DyB%-UyCLx$ohng|lZ-qWd{ zn{)dY&i+NyZ!Kl6UdR~kS~v!|dLeiCD?b-|F_!kVXug(f>uwIFd^^(49k-o3-dAbq zU)(gr^WWol3jfWH$O`&E`|t4J|a)B(n7#EYLPW5*Vz=Lp$Dc4dKG&%%aA7ZlF| z#RGO}vWb|zHw@U+{RRN*HW6Qi-pAFNZ*|JomUgz?cD5N7yrxe68s9FwZ0~%qcW5`i z+zT{hrJyrPe@YQvrs0Nuevnggu&2e!qx`1K zDVm={#mW~68%fWgC$w~mbZ>=fpN0=YKSM*h3JBgk&#lz4WUUrbpups#*JEc?Mkh!m z7QC*=wJWr`=j!vC1XO;Uv1o=$LHP~=1V(eW({s8NbLS{uq3(PYL8$DZ$_Kr>L^U&B zNK?tlaYGM5q*9^Xqpz%&DRzZ|B6S0uT};4jr2!zl38@?WP&cgRNV%|Tsk}KQG%ty5 z#!c0>rRJ7J0amk=&~ndK{`VqbQ-Z{81T6ZEG6zJ=~rC-&|6A5p7>92 zLn(I;%jBU;-cHI@SW1rmSKUm?-9|F2BXJ_H66rSP<%4e}8H1I(mn52Zkw!*evFhqh zlgTiJT_WhT1{s0ej0J+rt^7O}Mw0%_Tj357Cz)eEvr*a<4l&ElO9Z}Q${J9sce}_djOv~uY~VY7E3i}{sE7KFhsw}WH>xmgFU}H--_N` z#sZPcPXiNfMg_Qrjs@Y4vv#Rt1Khki-QONh4;TGLuoIm=;1o>h?{}w z!dY9oeyvu&_SN0r9C>Brj(_Xj3S3G$aJRDNs*tYj)M`6Zm7#Ry2CZ_#VnsigyYfwN zN2v6{9ihwzN?O;lAbhrLsdZpM_?c5=baMs!LM!eCBAH|h`%|$m=Xh6vFJH;~MA#># zRyI;gtX-sfo>%!B2EjMkC&Md|xsmOG=t6gl%+(Ij1@_wf`d*=m`T+kyCY)GC zlz&9MI1XrCWE{qlD-c3fE*1UYCyf9&4#vk46R^So>xW2~3l=RL1Mf?;ZaxJ7#=0?2 z>JF`@1OC)n&AL=gU%I?+!Jf6aTorfgR)4kWOHFiRt*-H_jbCb9Y7o;6-C9F8lPk7q zZQJ0tR^PeI+3InJ%~pk_VZ+j}aTOch%?kK_4^HNRMyyC6t7yHpH&xM<_I7FBE|TYM zNd3LK2Q9hKw95k~acGV3vVhp%4-SR6TOvQyA>3-QQoPNAR2u~}rp3Gqkw|uk z&(okjg|Ca;TNW31mnKeZGmIc*6}Ct2Rrh3Vcw^hZ?%|@Co6H^_ih0TEK~T8m2lm8I zu};RBcy!JN_6o#w&V;HA_0#X7Ow7RWh2KR{a7bX;;I~h3hcm3aLT$pnSygC*WL%`^O~NFn>Vgv^Y<65Dg~Capqd=i` zuly$p0u&Hg*ELk6oYF6s25?1Hk$b~*`xG@K6{VW;f(SBJY5^0{*kqBDgHlfcalc9f zfp`t`Dbs)HKW0>}w*bHJ1ak+OEL5e1;8#2aEX*%zG-BWYbo$|DvcP>@eU)^-A^4j>d z+ArPUI1iZ4t6Q{+HOm}*7=RSLKW*veD;BHQ L{+7d=E!h7H;id90 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/anyio/streams/buffered.py b/backend/venv/Lib/site-packages/anyio/streams/buffered.py new file mode 100644 index 0000000..57c7cd7 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/buffered.py @@ -0,0 +1,188 @@ +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): + 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/backend/venv/Lib/site-packages/anyio/streams/file.py b/backend/venv/Lib/site-packages/anyio/streams/file.py new file mode 100644 index 0000000..82d2da8 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/file.py @@ -0,0 +1,154 @@ +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 Any, BinaryIO, cast + +from .. import ( + BrokenResourceError, + ClosedResourceError, + EndOfStream, + TypedAttributeSet, + to_thread, + typed_attribute, +) +from ..abc import ByteReceiveStream, ByteSendStream + + +class FileStreamAttribute(TypedAttributeSet): + #: the open file descriptor + file: BinaryIO = 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: BinaryIO): + 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(cast(BinaryIO, 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(cast(BinaryIO, 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/backend/venv/Lib/site-packages/anyio/streams/memory.py b/backend/venv/Lib/site-packages/anyio/streams/memory.py new file mode 100644 index 0000000..a3fa0c3 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/memory.py @@ -0,0 +1,325 @@ +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/backend/venv/Lib/site-packages/anyio/streams/stapled.py b/backend/venv/Lib/site-packages/anyio/streams/stapled.py new file mode 100644 index 0000000..9248b68 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/stapled.py @@ -0,0 +1,147 @@ +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/backend/venv/Lib/site-packages/anyio/streams/text.py b/backend/venv/Lib/site-packages/anyio/streams/text.py new file mode 100644 index 0000000..296cd25 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/text.py @@ -0,0 +1,176 @@ +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/backend/venv/Lib/site-packages/anyio/streams/tls.py b/backend/venv/Lib/site-packages/anyio/streams/tls.py new file mode 100644 index 0000000..b507488 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/streams/tls.py @@ -0,0 +1,424 @@ +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, 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, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +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/backend/venv/Lib/site-packages/anyio/to_interpreter.py b/backend/venv/Lib/site-packages/anyio/to_interpreter.py new file mode 100644 index 0000000..694dbe7 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/to_interpreter.py @@ -0,0 +1,246 @@ +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/backend/venv/Lib/site-packages/anyio/to_process.py b/backend/venv/Lib/site-packages/anyio/to_process.py new file mode 100644 index 0000000..e6796cd --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/to_process.py @@ -0,0 +1,264 @@ +from __future__ import annotations + +__all__ = ( + "current_default_process_limiter", + "process_worker", + "run_sync", +) + +import os +import pickle +import subprocess +import sys +from collections import deque +from collections.abc import Callable +from importlib.util import module_from_spec, spec_from_file_location +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) + :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: + spec = spec_from_file_location("__mp_main__", main_module_path) + if spec and spec.loader: + main = module_from_spec(spec) + spec.loader.exec_module(main) + sys.modules["__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/backend/venv/Lib/site-packages/anyio/to_thread.py b/backend/venv/Lib/site-packages/anyio/to_thread.py new file mode 100644 index 0000000..1f05ed9 --- /dev/null +++ b/backend/venv/Lib/site-packages/anyio/to_thread.py @@ -0,0 +1,74 @@ +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 ``cancellable`` 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) + :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 + + """ + return get_async_backend().current_default_thread_limiter() diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/INSTALLER b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/METADATA b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/METADATA new file mode 100644 index 0000000..6939bac --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.4 +Name: certifi +Version: 2025.11.12 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Requires-Python: >=3.7 +License-File: LICENSE +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: project-url +Dynamic: requires-python +Dynamic: summary + +Certifi: Python SSL Certificates +================================ + +Certifi provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/RECORD b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/RECORD new file mode 100644 index 0000000..6c79fae --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/RECORD @@ -0,0 +1,14 @@ +certifi-2025.11.12.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2025.11.12.dist-info/METADATA,sha256=_JprGu_1lWSdHlruRBKcorXnrfvBDhvX_6KRr8HQbLc,2475 +certifi-2025.11.12.dist-info/RECORD,, +certifi-2025.11.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +certifi-2025.11.12.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 +certifi-2025.11.12.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=1BRSxNMnZW7CZ2oJtYWLoJgfHfcB9i273exwiPwfjJM,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-312.pyc,, +certifi/__pycache__/__main__.cpython-312.pyc,, +certifi/__pycache__/core.cpython-312.pyc,, +certifi/cacert.pem,sha256=oa1dZD4hxDtb7XTH4IkdzbWPavUcis4eTwINZUqlKhY,283932 +certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/WHEEL b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/licenses/LICENSE new file mode 100644 index 0000000..62b076c --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/licenses/LICENSE @@ -0,0 +1,20 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/top_level.txt b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi-2025.11.12.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/backend/venv/Lib/site-packages/certifi/__init__.py b/backend/venv/Lib/site-packages/certifi/__init__.py new file mode 100644 index 0000000..f11f5ae --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2025.11.12" diff --git a/backend/venv/Lib/site-packages/certifi/__main__.py b/backend/venv/Lib/site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/backend/venv/Lib/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/backend/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff85ce374fa0d1a6828894941258f60a97421283 GIT binary patch literal 311 zcmYjMu}Z{15Z&D*-kETABG{;93Zn_wh}hVQpp6g~mt1y@i`i`0#DrX>e_-b~*!Uwh zma>h4m7Q>%m2;rr6mRCuo5y3GClen*oj#q(3+NvU@>k?{m~X=HfH>l~L<*-^k(6M> z33m#TI^0d&!3&o@F`R|Oj&ohLqG}uK^;g0O=DhuioVZ}_GxW&VKSv;RnT7RTq`9^E|{!32-Iev(=5Lh6{o;E zdMu~3k*(OSVVf1Ap}8=vyp%f(EV5-Rss}qhP@3PA;?M+;vv{Ie1Nd?<#&2lrJy^Z( RU;K^R(d)|kU0{|$`vG@gRuKRI literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f984683479cc442c1a10c20d47fcba90d335237a GIT binary patch literal 626 zcmZuu&ubGw6n?Y6cQLIPgy1PCq7kEaX$zu9De6TD3(IzATqkCCmbaUh6c42!D!q8q zKS7E3k9aY(k~&^09>kl_n^V3- zP~a_4pkx3&9gP9WjGmF1J(GX|4EkQZX%WYB*t414Z!Gv4QIlHK{^*R&6NZ5DE!XNI zp4Rc0*S8jYjc`eI;HzoW&M`UB2#m;FGykV`+~3-`-Z7+?h`eHXRZ4s7DMPkxbd&9% z+dZX&vJ%Lm3Wuyiq!T9<7kMX;UW{oGW67kOFs%3!j`}{R8A?0xM(>CBuc z&%~5QYU50k!Hm^;DXrOR7s&JK1L!Y-zmM+R3JVk|##zSmG~5y*5n0ACVG++aRe6D< za3fBhv7Ck~-wf~Zjj-eu>lTWQQ&xua=59t&7V|ucZWJTwtz?1@2W$<`sdMzBm5z>Bw)tYEAw2#BcBW7k8XPaHi0lK=aMrch}!P{{qbeSUGeXQ@1s7Tl?;X i9qY(+U#{-1ezW}7SNE=cwa))g=UE4Nl2W!N-QHF<|9ZUYJmVs>mmV(5=bIMElaD-?j%{)_FA)( zFOX0U9LkB@nnQ(h;E*babN>V+IK;TfXz2k7B$Qi_BO&#~oAvJ6F*)(1dGGDad+XWX z?>FNglgStY`}q4M>sAt>Klnpnf}gYwA-RuCR6r&+g)%N+FA4?0OqkM_Qb8oRqy%l9 zXv%ks2+>if?kmfczCvFmQixz=3c3O#YKkPbCYTX;L)_05$P>E)bVQ*eS-4VB3+jJ5 zVqG2ac1JGx8HpK$GHcD6tnJ3W2rU*{*|3~U#Wpv~Btr??q*W)wHb};*I!rH@b!OSs zOxZTtiM^IFbpEEv8mVM#nz5LZG3+WMRpv~_PWksOxP9#x8J(|1NQMUyMr#V(eZ<1G z5})lc696^QvA=@RF3RDBoZ!Z_{LTD(ODkG_79+3LU{+rzPSJQd@p=ztxr{35+XIomnml<)pD?&WSoceFLD zOkA0J$AH<;LS%k|scvNU?ywLW#;ZIt@iA^^rHDV(6-*&m4WceFz6sA*D8v#7y4Q~V ziLetfHK-}|2U#bwfgle$a2K!3=%KjaMtnS<#yYym#oRLfmXK8(`YZ=XMkHnLOA>`Xm7^Ju=2{h)F6!+Ud2(qj)kZ;nsb$EO?P*Bj{@ z_vW7@2EJbWYVpD1axDo(HRRVic_Uf`Q4 zekTRpfTg@ZpMe$1F?VI%F)S;GU4>K)+XS)aL=Qm9Md?N<(M=7YV!hBP!C9r_P&f(0 zc>x^ASRLBG(@@8o>O@_gIJ(wQuQ%1%x;p#Aizn)ALtQ#imV9Bml1I=O^j$zff(Z|W zZy>p#<69ja^ULwrzdUt;g$ic8+p`kqu*WV@W~k{>qNf-h85fgh0fHBmNx7PH3LS*t zD(i%4q2?%;3?1ffgu4`X{Ji%->B-A;Z@{AS4!ACjrBM30!#9u0jjJ>NTUFt`z>&VF zDpT;(!O;d=Ml=l}hbgb@-6tp7V|xh_hiizlojMpjoPTuVv6??o@; None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + + +if sys.version_info >= (3, 11): + + from importlib.resources import as_file, files + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +else: + + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the + # file in cases where we're inside of a zipimport situation until + # someone actually calls where(), but we don't want to re-extract + # the file on every call of where(), so we'll do it once then store + # it in a global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you + # to manage the cleanup of this file, so it doesn't actually + # return a path, it returns a context manager that will give + # you the path when you enter it and will do any cleanup when + # you leave it. In the common case of not needing a temporary + # file, it will just return the file system location and the + # __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/backend/venv/Lib/site-packages/certifi/py.typed b/backend/venv/Lib/site-packages/certifi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/METADATA b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/METADATA new file mode 100644 index 0000000..8d32edc --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/METADATA @@ -0,0 +1,764 @@ +Metadata-Version: 2.4 +Name: charset-normalizer +Version: 3.4.4 +Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. +Author-email: "Ahmed R. TAHRI" +Maintainer-email: "Ahmed R. TAHRI" +License: MIT +Project-URL: Changelog, https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md +Project-URL: Documentation, https://charset-normalizer.readthedocs.io/ +Project-URL: Code, https://github.com/jawah/charset_normalizer +Project-URL: Issue tracker, https://github.com/jawah/charset_normalizer/issues +Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Text Processing :: Linguistic +Classifier: Topic :: Utilities +Classifier: Typing :: Typed +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: unicode-backport +Dynamic: license-file + +

    Charset Detection, for Everyone 👋

    + +

    + The Real First Universal Charset Detector
    +
    + + + + Download Count Total + + + + +

    +

    + Featured Packages
    + + Static Badge + + + Static Badge + +

    +

    + In other language (unofficial port - by the community)
    + + Static Badge + +

    + +> A library that helps you read text from an unknown charset encoding.
    Motivated by `chardet`, +> I'm trying to resolve the issue by taking a new approach. +> All IANA character set names for which the Python core library provides codecs are supported. + +

    + >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<< +

    + +This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**. + +| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) | +|--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:| +| `Fast` | ❌ | ✅ | ✅ | +| `Universal**` | ❌ | ✅ | ❌ | +| `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ | +| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ | +| `License` | LGPL-2.1
    _restrictive_ | MIT | MPL-1.1
    _restrictive_ | +| `Native Python` | ✅ | ✅ | ❌ | +| `Detect spoken language` | ❌ | ✅ | N/A | +| `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ | +| `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB | +| `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 | + +

    +Reading Normalized TextCat Reading Text +

    + +*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
    + +## ⚡ Performance + +This package offer better performance than its counterpart Chardet. Here are some numbers. + +| Package | Accuracy | Mean per file (ms) | File per sec (est) | +|-----------------------------------------------|:--------:|:------------------:|:------------------:| +| [chardet](https://github.com/chardet/chardet) | 86 % | 63 ms | 16 file/sec | +| charset-normalizer | **98 %** | **10 ms** | 100 file/sec | + +| Package | 99th percentile | 95th percentile | 50th percentile | +|-----------------------------------------------|:---------------:|:---------------:|:---------------:| +| [chardet](https://github.com/chardet/chardet) | 265 ms | 71 ms | 7 ms | +| charset-normalizer | 100 ms | 50 ms | 5 ms | + +_updated as of december 2024 using CPython 3.12_ + +Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload. + +> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. +> And yes, these results might change at any time. The dataset can be updated to include more files. +> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. +> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability +> (e.g. Supported Encoding) Challenge-them if you want. + +## ✨ Installation + +Using pip: + +```sh +pip install charset-normalizer -U +``` + +## 🚀 Basic Usage + +### CLI +This package comes with a CLI. + +``` +usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] + file [file ...] + +The Real First Universal Charset Detector. Discover originating encoding used +on text file. Normalize text to unicode. + +positional arguments: + files File(s) to be analysed + +optional arguments: + -h, --help show this help message and exit + -v, --verbose Display complementary information about file if any. + Stdout will contain logs about the detection process. + -a, --with-alternative + Output complementary possibilities if any. Top-level + JSON WILL be a list. + -n, --normalize Permit to normalize input file. If not set, program + does not write anything. + -m, --minimal Only output the charset detected to STDOUT. Disabling + JSON output. + -r, --replace Replace file when trying to normalize it instead of + creating a new one. + -f, --force Replace file without asking if you are sure, use this + flag with caution. + -t THRESHOLD, --threshold THRESHOLD + Define a custom maximum amount of chaos allowed in + decoded content. 0. <= chaos <= 1. + --version Show version information and exit. +``` + +```bash +normalizer ./data/sample.1.fr.srt +``` + +or + +```bash +python -m charset_normalizer ./data/sample.1.fr.srt +``` + +🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. + +```json +{ + "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", + "encoding": "cp1252", + "encoding_aliases": [ + "1252", + "windows_1252" + ], + "alternative_encodings": [ + "cp1254", + "cp1256", + "cp1258", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + "mbcs" + ], + "language": "French", + "alphabets": [ + "Basic Latin", + "Latin-1 Supplement" + ], + "has_sig_or_bom": false, + "chaos": 0.149, + "coherence": 97.152, + "unicode_path": null, + "is_preferred": true +} +``` + +### Python +*Just print out normalized text* +```python +from charset_normalizer import from_path + +results = from_path('./my_subtitle.srt') + +print(str(results.best())) +``` + +*Upgrade your code without effort* +```python +from charset_normalizer import detect +``` + +The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. + +See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) + +## 😇 Why + +When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a +reliable alternative using a completely different method. Also! I never back down on a good challenge! + +I **don't care** about the **originating charset** encoding, because **two different tables** can +produce **two identical rendered string.** +What I want is to get readable text, the best I can. + +In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 + +Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair Unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. + +## 🍰 How + + - Discard all charset encoding table that could not fit the binary content. + - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. + - Extract matches with the lowest mess detected. + - Additionally, we measure coherence / probe for a language. + +**Wait a minute**, what is noise/mess and coherence according to **YOU ?** + +*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then +**I established** some ground rules about **what is obvious** when **it seems like** a mess (aka. defining noise in rendered text). + I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to + improve or rewrite it. + +*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought +that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. + +## ⚡ Known limitations + + - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) + - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. + +## ⚠️ About Python EOLs + +**If you are running:** + +- Python >=2.7,<3.5: Unsupported +- Python 3.5: charset-normalizer < 2.1 +- Python 3.6: charset-normalizer < 3.1 +- Python 3.7: charset-normalizer < 4.0 + +Upgrade your Python interpreter as soon as possible. + +## 👤 Contributing + +Contributions, issues and feature requests are very much welcome.
    +Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. + +## 📝 License + +Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
    +This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. + +Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) + +## 💼 For Enterprise + +Professional support for charset-normalizer is available as part of the [Tidelift +Subscription][1]. 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. + +[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme + +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297) + +# Changelog +All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [3.4.4](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.4) (2025-10-13) + +### Changed +- Bound `setuptools` to a specific constraint `setuptools>=68,<=81`. +- Raised upper bound of mypyc for the optional pre-built extension to v1.18.2 + +### Removed +- `setuptools-scm` as a build dependency. + +### Misc +- Enforced hashes in `dev-requirements.txt` and created `ci-requirements.txt` for security purposes. +- Additional pre-built wheels for riscv64, s390x, and armv7l architectures. +- Restore ` multiple.intoto.jsonl` in GitHub releases in addition to individual attestation file per wheel. + +## [3.4.3](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.3) (2025-08-09) + +### Changed +- mypy(c) is no longer a required dependency at build time if `CHARSET_NORMALIZER_USE_MYPYC` isn't set to `1`. (#595) (#583) +- automatically lower confidence on small bytes samples that are not Unicode in `detect` output legacy function. (#391) + +### Added +- Custom build backend to overcome inability to mark mypy as an optional dependency in the build phase. +- Support for Python 3.14 + +### Fixed +- sdist archive contained useless directories. +- automatically fallback on valid UTF-16 or UTF-32 even if the md says it's noisy. (#633) + +### Misc +- SBOM are automatically published to the relevant GitHub release to comply with regulatory changes. + Each published wheel comes with its SBOM. We choose CycloneDX as the format. +- Prebuilt optimized wheel are no longer distributed by default for CPython 3.7 due to a change in cibuildwheel. + +## [3.4.2](https://github.com/Ousret/charset_normalizer/compare/3.4.1...3.4.2) (2025-05-02) + +### Fixed +- Addressed the DeprecationWarning in our CLI regarding `argparse.FileType` by backporting the target class into the package. (#591) +- Improved the overall reliability of the detector with CJK Ideographs. (#605) (#587) + +### Changed +- Optional mypyc compilation upgraded to version 1.15 for Python >= 3.8 + +## [3.4.1](https://github.com/Ousret/charset_normalizer/compare/3.4.0...3.4.1) (2024-12-24) + +### Changed +- Project metadata are now stored using `pyproject.toml` instead of `setup.cfg` using setuptools as the build backend. +- Enforce annotation delayed loading for a simpler and consistent types in the project. +- Optional mypyc compilation upgraded to version 1.14 for Python >= 3.8 + +### Added +- pre-commit configuration. +- noxfile. + +### Removed +- `build-requirements.txt` as per using `pyproject.toml` native build configuration. +- `bin/integration.py` and `bin/serve.py` in favor of downstream integration test (see noxfile). +- `setup.cfg` in favor of `pyproject.toml` metadata configuration. +- Unused `utils.range_scan` function. + +### Fixed +- Converting content to Unicode bytes may insert `utf_8` instead of preferred `utf-8`. (#572) +- Deprecation warning "'count' is passed as positional argument" when converting to Unicode bytes on Python 3.13+ + +## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08) + +### Added +- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints. +- Support for Python 3.13 (#512) + +### Fixed +- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch. +- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537) +- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381) + +## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) + +### Fixed +- Unintentional memory usage regression when using large payload that match several encoding (#376) +- Regression on some detection case showcased in the documentation (#371) + +### Added +- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) + +## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) + +### Changed +- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 +- Improved the general detection reliability based on reports from the community + +## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) + +### Added +- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` +- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) + +### Removed +- (internal) Redundant utils.is_ascii function and unused function is_private_use_only +- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant + +### Changed +- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection +- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 + +### Fixed +- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) + +## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) + +### Changed +- Typehint for function `from_path` no longer enforce `PathLike` as its first argument +- Minor improvement over the global detection reliability + +### Added +- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries +- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) +- Explicit support for Python 3.12 + +### Fixed +- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) + +## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) + +### Added +- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) + +### Removed +- Support for Python 3.6 (PR #260) + +### Changed +- Optional speedup provided by mypy/c 1.0.1 + +## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) + +### Fixed +- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) + +### Changed +- Speedup provided by mypy/c 0.990 on Python >= 3.7 + +## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it +- Sphinx warnings when generating the documentation + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' + +## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) + +### Added +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Removed +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) + +### Fixed +- Sphinx warnings when generating the documentation + +## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) + +### Changed +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Removed +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) + +### Deprecated +- Function `normalize` scheduled for removal in 3.0 + +### Changed +- Removed useless call to decode in fn is_unprintable (#206) + +### Fixed +- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) + +## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) + +### Added +- Output the Unicode table version when running the CLI with `--version` (PR #194) + +### Changed +- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) +- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) + +### Fixed +- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) +- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) + +### Removed +- Support for Python 3.5 (PR #192) + +### Deprecated +- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) + +## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) + +### Fixed +- ASCII miss-detection on rare cases (PR #170) + +## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) + +### Added +- Explicit support for Python 3.11 (PR #164) + +### Changed +- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) + +## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) + +### Fixed +- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) + +### Changed +- Skipping the language-detection (CD) on ASCII (PR #155) + +## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) + +### Changed +- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) + +### Fixed +- Wrong logging level applied when setting kwarg `explain` to True (PR #146) + +## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) +### Changed +- Improvement over Vietnamese detection (PR #126) +- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) +- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) +- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) +- Code style as refactored by Sourcery-AI (PR #131) +- Minor adjustment on the MD around european words (PR #133) +- Remove and replace SRTs from assets / tests (PR #139) +- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) + +### Fixed +- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) +- Avoid using too insignificant chunk (PR #137) + +### Added +- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) + +## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) +### Added +- Add support for Kazakh (Cyrillic) language detection (PR #109) + +### Changed +- Further, improve inferring the language from a given single-byte code page (PR #112) +- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) +- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) +- Various detection improvement (MD+CD) (PR #117) + +### Removed +- Remove redundant logging entry about detected language(s) (PR #115) + +### Fixed +- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) + +## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) +### Fixed +- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) +- Fix CLI crash when using --minimal output in certain cases (PR #103) + +### Changed +- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) + +## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) +### Changed +- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) +- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) +- The Unicode detection is slightly improved (PR #93) +- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) + +### Removed +- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) + +### Fixed +- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) +- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) +- The MANIFEST.in was not exhaustive (PR #78) + +## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) +### Fixed +- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) +- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) +- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) +- Submatch factoring could be wrong in rare edge cases (PR #72) +- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) +- Fix line endings from CRLF to LF for certain project files (PR #67) + +### Changed +- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) +- Allow fallback on specified encoding if any (PR #71) + +## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) +### Changed +- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) +- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) + +## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) +### Fixed +- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) + +### Changed +- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) + +## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) +### Fixed +- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) +- Using explain=False permanently disable the verbose output in the current runtime (PR #47) +- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) +- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) + +### Changed +- Public function normalize default args values were not aligned with from_bytes (PR #53) + +### Added +- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) + +## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) +### Changed +- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. +- Accent has been made on UTF-8 detection, should perform rather instantaneous. +- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. +- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) +- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ +- utf_7 detection has been reinstated. + +### Removed +- This package no longer require anything when used with Python 3.5 (Dropped cached_property) +- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. +- The exception hook on UnicodeDecodeError has been removed. + +### Deprecated +- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 + +### Fixed +- The CLI output used the relative path of the file(s). Should be absolute. + +## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) +### Fixed +- Logger configuration/usage no longer conflict with others (PR #44) + +## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) +### Removed +- Using standard logging instead of using the package loguru. +- Dropping nose test framework in favor of the maintained pytest. +- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. +- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. +- Stop support for UTF-7 that does not contain a SIG. +- Dropping PrettyTable, replaced with pure JSON output in CLI. + +### Fixed +- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. +- Not searching properly for the BOM when trying utf32/16 parent codec. + +### Changed +- Improving the package final size by compressing frequencies.json. +- Huge improvement over the larges payload. + +### Added +- CLI now produces JSON consumable output. +- Return ASCII if given sequences fit. Given reasonable confidence. + +## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) + +### Fixed +- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) + +## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) + +### Fixed +- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) + +## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) + +### Fixed +- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) + +## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) + +### Changed +- Amend the previous release to allow prettytable 2.0 (PR #35) + +## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) + +### Fixed +- Fix error while using the package with a python pre-release interpreter (PR #33) + +### Changed +- Dependencies refactoring, constraints revised. + +### Added +- Add python 3.9 and 3.10 to the supported interpreters + +MIT License + +Copyright (c) 2025 TAHRI Ahmed R. + +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/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD new file mode 100644 index 0000000..16c2a74 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD @@ -0,0 +1,35 @@ +../../Scripts/normalizer.exe,sha256=V1bjlCWZvZ6VY_X6__I_wdjyx8zGsVd3Tiv0KtSJ_nc,108437 +charset_normalizer-3.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +charset_normalizer-3.4.4.dist-info/METADATA,sha256=Mg5oc0yfpVMtDcprHt_pPbbV0qUSHEeaEz4NG53pmyY,38067 +charset_normalizer-3.4.4.dist-info/RECORD,, +charset_normalizer-3.4.4.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 +charset_normalizer-3.4.4.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 +charset_normalizer-3.4.4.dist-info/licenses/LICENSE,sha256=GFd0hdNwTxpHne2OVzwJds_tMV_S_ReYP6mI2kwvcNE,1092 +charset_normalizer-3.4.4.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 +charset_normalizer/__init__.py,sha256=0NT8MHi7SKq3juMqYfOdrkzjisK0L73lneNHH4qaUAs,1638 +charset_normalizer/__main__.py,sha256=2sj_BS6H0sU25C1bMqz9DVwa6kOK9lchSEbSU-_iu7M,115 +charset_normalizer/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/__pycache__/api.cpython-312.pyc,, +charset_normalizer/__pycache__/cd.cpython-312.pyc,, +charset_normalizer/__pycache__/constant.cpython-312.pyc,, +charset_normalizer/__pycache__/legacy.cpython-312.pyc,, +charset_normalizer/__pycache__/md.cpython-312.pyc,, +charset_normalizer/__pycache__/models.cpython-312.pyc,, +charset_normalizer/__pycache__/utils.cpython-312.pyc,, +charset_normalizer/__pycache__/version.cpython-312.pyc,, +charset_normalizer/api.py,sha256=ODy4hX78b3ldTl5sViYPU1yzQ5qkclfgSIFE8BtNrTI,23337 +charset_normalizer/cd.py,sha256=uq8nVxRpR6Guc16ACvOWtL8KO3w7vYaCh8hHisuOyTg,12917 +charset_normalizer/cli/__init__.py,sha256=d9MUx-1V_qD3x9igIy4JT4oC5CU0yjulk7QyZWeRFhg,144 +charset_normalizer/cli/__main__.py,sha256=-pdJCyPywouPyFsC8_eTSgTmvh1YEvgjsvy1WZ0XjaA,13027 +charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/constant.py,sha256=mCJmYzpBU27Ut9kiNWWoBbhhxQ-aRVw3K7LSwoFwBGI,44728 +charset_normalizer/legacy.py,sha256=ui08NlKqAXU3Y7smK-NFJjEgRRQz9ruM7aNCbT0OOrE,2811 +charset_normalizer/md.cp312-win_amd64.pyd,sha256=dqU14JU7SKI0i4dyNqV5nPHQHLIUIsfxeULzU2fLXI8,10752 +charset_normalizer/md.py,sha256=LSuW2hNgXSgF7JGdRapLAHLuj6pABHiP85LTNAYmu7c,20780 +charset_normalizer/md__mypyc.cp312-win_amd64.pyd,sha256=CDDD_25vg5Sn3xcPlfwQ3mWrnyKzD50jg_DMKZuN8QE,126976 +charset_normalizer/models.py,sha256=ZR2PE-fqf6dASZfqdE5Uhkmr0o1MciSdXOjuNqwkmvg,12754 +charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +charset_normalizer/utils.py,sha256=XtWIQeOuz7cnGebMzyi4Vvi1JtA84QBSIeR9PDzF7pw,12584 +charset_normalizer/version.py,sha256=MhW8dOLls4GbbxBUqeS1huc7Rth1ArKi4nS90qTFwz8,123 diff --git a/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL new file mode 100644 index 0000000..10ac2c2 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: false +Tag: cp312-cp312-win_amd64 + diff --git a/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt new file mode 100644 index 0000000..65619e7 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +normalizer = charset_normalizer.cli:cli_detect diff --git a/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE new file mode 100644 index 0000000..9725772 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 TAHRI Ahmed R. + +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/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt new file mode 100644 index 0000000..66958f0 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt @@ -0,0 +1 @@ +charset_normalizer diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__init__.py b/backend/venv/Lib/site-packages/charset_normalizer/__init__.py new file mode 100644 index 0000000..0d3a379 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/__init__.py @@ -0,0 +1,48 @@ +""" +Charset-Normalizer +~~~~~~~~~~~~~~ +The Real First Universal Charset Detector. +A library that helps you read text from an unknown charset encoding. +Motivated by chardet, This package is trying to resolve the issue by taking a new approach. +All IANA character set names for which the Python core library provides codecs are supported. + +Basic usage: + >>> from charset_normalizer import from_bytes + >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) + >>> best_guess = results.best() + >>> str(best_guess) + 'Bсеки човек има право на образование. Oбразованието!' + +Others methods and usages are available - see the full documentation +at . +:copyright: (c) 2021 by Ahmed TAHRI +:license: MIT, see LICENSE for more details. +""" + +from __future__ import annotations + +import logging + +from .api import from_bytes, from_fp, from_path, is_binary +from .legacy import detect +from .models import CharsetMatch, CharsetMatches +from .utils import set_logging_handler +from .version import VERSION, __version__ + +__all__ = ( + "from_fp", + "from_path", + "from_bytes", + "is_binary", + "detect", + "CharsetMatch", + "CharsetMatches", + "__version__", + "VERSION", + "set_logging_handler", +) + +# Attach a NullHandler to the top level logger by default +# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library + +logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__main__.py b/backend/venv/Lib/site-packages/charset_normalizer/__main__.py new file mode 100644 index 0000000..e0e76f7 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/__main__.py @@ -0,0 +1,6 @@ +from __future__ import annotations + +from .cli import cli_detect + +if __name__ == "__main__": + cli_detect() diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..061c046e3d0ef5699d9b27434dd6e2c92829c724 GIT binary patch literal 1777 zcmcIkPirJa6tA9{%w&3!tVs@nAeIQ5j3$#cIVi&#$i{>WBoobMJv0MNO?S<7Z>s-L zRXuS$NZgAb!OtKI5{1Pe8b5%S9)biKmObo2_7+*Zc=A>EOlBos?ZfN$Ue$Z=_x{yy z)6+VF@6+!N+)fdp=SmoTg^bZ&#=v}oY-Au?vvW-Iaz;*5e4gcvyj`#-SizexCcL6i z^h!p_n=~fjykHku+0zX@HR-I~4^NVi8MwQ;+j9@|td;X}t2I3(5)=~4`= zF~ zaD42zmXo^rq%WNS@CBS+X9aG0t_@cKE42hBa3-QK3^>58>H0k)Tnk46FxGX9@%s9D zmhdo3)4#4Vc0Fa59-HmHq+(iF5;BhZ()=NEwRy%1YOjPSmbhfw!_B2~Oq8&8Dr_^tu&Phn@Pnq)s91nOtY$Uco-2c zDKeqRq#|WS)Z57`ip(f7t;iIRWbS6|s;?&{(}en)W}=&BCz27Trpe(ELP==|Cdre~ z&7zEhs(49}(Jrz2Y22jf!TvEZj-O0K5~`U6FAcG0coZ@fnJ@;C%UvpWA#utRo!ItH zmU~iZ!f*_QZ_!IIL4UV5>n&LLE+?J`b!r_40St#nxkXLa@4*lSyx(fWlSF;H1#+*o z>$Y3Mm2`RdP>I&fI;@yr?Ml&>Hw|AYul$E UT&`^o*0wL!c78_<{w8?-2Y+;6wEzGB literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3a8a5182fb00adccd083d58c53ec0a13fcbc316 GIT binary patch literal 352 zcmXv|u}T9$5S_iflaLU56&ov4sGWs~jcpLL3=7NVc8p7Icf;H!a_I&Cz;6)2AF;FZ zKoGn0f1V+YoX6dSlAizZIvpPZP%8oCFaO&Ns;tU-TZ=~bSlv<1`JjUFu3WIS*Uk$gH3rN>-ICHO)d)hE%1W6@nrLT ixgX1tGsZsQ;0N};c;|8c&UZf2?T7x7L%K_ynD_&ko?~19 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb1697557170f4fda38537a63e43171520d72208 GIT binary patch literal 18160 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 Hk?#KoIpl+_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2764a4d6b0e28e0efb399a63f5104e2a0e83bbd9 GIT binary patch literal 13239 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..066baacd512bcaab5aa6139ee3142dec0a96f797 GIT binary patch literal 3007 zcmZ`*Uu+yl8K1q~yW3meo&Uv--8j)Cp{-Ai9Uy8NqEa_F=O#^Rr~U)v>S|fv&YjoZ zKj+yw+jpEL7X`_s5;gD;LtCj2JfsSOz)N`q6$ua^*@-1iD@Q~EgeviHk^KZOe6xG& zL~)pvX1|&F{>|_E=9~FbDy1N3Z~lDT_%Bd@=Yz0C147tc1L7vqkuI3X5^{pT>4+Jz z#GGhJImsW3X4H!1Vn9oJ)QnqlPWI`TnXr_cVzuO21VlvI4zh7GX{B;00Y%VjNSALQ zJwZ~p#lT)Joj`grfgb<#l&;)}=2|N)ne^wJEhBg>nr%BwV}@h9nTVH~ynZdK4qwU+ zU%5Q`nkQbcE5IZzY1IB)2qcsObu4wJ!Uz}W9=>#8{9<-e9UdDW&rVz$8@-qv9nN|k zlVfA*#2Xi`UR5WuZ%*+!P?VUgl!$)O$g_OlX3#f%7Isg;_$DGKC+H{_nF6ecs7GFg zSzQE5@~J3LF-}$D8QD|DiCZ=q*I89uMsW>~IyUiSV&@&*u#27uvz}~fcCoA#Ni|t8 z9gT%-O5U*xh7QbRG$VPks@j@GRMk^d)pGQ*$?2r3E|fL1xzehtkAbGDpP*g7jsJXW z`22KxwQN5$@p4?aO=z1?zKZLhsOb>@# z`3O*9O90V=kg)rGn7xS@kEY*hk=sq0zQ~%90K5e~GS|%AkdyyeJRH>`b6n>W?RIk< z>J0xMKm5wW!Za2Mm53}}gR+kvxwclze)b;`TXnzmi5uUC& z)J9ua>p=}Gh;<#Do#RM8(Zc<$h&Az@WKEpwd4d6kwxCB>Bv?NJ>(3lq*JJZ9K_I#G zQ&vGbz7hrLR$T^;zJu~rs4>2cSS|L>U@fL6=BGhlrY7miqClSosbdGF^p-NBhaZdk zK7I^`-1C4rje^Ex752Uo124KkYihn9=G&jH7x*PTU4@i{Jqx~-_L{^_ggO@yO*|Ua zq+VD6PN~N2w0Ez@!bqNBHcN1Lw6Rn0$3+89 z6Xqoe!&!&3H;6AY?9Mu6Q^zv|TaL@j3g$--Dw#e2$Fc+^Z^k5pzUpkVRA7F>@seSh z*wR>j77sVQah7bnL=6V2@zN}@$s(b+dbK*h~^q*)4r+y+kr*ci$Nizl*d&k6kuN{8{j)^+#T|DRQsD{bl_1L#k%2AsH7B7rbQnn z7eDU_r>aMv2WY~C+YbyRA;8?9seUQDTmlMka%OzwdD6i(=40Vvz>b5WQK~^SiVi!E zN4@xzJ#RzOc&Hd0gT_$tFMsCk-$SqPy5>bSH*XkTw9E?Xxsl>ee$3k+hbTX|o}{`) zF(Xo54QU(icm>RKcp_|)#(b7J$FM!gG+gFM^Q7W>is2fz%QOg#m)Lj7i*nKpZr&`V z4)rANJ(YbeGX%oBZ^nxPZjS4TGmb_1lZNsNpNV@iSHd&FJM^^RdNF>kimoTnN6LJk zU4C6Oqe*$G^kM<9^ouaywcMSA+h-N+^&z=s?d*+j@5sq|`s^L|)8$_-|4#bN*MI-k zZ{Pat?R&3I+f|Wmf4OUK^{CHr!bA93F(hrt?c=XQX z>g$apN_1|@$Lh)MjgxniN9)N$jfmK$JQSsr(oj$;{eJe{?E2KZqdUpgb@{zFw)+O} zCI=sY7x^u@cTH)?NKUM-Z1jBmjk~?4?zDf}^{cMB+_pZlB|oz!KZqaMC~w8TaI0tg z#VcExD?6Q;Tm4&|XV&CK40Ro?AL^@jSMr@bAG%3IRgXav-1KQ0y|J~x}i2QQ!^m>JU1s3@0#2tsO zAqs+UAD#FYdiFl*{U^*sc?MjD+t*ATxd#OmqJ;Qzwu S;6FU#{~ttK_oA@w+x#EcP!?PO literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30b92cd311aef34ec1394ba21a092fbd5ef5a2ba GIT binary patch literal 24333 zcmc(H4R9RCmEO$$0K3=)b^$E@0b&;aOMn1KP!dUzpdf&hK#`zCQfCXHyjkun!6o+x znpubf4m{J2QlWLS1zl{DwsU1TWm{0m$x(@uW7Xw{xw=&Oa+SIr{0Qp}or3Fh@2)EOUeC`ib{Bx?(p?(Zo|&HRp4YEmzxVp}>;ALS(h?5grGI%Y-18F0{RKVf z!K&Wy8-K!c+-*+eL_Wer`Ej17dsD;|HIJLwy*XluTF0%pw}{qAQM7oxIBFZWMeXBu zmR1xgi8{s|QRlcbS~^}DEgLV3y2f2m_qaP+K3*QJ7_W#{j#oxK!S_h4bjH&MxHZq&v9b$o1AF-z@$Pr-o(=ENGl07ePGs7_pnq4 zQk_|;%`CMPsbyKI0!wuv)t!~*2f#N4d)A-m6`S6)e4xJI#yeTwJ=uB1mhAj?PHYvM-?SPf zx~2tR+e0evEmxX12AQ%kA5>tUhNKD)5SqfYV2h%mitv@WsBlOyTIW9%h zZoCKvN+32d6=CUD!ct%&5DTz}Yk@@I z8a>!h0#%1&43f#ISdah#4$@A%kwcRJCJ~odW%6|NQaq9_#*4(2K$w-7icL!4Sb{-O zD&gC&hqU&jOQ&LhLk#&P01-;NPz*5o@rige8jl6Feq$GnKKYF!c)ZPpxN%uYi)a(gxLQTKXu-88R4kT=)~x=wO&9qb>54NUSsn=`LP3E2Vq|I}9GjUg z5fGjQ%7nlrIUxmt2_YB>$g(gcheQEL6{095h^!bIFHEw6axW`56p3iB;*u3Lt}u#>5G>F z!E0#jMLfTL@pSmoMLC=Z?VChuU?L=6q*~=r!XE=^1|s2^kkl6ydnc#UwooKI5e9kA zH01Y5ul}+VpllGsy~%CbI9E&3=H0*(_ZXP_ih;QcS3*KG5RM5_d)}N33QJ0$w}tCE+A*}`uo#k19crSn zmZ?W-2IP_#k%nTa4fkowh4JVItB_@R7~jaeOee}xJXFhAn`R}B7s!n+iH(>=QWxDDBNgzLtIMl zGG|tojlFM?TJbJz2A4?}Nuk7)6iZt!#p4m}jnq%5+D~~bWARw%eG_|-2#wl(+Il$> z4`4&y zwA4#gtKGx8RBED36fr{Gi<>vOM<%n?woziSwrn`9h{|xc?&ONfJ~7dw8F!E9j`cDt z97H)IfHW!a8-s|m_;<0$gIAluyHy@;*LZmGjyznr5Rab;#HPR08V_UQH-d__y~K(NXQzabx4hIF<6vJ`?y(o2V9{_Al`lyXTBeNQ9R@1ODQ zhK*i5>j=P=sXuRWsm`ujmStOWs-=~#^{Ms_x;Cx#AEc`{)wBPWWyRL2j#>jHC~Kgz z1rN8mS^lblJ|t*CSE0^x@AG32JWxE0cINRvMw*|Z8M;U~jgM@UBSJG=wX3c+#nrat z>PXr;@}Z^fW1W8pPy$-+4gRVIWA;VlXG%$?WC&vxWO6mT-CFi*PhoJxXZeId3a|6h zM50))ZI=H)!-v$wzGlCtM7PL>kcS& z2Ns|(JD#({;gdRq1 z#8WZ-`_!yv8q8f~Cq6U7q>5sOyPT2F*!N7wuBcvivgg%0z=V zxiyDt)gdSjVSZ@Q(VnWTCh{v^b+#(b)_HNY1>wyh7Z|&SDa$9>h+RWDG^%5q&ZPwGgCco)ct%!;T z@iPLbn!;x!z-u+?9m>pXcM{wJzP$5jn&zYzkqH_SH5&3bYtF2S+gt(4a604N4iH0T z%BWASKm_ii$w($US8UDd$RXm?gE9VFkg~gMl%7X6m=C};1CdG0lk(Uk_4y7!>Jsrf zvdLKzQBYjM63vxVeQe8IiFy)0eq$0hk0TKi8Vz6sXJlM8lPU#9x*_8X{7iEymm^7{ zkKGd7OXC#fHJwz|nWk;~hfSG~MJ8RjfModCQFq6;>}X?yv2_sx^fkrV^^vo6-OM@L z)vn`FR1Zei2}t==#3sFhoOxtL<85ZowqP@^d=q(en$o#3ac6_33Iaxqi27?AZj1)( z$c<4tH|)T3ACfX4okKKnnT3yzv-avdw#wkK#z-T>7-3ORXNHV7?Su(pu5Tj0O#CaG zx$a*?w^dfJb#||I4l134_dTmazop>6^S6?=rc~Fl`<}(F6G>NF(l+*!0Yt1f3$jw_ zWz?O^AU{WGETXUL4ANxvZP<8g>qe0UcTSVF4QyMT-<;JMq}6&>V~|ulh@TO(!SNX} z$nuvncC*ifGx|(midn`ujVTTT{yY*UX){xw2Z6y7zlQfZ`RdaMVvW$p@>wDw2)N-l zh)3M!rg#nxORYDv$+r%bI-f7~A?b!ABe$=--`P5m(=VUG1nm zVoHK;F3jqPX=T(x#-gMEz6H)Sj7#BmF@>*CyNC(>K8netf@L!yO~Yf#e<$?*1>wnMkW9@REb)3h7DbIaSv)NtoPlQYA%syn(U5U7Mpb!yi#|8W0gPgcU^7`4(MAzW>Hu z`%>qTr0qyPi?pBsV-CLqmhm{+9|oh*fv7_ZU;0LZ_%RDvO!lp;)Pm&<8_5(b9fs{h zuZiP6&~Bx^!r$GojLPCkfyoI5<0dSykN`7LLk9Y+v>jn*^WVq#R<2b=6&Xb;*OCB* zM7)(I15=Z*%u26OQXNHkl)|J)+irwUGUX3YUj90w0xI$v%~LxRXGhX`;DLM3o#|z_ zkFJT;=EF+!;br%cHJz}QT`lv8)y^TMb7-}5ROuXD?tFonRyr2l9gH=uxH~>}HQsq; z$<_IzWA{9(htDgA&o6afSae;;%a~FvFxqefAsWGuUB4kuk!Vtr$0wLh-o6{Un2h`P zD6caKZ;Q$#bQQhbm&GIsLjCtC^UeTLUFI=T$(7|y=I!2Ul7N3qt=>rjb|~oPa>c!O zL0s(}R`Bl{PTGbaQv$}Qb13=&eNUHw7VDE6PTuFnx6x>}?$s<47VAhx0*+`B zkc$5uNk(n_KXr(RxlfmPDYEm!2%0Y;j3L;<8o8T&pUE|86nXR66ccE9(CGp!No8K3 zh-_C|Y!rr+I{LU$iodF9M5xjTA82=SWtLnrY#6c)*8Czp^Xr^sV+%iqjDR(syIMe+ z+(fypOF~;DM}ZQ$)VpEI%4xuH!<=Q&H_e)LR~<=}F=aZ0nX4hs3<;VGkt$LR9Vivx#0kj_cCBoht= z1l2Ifq?RX_SV>APA)ov%q5@KiY^>F*&L+j#wCrqtpxgCbwabl%6xX4(uAW;X%g*+c zvx1pt+Z0Dz($SOZ+OH>n+%a%>WcA<~<=~m6jKMG``qm*>Q$h zi3S#(19xF1I<(>(_-t(ah16c%^hM}Y@t@1MnYgOT#S;@x|C11JkcC=hbbBA-QI$<+mwuK_iS4Bkd~#?X<4?2V$`D<=$j4WQHJ7FFChPvOim-j zgLJAPUOSVI4H8@b8?R(i%(EwM&n`MTGN$UgeAwYAfDZcKGS-CVW_YkT|X>P`8uY)Q}hDuiz@OJ8fmI^NsPl=jGqt=NQo zp-MPL=VdH$(iNoaWQr>cyDq;m)#aoxRgovZsju0mehC`bZPqNUvo!>R%1~Adv-+yM z!OaTEZ%sZL)TWn)%Z6UwpxMHboUM=l!$LBd-pG!EUwuAHS{pK))%5hXYw*2^avi$N ze3O;&CdekhLe3jcqH3Er#cW)WjAfw^JaSJVSY&S@IOOU=Frf7XzOUh&R{3*+fpdrc zg6U5MdROL|p99TsbAq9-)g;Kk!9oTrvNO??pE}1&e^c02fH%Kn6t+h%mAM+wy7aV! zSHCMGOr*R&!mYp_&tPY)elkNJC>mgtK_zdPWS}jQ&MNzpAebiNl;=VA!Cd zoc49&I|b>8*;g93=4LqmR9~4ji8hAMe}wuCX_Em?x}MmlKNW6if+oZ)i1t~Nu8r&0 z5$+xHJC>k%0yCFaYdG#ADEx-`hGo{gBaTh8mUm5W*IBq5R?01!ZWPU0rOGU-v+8)& zsG{T=>18I-jGRSsFvo}r4d$Ne3e#p0*KnUxg?q z(jNHFUZQOcNYY=3GBp|VT?$!q-nwmZUPcIZgA$OA}+qdwN;_h8>``F@Cm*VbPIH9=rKd6H9+ENugRPF!q7w(TPKQZ>e zQ-A01lBa#4O7ZkE@3timW$^6Z;^LO`&~RsT$>kPA4dl#MF z`BxR^ffc8B&4rwcE^n%`X0@_Msq9&}p;R8dZ(gh%hJ|ZxWW}=&y9TOS=MTPj^m|9| znv~XoWzWG>ZR2;H-*V2MQ);_bYx|Yj{^i;O4{95fhQYg@KWzM0jY|!KOSOad+m+hq z);zVVo}NWd&s`o^Tk-Vh^`@%oR;%_YRr~IiFIF93smq>ysl4of(6p$U&yO#59^WkD z(4>*~PJi$8kK6C@_l_+c7+n@lZCWiY6+ahFeamu(zq3D8Q+s>*-RZCY_9s@ZsyZc{ zTDNlL&5tk2dG5Wcbe{T2aIy2HRCiy})AjS3?tCZ+831q1 zRk`ZwTGad^+ZNqz3%ug?t+?Bmk)DX_N9PF#A2u%S8&uqbpfb1u6AAd%I+>-VE!EI; zYvk?IG|^y&7q|e7tT@}yx5=hw6z4PW!OZchbdxKNyDej?$x!##POlep3=!fzySlQ(xI7wwGHpeKWmGagSYmj(7@XwK{@ zGj}EZ%h1x;I~vw3sPj|eZYP;nqR%EV7RFc(<6exp5JOUV5o0sNf$~hZ%*s<=kTWn- z4>d#{LP@ZOnmRVcYhyD)Z>p8~ZVRbqfo6b>sfI?n)*7Cj>I@S3+Q=fLO$80Sph^Ra z5*~K32)PSuN1}=8XZ$poH0(`jZ88D zp6yb!4bI3Q6egUJh}R544T_`TjJR}7ME;HyD zZDCIa>E*a-x{S?!J6TZb^ME(ZC$Cd~lY)RTqMJpC_*ZO=`9=vsD}MY2=_q95Jg%OzH-dTkO8*);3-i>Pe2^JKeUo6;h())Z z69+Yjr65ER1`)U!uDJm|@PK@Kn|a|+Qk9!WxzIj6WfleRNIfh+r&?K!5eB-e}mX==wwifCalvlnf9SN0DnA4RVb z%=>XeJJC$oiDol_wZd=8yHRAdR&JD;tX=>~?wU61n9gJAmI27>2%@+Vh#4S!Mt)N@ zLlO+g;o!^UxN(}c7w%+szl;y(5&2H43%%0-&fSN`mMXVVU6`_>>M0j|#c2!KtkcaI ze=3#f`sHv8`+3=3H0-IgP&4p#wA2d)c5B<^f^Q z3RqzAn92elK7(Rx8{-A(3~qg;stJnJHR(T4#H>MoOn3Jw`i~U-CyK}^Oyy~`Q-@fW zYF@$XtWj`ag#abH426F_0Lrc0^m zTB_N*SaWK*@A!TDQs1dt&Xh-(KauqKZrOkC@X$WUV@lnz`}|_v5HrLaRNM#enHJqg zQl6$&59~SZOPI)Kcw^z zE%guIpHliyr!;$lp@fjzhHg7pcDF8AR=bWVUB_0tPAFX`mb;$Y@#R`&&F#bQ9-g-- zm2GM(7Clei^D3UFS3FOqg!Z|SZ;Y-9ZS2zMowI!1zLu-FGEKH;(MF~o+x`_>PfB1O zf7-4F^n?+J+!*sND9g7ftc*<<YnZ2QDJAz{x@}CpMX+l-kko%a_>`CootIvCh3P`G^1lSfxntI4I zVNbQfp?YUi!v(;zgQ=klE!b%@DN5%C&6uF=!&mJH+9rVe$eX8G&;)&Edkm0noFWYD zMZRp^SllK>G;6+`XwOC)&)LAMY#LoyCMQy9jKHeEQwL|QLp;7Hrp_4edWhZ@B z02q1t?3OW*Gw&xCjjRKUcAETqw*$q{1bCe%+JW^tVY0tK> zvC;IGS%B%INi|Ls@VcZ9#P8D?CmaNl7g4@(Vtah)Dk+^%W!NZc@6;{PmgEBGJQxuD zf45PP<{>2uwwc)|Fr?`~tbB6qB{BNHsJ%3GENH4|nTM%j9}{Bji_UiVI6L=#f3>tflvP?%uMs4149c?YtKwZV-#~ zWpF6(JHCfo0H$;!+^gkS3AW5y5{B+T^}p?$g^K~c$iH3AbJHdZ+9DRej#f~7qv(cp z)+(E3izK^f(;$PJvIdz|GUE-k3rpw>YCC)9DUcWE0+NAWCi4`#W98I3oydM9=bM(POV<2{!Ot|ODWY;P^Li5)4Z>2CScg4jpNM{*W<#=>N#;Z^$8C7>|7@S zi`ncDs}K(06JVLfc}_tb=Y+$ZvX0-PL!bm;JI zmE@+3`m8dx(j_FCh(dMy66O9f<#t~SP1D&vvgZ35$V<7DHiaT-x4JnX;J-S_j5o5L za>+=M^A?_O(q}08TTq+)Wkff*^)k*@lPumd-(aHY**^u#}3qxKiA{&~VSC_?|-w<^p#2+;N<|qUW+z&V5m_bu4t>YgYC?zlJPD zoV^xDv?#WwJHaJeOUhQ0^#tp0O=r^L!Fg`3=3Azeqjb5vUvc!OoF3dK%e`2s`DtbC zx*e}^PK&*E-DGx_teY+N5-fY#Ym*Jw?LB~VTUafRkfTm%>`B>5=b9B8CPE8-rR^x7 z_-SzsrBkb1fVa41{>t4xrDG`NaL=8k>B!Vwm(qDWRau*Ytvb30H}Egs-?!Lz7Ae$% zvh4cM1bkPq4Wyh6$>yivO1$Q%y@P7H7jE2lDXdV+LAY|XFVx&UtN5_MRG?x^a~QJ< zbC~}IHH8iRLuXcMvj6{JsAFM*B~rB0UIy|%3YwVr5z5~%n>g$k&`QF?$N>){_@iX| zj_C{ts|v_>!>alo;k*@+R%X$1qc~PFYlRnDJ$o*~vq>zzQJi(Q5e^WgvI&Big;~Q} zDdQLQ>K8O`DBBJDtObk=*4`T>vn7R2G@7;PP=TRUAy27ZbLN`K1E-fxFg&|xXZ9@H ztbMk42DS%06RWc0*^1V|2F0HFw@+rgAH|Y4If6#Vk^Wuss)7i(i1Pf~U*NeIk1v>{ zA7(rxMTe2sG3&TW?kPDT;n5So0E@rFf$0??E}P}Q!~K4djv4F>H70knhQFTZVr@CJ zYt2}P70X3eJ%>6CZ#16UwOj?tRf^?#<)~+%7Ts{}R>Q2bkbfT9=fN9VOUns>&)BI4;*eAI)KZ){iIZO=({h;57myOYI1`di91V%#fHdu= z^vvuOE^kXxXIBS!23XX%-I_20yAc&iBou_&saOo7yD@TN}nbH$6 zG4mW=hqK&_>4@-<_@u9l9VnPC^JDGd5<8eRB;!QG@8g~HLyF#`2y8}ORKn?sQ&EY= z8l1v#dMWrVm$v);tR%`2!r=>sQ~E?-Y1*w(6>M}WJ*CU@z)oAm(50z~v@I&CwWRGj z(&TiJ<|pRLK}_1aE85h3RMv1z484)I=~bdec9yX8O90BIYBVy8z#PlcC7B+O;C{%R zBr^E7Ow4aqaBWYnwvH&RBg?HPH_WE)qMx>&oO|Odwy%~XTTfzcV=Y_fkP6qR%Iaiw z$5I6yZ&1;F^W<8SaP#b1ap|1-%d@Hdkb1t9-8Factv#upUOcSzV8@K_?_1 zfhaGnm>YU)^iF%SWmu^nzW>@{{qrfLUB2_$yH}S=g$H}Q3eoYB_xRGD)`_CuO zi^)(TDNe0({Oi0oGjmWuZpzt=cl zws7fg#UIvwSbMi5x##H>=TTt3vJnno&hokDdG8W7s#)58{mDPz(G@b0>+P}=Pg=%& zMNCKh>k^z1D$L?|(pZS;i;@|=E743=I)KP$n)vp&DE#U1lW;@&6{XX(PWmf~o}%d2 z6j5Ha6s7rmbXMr)DI7eCvqB{rUTOPfIzJO!U-Q$uW0unTN`J zlIPv2s^)bwyEy==qnkCW{SzzQVD4N@q>JD^^l1;0T0 TnziH;E3T~cBNOhJGW-7krVJ^A literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..963edbd2100c3807275dd50cc38f6f6392be25e7 GIT binary patch literal 17120 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ed31adacf7cd5f713fc823d1093a6c8bb5897d3 GIT binary patch literal 13707 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 CharsetMatches: + """ + Given a raw bytes sequence, return the best possibles charset usable to render str objects. + If there is no results, it is a strong indicator that the source is binary/not text. + By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. + And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. + + The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page + but never take it for granted. Can improve the performance. + + You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that + purpose. + + This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. + By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' + toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. + Custom logging format and handler can be set manually. + """ + + if not isinstance(sequences, (bytearray, bytes)): + raise TypeError( + "Expected object of type bytes or bytearray, got: {}".format( + type(sequences) + ) + ) + + if explain: + previous_logger_level: int = logger.level + logger.addHandler(explain_handler) + logger.setLevel(TRACE) + + length: int = len(sequences) + + if length == 0: + logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level or logging.WARNING) + return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) + + if cp_isolation is not None: + logger.log( + TRACE, + "cp_isolation is set. use this flag for debugging purpose. " + "limited list of encoding allowed : %s.", + ", ".join(cp_isolation), + ) + cp_isolation = [iana_name(cp, False) for cp in cp_isolation] + else: + cp_isolation = [] + + if cp_exclusion is not None: + logger.log( + TRACE, + "cp_exclusion is set. use this flag for debugging purpose. " + "limited list of encoding excluded : %s.", + ", ".join(cp_exclusion), + ) + cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] + else: + cp_exclusion = [] + + if length <= (chunk_size * steps): + logger.log( + TRACE, + "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", + steps, + chunk_size, + length, + ) + steps = 1 + chunk_size = length + + if steps > 1 and length / steps < chunk_size: + chunk_size = int(length / steps) + + is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE + is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE + + if is_too_small_sequence: + logger.log( + TRACE, + "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( + length + ), + ) + elif is_too_large_sequence: + logger.log( + TRACE, + "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( + length + ), + ) + + prioritized_encodings: list[str] = [] + + specified_encoding: str | None = ( + any_specified_encoding(sequences) if preemptive_behaviour else None + ) + + if specified_encoding is not None: + prioritized_encodings.append(specified_encoding) + logger.log( + TRACE, + "Detected declarative mark in sequence. Priority +1 given for %s.", + specified_encoding, + ) + + tested: set[str] = set() + tested_but_hard_failure: list[str] = [] + tested_but_soft_failure: list[str] = [] + + fallback_ascii: CharsetMatch | None = None + fallback_u8: CharsetMatch | None = None + fallback_specified: CharsetMatch | None = None + + results: CharsetMatches = CharsetMatches() + + early_stop_results: CharsetMatches = CharsetMatches() + + sig_encoding, sig_payload = identify_sig_or_bom(sequences) + + if sig_encoding is not None: + prioritized_encodings.append(sig_encoding) + logger.log( + TRACE, + "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", + len(sig_payload), + sig_encoding, + ) + + prioritized_encodings.append("ascii") + + if "utf_8" not in prioritized_encodings: + prioritized_encodings.append("utf_8") + + for encoding_iana in prioritized_encodings + IANA_SUPPORTED: + if cp_isolation and encoding_iana not in cp_isolation: + continue + + if cp_exclusion and encoding_iana in cp_exclusion: + continue + + if encoding_iana in tested: + continue + + tested.add(encoding_iana) + + decoded_payload: str | None = None + bom_or_sig_available: bool = sig_encoding == encoding_iana + strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( + encoding_iana + ) + + if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", + encoding_iana, + ) + continue + if encoding_iana in {"utf_7"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", + encoding_iana, + ) + continue + + try: + is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) + except (ModuleNotFoundError, ImportError): + logger.log( + TRACE, + "Encoding %s does not provide an IncrementalDecoder", + encoding_iana, + ) + continue + + try: + if is_too_large_sequence and is_multi_byte_decoder is False: + str( + ( + sequences[: int(50e4)] + if strip_sig_or_bom is False + else sequences[len(sig_payload) : int(50e4)] + ), + encoding=encoding_iana, + ) + else: + decoded_payload = str( + ( + sequences + if strip_sig_or_bom is False + else sequences[len(sig_payload) :] + ), + encoding=encoding_iana, + ) + except (UnicodeDecodeError, LookupError) as e: + if not isinstance(e, LookupError): + logger.log( + TRACE, + "Code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + similar_soft_failure_test: bool = False + + for encoding_soft_failed in tested_but_soft_failure: + if is_cp_similar(encoding_iana, encoding_soft_failed): + similar_soft_failure_test = True + break + + if similar_soft_failure_test: + logger.log( + TRACE, + "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", + encoding_iana, + encoding_soft_failed, + ) + continue + + r_ = range( + 0 if not bom_or_sig_available else len(sig_payload), + length, + int(length / steps), + ) + + multi_byte_bonus: bool = ( + is_multi_byte_decoder + and decoded_payload is not None + and len(decoded_payload) < length + ) + + if multi_byte_bonus: + logger.log( + TRACE, + "Code page %s is a multi byte encoding table and it appear that at least one character " + "was encoded using n-bytes.", + encoding_iana, + ) + + max_chunk_gave_up: int = int(len(r_) / 4) + + max_chunk_gave_up = max(max_chunk_gave_up, 2) + early_stop_count: int = 0 + lazy_str_hard_failure = False + + md_chunks: list[str] = [] + md_ratios = [] + + try: + for chunk in cut_sequence_chunks( + sequences, + encoding_iana, + r_, + chunk_size, + bom_or_sig_available, + strip_sig_or_bom, + sig_payload, + is_multi_byte_decoder, + decoded_payload, + ): + md_chunks.append(chunk) + + md_ratios.append( + mess_ratio( + chunk, + threshold, + explain is True and 1 <= len(cp_isolation) <= 2, + ) + ) + + if md_ratios[-1] >= threshold: + early_stop_count += 1 + + if (early_stop_count >= max_chunk_gave_up) or ( + bom_or_sig_available and strip_sig_or_bom is False + ): + break + except ( + UnicodeDecodeError + ) as e: # Lazy str loading may have missed something there + logger.log( + TRACE, + "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + early_stop_count = max_chunk_gave_up + lazy_str_hard_failure = True + + # We might want to check the sequence again with the whole content + # Only if initial MD tests passes + if ( + not lazy_str_hard_failure + and is_too_large_sequence + and not is_multi_byte_decoder + ): + try: + sequences[int(50e3) :].decode(encoding_iana, errors="strict") + except UnicodeDecodeError as e: + logger.log( + TRACE, + "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 + if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: + tested_but_soft_failure.append(encoding_iana) + logger.log( + TRACE, + "%s was excluded because of initial chaos probing. Gave up %i time(s). " + "Computed mean chaos is %f %%.", + encoding_iana, + early_stop_count, + round(mean_mess_ratio * 100, ndigits=3), + ) + # Preparing those fallbacks in case we got nothing. + if ( + enable_fallback + and encoding_iana + in ["ascii", "utf_8", specified_encoding, "utf_16", "utf_32"] + and not lazy_str_hard_failure + ): + fallback_entry = CharsetMatch( + sequences, + encoding_iana, + threshold, + bom_or_sig_available, + [], + decoded_payload, + preemptive_declaration=specified_encoding, + ) + if encoding_iana == specified_encoding: + fallback_specified = fallback_entry + elif encoding_iana == "ascii": + fallback_ascii = fallback_entry + else: + fallback_u8 = fallback_entry + continue + + logger.log( + TRACE, + "%s passed initial chaos probing. Mean measured chaos is %f %%", + encoding_iana, + round(mean_mess_ratio * 100, ndigits=3), + ) + + if not is_multi_byte_decoder: + target_languages: list[str] = encoding_languages(encoding_iana) + else: + target_languages = mb_encoding_languages(encoding_iana) + + if target_languages: + logger.log( + TRACE, + "{} should target any language(s) of {}".format( + encoding_iana, str(target_languages) + ), + ) + + cd_ratios = [] + + # We shall skip the CD when its about ASCII + # Most of the time its not relevant to run "language-detection" on it. + if encoding_iana != "ascii": + for chunk in md_chunks: + chunk_languages = coherence_ratio( + chunk, + language_threshold, + ",".join(target_languages) if target_languages else None, + ) + + cd_ratios.append(chunk_languages) + + cd_ratios_merged = merge_coherence_ratios(cd_ratios) + + if cd_ratios_merged: + logger.log( + TRACE, + "We detected language {} using {}".format( + cd_ratios_merged, encoding_iana + ), + ) + + current_match = CharsetMatch( + sequences, + encoding_iana, + mean_mess_ratio, + bom_or_sig_available, + cd_ratios_merged, + ( + decoded_payload + if ( + is_too_large_sequence is False + or encoding_iana in [specified_encoding, "ascii", "utf_8"] + ) + else None + ), + preemptive_declaration=specified_encoding, + ) + + results.append(current_match) + + if ( + encoding_iana in [specified_encoding, "ascii", "utf_8"] + and mean_mess_ratio < 0.1 + ): + # If md says nothing to worry about, then... stop immediately! + if mean_mess_ratio == 0.0: + logger.debug( + "Encoding detection: %s is most likely the one.", + current_match.encoding, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([current_match]) + + early_stop_results.append(current_match) + + if ( + len(early_stop_results) + and (specified_encoding is None or specified_encoding in tested) + and "ascii" in tested + and "utf_8" in tested + ): + probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment] + logger.debug( + "Encoding detection: %s is most likely the one.", + probable_result.encoding, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return CharsetMatches([probable_result]) + + if encoding_iana == sig_encoding: + logger.debug( + "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " + "the beginning of the sequence.", + encoding_iana, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([results[encoding_iana]]) + + if len(results) == 0: + if fallback_u8 or fallback_ascii or fallback_specified: + logger.log( + TRACE, + "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", + ) + + if fallback_specified: + logger.debug( + "Encoding detection: %s will be used as a fallback match", + fallback_specified.encoding, + ) + results.append(fallback_specified) + elif ( + (fallback_u8 and fallback_ascii is None) + or ( + fallback_u8 + and fallback_ascii + and fallback_u8.fingerprint != fallback_ascii.fingerprint + ) + or (fallback_u8 is not None) + ): + logger.debug("Encoding detection: utf_8 will be used as a fallback match") + results.append(fallback_u8) + elif fallback_ascii: + logger.debug("Encoding detection: ascii will be used as a fallback match") + results.append(fallback_ascii) + + if results: + logger.debug( + "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", + results.best().encoding, # type: ignore + len(results) - 1, + ) + else: + logger.debug("Encoding detection: Unable to determine any suitable charset.") + + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return results + + +def from_fp( + fp: BinaryIO, + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but using a file pointer that is already ready. + Will not close the file pointer. + """ + return from_bytes( + fp.read(), + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def from_path( + path: str | bytes | PathLike, # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. + Can raise IOError. + """ + with open(path, "rb") as fp: + return from_fp( + fp, + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def is_binary( + fp_or_path_or_payload: PathLike | str | BinaryIO | bytes, # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = False, +) -> bool: + """ + Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. + Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match + are disabled to be stricter around ASCII-compatible but unlikely to be a string. + """ + if isinstance(fp_or_path_or_payload, (str, PathLike)): + guesses = from_path( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + elif isinstance( + fp_or_path_or_payload, + ( + bytes, + bytearray, + ), + ): + guesses = from_bytes( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + else: + guesses = from_fp( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + + return not guesses diff --git a/backend/venv/Lib/site-packages/charset_normalizer/cd.py b/backend/venv/Lib/site-packages/charset_normalizer/cd.py new file mode 100644 index 0000000..71a3ed5 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/cd.py @@ -0,0 +1,395 @@ +from __future__ import annotations + +import importlib +from codecs import IncrementalDecoder +from collections import Counter +from functools import lru_cache +from typing import Counter as TypeCounter + +from .constant import ( + FREQUENCIES, + KO_NAMES, + LANGUAGE_SUPPORTED_COUNT, + TOO_SMALL_SEQUENCE, + ZH_NAMES, +) +from .md import is_suspiciously_successive_range +from .models import CoherenceMatches +from .utils import ( + is_accentuated, + is_latin, + is_multi_byte_encoding, + is_unicode_range_secondary, + unicode_range, +) + + +def encoding_unicode_range(iana_name: str) -> list[str]: + """ + Return associated unicode ranges in a single byte code page. + """ + if is_multi_byte_encoding(iana_name): + raise OSError("Function not supported on multi-byte code page") + + decoder = importlib.import_module(f"encodings.{iana_name}").IncrementalDecoder + + p: IncrementalDecoder = decoder(errors="ignore") + seen_ranges: dict[str, int] = {} + character_count: int = 0 + + for i in range(0x40, 0xFF): + chunk: str = p.decode(bytes([i])) + + if chunk: + character_range: str | None = unicode_range(chunk) + + if character_range is None: + continue + + if is_unicode_range_secondary(character_range) is False: + if character_range not in seen_ranges: + seen_ranges[character_range] = 0 + seen_ranges[character_range] += 1 + character_count += 1 + + return sorted( + [ + character_range + for character_range in seen_ranges + if seen_ranges[character_range] / character_count >= 0.15 + ] + ) + + +def unicode_range_languages(primary_range: str) -> list[str]: + """ + Return inferred languages used with a unicode range. + """ + languages: list[str] = [] + + for language, characters in FREQUENCIES.items(): + for character in characters: + if unicode_range(character) == primary_range: + languages.append(language) + break + + return languages + + +@lru_cache() +def encoding_languages(iana_name: str) -> list[str]: + """ + Single-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + unicode_ranges: list[str] = encoding_unicode_range(iana_name) + primary_range: str | None = None + + for specified_range in unicode_ranges: + if "Latin" not in specified_range: + primary_range = specified_range + break + + if primary_range is None: + return ["Latin Based"] + + return unicode_range_languages(primary_range) + + +@lru_cache() +def mb_encoding_languages(iana_name: str) -> list[str]: + """ + Multi-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + if ( + iana_name.startswith("shift_") + or iana_name.startswith("iso2022_jp") + or iana_name.startswith("euc_j") + or iana_name == "cp932" + ): + return ["Japanese"] + if iana_name.startswith("gb") or iana_name in ZH_NAMES: + return ["Chinese"] + if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: + return ["Korean"] + + return [] + + +@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) +def get_target_features(language: str) -> tuple[bool, bool]: + """ + Determine main aspects from a supported language if it contains accents and if is pure Latin. + """ + target_have_accents: bool = False + target_pure_latin: bool = True + + for character in FREQUENCIES[language]: + if not target_have_accents and is_accentuated(character): + target_have_accents = True + if target_pure_latin and is_latin(character) is False: + target_pure_latin = False + + return target_have_accents, target_pure_latin + + +def alphabet_languages( + characters: list[str], ignore_non_latin: bool = False +) -> list[str]: + """ + Return associated languages associated to given characters. + """ + languages: list[tuple[str, float]] = [] + + source_have_accents = any(is_accentuated(character) for character in characters) + + for language, language_characters in FREQUENCIES.items(): + target_have_accents, target_pure_latin = get_target_features(language) + + if ignore_non_latin and target_pure_latin is False: + continue + + if target_have_accents is False and source_have_accents: + continue + + character_count: int = len(language_characters) + + character_match_count: int = len( + [c for c in language_characters if c in characters] + ) + + ratio: float = character_match_count / character_count + + if ratio >= 0.2: + languages.append((language, ratio)) + + languages = sorted(languages, key=lambda x: x[1], reverse=True) + + return [compatible_language[0] for compatible_language in languages] + + +def characters_popularity_compare( + language: str, ordered_characters: list[str] +) -> float: + """ + Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. + The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). + Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) + """ + if language not in FREQUENCIES: + raise ValueError(f"{language} not available") + + character_approved_count: int = 0 + FREQUENCIES_language_set = set(FREQUENCIES[language]) + + ordered_characters_count: int = len(ordered_characters) + target_language_characters_count: int = len(FREQUENCIES[language]) + + large_alphabet: bool = target_language_characters_count > 26 + + for character, character_rank in zip( + ordered_characters, range(0, ordered_characters_count) + ): + if character not in FREQUENCIES_language_set: + continue + + character_rank_in_language: int = FREQUENCIES[language].index(character) + expected_projection_ratio: float = ( + target_language_characters_count / ordered_characters_count + ) + character_rank_projection: int = int(character_rank * expected_projection_ratio) + + if ( + large_alphabet is False + and abs(character_rank_projection - character_rank_in_language) > 4 + ): + continue + + if ( + large_alphabet is True + and abs(character_rank_projection - character_rank_in_language) + < target_language_characters_count / 3 + ): + character_approved_count += 1 + continue + + characters_before_source: list[str] = FREQUENCIES[language][ + 0:character_rank_in_language + ] + characters_after_source: list[str] = FREQUENCIES[language][ + character_rank_in_language: + ] + characters_before: list[str] = ordered_characters[0:character_rank] + characters_after: list[str] = ordered_characters[character_rank:] + + before_match_count: int = len( + set(characters_before) & set(characters_before_source) + ) + + after_match_count: int = len( + set(characters_after) & set(characters_after_source) + ) + + if len(characters_before_source) == 0 and before_match_count <= 4: + character_approved_count += 1 + continue + + if len(characters_after_source) == 0 and after_match_count <= 4: + character_approved_count += 1 + continue + + if ( + before_match_count / len(characters_before_source) >= 0.4 + or after_match_count / len(characters_after_source) >= 0.4 + ): + character_approved_count += 1 + continue + + return character_approved_count / len(ordered_characters) + + +def alpha_unicode_split(decoded_sequence: str) -> list[str]: + """ + Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. + Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; + One containing the latin letters and the other hebrew. + """ + layers: dict[str, str] = {} + + for character in decoded_sequence: + if character.isalpha() is False: + continue + + character_range: str | None = unicode_range(character) + + if character_range is None: + continue + + layer_target_range: str | None = None + + for discovered_range in layers: + if ( + is_suspiciously_successive_range(discovered_range, character_range) + is False + ): + layer_target_range = discovered_range + break + + if layer_target_range is None: + layer_target_range = character_range + + if layer_target_range not in layers: + layers[layer_target_range] = character.lower() + continue + + layers[layer_target_range] += character.lower() + + return list(layers.values()) + + +def merge_coherence_ratios(results: list[CoherenceMatches]) -> CoherenceMatches: + """ + This function merge results previously given by the function coherence_ratio. + The return type is the same as coherence_ratio. + """ + per_language_ratios: dict[str, list[float]] = {} + for result in results: + for sub_result in result: + language, ratio = sub_result + if language not in per_language_ratios: + per_language_ratios[language] = [ratio] + continue + per_language_ratios[language].append(ratio) + + merge = [ + ( + language, + round( + sum(per_language_ratios[language]) / len(per_language_ratios[language]), + 4, + ), + ) + for language in per_language_ratios + ] + + return sorted(merge, key=lambda x: x[1], reverse=True) + + +def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: + """ + We shall NOT return "English—" in CoherenceMatches because it is an alternative + of "English". This function only keeps the best match and remove the em-dash in it. + """ + index_results: dict[str, list[float]] = dict() + + for result in results: + language, ratio = result + no_em_name: str = language.replace("—", "") + + if no_em_name not in index_results: + index_results[no_em_name] = [] + + index_results[no_em_name].append(ratio) + + if any(len(index_results[e]) > 1 for e in index_results): + filtered_results: CoherenceMatches = [] + + for language in index_results: + filtered_results.append((language, max(index_results[language]))) + + return filtered_results + + return results + + +@lru_cache(maxsize=2048) +def coherence_ratio( + decoded_sequence: str, threshold: float = 0.1, lg_inclusion: str | None = None +) -> CoherenceMatches: + """ + Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. + A layer = Character extraction by alphabets/ranges. + """ + + results: list[tuple[str, float]] = [] + ignore_non_latin: bool = False + + sufficient_match_count: int = 0 + + lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] + if "Latin Based" in lg_inclusion_list: + ignore_non_latin = True + lg_inclusion_list.remove("Latin Based") + + for layer in alpha_unicode_split(decoded_sequence): + sequence_frequencies: TypeCounter[str] = Counter(layer) + most_common = sequence_frequencies.most_common() + + character_count: int = sum(o for c, o in most_common) + + if character_count <= TOO_SMALL_SEQUENCE: + continue + + popular_character_ordered: list[str] = [c for c, o in most_common] + + for language in lg_inclusion_list or alphabet_languages( + popular_character_ordered, ignore_non_latin + ): + ratio: float = characters_popularity_compare( + language, popular_character_ordered + ) + + if ratio < threshold: + continue + elif ratio >= 0.8: + sufficient_match_count += 1 + + results.append((language, round(ratio, 4))) + + if sufficient_match_count >= 3: + break + + return sorted( + filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True + ) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/cli/__init__.py b/backend/venv/Lib/site-packages/charset_normalizer/cli/__init__.py new file mode 100644 index 0000000..543a5a4 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/cli/__init__.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +from .__main__ import cli_detect, query_yes_no + +__all__ = ( + "cli_detect", + "query_yes_no", +) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/cli/__main__.py b/backend/venv/Lib/site-packages/charset_normalizer/cli/__main__.py new file mode 100644 index 0000000..cb64156 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/cli/__main__.py @@ -0,0 +1,381 @@ +from __future__ import annotations + +import argparse +import sys +import typing +from json import dumps +from os.path import abspath, basename, dirname, join, realpath +from platform import python_version +from unicodedata import unidata_version + +import charset_normalizer.md as md_module +from charset_normalizer import from_fp +from charset_normalizer.models import CliDetectionResult +from charset_normalizer.version import __version__ + + +def query_yes_no(question: str, default: str = "yes") -> bool: + """Ask a yes/no question via input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits . + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is True for "yes" or False for "no". + + Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input + """ + valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} + if default is None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + + while True: + sys.stdout.write(question + prompt) + choice = input().lower() + if default is not None and choice == "": + return valid[default] + elif choice in valid: + return valid[choice] + else: + sys.stdout.write("Please respond with 'yes' or 'no' (or 'y' or 'n').\n") + + +class FileType: + """Factory for creating file object types + + Instances of FileType are typically passed as type= arguments to the + ArgumentParser add_argument() method. + + Keyword Arguments: + - mode -- A string indicating how the file is to be opened. Accepts the + same values as the builtin open() function. + - bufsize -- The file's desired buffer size. Accepts the same values as + the builtin open() function. + - encoding -- The file's encoding. Accepts the same values as the + builtin open() function. + - errors -- A string indicating how encoding and decoding errors are to + be handled. Accepts the same value as the builtin open() function. + + Backported from CPython 3.12 + """ + + def __init__( + self, + mode: str = "r", + bufsize: int = -1, + encoding: str | None = None, + errors: str | None = None, + ): + self._mode = mode + self._bufsize = bufsize + self._encoding = encoding + self._errors = errors + + def __call__(self, string: str) -> typing.IO: # type: ignore[type-arg] + # the special argument "-" means sys.std{in,out} + if string == "-": + if "r" in self._mode: + return sys.stdin.buffer if "b" in self._mode else sys.stdin + elif any(c in self._mode for c in "wax"): + return sys.stdout.buffer if "b" in self._mode else sys.stdout + else: + msg = f'argument "-" with mode {self._mode}' + raise ValueError(msg) + + # all other arguments are used as file names + try: + return open(string, self._mode, self._bufsize, self._encoding, self._errors) + except OSError as e: + message = f"can't open '{string}': {e}" + raise argparse.ArgumentTypeError(message) + + def __repr__(self) -> str: + args = self._mode, self._bufsize + kwargs = [("encoding", self._encoding), ("errors", self._errors)] + args_str = ", ".join( + [repr(arg) for arg in args if arg != -1] + + [f"{kw}={arg!r}" for kw, arg in kwargs if arg is not None] + ) + return f"{type(self).__name__}({args_str})" + + +def cli_detect(argv: list[str] | None = None) -> int: + """ + CLI assistant using ARGV and ArgumentParser + :param argv: + :return: 0 if everything is fine, anything else equal trouble + """ + parser = argparse.ArgumentParser( + description="The Real First Universal Charset Detector. " + "Discover originating encoding used on text file. " + "Normalize text to unicode." + ) + + parser.add_argument( + "files", type=FileType("rb"), nargs="+", help="File(s) to be analysed" + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + default=False, + dest="verbose", + help="Display complementary information about file if any. " + "Stdout will contain logs about the detection process.", + ) + parser.add_argument( + "-a", + "--with-alternative", + action="store_true", + default=False, + dest="alternatives", + help="Output complementary possibilities if any. Top-level JSON WILL be a list.", + ) + parser.add_argument( + "-n", + "--normalize", + action="store_true", + default=False, + dest="normalize", + help="Permit to normalize input file. If not set, program does not write anything.", + ) + parser.add_argument( + "-m", + "--minimal", + action="store_true", + default=False, + dest="minimal", + help="Only output the charset detected to STDOUT. Disabling JSON output.", + ) + parser.add_argument( + "-r", + "--replace", + action="store_true", + default=False, + dest="replace", + help="Replace file when trying to normalize it instead of creating a new one.", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + dest="force", + help="Replace file without asking if you are sure, use this flag with caution.", + ) + parser.add_argument( + "-i", + "--no-preemptive", + action="store_true", + default=False, + dest="no_preemptive", + help="Disable looking at a charset declaration to hint the detector.", + ) + parser.add_argument( + "-t", + "--threshold", + action="store", + default=0.2, + type=float, + dest="threshold", + help="Define a custom maximum amount of noise allowed in decoded content. 0. <= noise <= 1.", + ) + parser.add_argument( + "--version", + action="version", + version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( + __version__, + python_version(), + unidata_version, + "OFF" if md_module.__file__.lower().endswith(".py") else "ON", + ), + help="Show version information and exit.", + ) + + args = parser.parse_args(argv) + + if args.replace is True and args.normalize is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --replace in addition of --normalize only.", file=sys.stderr) + return 1 + + if args.force is True and args.replace is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --force in addition of --replace only.", file=sys.stderr) + return 1 + + if args.threshold < 0.0 or args.threshold > 1.0: + if args.files: + for my_file in args.files: + my_file.close() + print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) + return 1 + + x_ = [] + + for my_file in args.files: + matches = from_fp( + my_file, + threshold=args.threshold, + explain=args.verbose, + preemptive_behaviour=args.no_preemptive is False, + ) + + best_guess = matches.best() + + if best_guess is None: + print( + 'Unable to identify originating encoding for "{}". {}'.format( + my_file.name, + ( + "Maybe try increasing maximum amount of chaos." + if args.threshold < 1.0 + else "" + ), + ), + file=sys.stderr, + ) + x_.append( + CliDetectionResult( + abspath(my_file.name), + None, + [], + [], + "Unknown", + [], + False, + 1.0, + 0.0, + None, + True, + ) + ) + else: + x_.append( + CliDetectionResult( + abspath(my_file.name), + best_guess.encoding, + best_guess.encoding_aliases, + [ + cp + for cp in best_guess.could_be_from_charset + if cp != best_guess.encoding + ], + best_guess.language, + best_guess.alphabets, + best_guess.bom, + best_guess.percent_chaos, + best_guess.percent_coherence, + None, + True, + ) + ) + + if len(matches) > 1 and args.alternatives: + for el in matches: + if el != best_guess: + x_.append( + CliDetectionResult( + abspath(my_file.name), + el.encoding, + el.encoding_aliases, + [ + cp + for cp in el.could_be_from_charset + if cp != el.encoding + ], + el.language, + el.alphabets, + el.bom, + el.percent_chaos, + el.percent_coherence, + None, + False, + ) + ) + + if args.normalize is True: + if best_guess.encoding.startswith("utf") is True: + print( + '"{}" file does not need to be normalized, as it already came from unicode.'.format( + my_file.name + ), + file=sys.stderr, + ) + if my_file.closed is False: + my_file.close() + continue + + dir_path = dirname(realpath(my_file.name)) + file_name = basename(realpath(my_file.name)) + + o_: list[str] = file_name.split(".") + + if args.replace is False: + o_.insert(-1, best_guess.encoding) + if my_file.closed is False: + my_file.close() + elif ( + args.force is False + and query_yes_no( + 'Are you sure to normalize "{}" by replacing it ?'.format( + my_file.name + ), + "no", + ) + is False + ): + if my_file.closed is False: + my_file.close() + continue + + try: + x_[0].unicode_path = join(dir_path, ".".join(o_)) + + with open(x_[0].unicode_path, "wb") as fp: + fp.write(best_guess.output()) + except OSError as e: + print(str(e), file=sys.stderr) + if my_file.closed is False: + my_file.close() + return 2 + + if my_file.closed is False: + my_file.close() + + if args.minimal is False: + print( + dumps( + [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, + ensure_ascii=True, + indent=4, + ) + ) + else: + for my_file in args.files: + print( + ", ".join( + [ + el.encoding or "undefined" + for el in x_ + if el.path == abspath(my_file.name) + ] + ) + ) + + return 0 + + +if __name__ == "__main__": + cli_detect() diff --git a/backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..549eedb085371d17fc3b23e1fbb55046331b3ed2 GIT binary patch literal 340 zcmXw!y-EW?5XX0KFCQeP@e#x(g-I`BV=ID|$HK6=oy5ich8zYXoML8vf9CUZG8r+l+mAc*O7Xjcf6M+7emJG%jcKO2WsVn|Go5K+Gbak+ z@**b|MX$-HyZmUXHl z0z^Ue?GV5z;|Y6&vEOL}0A($}J3A1vpXJrLT*t7A$~og#@+pKeIES%BFn)tRh1kf2 zDj(2mNxYHQW+5w+@N7-0T45#2dlf58bVqc`nrDo2I&=;+!6bm$x@m_OF6i3gWt`C3 a?w#tG++J|bzu3u^&Gxw%XD@>|Cixc_`(p6` literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e205db182ffac6cd421e4c80dce309a295e3c08 GIT binary patch literal 14390 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 eKu=>HG8(>GTD literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/constant.py b/backend/venv/Lib/site-packages/charset_normalizer/constant.py new file mode 100644 index 0000000..cc71a01 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/constant.py @@ -0,0 +1,2015 @@ +from __future__ import annotations + +from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE +from encodings.aliases import aliases +from re import IGNORECASE +from re import compile as re_compile + +# Contain for each eligible encoding a list of/item bytes SIG/BOM +ENCODING_MARKS: dict[str, bytes | list[bytes]] = { + "utf_8": BOM_UTF8, + "utf_7": [ + b"\x2b\x2f\x76\x38", + b"\x2b\x2f\x76\x39", + b"\x2b\x2f\x76\x2b", + b"\x2b\x2f\x76\x2f", + b"\x2b\x2f\x76\x38\x2d", + ], + "gb18030": b"\x84\x31\x95\x33", + "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE], + "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE], +} + +TOO_SMALL_SEQUENCE: int = 32 +TOO_BIG_SEQUENCE: int = int(10e6) + +UTF8_MAXIMAL_ALLOCATION: int = 1_112_064 + +# Up-to-date Unicode ucd/15.0.0 +UNICODE_RANGES_COMBINED: dict[str, range] = { + "Control character": range(32), + "Basic Latin": range(32, 128), + "Latin-1 Supplement": range(128, 256), + "Latin Extended-A": range(256, 384), + "Latin Extended-B": range(384, 592), + "IPA Extensions": range(592, 688), + "Spacing Modifier Letters": range(688, 768), + "Combining Diacritical Marks": range(768, 880), + "Greek and Coptic": range(880, 1024), + "Cyrillic": range(1024, 1280), + "Cyrillic Supplement": range(1280, 1328), + "Armenian": range(1328, 1424), + "Hebrew": range(1424, 1536), + "Arabic": range(1536, 1792), + "Syriac": range(1792, 1872), + "Arabic Supplement": range(1872, 1920), + "Thaana": range(1920, 1984), + "NKo": range(1984, 2048), + "Samaritan": range(2048, 2112), + "Mandaic": range(2112, 2144), + "Syriac Supplement": range(2144, 2160), + "Arabic Extended-B": range(2160, 2208), + "Arabic Extended-A": range(2208, 2304), + "Devanagari": range(2304, 2432), + "Bengali": range(2432, 2560), + "Gurmukhi": range(2560, 2688), + "Gujarati": range(2688, 2816), + "Oriya": range(2816, 2944), + "Tamil": range(2944, 3072), + "Telugu": range(3072, 3200), + "Kannada": range(3200, 3328), + "Malayalam": range(3328, 3456), + "Sinhala": range(3456, 3584), + "Thai": range(3584, 3712), + "Lao": range(3712, 3840), + "Tibetan": range(3840, 4096), + "Myanmar": range(4096, 4256), + "Georgian": range(4256, 4352), + "Hangul Jamo": range(4352, 4608), + "Ethiopic": range(4608, 4992), + "Ethiopic Supplement": range(4992, 5024), + "Cherokee": range(5024, 5120), + "Unified Canadian Aboriginal Syllabics": range(5120, 5760), + "Ogham": range(5760, 5792), + "Runic": range(5792, 5888), + "Tagalog": range(5888, 5920), + "Hanunoo": range(5920, 5952), + "Buhid": range(5952, 5984), + "Tagbanwa": range(5984, 6016), + "Khmer": range(6016, 6144), + "Mongolian": range(6144, 6320), + "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400), + "Limbu": range(6400, 6480), + "Tai Le": range(6480, 6528), + "New Tai Lue": range(6528, 6624), + "Khmer Symbols": range(6624, 6656), + "Buginese": range(6656, 6688), + "Tai Tham": range(6688, 6832), + "Combining Diacritical Marks Extended": range(6832, 6912), + "Balinese": range(6912, 7040), + "Sundanese": range(7040, 7104), + "Batak": range(7104, 7168), + "Lepcha": range(7168, 7248), + "Ol Chiki": range(7248, 7296), + "Cyrillic Extended-C": range(7296, 7312), + "Georgian Extended": range(7312, 7360), + "Sundanese Supplement": range(7360, 7376), + "Vedic Extensions": range(7376, 7424), + "Phonetic Extensions": range(7424, 7552), + "Phonetic Extensions Supplement": range(7552, 7616), + "Combining Diacritical Marks Supplement": range(7616, 7680), + "Latin Extended Additional": range(7680, 7936), + "Greek Extended": range(7936, 8192), + "General Punctuation": range(8192, 8304), + "Superscripts and Subscripts": range(8304, 8352), + "Currency Symbols": range(8352, 8400), + "Combining Diacritical Marks for Symbols": range(8400, 8448), + "Letterlike Symbols": range(8448, 8528), + "Number Forms": range(8528, 8592), + "Arrows": range(8592, 8704), + "Mathematical Operators": range(8704, 8960), + "Miscellaneous Technical": range(8960, 9216), + "Control Pictures": range(9216, 9280), + "Optical Character Recognition": range(9280, 9312), + "Enclosed Alphanumerics": range(9312, 9472), + "Box Drawing": range(9472, 9600), + "Block Elements": range(9600, 9632), + "Geometric Shapes": range(9632, 9728), + "Miscellaneous Symbols": range(9728, 9984), + "Dingbats": range(9984, 10176), + "Miscellaneous Mathematical Symbols-A": range(10176, 10224), + "Supplemental Arrows-A": range(10224, 10240), + "Braille Patterns": range(10240, 10496), + "Supplemental Arrows-B": range(10496, 10624), + "Miscellaneous Mathematical Symbols-B": range(10624, 10752), + "Supplemental Mathematical Operators": range(10752, 11008), + "Miscellaneous Symbols and Arrows": range(11008, 11264), + "Glagolitic": range(11264, 11360), + "Latin Extended-C": range(11360, 11392), + "Coptic": range(11392, 11520), + "Georgian Supplement": range(11520, 11568), + "Tifinagh": range(11568, 11648), + "Ethiopic Extended": range(11648, 11744), + "Cyrillic Extended-A": range(11744, 11776), + "Supplemental Punctuation": range(11776, 11904), + "CJK Radicals Supplement": range(11904, 12032), + "Kangxi Radicals": range(12032, 12256), + "Ideographic Description Characters": range(12272, 12288), + "CJK Symbols and Punctuation": range(12288, 12352), + "Hiragana": range(12352, 12448), + "Katakana": range(12448, 12544), + "Bopomofo": range(12544, 12592), + "Hangul Compatibility Jamo": range(12592, 12688), + "Kanbun": range(12688, 12704), + "Bopomofo Extended": range(12704, 12736), + "CJK Strokes": range(12736, 12784), + "Katakana Phonetic Extensions": range(12784, 12800), + "Enclosed CJK Letters and Months": range(12800, 13056), + "CJK Compatibility": range(13056, 13312), + "CJK Unified Ideographs Extension A": range(13312, 19904), + "Yijing Hexagram Symbols": range(19904, 19968), + "CJK Unified Ideographs": range(19968, 40960), + "Yi Syllables": range(40960, 42128), + "Yi Radicals": range(42128, 42192), + "Lisu": range(42192, 42240), + "Vai": range(42240, 42560), + "Cyrillic Extended-B": range(42560, 42656), + "Bamum": range(42656, 42752), + "Modifier Tone Letters": range(42752, 42784), + "Latin Extended-D": range(42784, 43008), + "Syloti Nagri": range(43008, 43056), + "Common Indic Number Forms": range(43056, 43072), + "Phags-pa": range(43072, 43136), + "Saurashtra": range(43136, 43232), + "Devanagari Extended": range(43232, 43264), + "Kayah Li": range(43264, 43312), + "Rejang": range(43312, 43360), + "Hangul Jamo Extended-A": range(43360, 43392), + "Javanese": range(43392, 43488), + "Myanmar Extended-B": range(43488, 43520), + "Cham": range(43520, 43616), + "Myanmar Extended-A": range(43616, 43648), + "Tai Viet": range(43648, 43744), + "Meetei Mayek Extensions": range(43744, 43776), + "Ethiopic Extended-A": range(43776, 43824), + "Latin Extended-E": range(43824, 43888), + "Cherokee Supplement": range(43888, 43968), + "Meetei Mayek": range(43968, 44032), + "Hangul Syllables": range(44032, 55216), + "Hangul Jamo Extended-B": range(55216, 55296), + "High Surrogates": range(55296, 56192), + "High Private Use Surrogates": range(56192, 56320), + "Low Surrogates": range(56320, 57344), + "Private Use Area": range(57344, 63744), + "CJK Compatibility Ideographs": range(63744, 64256), + "Alphabetic Presentation Forms": range(64256, 64336), + "Arabic Presentation Forms-A": range(64336, 65024), + "Variation Selectors": range(65024, 65040), + "Vertical Forms": range(65040, 65056), + "Combining Half Marks": range(65056, 65072), + "CJK Compatibility Forms": range(65072, 65104), + "Small Form Variants": range(65104, 65136), + "Arabic Presentation Forms-B": range(65136, 65280), + "Halfwidth and Fullwidth Forms": range(65280, 65520), + "Specials": range(65520, 65536), + "Linear B Syllabary": range(65536, 65664), + "Linear B Ideograms": range(65664, 65792), + "Aegean Numbers": range(65792, 65856), + "Ancient Greek Numbers": range(65856, 65936), + "Ancient Symbols": range(65936, 66000), + "Phaistos Disc": range(66000, 66048), + "Lycian": range(66176, 66208), + "Carian": range(66208, 66272), + "Coptic Epact Numbers": range(66272, 66304), + "Old Italic": range(66304, 66352), + "Gothic": range(66352, 66384), + "Old Permic": range(66384, 66432), + "Ugaritic": range(66432, 66464), + "Old Persian": range(66464, 66528), + "Deseret": range(66560, 66640), + "Shavian": range(66640, 66688), + "Osmanya": range(66688, 66736), + "Osage": range(66736, 66816), + "Elbasan": range(66816, 66864), + "Caucasian Albanian": range(66864, 66928), + "Vithkuqi": range(66928, 67008), + "Linear A": range(67072, 67456), + "Latin Extended-F": range(67456, 67520), + "Cypriot Syllabary": range(67584, 67648), + "Imperial Aramaic": range(67648, 67680), + "Palmyrene": range(67680, 67712), + "Nabataean": range(67712, 67760), + "Hatran": range(67808, 67840), + "Phoenician": range(67840, 67872), + "Lydian": range(67872, 67904), + "Meroitic Hieroglyphs": range(67968, 68000), + "Meroitic Cursive": range(68000, 68096), + "Kharoshthi": range(68096, 68192), + "Old South Arabian": range(68192, 68224), + "Old North Arabian": range(68224, 68256), + "Manichaean": range(68288, 68352), + "Avestan": range(68352, 68416), + "Inscriptional Parthian": range(68416, 68448), + "Inscriptional Pahlavi": range(68448, 68480), + "Psalter Pahlavi": range(68480, 68528), + "Old Turkic": range(68608, 68688), + "Old Hungarian": range(68736, 68864), + "Hanifi Rohingya": range(68864, 68928), + "Rumi Numeral Symbols": range(69216, 69248), + "Yezidi": range(69248, 69312), + "Arabic Extended-C": range(69312, 69376), + "Old Sogdian": range(69376, 69424), + "Sogdian": range(69424, 69488), + "Old Uyghur": range(69488, 69552), + "Chorasmian": range(69552, 69600), + "Elymaic": range(69600, 69632), + "Brahmi": range(69632, 69760), + "Kaithi": range(69760, 69840), + "Sora Sompeng": range(69840, 69888), + "Chakma": range(69888, 69968), + "Mahajani": range(69968, 70016), + "Sharada": range(70016, 70112), + "Sinhala Archaic Numbers": range(70112, 70144), + "Khojki": range(70144, 70224), + "Multani": range(70272, 70320), + "Khudawadi": range(70320, 70400), + "Grantha": range(70400, 70528), + "Newa": range(70656, 70784), + "Tirhuta": range(70784, 70880), + "Siddham": range(71040, 71168), + "Modi": range(71168, 71264), + "Mongolian Supplement": range(71264, 71296), + "Takri": range(71296, 71376), + "Ahom": range(71424, 71504), + "Dogra": range(71680, 71760), + "Warang Citi": range(71840, 71936), + "Dives Akuru": range(71936, 72032), + "Nandinagari": range(72096, 72192), + "Zanabazar Square": range(72192, 72272), + "Soyombo": range(72272, 72368), + "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384), + "Pau Cin Hau": range(72384, 72448), + "Devanagari Extended-A": range(72448, 72544), + "Bhaiksuki": range(72704, 72816), + "Marchen": range(72816, 72896), + "Masaram Gondi": range(72960, 73056), + "Gunjala Gondi": range(73056, 73136), + "Makasar": range(73440, 73472), + "Kawi": range(73472, 73568), + "Lisu Supplement": range(73648, 73664), + "Tamil Supplement": range(73664, 73728), + "Cuneiform": range(73728, 74752), + "Cuneiform Numbers and Punctuation": range(74752, 74880), + "Early Dynastic Cuneiform": range(74880, 75088), + "Cypro-Minoan": range(77712, 77824), + "Egyptian Hieroglyphs": range(77824, 78896), + "Egyptian Hieroglyph Format Controls": range(78896, 78944), + "Anatolian Hieroglyphs": range(82944, 83584), + "Bamum Supplement": range(92160, 92736), + "Mro": range(92736, 92784), + "Tangsa": range(92784, 92880), + "Bassa Vah": range(92880, 92928), + "Pahawh Hmong": range(92928, 93072), + "Medefaidrin": range(93760, 93856), + "Miao": range(93952, 94112), + "Ideographic Symbols and Punctuation": range(94176, 94208), + "Tangut": range(94208, 100352), + "Tangut Components": range(100352, 101120), + "Khitan Small Script": range(101120, 101632), + "Tangut Supplement": range(101632, 101760), + "Kana Extended-B": range(110576, 110592), + "Kana Supplement": range(110592, 110848), + "Kana Extended-A": range(110848, 110896), + "Small Kana Extension": range(110896, 110960), + "Nushu": range(110960, 111360), + "Duployan": range(113664, 113824), + "Shorthand Format Controls": range(113824, 113840), + "Znamenny Musical Notation": range(118528, 118736), + "Byzantine Musical Symbols": range(118784, 119040), + "Musical Symbols": range(119040, 119296), + "Ancient Greek Musical Notation": range(119296, 119376), + "Kaktovik Numerals": range(119488, 119520), + "Mayan Numerals": range(119520, 119552), + "Tai Xuan Jing Symbols": range(119552, 119648), + "Counting Rod Numerals": range(119648, 119680), + "Mathematical Alphanumeric Symbols": range(119808, 120832), + "Sutton SignWriting": range(120832, 121520), + "Latin Extended-G": range(122624, 122880), + "Glagolitic Supplement": range(122880, 122928), + "Cyrillic Extended-D": range(122928, 123024), + "Nyiakeng Puachue Hmong": range(123136, 123216), + "Toto": range(123536, 123584), + "Wancho": range(123584, 123648), + "Nag Mundari": range(124112, 124160), + "Ethiopic Extended-B": range(124896, 124928), + "Mende Kikakui": range(124928, 125152), + "Adlam": range(125184, 125280), + "Indic Siyaq Numbers": range(126064, 126144), + "Ottoman Siyaq Numbers": range(126208, 126288), + "Arabic Mathematical Alphabetic Symbols": range(126464, 126720), + "Mahjong Tiles": range(126976, 127024), + "Domino Tiles": range(127024, 127136), + "Playing Cards": range(127136, 127232), + "Enclosed Alphanumeric Supplement": range(127232, 127488), + "Enclosed Ideographic Supplement": range(127488, 127744), + "Miscellaneous Symbols and Pictographs": range(127744, 128512), + "Emoticons range(Emoji)": range(128512, 128592), + "Ornamental Dingbats": range(128592, 128640), + "Transport and Map Symbols": range(128640, 128768), + "Alchemical Symbols": range(128768, 128896), + "Geometric Shapes Extended": range(128896, 129024), + "Supplemental Arrows-C": range(129024, 129280), + "Supplemental Symbols and Pictographs": range(129280, 129536), + "Chess Symbols": range(129536, 129648), + "Symbols and Pictographs Extended-A": range(129648, 129792), + "Symbols for Legacy Computing": range(129792, 130048), + "CJK Unified Ideographs Extension B": range(131072, 173792), + "CJK Unified Ideographs Extension C": range(173824, 177984), + "CJK Unified Ideographs Extension D": range(177984, 178208), + "CJK Unified Ideographs Extension E": range(178208, 183984), + "CJK Unified Ideographs Extension F": range(183984, 191472), + "CJK Compatibility Ideographs Supplement": range(194560, 195104), + "CJK Unified Ideographs Extension G": range(196608, 201552), + "CJK Unified Ideographs Extension H": range(201552, 205744), + "Tags": range(917504, 917632), + "Variation Selectors Supplement": range(917760, 918000), + "Supplementary Private Use Area-A": range(983040, 1048576), + "Supplementary Private Use Area-B": range(1048576, 1114112), +} + + +UNICODE_SECONDARY_RANGE_KEYWORD: list[str] = [ + "Supplement", + "Extended", + "Extensions", + "Modifier", + "Marks", + "Punctuation", + "Symbols", + "Forms", + "Operators", + "Miscellaneous", + "Drawing", + "Block", + "Shapes", + "Supplemental", + "Tags", +] + +RE_POSSIBLE_ENCODING_INDICATION = re_compile( + r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)", + IGNORECASE, +) + +IANA_NO_ALIASES = [ + "cp720", + "cp737", + "cp856", + "cp874", + "cp875", + "cp1006", + "koi8_r", + "koi8_t", + "koi8_u", +] + +IANA_SUPPORTED: list[str] = sorted( + filter( + lambda x: x.endswith("_codec") is False + and x not in {"rot_13", "tactis", "mbcs"}, + list(set(aliases.values())) + IANA_NO_ALIASES, + ) +) + +IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED) + +# pre-computed code page that are similar using the function cp_similarity. +IANA_SUPPORTED_SIMILAR: dict[str, list[str]] = { + "cp037": ["cp1026", "cp1140", "cp273", "cp500"], + "cp1026": ["cp037", "cp1140", "cp273", "cp500"], + "cp1125": ["cp866"], + "cp1140": ["cp037", "cp1026", "cp273", "cp500"], + "cp1250": ["iso8859_2"], + "cp1251": ["kz1048", "ptcp154"], + "cp1252": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1253": ["iso8859_7"], + "cp1254": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1257": ["iso8859_13"], + "cp273": ["cp037", "cp1026", "cp1140", "cp500"], + "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"], + "cp500": ["cp037", "cp1026", "cp1140", "cp273"], + "cp850": ["cp437", "cp857", "cp858", "cp865"], + "cp857": ["cp850", "cp858", "cp865"], + "cp858": ["cp437", "cp850", "cp857", "cp865"], + "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"], + "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"], + "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"], + "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"], + "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"], + "cp866": ["cp1125"], + "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"], + "iso8859_11": ["tis_620"], + "iso8859_13": ["cp1257"], + "iso8859_14": [ + "iso8859_10", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_15": [ + "cp1252", + "cp1254", + "iso8859_10", + "iso8859_14", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_16": [ + "iso8859_14", + "iso8859_15", + "iso8859_2", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"], + "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"], + "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"], + "iso8859_7": ["cp1253"], + "iso8859_9": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "latin_1", + ], + "kz1048": ["cp1251", "ptcp154"], + "latin_1": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "iso8859_9", + ], + "mac_iceland": ["mac_roman", "mac_turkish"], + "mac_roman": ["mac_iceland", "mac_turkish"], + "mac_turkish": ["mac_iceland", "mac_roman"], + "ptcp154": ["cp1251", "kz1048"], + "tis_620": ["iso8859_11"], +} + + +CHARDET_CORRESPONDENCE: dict[str, str] = { + "iso2022_kr": "ISO-2022-KR", + "iso2022_jp": "ISO-2022-JP", + "euc_kr": "EUC-KR", + "tis_620": "TIS-620", + "utf_32": "UTF-32", + "euc_jp": "EUC-JP", + "koi8_r": "KOI8-R", + "iso8859_1": "ISO-8859-1", + "iso8859_2": "ISO-8859-2", + "iso8859_5": "ISO-8859-5", + "iso8859_6": "ISO-8859-6", + "iso8859_7": "ISO-8859-7", + "iso8859_8": "ISO-8859-8", + "utf_16": "UTF-16", + "cp855": "IBM855", + "mac_cyrillic": "MacCyrillic", + "gb2312": "GB2312", + "gb18030": "GB18030", + "cp932": "CP932", + "cp866": "IBM866", + "utf_8": "utf-8", + "utf_8_sig": "UTF-8-SIG", + "shift_jis": "SHIFT_JIS", + "big5": "Big5", + "cp1250": "windows-1250", + "cp1251": "windows-1251", + "cp1252": "Windows-1252", + "cp1253": "windows-1253", + "cp1255": "windows-1255", + "cp1256": "windows-1256", + "cp1254": "Windows-1254", + "cp949": "CP949", +} + + +COMMON_SAFE_ASCII_CHARACTERS: set[str] = { + "<", + ">", + "=", + ":", + "/", + "&", + ";", + "{", + "}", + "[", + "]", + ",", + "|", + '"', + "-", + "(", + ")", +} + +# Sample character sets — replace with full lists if needed +COMMON_CHINESE_CHARACTERS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞" + +COMMON_JAPANESE_CHARACTERS = "日一国年大十二本中長出三時行見月分後前生五間上東四今金九入学高円子外八六下来気小七山話女北午百書先名川千水半男西電校語土木聞食車何南万毎白天母火右読友左休父雨" + +COMMON_KOREAN_CHARACTERS = "一二三四五六七八九十百千萬上下左右中人女子大小山川日月火水木金土父母天地國名年時文校學生" + +# Combine all into a set +COMMON_CJK_CHARACTERS = set( + "".join( + [ + COMMON_CHINESE_CHARACTERS, + COMMON_JAPANESE_CHARACTERS, + COMMON_KOREAN_CHARACTERS, + ] + ) +) + +KO_NAMES: set[str] = {"johab", "cp949", "euc_kr"} +ZH_NAMES: set[str] = {"big5", "cp950", "big5hkscs", "hz"} + +# Logging LEVEL below DEBUG +TRACE: int = 5 + + +# Language label that contain the em dash "—" +# character are to be considered alternative seq to origin +FREQUENCIES: dict[str, list[str]] = { + "English": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "u", + "m", + "f", + "p", + "g", + "w", + "y", + "b", + "v", + "k", + "x", + "j", + "z", + "q", + ], + "English—": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "m", + "u", + "f", + "p", + "g", + "w", + "b", + "y", + "v", + "k", + "j", + "x", + "z", + "q", + ], + "German": [ + "e", + "n", + "i", + "r", + "s", + "t", + "a", + "d", + "h", + "u", + "l", + "g", + "o", + "c", + "m", + "b", + "f", + "k", + "w", + "z", + "p", + "v", + "ü", + "ä", + "ö", + "j", + ], + "French": [ + "e", + "a", + "s", + "n", + "i", + "t", + "r", + "l", + "u", + "o", + "d", + "c", + "p", + "m", + "é", + "v", + "g", + "f", + "b", + "h", + "q", + "à", + "x", + "è", + "y", + "j", + ], + "Dutch": [ + "e", + "n", + "a", + "i", + "r", + "t", + "o", + "d", + "s", + "l", + "g", + "h", + "v", + "m", + "u", + "k", + "c", + "p", + "b", + "w", + "j", + "z", + "f", + "y", + "x", + "ë", + ], + "Italian": [ + "e", + "i", + "a", + "o", + "n", + "l", + "t", + "r", + "s", + "c", + "d", + "u", + "p", + "m", + "g", + "v", + "f", + "b", + "z", + "h", + "q", + "è", + "à", + "k", + "y", + "ò", + ], + "Polish": [ + "a", + "i", + "o", + "e", + "n", + "r", + "z", + "w", + "s", + "c", + "t", + "k", + "y", + "d", + "p", + "m", + "u", + "l", + "j", + "ł", + "g", + "b", + "h", + "ą", + "ę", + "ó", + ], + "Spanish": [ + "e", + "a", + "o", + "n", + "s", + "r", + "i", + "l", + "d", + "t", + "c", + "u", + "m", + "p", + "b", + "g", + "v", + "f", + "y", + "ó", + "h", + "q", + "í", + "j", + "z", + "á", + ], + "Russian": [ + "о", + "а", + "е", + "и", + "н", + "с", + "т", + "р", + "в", + "л", + "к", + "м", + "д", + "п", + "у", + "г", + "я", + "ы", + "з", + "б", + "й", + "ь", + "ч", + "х", + "ж", + "ц", + ], + # Jap-Kanji + "Japanese": [ + "人", + "一", + "大", + "亅", + "丁", + "丨", + "竹", + "笑", + "口", + "日", + "今", + "二", + "彳", + "行", + "十", + "土", + "丶", + "寸", + "寺", + "時", + "乙", + "丿", + "乂", + "气", + "気", + "冂", + "巾", + "亠", + "市", + "目", + "儿", + "見", + "八", + "小", + "凵", + "県", + "月", + "彐", + "門", + "間", + "木", + "東", + "山", + "出", + "本", + "中", + "刀", + "分", + "耳", + "又", + "取", + "最", + "言", + "田", + "心", + "思", + "刂", + "前", + "京", + "尹", + "事", + "生", + "厶", + "云", + "会", + "未", + "来", + "白", + "冫", + "楽", + "灬", + "馬", + "尸", + "尺", + "駅", + "明", + "耂", + "者", + "了", + "阝", + "都", + "高", + "卜", + "占", + "厂", + "广", + "店", + "子", + "申", + "奄", + "亻", + "俺", + "上", + "方", + "冖", + "学", + "衣", + "艮", + "食", + "自", + ], + # Jap-Katakana + "Japanese—": [ + "ー", + "ン", + "ス", + "・", + "ル", + "ト", + "リ", + "イ", + "ア", + "ラ", + "ッ", + "ク", + "ド", + "シ", + "レ", + "ジ", + "タ", + "フ", + "ロ", + "カ", + "テ", + "マ", + "ィ", + "グ", + "バ", + "ム", + "プ", + "オ", + "コ", + "デ", + "ニ", + "ウ", + "メ", + "サ", + "ビ", + "ナ", + "ブ", + "ャ", + "エ", + "ュ", + "チ", + "キ", + "ズ", + "ダ", + "パ", + "ミ", + "ェ", + "ョ", + "ハ", + "セ", + "ベ", + "ガ", + "モ", + "ツ", + "ネ", + "ボ", + "ソ", + "ノ", + "ァ", + "ヴ", + "ワ", + "ポ", + "ペ", + "ピ", + "ケ", + "ゴ", + "ギ", + "ザ", + "ホ", + "ゲ", + "ォ", + "ヤ", + "ヒ", + "ユ", + "ヨ", + "ヘ", + "ゼ", + "ヌ", + "ゥ", + "ゾ", + "ヶ", + "ヂ", + "ヲ", + "ヅ", + "ヵ", + "ヱ", + "ヰ", + "ヮ", + "ヽ", + "゠", + "ヾ", + "ヷ", + "ヿ", + "ヸ", + "ヹ", + "ヺ", + ], + # Jap-Hiragana + "Japanese——": [ + "の", + "に", + "る", + "た", + "と", + "は", + "し", + "い", + "を", + "で", + "て", + "が", + "な", + "れ", + "か", + "ら", + "さ", + "っ", + "り", + "す", + "あ", + "も", + "こ", + "ま", + "う", + "く", + "よ", + "き", + "ん", + "め", + "お", + "け", + "そ", + "つ", + "だ", + "や", + "え", + "ど", + "わ", + "ち", + "み", + "せ", + "じ", + "ば", + "へ", + "び", + "ず", + "ろ", + "ほ", + "げ", + "む", + "べ", + "ひ", + "ょ", + "ゆ", + "ぶ", + "ご", + "ゃ", + "ね", + "ふ", + "ぐ", + "ぎ", + "ぼ", + "ゅ", + "づ", + "ざ", + "ぞ", + "ぬ", + "ぜ", + "ぱ", + "ぽ", + "ぷ", + "ぴ", + "ぃ", + "ぁ", + "ぇ", + "ぺ", + "ゞ", + "ぢ", + "ぉ", + "ぅ", + "ゐ", + "ゝ", + "ゑ", + "゛", + "゜", + "ゎ", + "ゔ", + "゚", + "ゟ", + "゙", + "ゕ", + "ゖ", + ], + "Portuguese": [ + "a", + "e", + "o", + "s", + "i", + "r", + "d", + "n", + "t", + "m", + "u", + "c", + "l", + "p", + "g", + "v", + "b", + "f", + "h", + "ã", + "q", + "é", + "ç", + "á", + "z", + "í", + ], + "Swedish": [ + "e", + "a", + "n", + "r", + "t", + "s", + "i", + "l", + "d", + "o", + "m", + "k", + "g", + "v", + "h", + "f", + "u", + "p", + "ä", + "c", + "b", + "ö", + "å", + "y", + "j", + "x", + ], + "Chinese": [ + "的", + "一", + "是", + "不", + "了", + "在", + "人", + "有", + "我", + "他", + "这", + "个", + "们", + "中", + "来", + "上", + "大", + "为", + "和", + "国", + "地", + "到", + "以", + "说", + "时", + "要", + "就", + "出", + "会", + "可", + "也", + "你", + "对", + "生", + "能", + "而", + "子", + "那", + "得", + "于", + "着", + "下", + "自", + "之", + "年", + "过", + "发", + "后", + "作", + "里", + "用", + "道", + "行", + "所", + "然", + "家", + "种", + "事", + "成", + "方", + "多", + "经", + "么", + "去", + "法", + "学", + "如", + "都", + "同", + "现", + "当", + "没", + "动", + "面", + "起", + "看", + "定", + "天", + "分", + "还", + "进", + "好", + "小", + "部", + "其", + "些", + "主", + "样", + "理", + "心", + "她", + "本", + "前", + "开", + "但", + "因", + "只", + "从", + "想", + "实", + ], + "Ukrainian": [ + "о", + "а", + "н", + "і", + "и", + "р", + "в", + "т", + "е", + "с", + "к", + "л", + "у", + "д", + "м", + "п", + "з", + "я", + "ь", + "б", + "г", + "й", + "ч", + "х", + "ц", + "ї", + ], + "Norwegian": [ + "e", + "r", + "n", + "t", + "a", + "s", + "i", + "o", + "l", + "d", + "g", + "k", + "m", + "v", + "f", + "p", + "u", + "b", + "h", + "å", + "y", + "j", + "ø", + "c", + "æ", + "w", + ], + "Finnish": [ + "a", + "i", + "n", + "t", + "e", + "s", + "l", + "o", + "u", + "k", + "ä", + "m", + "r", + "v", + "j", + "h", + "p", + "y", + "d", + "ö", + "g", + "c", + "b", + "f", + "w", + "z", + ], + "Vietnamese": [ + "n", + "h", + "t", + "i", + "c", + "g", + "a", + "o", + "u", + "m", + "l", + "r", + "à", + "đ", + "s", + "e", + "v", + "p", + "b", + "y", + "ư", + "d", + "á", + "k", + "ộ", + "ế", + ], + "Czech": [ + "o", + "e", + "a", + "n", + "t", + "s", + "i", + "l", + "v", + "r", + "k", + "d", + "u", + "m", + "p", + "í", + "c", + "h", + "z", + "á", + "y", + "j", + "b", + "ě", + "é", + "ř", + ], + "Hungarian": [ + "e", + "a", + "t", + "l", + "s", + "n", + "k", + "r", + "i", + "o", + "z", + "á", + "é", + "g", + "m", + "b", + "y", + "v", + "d", + "h", + "u", + "p", + "j", + "ö", + "f", + "c", + ], + "Korean": [ + "이", + "다", + "에", + "의", + "는", + "로", + "하", + "을", + "가", + "고", + "지", + "서", + "한", + "은", + "기", + "으", + "년", + "대", + "사", + "시", + "를", + "리", + "도", + "인", + "스", + "일", + ], + "Indonesian": [ + "a", + "n", + "e", + "i", + "r", + "t", + "u", + "s", + "d", + "k", + "m", + "l", + "g", + "p", + "b", + "o", + "h", + "y", + "j", + "c", + "w", + "f", + "v", + "z", + "x", + "q", + ], + "Turkish": [ + "a", + "e", + "i", + "n", + "r", + "l", + "ı", + "k", + "d", + "t", + "s", + "m", + "y", + "u", + "o", + "b", + "ü", + "ş", + "v", + "g", + "z", + "h", + "c", + "p", + "ç", + "ğ", + ], + "Romanian": [ + "e", + "i", + "a", + "r", + "n", + "t", + "u", + "l", + "o", + "c", + "s", + "d", + "p", + "m", + "ă", + "f", + "v", + "î", + "g", + "b", + "ș", + "ț", + "z", + "h", + "â", + "j", + ], + "Farsi": [ + "ا", + "ی", + "ر", + "د", + "ن", + "ه", + "و", + "م", + "ت", + "ب", + "س", + "ل", + "ک", + "ش", + "ز", + "ف", + "گ", + "ع", + "خ", + "ق", + "ج", + "آ", + "پ", + "ح", + "ط", + "ص", + ], + "Arabic": [ + "ا", + "ل", + "ي", + "م", + "و", + "ن", + "ر", + "ت", + "ب", + "ة", + "ع", + "د", + "س", + "ف", + "ه", + "ك", + "ق", + "أ", + "ح", + "ج", + "ش", + "ط", + "ص", + "ى", + "خ", + "إ", + ], + "Danish": [ + "e", + "r", + "n", + "t", + "a", + "i", + "s", + "d", + "l", + "o", + "g", + "m", + "k", + "f", + "v", + "u", + "b", + "h", + "p", + "å", + "y", + "ø", + "æ", + "c", + "j", + "w", + ], + "Serbian": [ + "а", + "и", + "о", + "е", + "н", + "р", + "с", + "у", + "т", + "к", + "ј", + "в", + "д", + "м", + "п", + "л", + "г", + "з", + "б", + "a", + "i", + "e", + "o", + "n", + "ц", + "ш", + ], + "Lithuanian": [ + "i", + "a", + "s", + "o", + "r", + "e", + "t", + "n", + "u", + "k", + "m", + "l", + "p", + "v", + "d", + "j", + "g", + "ė", + "b", + "y", + "ų", + "š", + "ž", + "c", + "ą", + "į", + ], + "Slovene": [ + "e", + "a", + "i", + "o", + "n", + "r", + "s", + "l", + "t", + "j", + "v", + "k", + "d", + "p", + "m", + "u", + "z", + "b", + "g", + "h", + "č", + "c", + "š", + "ž", + "f", + "y", + ], + "Slovak": [ + "o", + "a", + "e", + "n", + "i", + "r", + "v", + "t", + "s", + "l", + "k", + "d", + "m", + "p", + "u", + "c", + "h", + "j", + "b", + "z", + "á", + "y", + "ý", + "í", + "č", + "é", + ], + "Hebrew": [ + "י", + "ו", + "ה", + "ל", + "ר", + "ב", + "ת", + "מ", + "א", + "ש", + "נ", + "ע", + "ם", + "ד", + "ק", + "ח", + "פ", + "ס", + "כ", + "ג", + "ט", + "צ", + "ן", + "ז", + "ך", + ], + "Bulgarian": [ + "а", + "и", + "о", + "е", + "н", + "т", + "р", + "с", + "в", + "л", + "к", + "д", + "п", + "м", + "з", + "г", + "я", + "ъ", + "у", + "б", + "ч", + "ц", + "й", + "ж", + "щ", + "х", + ], + "Croatian": [ + "a", + "i", + "o", + "e", + "n", + "r", + "j", + "s", + "t", + "u", + "k", + "l", + "v", + "d", + "m", + "p", + "g", + "z", + "b", + "c", + "č", + "h", + "š", + "ž", + "ć", + "f", + ], + "Hindi": [ + "क", + "र", + "स", + "न", + "त", + "म", + "ह", + "प", + "य", + "ल", + "व", + "ज", + "द", + "ग", + "ब", + "श", + "ट", + "अ", + "ए", + "थ", + "भ", + "ड", + "च", + "ध", + "ष", + "इ", + ], + "Estonian": [ + "a", + "i", + "e", + "s", + "t", + "l", + "u", + "n", + "o", + "k", + "r", + "d", + "m", + "v", + "g", + "p", + "j", + "h", + "ä", + "b", + "õ", + "ü", + "f", + "c", + "ö", + "y", + ], + "Thai": [ + "า", + "น", + "ร", + "อ", + "ก", + "เ", + "ง", + "ม", + "ย", + "ล", + "ว", + "ด", + "ท", + "ส", + "ต", + "ะ", + "ป", + "บ", + "ค", + "ห", + "แ", + "จ", + "พ", + "ช", + "ข", + "ใ", + ], + "Greek": [ + "α", + "τ", + "ο", + "ι", + "ε", + "ν", + "ρ", + "σ", + "κ", + "η", + "π", + "ς", + "υ", + "μ", + "λ", + "ί", + "ό", + "ά", + "γ", + "έ", + "δ", + "ή", + "ω", + "χ", + "θ", + "ύ", + ], + "Tamil": [ + "க", + "த", + "ப", + "ட", + "ர", + "ம", + "ல", + "ன", + "வ", + "ற", + "ய", + "ள", + "ச", + "ந", + "இ", + "ண", + "அ", + "ஆ", + "ழ", + "ங", + "எ", + "உ", + "ஒ", + "ஸ", + ], + "Kazakh": [ + "а", + "ы", + "е", + "н", + "т", + "р", + "л", + "і", + "д", + "с", + "м", + "қ", + "к", + "о", + "б", + "и", + "у", + "ғ", + "ж", + "ң", + "з", + "ш", + "й", + "п", + "г", + "ө", + ], +} + +LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/legacy.py b/backend/venv/Lib/site-packages/charset_normalizer/legacy.py new file mode 100644 index 0000000..360a310 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/legacy.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any +from warnings import warn + +from .api import from_bytes +from .constant import CHARDET_CORRESPONDENCE, TOO_SMALL_SEQUENCE + +# TODO: remove this check when dropping Python 3.7 support +if TYPE_CHECKING: + from typing_extensions import TypedDict + + class ResultDict(TypedDict): + encoding: str | None + language: str + confidence: float | None + + +def detect( + byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any +) -> ResultDict: + """ + chardet legacy method + Detect the encoding of the given byte string. It should be mostly backward-compatible. + Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) + This function is deprecated and should be used to migrate your project easily, consult the documentation for + further information. Not planned for removal. + + :param byte_str: The byte sequence to examine. + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + """ + if len(kwargs): + warn( + f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" + ) + + if not isinstance(byte_str, (bytearray, bytes)): + raise TypeError( # pragma: nocover + f"Expected object of type bytes or bytearray, got: {type(byte_str)}" + ) + + if isinstance(byte_str, bytearray): + byte_str = bytes(byte_str) + + r = from_bytes(byte_str).best() + + encoding = r.encoding if r is not None else None + language = r.language if r is not None and r.language != "Unknown" else "" + confidence = 1.0 - r.chaos if r is not None else None + + # automatically lower confidence + # on small bytes samples. + # https://github.com/jawah/charset_normalizer/issues/391 + if ( + confidence is not None + and confidence >= 0.9 + and encoding + not in { + "utf_8", + "ascii", + } + and r.bom is False # type: ignore[union-attr] + and len(byte_str) < TOO_SMALL_SEQUENCE + ): + confidence -= 0.2 + + # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process + # but chardet does return 'utf-8-sig' and it is a valid codec name. + if r is not None and encoding == "utf_8" and r.bom: + encoding += "_sig" + + if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: + encoding = CHARDET_CORRESPONDENCE[encoding] + + return { + "encoding": encoding, + "language": language, + "confidence": confidence, + } diff --git a/backend/venv/Lib/site-packages/charset_normalizer/md.cp312-win_amd64.pyd b/backend/venv/Lib/site-packages/charset_normalizer/md.cp312-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..047d0bcd4b249e95470fe14ee916e25006f8eba2 GIT binary patch literal 10752 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 bool: + """ + Determine if given character should be fed in. + """ + raise NotImplementedError # pragma: nocover + + def feed(self, character: str) -> None: + """ + The main routine to be executed upon character. + Insert the logic in witch the text would be considered chaotic. + """ + raise NotImplementedError # pragma: nocover + + def reset(self) -> None: # pragma: no cover + """ + Permit to reset the plugin to the initial state. + """ + raise NotImplementedError + + @property + def ratio(self) -> float: + """ + Compute the chaos ratio based on what your feed() has seen. + Must NOT be lower than 0.; No restriction gt 0. + """ + raise NotImplementedError # pragma: nocover + + +class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._punctuation_count: int = 0 + self._symbol_count: int = 0 + self._character_count: int = 0 + + self._last_printable_char: str | None = None + self._frenzy_symbol_in_word: bool = False + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character != self._last_printable_char + and character not in COMMON_SAFE_ASCII_CHARACTERS + ): + if is_punctuation(character): + self._punctuation_count += 1 + elif ( + character.isdigit() is False + and is_symbol(character) + and is_emoticon(character) is False + ): + self._symbol_count += 2 + + self._last_printable_char = character + + def reset(self) -> None: # Abstract + self._punctuation_count = 0 + self._character_count = 0 + self._symbol_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + ratio_of_punctuation: float = ( + self._punctuation_count + self._symbol_count + ) / self._character_count + + return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 + + +class TooManyAccentuatedPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._accentuated_count: int = 0 + + def eligible(self, character: str) -> bool: + return character.isalpha() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_accentuated(character): + self._accentuated_count += 1 + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._accentuated_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + ratio_of_accentuation: float = self._accentuated_count / self._character_count + return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 + + +class UnprintablePlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._unprintable_count: int = 0 + self._character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if is_unprintable(character): + self._unprintable_count += 1 + self._character_count += 1 + + def reset(self) -> None: # Abstract + self._unprintable_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._unprintable_count * 8) / self._character_count + + +class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._successive_count: int = 0 + self._character_count: int = 0 + + self._last_latin_character: str | None = None + + def eligible(self, character: str) -> bool: + return character.isalpha() and is_latin(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + if ( + self._last_latin_character is not None + and is_accentuated(character) + and is_accentuated(self._last_latin_character) + ): + if character.isupper() and self._last_latin_character.isupper(): + self._successive_count += 1 + # Worse if its the same char duplicated with different accent. + if remove_accent(character) == remove_accent(self._last_latin_character): + self._successive_count += 1 + self._last_latin_character = character + + def reset(self) -> None: # Abstract + self._successive_count = 0 + self._character_count = 0 + self._last_latin_character = None + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._successive_count * 2) / self._character_count + + +class SuspiciousRange(MessDetectorPlugin): + def __init__(self) -> None: + self._suspicious_successive_range_count: int = 0 + self._character_count: int = 0 + self._last_printable_seen: str | None = None + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character.isspace() + or is_punctuation(character) + or character in COMMON_SAFE_ASCII_CHARACTERS + ): + self._last_printable_seen = None + return + + if self._last_printable_seen is None: + self._last_printable_seen = character + return + + unicode_range_a: str | None = unicode_range(self._last_printable_seen) + unicode_range_b: str | None = unicode_range(character) + + if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): + self._suspicious_successive_range_count += 1 + + self._last_printable_seen = character + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._suspicious_successive_range_count = 0 + self._last_printable_seen = None + + @property + def ratio(self) -> float: + if self._character_count <= 13: + return 0.0 + + ratio_of_suspicious_range_usage: float = ( + self._suspicious_successive_range_count * 2 + ) / self._character_count + + return ratio_of_suspicious_range_usage + + +class SuperWeirdWordPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._word_count: int = 0 + self._bad_word_count: int = 0 + self._foreign_long_count: int = 0 + + self._is_current_word_bad: bool = False + self._foreign_long_watch: bool = False + + self._character_count: int = 0 + self._bad_character_count: int = 0 + + self._buffer: str = "" + self._buffer_accent_count: int = 0 + self._buffer_glyph_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character.isalpha(): + self._buffer += character + if is_accentuated(character): + self._buffer_accent_count += 1 + if ( + self._foreign_long_watch is False + and (is_latin(character) is False or is_accentuated(character)) + and is_cjk(character) is False + and is_hangul(character) is False + and is_katakana(character) is False + and is_hiragana(character) is False + and is_thai(character) is False + ): + self._foreign_long_watch = True + if ( + is_cjk(character) + or is_hangul(character) + or is_katakana(character) + or is_hiragana(character) + or is_thai(character) + ): + self._buffer_glyph_count += 1 + return + if not self._buffer: + return + if ( + character.isspace() or is_punctuation(character) or is_separator(character) + ) and self._buffer: + self._word_count += 1 + buffer_length: int = len(self._buffer) + + self._character_count += buffer_length + + if buffer_length >= 4: + if self._buffer_accent_count / buffer_length >= 0.5: + self._is_current_word_bad = True + # Word/Buffer ending with an upper case accentuated letter are so rare, + # that we will consider them all as suspicious. Same weight as foreign_long suspicious. + elif ( + is_accentuated(self._buffer[-1]) + and self._buffer[-1].isupper() + and all(_.isupper() for _ in self._buffer) is False + ): + self._foreign_long_count += 1 + self._is_current_word_bad = True + elif self._buffer_glyph_count == 1: + self._is_current_word_bad = True + self._foreign_long_count += 1 + if buffer_length >= 24 and self._foreign_long_watch: + camel_case_dst = [ + i + for c, i in zip(self._buffer, range(0, buffer_length)) + if c.isupper() + ] + probable_camel_cased: bool = False + + if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3): + probable_camel_cased = True + + if not probable_camel_cased: + self._foreign_long_count += 1 + self._is_current_word_bad = True + + if self._is_current_word_bad: + self._bad_word_count += 1 + self._bad_character_count += len(self._buffer) + self._is_current_word_bad = False + + self._foreign_long_watch = False + self._buffer = "" + self._buffer_accent_count = 0 + self._buffer_glyph_count = 0 + elif ( + character not in {"<", ">", "-", "=", "~", "|", "_"} + and character.isdigit() is False + and is_symbol(character) + ): + self._is_current_word_bad = True + self._buffer += character + + def reset(self) -> None: # Abstract + self._buffer = "" + self._is_current_word_bad = False + self._foreign_long_watch = False + self._bad_word_count = 0 + self._word_count = 0 + self._character_count = 0 + self._bad_character_count = 0 + self._foreign_long_count = 0 + + @property + def ratio(self) -> float: + if self._word_count <= 10 and self._foreign_long_count == 0: + return 0.0 + + return self._bad_character_count / self._character_count + + +class CjkUncommonPlugin(MessDetectorPlugin): + """ + Detect messy CJK text that probably means nothing. + """ + + def __init__(self) -> None: + self._character_count: int = 0 + self._uncommon_count: int = 0 + + def eligible(self, character: str) -> bool: + return is_cjk(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_cjk_uncommon(character): + self._uncommon_count += 1 + return + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._uncommon_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + uncommon_form_usage: float = self._uncommon_count / self._character_count + + # we can be pretty sure it's garbage when uncommon characters are widely + # used. otherwise it could just be traditional chinese for example. + return uncommon_form_usage / 10 if uncommon_form_usage > 0.5 else 0.0 + + +class ArchaicUpperLowerPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._buf: bool = False + + self._character_count_since_last_sep: int = 0 + + self._successive_upper_lower_count: int = 0 + self._successive_upper_lower_count_final: int = 0 + + self._character_count: int = 0 + + self._last_alpha_seen: str | None = None + self._current_ascii_only: bool = True + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + is_concerned = character.isalpha() and is_case_variable(character) + chunk_sep = is_concerned is False + + if chunk_sep and self._character_count_since_last_sep > 0: + if ( + self._character_count_since_last_sep <= 64 + and character.isdigit() is False + and self._current_ascii_only is False + ): + self._successive_upper_lower_count_final += ( + self._successive_upper_lower_count + ) + + self._successive_upper_lower_count = 0 + self._character_count_since_last_sep = 0 + self._last_alpha_seen = None + self._buf = False + self._character_count += 1 + self._current_ascii_only = True + + return + + if self._current_ascii_only is True and character.isascii() is False: + self._current_ascii_only = False + + if self._last_alpha_seen is not None: + if (character.isupper() and self._last_alpha_seen.islower()) or ( + character.islower() and self._last_alpha_seen.isupper() + ): + if self._buf is True: + self._successive_upper_lower_count += 2 + self._buf = False + else: + self._buf = True + else: + self._buf = False + + self._character_count += 1 + self._character_count_since_last_sep += 1 + self._last_alpha_seen = character + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._character_count_since_last_sep = 0 + self._successive_upper_lower_count = 0 + self._successive_upper_lower_count_final = 0 + self._last_alpha_seen = None + self._buf = False + self._current_ascii_only = True + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return self._successive_upper_lower_count_final / self._character_count + + +class ArabicIsolatedFormPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._isolated_form_count: int = 0 + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._isolated_form_count = 0 + + def eligible(self, character: str) -> bool: + return is_arabic(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_arabic_isolated_form(character): + self._isolated_form_count += 1 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + isolated_form_usage: float = self._isolated_form_count / self._character_count + + return isolated_form_usage + + +@lru_cache(maxsize=1024) +def is_suspiciously_successive_range( + unicode_range_a: str | None, unicode_range_b: str | None +) -> bool: + """ + Determine if two Unicode range seen next to each other can be considered as suspicious. + """ + if unicode_range_a is None or unicode_range_b is None: + return True + + if unicode_range_a == unicode_range_b: + return False + + if "Latin" in unicode_range_a and "Latin" in unicode_range_b: + return False + + if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: + return False + + # Latin characters can be accompanied with a combining diacritical mark + # eg. Vietnamese. + if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( + "Combining" in unicode_range_a or "Combining" in unicode_range_b + ): + return False + + keywords_range_a, keywords_range_b = ( + unicode_range_a.split(" "), + unicode_range_b.split(" "), + ) + + for el in keywords_range_a: + if el in UNICODE_SECONDARY_RANGE_KEYWORD: + continue + if el in keywords_range_b: + return False + + # Japanese Exception + range_a_jp_chars, range_b_jp_chars = ( + unicode_range_a + in ( + "Hiragana", + "Katakana", + ), + unicode_range_b in ("Hiragana", "Katakana"), + ) + if (range_a_jp_chars or range_b_jp_chars) and ( + "CJK" in unicode_range_a or "CJK" in unicode_range_b + ): + return False + if range_a_jp_chars and range_b_jp_chars: + return False + + if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: + if "CJK" in unicode_range_a or "CJK" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + # Chinese/Japanese use dedicated range for punctuation and/or separators. + if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( + unicode_range_a in ["Katakana", "Hiragana"] + and unicode_range_b in ["Katakana", "Hiragana"] + ): + if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: + return False + if "Forms" in unicode_range_a or "Forms" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + return True + + +@lru_cache(maxsize=2048) +def mess_ratio( + decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False +) -> float: + """ + Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. + """ + + detectors: list[MessDetectorPlugin] = [ + md_class() for md_class in MessDetectorPlugin.__subclasses__() + ] + + length: int = len(decoded_sequence) + 1 + + mean_mess_ratio: float = 0.0 + + if length < 512: + intermediary_mean_mess_ratio_calc: int = 32 + elif length <= 1024: + intermediary_mean_mess_ratio_calc = 64 + else: + intermediary_mean_mess_ratio_calc = 128 + + for character, index in zip(decoded_sequence + "\n", range(length)): + for detector in detectors: + if detector.eligible(character): + detector.feed(character) + + if ( + index > 0 and index % intermediary_mean_mess_ratio_calc == 0 + ) or index == length - 1: + mean_mess_ratio = sum(dt.ratio for dt in detectors) + + if mean_mess_ratio >= maximum_threshold: + break + + if debug: + logger = getLogger("charset_normalizer") + + logger.log( + TRACE, + "Mess-detector extended-analysis start. " + f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} " + f"maximum_threshold={maximum_threshold}", + ) + + if len(decoded_sequence) > 16: + logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") + logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") + + for dt in detectors: + logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") + + return round(mean_mess_ratio, 3) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/md__mypyc.cp312-win_amd64.pyd b/backend/venv/Lib/site-packages/charset_normalizer/md__mypyc.cp312-win_amd64.pyd new file mode 100644 index 0000000000000000000000000000000000000000..c2c489e9c2bee8a03772f7e7fc2fea5a2e6455b0 GIT binary patch literal 126976 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/models.py b/backend/venv/Lib/site-packages/charset_normalizer/models.py new file mode 100644 index 0000000..1042758 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/models.py @@ -0,0 +1,360 @@ +from __future__ import annotations + +from encodings.aliases import aliases +from hashlib import sha256 +from json import dumps +from re import sub +from typing import Any, Iterator, List, Tuple + +from .constant import RE_POSSIBLE_ENCODING_INDICATION, TOO_BIG_SEQUENCE +from .utils import iana_name, is_multi_byte_encoding, unicode_range + + +class CharsetMatch: + def __init__( + self, + payload: bytes, + guessed_encoding: str, + mean_mess_ratio: float, + has_sig_or_bom: bool, + languages: CoherenceMatches, + decoded_payload: str | None = None, + preemptive_declaration: str | None = None, + ): + self._payload: bytes = payload + + self._encoding: str = guessed_encoding + self._mean_mess_ratio: float = mean_mess_ratio + self._languages: CoherenceMatches = languages + self._has_sig_or_bom: bool = has_sig_or_bom + self._unicode_ranges: list[str] | None = None + + self._leaves: list[CharsetMatch] = [] + self._mean_coherence_ratio: float = 0.0 + + self._output_payload: bytes | None = None + self._output_encoding: str | None = None + + self._string: str | None = decoded_payload + + self._preemptive_declaration: str | None = preemptive_declaration + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CharsetMatch): + if isinstance(other, str): + return iana_name(other) == self.encoding + return False + return self.encoding == other.encoding and self.fingerprint == other.fingerprint + + def __lt__(self, other: object) -> bool: + """ + Implemented to make sorted available upon CharsetMatches items. + """ + if not isinstance(other, CharsetMatch): + raise ValueError + + chaos_difference: float = abs(self.chaos - other.chaos) + coherence_difference: float = abs(self.coherence - other.coherence) + + # Below 1% difference --> Use Coherence + if chaos_difference < 0.01 and coherence_difference > 0.02: + return self.coherence > other.coherence + elif chaos_difference < 0.01 and coherence_difference <= 0.02: + # When having a difficult decision, use the result that decoded as many multi-byte as possible. + # preserve RAM usage! + if len(self._payload) >= TOO_BIG_SEQUENCE: + return self.chaos < other.chaos + return self.multi_byte_usage > other.multi_byte_usage + + return self.chaos < other.chaos + + @property + def multi_byte_usage(self) -> float: + return 1.0 - (len(str(self)) / len(self.raw)) + + def __str__(self) -> str: + # Lazy Str Loading + if self._string is None: + self._string = str(self._payload, self._encoding, "strict") + return self._string + + def __repr__(self) -> str: + return f"" + + def add_submatch(self, other: CharsetMatch) -> None: + if not isinstance(other, CharsetMatch) or other == self: + raise ValueError( + "Unable to add instance <{}> as a submatch of a CharsetMatch".format( + other.__class__ + ) + ) + + other._string = None # Unload RAM usage; dirty trick. + self._leaves.append(other) + + @property + def encoding(self) -> str: + return self._encoding + + @property + def encoding_aliases(self) -> list[str]: + """ + Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. + """ + also_known_as: list[str] = [] + for u, p in aliases.items(): + if self.encoding == u: + also_known_as.append(p) + elif self.encoding == p: + also_known_as.append(u) + return also_known_as + + @property + def bom(self) -> bool: + return self._has_sig_or_bom + + @property + def byte_order_mark(self) -> bool: + return self._has_sig_or_bom + + @property + def languages(self) -> list[str]: + """ + Return the complete list of possible languages found in decoded sequence. + Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. + """ + return [e[0] for e in self._languages] + + @property + def language(self) -> str: + """ + Most probable language found in decoded sequence. If none were detected or inferred, the property will return + "Unknown". + """ + if not self._languages: + # Trying to infer the language based on the given encoding + # Its either English or we should not pronounce ourselves in certain cases. + if "ascii" in self.could_be_from_charset: + return "English" + + # doing it there to avoid circular import + from charset_normalizer.cd import encoding_languages, mb_encoding_languages + + languages = ( + mb_encoding_languages(self.encoding) + if is_multi_byte_encoding(self.encoding) + else encoding_languages(self.encoding) + ) + + if len(languages) == 0 or "Latin Based" in languages: + return "Unknown" + + return languages[0] + + return self._languages[0][0] + + @property + def chaos(self) -> float: + return self._mean_mess_ratio + + @property + def coherence(self) -> float: + if not self._languages: + return 0.0 + return self._languages[0][1] + + @property + def percent_chaos(self) -> float: + return round(self.chaos * 100, ndigits=3) + + @property + def percent_coherence(self) -> float: + return round(self.coherence * 100, ndigits=3) + + @property + def raw(self) -> bytes: + """ + Original untouched bytes. + """ + return self._payload + + @property + def submatch(self) -> list[CharsetMatch]: + return self._leaves + + @property + def has_submatch(self) -> bool: + return len(self._leaves) > 0 + + @property + def alphabets(self) -> list[str]: + if self._unicode_ranges is not None: + return self._unicode_ranges + # list detected ranges + detected_ranges: list[str | None] = [unicode_range(char) for char in str(self)] + # filter and sort + self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) + return self._unicode_ranges + + @property + def could_be_from_charset(self) -> list[str]: + """ + The complete list of encoding that output the exact SAME str result and therefore could be the originating + encoding. + This list does include the encoding available in property 'encoding'. + """ + return [self._encoding] + [m.encoding for m in self._leaves] + + def output(self, encoding: str = "utf_8") -> bytes: + """ + Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. + Any errors will be simply ignored by the encoder NOT replaced. + """ + if self._output_encoding is None or self._output_encoding != encoding: + self._output_encoding = encoding + decoded_string = str(self) + if ( + self._preemptive_declaration is not None + and self._preemptive_declaration.lower() + not in ["utf-8", "utf8", "utf_8"] + ): + patched_header = sub( + RE_POSSIBLE_ENCODING_INDICATION, + lambda m: m.string[m.span()[0] : m.span()[1]].replace( + m.groups()[0], + iana_name(self._output_encoding).replace("_", "-"), # type: ignore[arg-type] + ), + decoded_string[:8192], + count=1, + ) + + decoded_string = patched_header + decoded_string[8192:] + + self._output_payload = decoded_string.encode(encoding, "replace") + + return self._output_payload # type: ignore + + @property + def fingerprint(self) -> str: + """ + Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one. + """ + return sha256(self.output()).hexdigest() + + +class CharsetMatches: + """ + Container with every CharsetMatch items ordered by default from most probable to the less one. + Act like a list(iterable) but does not implements all related methods. + """ + + def __init__(self, results: list[CharsetMatch] | None = None): + self._results: list[CharsetMatch] = sorted(results) if results else [] + + def __iter__(self) -> Iterator[CharsetMatch]: + yield from self._results + + def __getitem__(self, item: int | str) -> CharsetMatch: + """ + Retrieve a single item either by its position or encoding name (alias may be used here). + Raise KeyError upon invalid index or encoding not present in results. + """ + if isinstance(item, int): + return self._results[item] + if isinstance(item, str): + item = iana_name(item, False) + for result in self._results: + if item in result.could_be_from_charset: + return result + raise KeyError + + def __len__(self) -> int: + return len(self._results) + + def __bool__(self) -> bool: + return len(self._results) > 0 + + def append(self, item: CharsetMatch) -> None: + """ + Insert a single match. Will be inserted accordingly to preserve sort. + Can be inserted as a submatch. + """ + if not isinstance(item, CharsetMatch): + raise ValueError( + "Cannot append instance '{}' to CharsetMatches".format( + str(item.__class__) + ) + ) + # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) + if len(item.raw) < TOO_BIG_SEQUENCE: + for match in self._results: + if match.fingerprint == item.fingerprint and match.chaos == item.chaos: + match.add_submatch(item) + return + self._results.append(item) + self._results = sorted(self._results) + + def best(self) -> CharsetMatch | None: + """ + Simply return the first match. Strict equivalent to matches[0]. + """ + if not self._results: + return None + return self._results[0] + + def first(self) -> CharsetMatch | None: + """ + Redundant method, call the method best(). Kept for BC reasons. + """ + return self.best() + + +CoherenceMatch = Tuple[str, float] +CoherenceMatches = List[CoherenceMatch] + + +class CliDetectionResult: + def __init__( + self, + path: str, + encoding: str | None, + encoding_aliases: list[str], + alternative_encodings: list[str], + language: str, + alphabets: list[str], + has_sig_or_bom: bool, + chaos: float, + coherence: float, + unicode_path: str | None, + is_preferred: bool, + ): + self.path: str = path + self.unicode_path: str | None = unicode_path + self.encoding: str | None = encoding + self.encoding_aliases: list[str] = encoding_aliases + self.alternative_encodings: list[str] = alternative_encodings + self.language: str = language + self.alphabets: list[str] = alphabets + self.has_sig_or_bom: bool = has_sig_or_bom + self.chaos: float = chaos + self.coherence: float = coherence + self.is_preferred: bool = is_preferred + + @property + def __dict__(self) -> dict[str, Any]: # type: ignore + return { + "path": self.path, + "encoding": self.encoding, + "encoding_aliases": self.encoding_aliases, + "alternative_encodings": self.alternative_encodings, + "language": self.language, + "alphabets": self.alphabets, + "has_sig_or_bom": self.has_sig_or_bom, + "chaos": self.chaos, + "coherence": self.coherence, + "unicode_path": self.unicode_path, + "is_preferred": self.is_preferred, + } + + def to_json(self) -> str: + return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/backend/venv/Lib/site-packages/charset_normalizer/py.typed b/backend/venv/Lib/site-packages/charset_normalizer/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/charset_normalizer/utils.py b/backend/venv/Lib/site-packages/charset_normalizer/utils.py new file mode 100644 index 0000000..6bf0384 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/utils.py @@ -0,0 +1,414 @@ +from __future__ import annotations + +import importlib +import logging +import unicodedata +from codecs import IncrementalDecoder +from encodings.aliases import aliases +from functools import lru_cache +from re import findall +from typing import Generator + +from _multibytecodec import ( # type: ignore[import-not-found,import] + MultibyteIncrementalDecoder, +) + +from .constant import ( + ENCODING_MARKS, + IANA_SUPPORTED_SIMILAR, + RE_POSSIBLE_ENCODING_INDICATION, + UNICODE_RANGES_COMBINED, + UNICODE_SECONDARY_RANGE_KEYWORD, + UTF8_MAXIMAL_ALLOCATION, + COMMON_CJK_CHARACTERS, +) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_accentuated(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + return ( + "WITH GRAVE" in description + or "WITH ACUTE" in description + or "WITH CEDILLA" in description + or "WITH DIAERESIS" in description + or "WITH CIRCUMFLEX" in description + or "WITH TILDE" in description + or "WITH MACRON" in description + or "WITH RING ABOVE" in description + ) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def remove_accent(character: str) -> str: + decomposed: str = unicodedata.decomposition(character) + if not decomposed: + return character + + codes: list[str] = decomposed.split(" ") + + return chr(int(codes[0], 16)) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def unicode_range(character: str) -> str | None: + """ + Retrieve the Unicode range official name from a single character. + """ + character_ord: int = ord(character) + + for range_name, ord_range in UNICODE_RANGES_COMBINED.items(): + if character_ord in ord_range: + return range_name + + return None + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_latin(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + return "LATIN" in description + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_punctuation(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "P" in character_category: + return True + + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Punctuation" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_symbol(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "S" in character_category or "N" in character_category: + return True + + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Forms" in character_range and character_category != "Lo" + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_emoticon(character: str) -> bool: + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Emoticons" in character_range or "Pictographs" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_separator(character: str) -> bool: + if character.isspace() or character in {"|", "+", "<", ">"}: + return True + + character_category: str = unicodedata.category(character) + + return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_case_variable(character: str) -> bool: + return character.islower() != character.isupper() + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "CJK" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hiragana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "HIRAGANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_katakana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "KATAKANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hangul(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "HANGUL" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_thai(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "THAI" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "ARABIC" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic_isolated_form(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "ARABIC" in character_name and "ISOLATED FORM" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk_uncommon(character: str) -> bool: + return character not in COMMON_CJK_CHARACTERS + + +@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) +def is_unicode_range_secondary(range_name: str) -> bool: + return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_unprintable(character: str) -> bool: + return ( + character.isspace() is False # includes \n \t \r \v + and character.isprintable() is False + and character != "\x1a" # Why? Its the ASCII substitute character. + and character != "\ufeff" # bug discovered in Python, + # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. + ) + + +def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> str | None: + """ + Extract using ASCII-only decoder any specified encoding in the first n-bytes. + """ + if not isinstance(sequence, bytes): + raise TypeError + + seq_len: int = len(sequence) + + results: list[str] = findall( + RE_POSSIBLE_ENCODING_INDICATION, + sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), + ) + + if len(results) == 0: + return None + + for specified_encoding in results: + specified_encoding = specified_encoding.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if encoding_alias == specified_encoding: + return encoding_iana + if encoding_iana == specified_encoding: + return encoding_iana + + return None + + +@lru_cache(maxsize=128) +def is_multi_byte_encoding(name: str) -> bool: + """ + Verify is a specific encoding is a multi byte one based on it IANA name + """ + return name in { + "utf_8", + "utf_8_sig", + "utf_16", + "utf_16_be", + "utf_16_le", + "utf_32", + "utf_32_le", + "utf_32_be", + "utf_7", + } or issubclass( + importlib.import_module(f"encodings.{name}").IncrementalDecoder, + MultibyteIncrementalDecoder, + ) + + +def identify_sig_or_bom(sequence: bytes) -> tuple[str | None, bytes]: + """ + Identify and extract SIG/BOM in given sequence. + """ + + for iana_encoding in ENCODING_MARKS: + marks: bytes | list[bytes] = ENCODING_MARKS[iana_encoding] + + if isinstance(marks, bytes): + marks = [marks] + + for mark in marks: + if sequence.startswith(mark): + return iana_encoding, mark + + return None, b"" + + +def should_strip_sig_or_bom(iana_encoding: str) -> bool: + return iana_encoding not in {"utf_16", "utf_32"} + + +def iana_name(cp_name: str, strict: bool = True) -> str: + """Returns the Python normalized encoding name (Not the IANA official name).""" + cp_name = cp_name.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if cp_name in [encoding_alias, encoding_iana]: + return encoding_iana + + if strict: + raise ValueError(f"Unable to retrieve IANA for '{cp_name}'") + + return cp_name + + +def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: + if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): + return 0.0 + + decoder_a = importlib.import_module(f"encodings.{iana_name_a}").IncrementalDecoder + decoder_b = importlib.import_module(f"encodings.{iana_name_b}").IncrementalDecoder + + id_a: IncrementalDecoder = decoder_a(errors="ignore") + id_b: IncrementalDecoder = decoder_b(errors="ignore") + + character_match_count: int = 0 + + for i in range(255): + to_be_decoded: bytes = bytes([i]) + if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): + character_match_count += 1 + + return character_match_count / 254 + + +def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: + """ + Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using + the function cp_similarity. + """ + return ( + iana_name_a in IANA_SUPPORTED_SIMILAR + and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] + ) + + +def set_logging_handler( + name: str = "charset_normalizer", + level: int = logging.INFO, + format_string: str = "%(asctime)s | %(levelname)s | %(message)s", +) -> None: + logger = logging.getLogger(name) + logger.setLevel(level) + + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter(format_string)) + logger.addHandler(handler) + + +def cut_sequence_chunks( + sequences: bytes, + encoding_iana: str, + offsets: range, + chunk_size: int, + bom_or_sig_available: bool, + strip_sig_or_bom: bool, + sig_payload: bytes, + is_multi_byte_decoder: bool, + decoded_payload: str | None = None, +) -> Generator[str, None, None]: + if decoded_payload and is_multi_byte_decoder is False: + for i in offsets: + chunk = decoded_payload[i : i + chunk_size] + if not chunk: + break + yield chunk + else: + for i in offsets: + chunk_end = i + chunk_size + if chunk_end > len(sequences) + 8: + continue + + cut_sequence = sequences[i : i + chunk_size] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode( + encoding_iana, + errors="ignore" if is_multi_byte_decoder else "strict", + ) + + # multi-byte bad cutting detector and adjustment + # not the cleanest way to perform that fix but clever enough for now. + if is_multi_byte_decoder and i > 0: + chunk_partial_size_chk: int = min(chunk_size, 16) + + if ( + decoded_payload + and chunk[:chunk_partial_size_chk] not in decoded_payload + ): + for j in range(i, i - 4, -1): + cut_sequence = sequences[j:chunk_end] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode(encoding_iana, errors="ignore") + + if chunk[:chunk_partial_size_chk] in decoded_payload: + break + + yield chunk diff --git a/backend/venv/Lib/site-packages/charset_normalizer/version.py b/backend/venv/Lib/site-packages/charset_normalizer/version.py new file mode 100644 index 0000000..c843e53 --- /dev/null +++ b/backend/venv/Lib/site-packages/charset_normalizer/version.py @@ -0,0 +1,8 @@ +""" +Expose version +""" + +from __future__ import annotations + +__version__ = "3.4.4" +VERSION = __version__.split(".") diff --git a/backend/venv/Lib/site-packages/click-8.3.1.dist-info/INSTALLER b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/click-8.3.1.dist-info/METADATA b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/METADATA new file mode 100644 index 0000000..3f433af --- /dev/null +++ b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/METADATA @@ -0,0 +1,84 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.3.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/backend/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD new file mode 100644 index 0000000..008d697 --- /dev/null +++ b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD @@ -0,0 +1,40 @@ +click-8.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.3.1.dist-info/METADATA,sha256=XZeBrMAE0ghTE88SjfrSDuSyNCpBPplxJR1tbwD9oZg,2621 +click-8.3.1.dist-info/RECORD,, +click-8.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.3.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 +click/__pycache__/__init__.cpython-312.pyc,, +click/__pycache__/_compat.cpython-312.pyc,, +click/__pycache__/_termui_impl.cpython-312.pyc,, +click/__pycache__/_textwrap.cpython-312.pyc,, +click/__pycache__/_utils.cpython-312.pyc,, +click/__pycache__/_winconsole.cpython-312.pyc,, +click/__pycache__/core.cpython-312.pyc,, +click/__pycache__/decorators.cpython-312.pyc,, +click/__pycache__/exceptions.cpython-312.pyc,, +click/__pycache__/formatting.cpython-312.pyc,, +click/__pycache__/globals.cpython-312.pyc,, +click/__pycache__/parser.cpython-312.pyc,, +click/__pycache__/shell_completion.cpython-312.pyc,, +click/__pycache__/termui.cpython-312.pyc,, +click/__pycache__/testing.cpython-312.pyc,, +click/__pycache__/types.cpython-312.pyc,, +click/__pycache__/utils.cpython-312.pyc,, +click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 +click/_termui_impl.py,sha256=rgCb3On8X5A4200rA5L6i13u5iapmFer7sru57Jy6zA,27093 +click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 +click/_utils.py,sha256=kZwtTf5gMuCilJJceS2iTCvRvCY-0aN5rJq8gKw7p8g,943 +click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 +click/core.py,sha256=U6Bfxt8GkjNDqyJ0HqXvluJHtyZ4sY5USAvM1Cdq7mQ,132105 +click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 +click/exceptions.py,sha256=8utf8w6V5hJXMnO_ic1FNrtbwuEn1NUu1aDwV8UqnG4,9954 +click/formatting.py,sha256=RVfwwr0rwWNpgGr8NaHodPzkIr7_tUyVh_nDdanLMNc,9730 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=Q31pH0FlQZEq-UXE_ABRzlygEfvxPTuZbWNh4xfXmzw,19010 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=Cc4GQUFuWpfQBa9sF5qXeeYI7n3tI_1k6ZdSn4BZbT0,20994 +click/termui.py,sha256=hqCEjNndU-nzW08nRAkBaVgfZp_FdCA9KxfIWlKYaMc,31037 +click/testing.py,sha256=EERbzcl1br0mW0qBS9EqkknfNfXB9WQEW0ELIpkvuSs,19102 +click/types.py,sha256=ek54BNSFwPKsqtfT7jsqcc4WHui8AIFVMKM4oVZIXhc,39927 +click/utils.py,sha256=gCUoewdAhA-QLBUUHxrLh4uj6m7T1WjZZMNPvR0I7YA,20257 diff --git a/backend/venv/Lib/site-packages/click-8.3.1.dist-info/WHEEL b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/backend/venv/Lib/site-packages/click-8.3.1.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv/Lib/site-packages/click/__init__.py b/backend/venv/Lib/site-packages/click/__init__.py new file mode 100644 index 0000000..1aa547c --- /dev/null +++ b/backend/venv/Lib/site-packages/click/__init__.py @@ -0,0 +1,123 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" + +from __future__ import annotations + +from .core import Argument as Argument +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + from .core import _BaseCommand + + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + from .core import _MultiCommand + + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + if name == "OptionParser": + from .parser import _OptionParser + + warnings.warn( + "'OptionParser' is deprecated and will be removed in Click 9.0. The" + " old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return _OptionParser + + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Click 9.1. Use feature detection or" + " 'importlib.metadata.version(\"click\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("click") + + raise AttributeError(name) diff --git a/backend/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbc37770fb732847152b4bb7c9edaa32e5527744 GIT binary patch literal 4068 zcmbW4Sx+3<700Wg_l0Khf^C)pY&UH~8?cQH#tW;>!~>QAjdFujs_rVF>{?p4s$sCq zD2nosJmnz|nU9cYqI{7^k!R*%Ms2k;(#$;g&5@m#Jmr5*cSB1VN1BxEfB){e_ny1f zImO>InWTc}>EE7Ohh2*DJr$ZyTOC60!tILkC&f^NVuXw~JLI&9wvb}98)3WM35zgu z1RN0&<|sHSqRcUHOvISu;JAo0C%_4jU`~RQBFUVxQ%+i>nbY8m$S`NX9ioG|1Dq9E z<}A2VbTW5>yF?dr7r0w=Gk1e~L=STh_>?%sd*Zcib>{i@RXQhF4)(d8{!7@HSkSwlX(I>EvA_#!MDUM<|*)P zahv%%ct*@H-vG~wS>~JIJK_%WG_0bR+t}vABu;}^WaC~5qQa1_-$CM9xmpWUsRKe zwpDtrTE42QzU7o{Q+;w6?0K&0ct!;!%k|5aG!3Ia5x6;-bsly&KwYT&7k z{@hF+NGq`1UA5#nj_w+&ZMkS%l2$qJ)t!o4P`6y$dTy#7yvT-ke@wN4oUayj-!ziC z^eX6iJdyb)s~A!bRKqiU)%5~$ZmI`Xu!mtWZl$z`!FR2aN+Vi+67^-z*Ne7UNWP)h zJs+y3bQfLq!17%GO{i{*&&%D4W4ZzAV~h0}1G^fy=-IYeq8{~nH!we?rjdu3VHprz zFE?rvPjsm}W?)K~<9dr*%!M`r=AM%0?pV^{IcV6qy5q=h!&_?4w96;<9@toy!Z zm?cl@fk)1x#~ssL2d9l`#kuSipP^Nj_`s9KiNB70Q~DV4#1fe=dXg5@xu6@(t=RJQ zT@$tr*y_t`TGFtzF0+I0%<`utv$>SSie;P2Qu0JQKel`ySE02_dd=IwX&rA{l6^OO zWFBDyRy^9F`bH)Wq+Zq<%j?-S1Fck%66d9ztU6M%O`SF-*4SQ}yII=vw0%p*_U-bK zgiXWZQ-+h$9=DI$dc`g6p?RdNSA1G?sw}--Y5IP#-U3CZ%qQ-XM{4Q^hc-2hRoo_q z7uMGw!xUZI^Q;n8#+UTK+_W6xFzpF`BP);B=Qjb#72DH;r@G7A+`hU-#`vmxY^vX- z&BHQxf1(F8$LPl9)77k*AtN1T6^+zeQ|kXV|fY1@YdEU|2C$Y-Qk_ob}+t+ zyGcE03-xkYGc4M%E-Dr+SC@yHA4pSoV9b({w*17D@XDskeoFM>G@l3nDKzx%Ggy&G zLxy52N1>OB(e`{)QKZVL6lwJcY4v63S*+RdTGm=(b)G5B{tKr2)uC@4oPJ{#T$uz3zdSpS!@%gpSXsw19R<5=9 z^T*so;`3}nEwg{lmixM8Q=*}5%6W}!m@8CMn%0cB+KWF@$6Sjgry|5jt5^xp@#mbt zWc>toOg*Sb6Gs=+6O`&nHHW;7c#gDOKqk@+JoxT&9Z@CS$dGsc|=uH$JJilB-l5t#5(+1r@sgd*EukIfZJhF^6i$d~?n9 zfFG@fDK5!1_~1d=b=_s+*rgvuwaU-Gw-#r&IYjG@g9&dRcpjx!QAmr;>>#`l1RQyE1i9>;uom- zXJ5toYw=u5bM>d1_rHqwoixw4G@t%o&1o{P<3q3GXODZdWgdjyN0rPVO)14wiegF~ zO6R$6vO`~HhrY??zs%?I5{ifN45XSgo1YrKq$ntRNzRd+C%Hh%0RLbdtSKWkCC4ySQ?AyOelF&lRWOb-qvcKJ8HW7(=wxV+*ZUtLs%ifK literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e39fd41ffc9c14580841a2cecc5dacfcafc5a2e5 GIT binary patch literal 24187 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 D6xs~q literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..670ae75b8b5059a6437cf88365a99219f02ba0fd GIT binary patch literal 2416 zcmaJ@>u=js6u*ANaUN~j^s%LFx~yGG!?t$ph1e!g*9ugDS{MjKmdSE$uXF0y-L=y; zog+=CA5uVCKhdBGseA%d!T+$YAfcvPN${9d36R*ghz@C*kl@_J?b2>=BORY}&-0%9 z^KpJ?Xz(Lgm%h8C&U+C0l?XcvWU{F31ke>EBbm}rno3X<;c1OdGYQt^JqZu&F&dZl zCcG4)(Hlr+7m@5yJgKH?m_1~Tsfh_bOUJo~M2J&PK-6`^5-rux&2f+$B}2EAc`GgI z;*^4=`VejaYWpJWt{?>^C>bSaAA0sDdt_>nO)v^8b27ciuDNlbWUtJChRd>X-U+-1 zsXoBs%nYP*&tA1;fkHZJ`}=Ati*o&u&DzWY^iQVN=-OV+W22PI?^uy1?zbtKjsTbA zY)(eDrvv4@HfKZEfa7gCRiDvywY_U@E(+N^iEsflS!B~@>_0rHl-G5xd+Z$eX|yav zi8JF5N%)8Vz>2dDlNRTlrb(=b(}HH`Q^K5qWz*qELv-0;W{jD*&tXkPyXu6nGOJ)y zkp<~mMxQnvUdmuWQ+37hRyjp?JaejSU32{Aj3_CBrd+igRufIjVWbQYteB<`(#Lkz zllMo?C1Pdn;n|w>1Oq!~t9ETj! zfDtn(X{t0mBoNrl!Cel{WSwT=nyAYf)Ub1^g=pPf4?d$NWtkYrP4uV{wMPnVs|P+m z^!4GpZO8Kdtw5+0h;0O7<(8h+lf{<){AfAczI>zLUk~@@M+m>Le51w(TW?J)O%z7% z1!Lu&zWhYt;zsb$&&`pttC%Qt4HdhF?smPj89Z5GP`G0ovLdM-K?Hrh1bx2%^CqGI z?0_+1wr}O==VLF&*l3=5o`+2>G>~knnV)Vp1 z-%*YoDaFnfV`ta-XqgX|_|6T!voKra`!@N`>PGhl-@V#jc}=p4qeYx7iK(J{o3*k5P9xb~u9W_(Oz`G!4g@J8`nV2P9;8 zR7cd0z^tGtl%wm$6qRzPB`9~-{-H36uDpy;5-vZ-@b(xLou&haUF1}1`N zDP*u{szqjwiOC(|E<%FDlua3`9_MN}VaY6TXgupMsyq)f2t05U%uG^0fx`|U0yRVl zhOT874%FkJPBB0{B_KCZxgnINe~a|2p8o2!FJHUcd-|uynWeG($Z~7BEmCS5D7Fpc zU*8Iam*4q#t{jP$B16T<&@#6bY`itLG*)OY@T;w>+!+;|`4%|YEBu+|$V-{(nfiDxID`3@6{D%l3R#h(Ub$CJ0#k3*_j$aVchMa*p zDmXzwxSkQUng$;v_5?0CM#zgmzCqR6t1lWReXbH781ro)i>N|3c}{IbdMX}xRyfqs zRq+yzN8z@Lk8pm})KUo$E{Ob%+YN*}g1FW{X}{{Afn=}{d1Lahg{ t;&Y%NbI$AqQeh~HdVqRIOYHV literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92a464d83ad9acc73dcf766145eab78cd8321b15 GIT binary patch literal 1196 zcmZ`&&1(}u6rb6TBu$grCbpuYuHIJcM!}C#MJzUcKnP;0;1ZZ_cc*pZW;f1ksu2%8 z6tQ@y#X}FpdqvQH!2iHYda|wv1y9~u+LI^WWE+Wy1N-Lpe(z)7do%Mnn@uBFcR$>9 zKgtOG5K4EcF~GZ@0IVVhIoLyWY+@|1 zK@+us823su*@wU~*vrM(Oo2tI<^HwMFQ4ruH&fR^8FyRLO1Yv z+3w9L#R}d%4`3BhWMT(FgV>ZMDB%6Ruc`i}B^%^wF~rQ@A=!j81MF_p~UE06x51>U8)V)q0FwSlgdN zR~P#l96Wd{y(9fS0@kX|SoS08J5|uCS$ z^~>!8m)faIyP~zSE=37O!zS}1nTJeIu|A-qG$HlCX?miu3?Yx3mbc$#k`O1bfldT7 zHEM^Edaqn5PDO(^N)tCpxmcX6koyy*dqtLoMDGw2uYhHQ5bvxbk^uNI5Q}I>Qq|PX z0LtcH-C8JqJ#_5N)3$POPr>R~94UhIj3{Wf31vb-OdN2eP`G(fB5XBaun`U;MO?-B zAH(3lMubJpV`QtX`{hyNx{l?2K8r_^(Fmv haU*?XA-RbzYz>dBK3I9sK2g{hKHEmQO?0hO#BU8$8Up|T literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..941276eeb97eec1e3213a72eb20a85e7407fb726 GIT binary patch literal 11761 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd3e538f128ef57b4c330081ddbffb5d55030c04 GIT binary patch literal 134392 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

    Lt569G_$2QED@d0@IEUcNpN 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

    nClxL^0om(^{Ny2?~V+_q!p^_XqPoz8@9 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98a93a8244e32ae306f7de8b58f5cfa3eb3818aa GIT binary patch literal 14773 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 G@c#>(sh-~e literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..761eed29d2ba35dc35acf5e2b32bba4674d68cd3 GIT binary patch literal 13594 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 P<{bRg-*Z#AWaIE}!gbef literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed3268d20766a82ce7e269ad0068e6e0db6acbae GIT binary patch literal 20420 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c03e3c8e959934a3a21b32c720686bf80c54c43d GIT binary patch literal 23295 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 Q?_%#2N5@?UezU#$U;2T}^8f$< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fcbfbf3a044ff57d113bb09c58b9bdce1494567 GIT binary patch literal 34648 zcmd^oYj9jgcHX`724?Uc00h9tB}j@G2?QyUA}L4|1yY1WJs>R!y&%e%!Q25bEuat0Iii;}Awo-PgR25fcwTV-9948|K+8vE3hw{oU^M{jJ zQFg7lNu2MT?)w-#C~nIBl@Zl*=HBkp-KV=xpI0~jq^71?!RO@foJ<~`QIsFk5A#ze z0QLI2UPXCLc~a38T}>$y>X51u>`J*N+(RA-dxyOI%s1rYZ~u^=zXL-7{;nFT#%0XGaaFdRrVPBaZQFWJQQZQI@LVUGStFw zFx5J-VQ2%xA;4`zZ4B1{ZXarAxHi=>v2kc4!*zf+4Q*1DMD>|_&Cc52h7awjPi>jd zhBQ@iQLdx*TNBb7-cbcS)S1{ev|VpZ?9iJCT~g7*dh@qcy+v?_XRMWR2?bNp+-LCIIdYirzX_p>Bdb@rH(r$eh(jI*`(mnc}NcZadknY#-`nEcB zn|@$ur~Z_F@SC2Yt|~?Rr$22%tH1SU^xkiJha&p3`aLLf`x-fhRzF+siT<2^FROO@JdL3UO$Z7-BpVI3-&vGSicWXcY(&IP0HHex=TN#-_7X}{eHbqKdNuVFBit= z*c&xAmY)~Wqxu8i^t~f18rr>f?O%mek9}2+uYRwO=*Pe5wOjI4CH|4>><7(v>v8=- z%z{0-t|#<|@Z`?5Yu88Detxs3`j~zK829Sq`opMWpPg4v+VDz9Kchc_Qu}W{9{Smp z<-~72r9bMR4u)wp8#|~ zcf}6sUjvUhNjyf+=~MbCJU^tL(+5G}yY*@Py#6Gf^v<{`vcO6pUyExDd! zu~aHHl1e=H92)g}w?=8H>0C0K#KYl9BQr6X8y=lX$4lOkR4jh>+Gg~o1$i*hi4=;mAKYPpnn4WO6OwNw(*PjOe}qEJAvNm@nkM>Z3n|> zS0Z<9C&8f+BRMvn8x}PV(W7elh$?>0nMc%5yslIu^T=jAPtSrDDzxSo=t-@7Vm4~n znT^{Pr6*<^L=$6pH0$YjZqGzqZc=!lC~on;dc7OKYuLFkEdE1m_~hM=+}<}m$cY?z^}EWOE)0xsVAiE| z&APg^k{SW{TuFUC;xAQWMWnO2SUR3C2vx~*CX-B;+!L|Mk{gSrDoxQD8)86KHR zrgS-a#$$L!gO_~)$-GjoS85yQ`-}cy!QcA&qwfyA@A-q#8(?jxBqVU+uciB4=%MHDzx1FenX-0o(}`}EclB4+Je9R^?WhhzIf>3-ZwIr$Cfr9 zC~P|T-V23>yYap@yztE8=;AYl;O2s7vvC-;RxAn{QJxd$0KBF+=7D0*gEJnyT=B_S zGi%gkj;ygES7m0)V}V)ELwRMb8F318ke64dAHG#ckAvc#R%rC6{UO3nLg)s zU~uPsCKc!0w12vke04r(ojl$Et#I2%Jpd4;CM2t;a^PSEj*n}fUjt@ z&5~fD<;G(%f9vo

      (3?0P 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68639c33fa530636301ab777dedcac5f343e2bd8 GIT binary patch literal 27390 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cba04e3abc13e4b4f4228601259b98ff76669d8c GIT binary patch literal 24865 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 OXrjvQmLS9o{Qm*5Fxedd literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/click/_compat.py b/backend/venv/Lib/site-packages/click/_compat.py new file mode 100644 index 0000000..f2726b9 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/_compat.py @@ -0,0 +1,622 @@ +from __future__ import annotations + +import codecs +import collections.abc as cabc +import io +import os +import re +import sys +import typing as t +from types import TracebackType +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write(b"") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: str | None, errors: str | None +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: str | None, + errors: str | None, + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: str | os.PathLike[str] | int, + mode: str, + encoding: str | None, + errors: str | None, +) -> t.IO[t.Any]: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, +) -> tuple[t.IO[t.Any], bool]: + binary = "b" in mode + filename = os.fspath(filename) + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: int | None = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[t.Any], af), True + + +class _AtomicFile: + def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> _AtomicFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s: str) -> int: + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write # type: ignore[method-assign] + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None + ) -> t.TextIO | None: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO | None], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.TextIO | None]: + cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO | None: + stream = src_func() + + if stream is None: + return None + + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/backend/venv/Lib/site-packages/click/_termui_impl.py b/backend/venv/Lib/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..ee8225c --- /dev/null +++ b/backend/venv/Lib/site-packages/click/_termui_impl.py @@ -0,0 +1,852 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" + +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import math +import os +import shlex +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +from pathlib import Path +from types import TracebackType + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: cabc.Iterable[V] | None, + length: int | None = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + label: str | None = None, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.hidden = hidden + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: str = label or "" + + if file is None: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + file = StringIO() + + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width: int = width + self.autowidth: bool = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast("cabc.Iterable[V]", range(length)) + self.iter: cabc.Iterable[V] = iter(iterable) + self.length = length + self.pos: int = 0 + self.avg: list[float] = [] + self.last_eta: float + self.start: float + self.start = self.last_eta = time.time() + self.eta_known: bool = False + self.finished: bool = False + self.max_width: int | None = None + self.entered: bool = False + self.current_item: V | None = None + self._is_atty = isatty(self.file) + self._last_line: str | None = None + + def __enter__(self) -> ProgressBar[V]: + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.render_finish() + + def __iter__(self) -> cabc.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.hidden or not self._is_atty: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + 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() + + +def pager(generator: cabc.Iterable[str], color: bool | None = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if stdout is None: + stdout = StringIO() + + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + + # Split and normalize the pager command into parts. + pager_cmd_parts = shlex.split(os.environ.get("PAGER", ""), posix=False) + if pager_cmd_parts: + if WIN: + if _tempfilepager(generator, pager_cmd_parts, color): + return + elif _pipepager(generator, pager_cmd_parts, color): + return + + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if (WIN or sys.platform.startswith("os2")) and _tempfilepager( + generator, ["more"], color + ): + return + if _pipepager(generator, ["less"], color): + return + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if _pipepager(generator, ["more"], color): + return + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + cmd_params = cmd_parts[1:] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + + # 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 + + c = subprocess.Popen( + [str(cmd_path)] + cmd_params, + shell=False, + stdin=subprocess.PIPE, + env=env, + errors="replace", + text=True, + ) + assert c.stdin is not None + try: + for text in generator: + if not color: + text = strip_ansi(text) + + c.stdin.write(text) + except BrokenPipeError: + # In case the pager exited unexpectedly, ignore the broken pipe error. + pass + except Exception as e: + # In case there is an exception we want to close the pager immediately + # and let the caller handle it. + # Otherwise the pager will keep running, and the user may not notice + # the error message, or worse yet it may leave the terminal in a broken state. + c.terminate() + raise e + finally: + # We must close stdin and wait for the pager to exit before we continue + try: + c.stdin.close() + # Close implies flush, so it might throw a BrokenPipeError if the pager + # process exited already. + except BrokenPipeError: + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + return True + + +def _tempfilepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by invoking a program on a temporary file. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + # 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 subprocess + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + subprocess.call([str(cmd_path), filename]) + except OSError: + # Command not found + pass + finally: + os.close(fd) + os.unlink(filename) + + return True + + +def _nullpager( + stream: t.TextIO, generator: cabc.Iterable[str], color: bool | None +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + + 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: + import subprocess + + editor = self.get_editor() + environ: dict[str, str] | None = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + exc_filename = " ".join(f'"{filename}"' for filename in filenames) + + try: + c = subprocess.Popen( + args=f"{editor} {exc_filename}", env=environ, shell=True + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + @t.overload + def edit(self, text: bytes | bytearray) -> bytes | None: ... + + # We cannot know whether or not the type expected is str or bytes when None + # is passed, so str is returned as that was what was done before. + @t.overload + def edit(self, text: str | None) -> str | None: ... + + def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: + import tempfile + + if text is None: + data: 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", f"/select,{url}"] + else: + args = ["start"] + if wait: + args.append("/WAIT") + args.append("") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> None: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if sys.platform == "win32": + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + + if echo: + func = t.cast(t.Callable[[], str], msvcrt.getwche) + else: + func = t.cast(t.Callable[[], str], msvcrt.getwch) + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import termios + import tty + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + f: t.TextIO | None + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/backend/venv/Lib/site-packages/click/_textwrap.py b/backend/venv/Lib/site-packages/click/_textwrap.py new file mode 100644 index 0000000..97fbee3 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/_textwrap.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import collections.abc as cabc +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: list[str], + cur_line: list[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> cabc.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/backend/venv/Lib/site-packages/click/_utils.py b/backend/venv/Lib/site-packages/click/_utils.py new file mode 100644 index 0000000..09fb008 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/_utils.py @@ -0,0 +1,36 @@ +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 = Sentinel.UNSET +"""Sentinel used to indicate that a value is not set.""" + +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.Literal[UNSET] # type: ignore[valid-type] +"""Type hint for the :data:`UNSET` sentinel value.""" + +T_FLAG_NEEDS_VALUE = t.Literal[FLAG_NEEDS_VALUE] # type: ignore[valid-type] +"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/backend/venv/Lib/site-packages/click/_winconsole.py b/backend/venv/Lib/site-packages/click/_winconsole.py new file mode 100644 index 0000000..e56c7c6 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/_winconsole.py @@ -0,0 +1,296 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +from __future__ import annotations + +import collections.abc as cabc +import io +import sys +import time +import typing as t +from ctypes import Array +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +if t.TYPE_CHECKING: + try: + # Using `typing_extensions.Buffer` instead of `collections.abc` + # on Windows for some reason does not have `Sized` implemented. + from collections.abc import Buffer # type: ignore + except ImportError: + from typing_extensions import Buffer + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ # noqa: RUF012 + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: + buf = Py_buffer() + flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + out: Array[c_char] = buffer_type.from_address(buf.buf) + return out + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle: int | None) -> None: + self.handle = handle + + def isatty(self) -> t.Literal[True]: + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self) -> t.Literal[True]: + return True + + def readinto(self, b: Buffer) -> int: + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self) -> t.Literal[True]: + return True + + @staticmethod + def _get_error_message(errno: int) -> str: + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b: Buffer) -> int: + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self) -> str: + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None +) -> t.TextIO | None: + if ( + get_buffer is None + or encoding not in {"utf-16-le", None} + or errors not in {"strict", None} + or not _is_console(f) + ): + return None + + func = _stream_factories.get(f.fileno()) + if func is None: + return None + + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/backend/venv/Lib/site-packages/click/core.py b/backend/venv/Lib/site-packages/click/core.py new file mode 100644 index 0000000..57f549c --- /dev/null +++ b/backend/venv/Lib/site-packages/click/core.py @@ -0,0 +1,3415 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from collections import Counter +from contextlib import AbstractContextManager +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from ._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 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 batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size), strict=False)) + + +@contextmanager +def augment_usage_errors( + ctx: Context, param: Parameter | None = None +) -> cabc.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: cabc.Sequence[Parameter], + declaration_order: cabc.Sequence[Parameter], +) -> list[Parameter]: + """Returns all declared parameters in the order they should be processed. + + The declared parameters are re-shuffled depending on the order in which + they were invoked, as well as the eagerness of each parameters. + + The invocation order takes precedence over the declaration order. I.e. the + order in which the user provided them to the CLI is respected. + + This behavior and its effect on callback evaluation is detailed at: + https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order + """ + + def sort_key(item: Parameter) -> tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.2 + The ``protected_args`` attribute is deprecated and will be removed in + Click 9.0. ``args`` will contain remaining unparsed tokens. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: type[HelpFormatter] = HelpFormatter + + def __init__( + self, + command: Command, + parent: Context | None = None, + info_name: str | None = None, + obj: t.Any | None = None, + auto_envvar_prefix: str | None = None, + default_map: cabc.MutableMapping[str, t.Any] | None = None, + terminal_width: int | None = None, + max_content_width: int | None = None, + resilient_parsing: bool = False, + allow_extra_args: bool | None = None, + allow_interspersed_args: bool | None = None, + ignore_unknown_options: bool | None = None, + help_option_names: list[str] | None = None, + token_normalize_func: t.Callable[[str], str] | None = None, + color: bool | None = None, + show_default: bool | None = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: dict[str, t.Any] = {} + #: the leftover arguments. + self.args: list[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self._protected_args: list[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: str | None = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: int | None = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: int | None = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: list[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: str | None = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: bool | None = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: bool | None = show_default + + self._close_callbacks: list[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + @property + def protected_args(self) -> list[str]: + import warnings + + warnings.warn( + "'protected_args' is deprecated and will be removed in Click 9.0." + " 'args' will contain remaining unparsed tokens.", + DeprecationWarning, + stacklevel=2, + ) + return self._protected_args + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> Context: + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> 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 + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[False] = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def lookup_default(self, name: str, call: bool = True) -> t.Any | None: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name, UNSET) + + if call and callable(value): + return value() + + return value + + return UNSET + + 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( # type: ignore + 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 odering by iter_params_for_processing(), which relies on + # object comparison. + if self._help_option is None: + # Avoid circular import. + from .decorators import help_option + + # Apply help_option decorator and pop resulting option + help_option(*help_option_names)(self) + self._help_option = self.params.pop() # type: ignore[assignment] + + return self._help_option + + def make_parser(self, ctx: Context) -> _OptionParser: + """Creates the underlying option parser for this command.""" + parser = _OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: Context | None = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + _, 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: + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" + ).format(name=self.name, extra_message=extra_message) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: list[CompletionItem] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, Group) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx._protected_args + ) + + return results + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: t.Literal[True] = True, + **extra: t.Any, + ) -> t.NoReturn: ... + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: ... + + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) as e: + echo(file=sys.stderr) + raise Abort() from e + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str | None = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. versionchanged:: 8.2.0 + Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). + """ + if complete_var is None: + complete_name = prog_name.replace("-", "_").replace(".", "_") + complete_var = f"_{complete_name}_COMPLETE".upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: type) -> bool: + return issubclass(subclass, cls.__bases__[0]) + + def __instancecheck__(cls, instance: t.Any) -> bool: + return isinstance(instance, cls.__bases__[0]) + + +class _BaseCommand(Command, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Command`` instead. + """ + + +class Group(Command): + """A group is a command that nests other commands (or more groups). + + :param name: The name of the group command. + :param commands: Map names to :class:`Command` objects. Can be a list, which + will use :attr:`Command.name` as the keys. + :param invoke_without_command: Invoke the group's callback even if a + subcommand is not given. + :param no_args_is_help: If no arguments are given, show the group's help and + exit. Defaults to the opposite of ``invoke_without_command``. + :param subcommand_metavar: How to represent the subcommand argument in help. + The default will represent whether ``chain`` is set or not. + :param chain: Allow passing more than one subcommand argument. After parsing + a command's arguments, if any arguments remain another command will be + matched, and so on. + :param result_callback: A function to call after the group's and + subcommand's callbacks. The value returned by the subcommand is passed. + If ``chain`` is enabled, the value will be a list of values returned by + all the commands. If ``invoke_without_command`` is enabled, the value + will be the value returned by the group's callback, or an empty list if + ``chain`` is enabled. + :param kwargs: Other arguments passed to :class:`Command`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + + .. versionchanged:: 8.2 + Merged with and replaces the ``MultiCommand`` base class. + """ + + allow_extra_args = True + allow_interspersed_args = False + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: type[Command] | None = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: type[Group] | type[type] | None = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: str | None = None, + commands: cabc.MutableMapping[str, Command] + | cabc.Sequence[Command] + | None = None, + invoke_without_command: bool = False, + no_args_is_help: bool | None = None, + subcommand_metavar: str | None = None, + chain: bool = False, + result_callback: t.Callable[..., t.Any] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: cabc.MutableMapping[str, Command] = commands + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "A group in chain mode cannot have optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def add_command(self, cmd: Command, name: str | None = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_nested_chain(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'command(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> Group: ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'group(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> Group: + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + inner = old_callback(value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv # type: ignore[return-value] + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Given a context and a command name, this returns a :class:`Command` + object if it exists or returns ``None``. + """ + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> list[str]: + """Returns a list of subcommand names in the order they should appear.""" + return sorted(self.commands) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx._protected_args = rest + ctx.args = [] + elif rest: + ctx._protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx._protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx._protected_args, *ctx.args] + ctx.args = [] + ctx._protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if _split_opt(cmd_name)[0]: + self.parse_args(ctx, args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class _MultiCommand(Group, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Group`` instead. + """ + + +class CommandCollection(Group): + """A :class:`Group` that looks up subcommands on other groups. If a command + is not found on this group, each registered source is checked in order. + Parameters on a source are not added to this group, and a source's callback + is not invoked when invoking its commands. In other words, this "flattens" + commands in many groups into this one group. + + :param name: The name of the group command. + :param sources: A list of :class:`Group` objects to look up commands from. + :param kwargs: Other arguments passed to :class:`Group`. + + .. versionchanged:: 8.2 + This is a subclass of ``Group``. Commands are looked up first on this + group, then each of its sources. + """ + + def __init__( + self, + name: str | None = None, + sources: list[Group] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + #: The list of registered groups. + self.sources: list[Group] = sources or [] + + def add_source(self, group: Group) -> None: + """Add a group as a source of commands.""" + self.sources.append(group) + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + rv = super().get_command(ctx, cmd_name) + + if rv is not None: + return rv + + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_nested_chain(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> list[str]: + rv: set[str] = set(super().list_commands(ctx)) + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The latter is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: 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 | 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 | None + self.opts: list[str] + self.secondary_opts: list[str] + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type: types.ParamType = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default: t.Any | t.Callable[[], t.Any] | None = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + self.deprecated = deprecated + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + 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}>" + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(param=self, ctx=ctx) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is UNSET: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, t.Any] + ) -> tuple[t.Any, ParameterSource]: + """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) # type: ignore + # 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) # type: ignore + if default_map_value is not UNSET: + value = default_map_value + source = ParameterSource.DEFAULT_MAP + + 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: + """ + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + ctx.set_parameter_source(self.name, source) # type: ignore + + # Display a deprecation warning if necessary. + if ( + self.deprecated + and value is not UNSET + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ): + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The {param_type} {name!r} is deprecated." + "{extra_message}" + ).format( + param_type=self.param_type_name, + name=self.human_readable_name, + extra_message=extra_message, + ) + echo(style(message, fg="red"), err=True) + + # 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 + + # Add parameter's value to the context. + if ( + self.expose_value + # We skip adding the value if it was previously set by another parameter + # targeting the same variable name. This prevents parameters competing for + # the same name to override each other. + and (self.name not in ctx.params or ctx.params[self.name] is UNSET) + ): + # Click is logically enforcing that the name is None if the parameter is + # not to be exposed. We still assert it here to please the type checker. + assert self.name is not None, ( + f"{self!r} parameter's name should not be None when exposing value." + ) + ctx.params[self.name] = value + + return value, args + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + pass + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast("list[CompletionItem]", results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page and error messages. + Normally, environment variables are not shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. A deprecated option cannot be + prompted. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.2 + ``envvar`` used with ``flag_value`` will always use the ``flag_value``, + previously it would use the value of the environment variable. + + .. versionchanged:: 8.1 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + show_default: bool | str | None = None, + prompt: bool | str = False, + confirmation_prompt: bool | str = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: bool | None = None, + flag_value: t.Any = UNSET, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: types.ParamType | t.Any | None = None, + help: str | None = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + deprecated: bool | str = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + super().__init__( + param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs + ) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: str | None = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + if deprecated: + deprecated_message = ( + f"(DEPRECATED: {deprecated})" + if isinstance(deprecated, str) + else "(DEPRECATED)" + ) + help = help + deprecated_message if help is not None else deprecated_message + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # 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 we do not know yet if it needs a + # value or not. So we look at the default value to determine it. + elif is_flag is False and not self._flag_needs_value: + self._flag_needs_value = 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 = 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: + self.type = types.convert_type(None, flag_value) + + 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 + + # Support the special case of aligning the default value with the flag_value + # for flags whose default is explicitly set to True. Note that as long as we + # have this condition, there is no way a flag can have a default set to True, + # and a flag_value set to something else. Refs: + # https://github.com/pallets/click/issues/3024#issuecomment-3146199461 + # https://github.com/pallets/click/pull/3030/commits/06847da + if self.default is True and self.flag_value is not UNSET: + self.default = self.flag_value + + # 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_error_hint(self, ctx: Context) -> 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 | None, list[str], list[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(_split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(_split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError( + f"Could not determine name for option with declarations {decls!r}" + ) + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: cabc.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar(ctx=ctx)}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + + extra = self.get_help_extra(ctx) + extra_items = [] + if "envvars" in extra: + extra_items.append( + _("env var: {var}").format(var=", ".join(extra["envvars"])) + ) + if "default" in extra: + extra_items.append(_("default: {default}").format(default=extra["default"])) + if "range" in extra: + extra_items.append(extra["range"]) + if "required" in extra: + extra_items.append(_(extra["required"])) + + if extra_items: + extra_str = "; ".join(extra_items) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: + extra: types.OptionHelpExtra = {} + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + if isinstance(envvar, str): + extra["envvars"] = (envvar,) + else: + extra["envvars"] = tuple(str(d) for d in envvar) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or ( + show_default and (default_value 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 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 set to True/False, provide this to `prompt` as well. For + # non-bool values of `show_default`, we use `prompt`'s default behavior + prompt_kwargs: t.Any = {} + if isinstance(self.show_default, bool): + prompt_kwargs["show_default"] = self.show_default + + return prompt( + self.prompt, + # 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 is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any: + """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 not in (ParameterSource.DEFAULT, 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 source not in (ParameterSource.DEFAULT, 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 in (ParameterSource.DEFAULT, 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() # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(param=self, ctx=ctx) + if not var: + var = self.name.upper() # type: ignore + if self.deprecated: + var += "!" + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Argument is marked as exposed, but does not have a name.") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}: {decls}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [self.make_metavar(ctx)] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar(ctx)}'" + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + raise AttributeError(name) diff --git a/backend/venv/Lib/site-packages/click/decorators.py b/backend/venv/Lib/site-packages/click/decorators.py new file mode 100644 index 0000000..21f4c34 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/decorators.py @@ -0,0 +1,551 @@ +from __future__ import annotations + +import inspect +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") +T = t.TypeVar("T") +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound="_AnyCallable | Command") + + +def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator( + object_type: type[T], ensure: bool = False +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + + obj: T | None + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: str | None = None +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +# variant: no call, directly as decorator for a function. +@t.overload +def command(name: _AnyCallable) -> Command: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) +@t.overload +def command( + name: str | None, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) +@t.overload +def command( + name: None = None, + *, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: ... + + +def command( + name: str | _AnyCallable | None = None, + cls: type[CmdType] | None = None, + **attrs: t.Any, +) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function, converted to + lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes + ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, + ``init_data_command`` becomes ``init-data``. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: The name of the command. Defaults to modifying the function's + name as described above. + :param cls: The command class to create. Defaults to :class:`Command`. + + .. versionchanged:: 8.2 + The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are + removed when generating the name. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Callable[[_AnyCallable], t.Any] | None = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast("type[CmdType]", Command) + + def decorator(f: _AnyCallable) -> CmdType: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + if t.TYPE_CHECKING: + assert cls is not None + assert not callable(name) + + if name is not None: + cmd_name = name + else: + cmd_name = f.__name__.lower().replace("_", "-") + cmd_left, sep, suffix = cmd_name.rpartition("-") + + if sep and suffix in {"command", "cmd", "group", "grp"}: + cmd_name = cmd_left + + cmd = cls(name=cmd_name, callback=f, params=params, **attrs) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +GrpType = t.TypeVar("GrpType", bound=Group) + + +# variant: no call, directly as decorator for a function. +@t.overload +def group(name: _AnyCallable) -> Group: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) +@t.overload +def group( + name: str | None, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) +@t.overload +def group( + name: None = None, + *, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: ... + + +def group( + name: str | _AnyCallable | None = None, + cls: type[GrpType] | None = None, + **attrs: t.Any, +) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if cls is None: + cls = t.cast("type[GrpType]", Group) + + if callable(name): + return command(cls=cls, **attrs)(name) + + return command(name, cls, **attrs) + + +def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument( + *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default argument class, refer to :class:`Argument` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Argument + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def option( + *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default option class, refer to :class:`Option` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Option + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: str | None = None, + *param_decls: str, + package_name: str | None = None, + prog_name: str | None = None, + message: str | None = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + import importlib.metadata + + try: + version = importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Pre-configured ``--help`` option which immediately prints the help page + and exits the program. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", show_help) + + return option(*param_decls, **kwargs) diff --git a/backend/venv/Lib/site-packages/click/exceptions.py b/backend/venv/Lib/site-packages/click/exceptions.py new file mode 100644 index 0000000..4d782ee --- /dev/null +++ b/backend/venv/Lib/site-packages/click/exceptions.py @@ -0,0 +1,308 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .globals import resolve_color_default +from .utils import echo +from .utils import format_filename + +if t.TYPE_CHECKING: + from .core import Command + from .core import Context + from .core import Parameter + + +def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + # The context will be removed by the time we print the message, so cache + # the color settings here to be used later on (in `show`) + self.show_color: bool | None = resolve_color_default() + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=self.show_color, + ) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: Context | None = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: Command | None = self.ctx.command if self.ctx else None + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: 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) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: str | None = None, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: 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) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message( + param=self.param, ctx=self.ctx + ) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: str | None = None, + possibilities: cabc.Sequence[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: Context | None = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class NoArgsIsHelpError(UsageError): + def __init__(self, ctx: Context) -> None: + self.ctx: Context + super().__init__(ctx.get_help(), ctx=ctx) + + def show(self, file: t.IO[t.Any] | None = None) -> None: + echo(self.format_message(), file=file, err=True, color=self.ctx.color) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: str | None = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: str = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code: int = code diff --git a/backend/venv/Lib/site-packages/click/formatting.py b/backend/venv/Lib/site-packages/click/formatting.py new file mode 100644 index 0000000..0b64f83 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +import collections.abc as cabc +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import _split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: int | None = None + + +def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: + widths: dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: cabc.Iterable[tuple[str, str]], col_count: int +) -> cabc.Iterator[tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: list[tuple[int, bool, str]] = [] + buf: list[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: int | None = None, + max_width: int | None = None, + ) -> None: + 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 = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: cabc.Sequence[tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> cabc.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> cabc.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = _split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/backend/venv/Lib/site-packages/click/globals.py b/backend/venv/Lib/site-packages/click/globals.py new file mode 100644 index 0000000..a2f9172 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/globals.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import typing as t +from threading import local + +if t.TYPE_CHECKING: + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: t.Literal[False] = False) -> Context: ... + + +@t.overload +def get_current_context(silent: bool = ...) -> Context | None: ... + + +def get_current_context(silent: bool = False) -> Context | None: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: Context) -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: bool | None = None) -> bool | None: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/backend/venv/Lib/site-packages/click/parser.py b/backend/venv/Lib/site-packages/click/parser.py new file mode 100644 index 0000000..1ea1f71 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/parser.py @@ -0,0 +1,532 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" + +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from ._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 | None] | None], list[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with ``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[V]) -> V | T_UNSET: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return UNSET + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) # type: ignore[arg-type] + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(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(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: t.Any, state: _ParsingState) -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class _Argument: + def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: str | cabc.Sequence[str | None] | None | T_UNSET, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert isinstance(value, cabc.Sequence) + holes = sum(1 for x in value if x is UNSET) + 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: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = 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 larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: _Option, state: _ParsingState + ) -> str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE: + nargs = option.nargs + + value: str | cabc.Sequence[str] | 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/backend/venv/Lib/site-packages/click/py.typed b/backend/venv/Lib/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/click/shell_completion.py b/backend/venv/Lib/site-packages/click/shell_completion.py new file mode 100644 index 0000000..8f1564c --- /dev/null +++ b/backend/venv/Lib/site-packages/click/shell_completion.py @@ -0,0 +1,667 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .utils import echo + + +def shell_complete( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: str | None = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: str | None = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +# 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 "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> tuple[list[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import shutil + import subprocess + + bash_exe = shutil.which("bash") + + if bash_exe is None: + match = None + else: + output = subprocess.run( + [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], + stdout=subprocess.PIPE, + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + echo( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ), + err=True, + ) + else: + echo( + _("Couldn't detect Bash version, shell completion is not supported."), + err=True, + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + 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: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") + + +_available_shells: dict[str, type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: str | None = None +) -> ShellCompleteType: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + return cls + + +def get_completion_class(shell: str) -> type[ShellComplete] | None: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def split_arg_string(string: str) -> list[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + + .. versionchanged:: 8.2 + Moved to ``shell_completion`` from ``parser``. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + # Will be None if expose_value is False. + value = ctx.params.get(param.name) + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + 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/backend/venv/Lib/site-packages/click/termui.py b/backend/venv/Lib/site-packages/click/termui.py new file mode 100644 index 0000000..2e98a07 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/termui.py @@ -0,0 +1,883 @@ +from __future__ import annotations + +import collections.abc as cabc +import inspect +import io +import itertools +import sys +import typing as t +from contextlib import AbstractContextManager +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Any | None = None, + show_choices: bool = True, + type: ParamType | None = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text: str, + default: t.Any | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType | t.Any | None = None, + value_proc: t.Callable[[str], t.Any] | None = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. 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: + # 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 f(text[-1:]) + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: bool | None = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.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: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt[:-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. + value = visible_prompt_func(prompt[-1:]).lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, + color: bool | None = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +@t.overload +def progressbar( + *, + length: int, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[int]: ... + + +@t.overload +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: ... + + +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param hidden: hide the progressbar. Defaults to ``False``. When no tty is + detected, it will only print the progressbar label. Setting this to + ``False`` also disables that. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionadded:: 8.2 + The ``hidden`` argument. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + The ``update_min_steps`` parameter. + + .. versionadded:: 4.0 + The ``color`` parameter and ``update`` method. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + hidden=hidden, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor + echo("\033[2J\033[1;1H", nl=False) + + +def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: int | tuple[int, int, int] | str | None = None, + bg: int | tuple[int, int, int] | str | None = None, + bold: bool | None = None, + dim: bool | None = None, + underline: bool | None = None, + overline: bool | None = None, + italic: bool | None = None, + blink: bool | None = None, + reverse: bool | None = None, + strikethrough: bool | None = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Any | None = None, + file: t.IO[t.AnyStr] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +@t.overload +def edit( + text: bytes | bytearray, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = False, + extension: str = ".txt", +) -> bytes | None: ... + + +@t.overload +def edit( + text: str, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", +) -> str | None: ... + + +@t.overload +def edit( + text: None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> None: ... + + +def edit( + text: str | bytes | bytearray | None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> str | bytes | bytearray | None: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. If the editor supports + editing multiple files at once, a sequence of files may be + passed as well. Invoke `click.file` once per file instead + if multiple files cannot be managed at once or editing the + files serially is desired. + + .. versionchanged:: 8.2.0 + ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` + if the ``editor`` supports editing multiple files at once. + + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + if isinstance(filename, str): + filename = (filename,) + + ed.edit_files(filenames=filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Callable[[bool], str] | None = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> AbstractContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: str | None = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/backend/venv/Lib/site-packages/click/testing.py b/backend/venv/Lib/site-packages/click/testing.py new file mode 100644 index 0000000..f6f60b8 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/testing.py @@ -0,0 +1,577 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +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 + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> list[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> cabc.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class BytesIOCopy(io.BytesIO): + """Patch ``io.BytesIO`` to let the written stream be copied to another. + + .. versionadded:: 8.2 + """ + + def __init__(self, copy_to: io.BytesIO) -> None: + super().__init__() + self.copy_to = copy_to + + def flush(self) -> None: + super().flush() + self.copy_to.flush() + + def write(self, b: ReadableBuffer) -> int: + self.copy_to.write(b) + return super().write(b) + + +class StreamMixer: + """Mixes `` and `` streams. + + The result is available in the ``output`` attribute. + + .. versionadded:: 8.2 + """ + + def __init__(self) -> None: + self.output: io.BytesIO = io.BytesIO() + self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) + self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) + + def __del__(self) -> None: + """ + Guarantee that embedded file-like objects are closed in a + predictable order, protecting against races between + self.output being closed and other streams being flushed on close + + .. versionadded:: 8.2.2 + """ + self.stderr.close() + self.stdout.close() + self.output.close() + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: str | bytes | t.IO[t.Any] | None, charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(input) + + +class Result: + """Holds the captured result of an invoked CLI script. + + :param runner: The runner that created the result + :param stdout_bytes: The standard output as bytes. + :param stderr_bytes: The standard error as bytes. + :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the + user would see it in its terminal. + :param return_value: The value returned from the invoked command. + :param exit_code: The exit code as integer. + :param exception: The exception that happened if one did. + :param exc_info: Exception information (exception type, exception instance, + traceback type). + + .. versionchanged:: 8.2 + ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and + ``mix_stderr`` has been removed. + + .. versionadded:: 8.0 + Added ``return_value``. + """ + + def __init__( + self, + runner: CliRunner, + stdout_bytes: bytes, + stderr_bytes: bytes, + output_bytes: bytes, + return_value: t.Any, + exit_code: int, + exception: BaseException | None, + exc_info: tuple[type[BaseException], BaseException, TracebackType] + | None = None, + ): + self.runner = runner + self.stdout_bytes = stdout_bytes + self.stderr_bytes = stderr_bytes + self.output_bytes = output_bytes + self.return_value = return_value + self.exit_code = exit_code + self.exception = exception + self.exc_info = exc_info + + @property + def output(self) -> str: + """The terminal output as unicode string, as the user would see it. + + .. versionchanged:: 8.2 + No longer a proxy for ``self.stdout``. Now has its own independent stream + that is mixing `` and ``, in the order they were written. + """ + return self.output_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string. + + .. versionchanged:: 8.2 + No longer raise an exception, always returns the `` string. + """ + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from `` writes + to ``. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param catch_exceptions: Whether to catch any exceptions other than + ``SystemExit`` when running :meth:`~CliRunner.invoke`. + + .. versionchanged:: 8.2 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 8.2 + ``mix_stderr`` parameter has been removed. + """ + + def __init__( + self, + charset: str = "utf-8", + env: cabc.Mapping[str, str | None] | None = None, + echo_stdin: bool = False, + catch_exceptions: bool = True, + ) -> None: + self.charset = charset + self.env: cabc.Mapping[str, str | None] = env or {} + self.echo_stdin = echo_stdin + self.catch_exceptions = catch_exceptions + + def get_default_prog_name(self, cli: Command) -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: cabc.Mapping[str, str | None] | None = None + ) -> cabc.Mapping[str, str | None]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + color: bool = False, + ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up `` with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into `sys.stdin`. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + An additional output stream is returned, which is a mix of + `` and `` streams. + + .. versionchanged:: 8.2 + Always returns the `` stream. + + .. versionchanged:: 8.0 + `` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + stream_mixer = StreamMixer() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + stream_mixer.stdout, encoding=self.charset, name="", mode="w" + ) + + sys.stderr = _NamedTextIOWrapper( + stream_mixer.stderr, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: str | None = None) -> str: + sys.stdout.write(prompt or "") + 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 + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + _compat.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + _compat.should_strip_ansi = old__compat_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: Command, + args: str | cabc.Sequence[str] | None = None, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + catch_exceptions: bool | None = None, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. If :data:`None`, the value + from :class:`CliRunner` is used. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + The result object has the ``output_bytes`` attribute with + the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would + see it in its terminal. + + .. versionchanged:: 8.2 + The result object always returns the ``stderr_bytes`` stream. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + if catch_exceptions is None: + catch_exceptions = self.catch_exceptions + + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: BaseException | None = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast("int | t.Any | None", e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + sys.stderr.flush() + stdout = outstreams[0].getvalue() + stderr = outstreams[1].getvalue() + output = outstreams[2].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + output_bytes=output, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: str | os.PathLike[str] | None = None + ) -> cabc.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + import shutil + + try: + shutil.rmtree(dt) + except OSError: + pass diff --git a/backend/venv/Lib/site-packages/click/types.py b/backend/venv/Lib/site-packages/click/types.py new file mode 100644 index 0000000..e71c1c2 --- /dev/null +++ b/backend/venv/Lib/site-packages/click/types.py @@ -0,0 +1,1209 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import os +import stat +import sys +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import format_filename +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + +ParamTypeValue = t.TypeVar("ParamTypeValue") + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[str | None] = None + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.NoReturn: + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name: str = func.__name__ + self.func = func + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = sys.getfilesystemencoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType, t.Generic[ParamTypeValue]): + """The choice type allows a value to be checked against a fixed set + of supported values. + + You may pass any iterable value which will be converted to a tuple + and thus will only be iterated once. + + The resulting value will always be one of the originally passed choices. + See :meth:`normalize_choice` for more info on the mapping of strings + to choices. See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + + .. versionchanged:: 8.2.0 + Non-``str`` ``choices`` are now supported. It can additionally be any + iterable. Before you were not recommended to pass anything but a list or + tuple. + + .. versionadded:: 8.2.0 + Choice normalization can be overridden via :meth:`normalize_choice`. + """ + + name = "choice" + + def __init__( + self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True + ) -> None: + self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def _normalized_mapping( + self, ctx: Context | None = None + ) -> cabc.Mapping[ParamTypeValue, str]: + """ + Returns mapping where keys are the original choices and the values are + the normalized values that are accepted via the command line. + + This is a simple wrapper around :meth:`normalize_choice`, use that + instead which is supported. + """ + return { + choice: self.normalize_choice( + choice=choice, + ctx=ctx, + ) + for choice in self.choices + } + + def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: + """ + Normalize a choice value, used to map a passed string to a choice. + Each choice must have a unique normalized value. + + By default uses :meth:`Context.token_normalize_func` and if not case + sensitive, convert it to a casefolded value. + + .. versionadded:: 8.2.0 + """ + normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(normed_value) + + if not self.case_sensitive: + normed_value = normed_value.casefold() + + return normed_value + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + if param.param_type_name == "option" and not param.show_choices: # type: ignore + choice_metavars = [ + convert_type(type(choice)).name.upper() for choice in self.choices + ] + choices_str = "|".join([*dict.fromkeys(choice_metavars)]) + else: + choices_str = "|".join( + [str(i) for i in self._normalized_mapping(ctx=ctx).values()] + ) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: + """ + Message shown when no choice is passed. + + .. versionchanged:: 8.2.0 Added ``ctx`` argument. + """ + return _("Choose from:\n\t{choices}").format( + choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) + ) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> ParamTypeValue: + """ + For a given value from the parser, normalize it and find its + matching normalized value in the list of choices. Then return the + matched "original" choice. + """ + normed_value = self.normalize_choice(choice=value, ctx=ctx) + normalized_mapping = self._normalized_mapping(ctx=ctx) + + try: + return next( + original + for original, normalized in normalized_mapping.items() + if normalized == normed_value + ) + except StopIteration: + self.fail( + self.get_invalid_choice_message(value=value, ctx=ctx), + param=param, + ctx=ctx, + ) + + def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: + """Get the error message when the given choice is invalid. + + :param value: The invalid value. + + .. versionadded:: 8.2 + """ + choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) + return ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: cabc.Sequence[str] | None = None): + self.formats: cabc.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[type[t.Any]] + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: t.Literal[1, -1], open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + if not open: + return bound + + # Could use math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + 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): + name = "uuid" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Files can also be opened atomically in which case all writes go into a + separate file in the same folder and upon completion the file will + be moved over to the original location. This is useful if a file + regularly read by other users is modified. + + See :ref:`file-args` for more information. + + .. versionchanged:: 2.0 + Added the ``atomic`` parameter. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool | None = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: + if self.lazy is not None: + return self.lazy + if os.fspath(value) == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, + value: str | os.PathLike[str] | t.IO[t.Any], + param: Parameter | None, + ctx: Context | None, + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("str | os.PathLike[str]", value) + + try: + lazy = self.resolve_lazy_flag(value) + + if lazy: + lf = LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + if ctx is not None: + ctx.call_on_close(lf.close_intelligently) + + return t.cast("t.IO[t.Any]", lf) + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: + return hasattr(value, "read") or hasattr(value, "write") + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``path_type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: type[t.Any] | None = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name: str = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result( + self, value: str | os.PathLike[str] + ) -> str | bytes | os.PathLike[str]: + if self.type is not None and not isinstance(value, self.type): + if self.type is str: + return os.fsdecode(value) + elif self.type is bytes: + return os.fsencode(value) + else: + return t.cast("os.PathLike[str]", self.type(value)) + + return value + + def convert( + self, + value: str | os.PathLike[str], + param: Parameter | None, + ctx: Context | None, + ) -> str | bytes | os.PathLike[str]: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} {filename!r} is a directory.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: + self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple( + ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) + ) + + +def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() + + +class OptionHelpExtra(t.TypedDict, total=False): + envvars: tuple[str, ...] + default: str + range: str + required: str diff --git a/backend/venv/Lib/site-packages/click/utils.py b/backend/venv/Lib/site-packages/click/utils.py new file mode 100644 index 0000000..beae26f --- /dev/null +++ b/backend/venv/Lib/site-packages/click/utils.py @@ -0,0 +1,627 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType +from types import TracebackType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: + try: + return func(*args, **kwargs) + except Exception: + pass + return None + + return update_wrapper(wrapper, func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(sys.getfilesystemencoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, + ): + self.name: str = os.fspath(filename) + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.IO[t.Any] | None + self.should_close: bool + + if self.name == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO[t.Any]: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> LazyFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close_intelligently() + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO[t.Any]) -> None: + self._file: t.IO[t.Any] = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> KeepOpenFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Any | None = None, + file: t.IO[t.Any] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + return + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: str | bytes | bytearray | None = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file, color) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: t.Literal["stdin", "stdout", "stderr"], + encoding: str | None = None, + errors: str | None = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[t.Any]: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name or Path of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast( + "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) + ) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) + + return f + + +def format_filename( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], + shorten: bool = False, +) -> str: + """Format a filename as a string for display. Ensures the filename can be + displayed by replacing any invalid bytes or surrogate escapes in the name + with the replacement character ``�``. + + Invalid bytes or surrogate escapes will raise an error when written to a + stream with ``errors="strict"``. This will typically happen with ``stdout`` + when the locale is something like ``en_GB.UTF-8``. + + Many scenarios *are* safe to write surrogates though, due to PEP 538 and + PEP 540, including: + + - Writing to ``stderr``, which uses ``errors="backslashreplace"``. + - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens + stdout and stderr with ``errors="surrogateescape"``. + - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. + - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. + Python opens stdout and stderr with ``errors="surrogateescape"``. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + else: + filename = os.fspath(filename) + + if isinstance(filename, bytes): + filename = filename.decode(sys.getfilesystemencoding(), "replace") + else: + filename = filename.encode("utf-8", "surrogateescape").decode( + "utf-8", "replace" + ) + + return filename + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no effect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO[t.Any]) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: str | None = None, _main: ModuleType | None = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # It is set to "" inside a Shiv or PEX zipapp. + if getattr(_main, "__package__", None) in {None, ""} or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: cabc.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> list[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA new file mode 100644 index 0000000..a1b5c57 --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA @@ -0,0 +1,441 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.6 +Summary: Cross-platform colored terminal text. +Project-URL: Homepage, https://github.com/tartley/colorama +Author-email: Jonathan Hartley +License-File: LICENSE.txt +Keywords: ansi,color,colour,crossplatform,terminal,text,windows,xplatform +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Terminals +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7 +Description-Content-Type: text/x-rst + +.. image:: https://img.shields.io/pypi/v/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Supported Python versions + +.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg + :target: https://github.com/tartley/colorama/actions/workflows/test.yml + :alt: Build Status + +Colorama +======== + +Makes ANSI escape character sequences (for producing colored terminal text and +cursor positioning) work under MS Windows. + +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + +Installation +------------ + +Tested on CPython 2.7, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + +Description +----------- + +ANSI escape character sequences have long been used to produce colored terminal +text and cursor positioning on Unix and Macs. Colorama makes this work on +Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which +would appear as gobbledygook in the output), and converting them into the +appropriate win32 calls to modify the state of the terminal. On other platforms, +Colorama does nothing. + +This has the upshot of providing a simple cross-platform API for printing +colored terminal text from Python, and has the happy side-effect that existing +applications or libraries which use ANSI sequences to produce colored output on +Linux or Macs can now also work on Windows, simply by calling +``colorama.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()`` +(all versions, but may have other side-effects – see below). + +An alternative approach is to install ``ansi.sys`` on Windows machines, which +provides the same behaviour for all applications running in terminals. Colorama +is intended for situations where that isn't easy (e.g., maybe your app doesn't +have an installer.) + +Demo scripts in the source code repository print some colored text using +ANSI sequences. Compare their output under Gnome-terminal's built in ANSI +handling, versus on Windows Command-Prompt using Colorama: + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png + :width: 661 + :height: 357 + :alt: ANSI sequences on Ubuntu under gnome-terminal. + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png + :width: 668 + :height: 325 + :alt: Same ANSI sequences on Windows, using Colorama. + +These screenshots show that, on Windows, Colorama does not support ANSI 'dim +text'; it looks the same as 'normal text'. + +Usage +----- + +Initialisation +.............. + +If the only thing you want from Colorama is to get ANSI escapes to work on +Windows, then run: + +.. code-block:: python + + from colorama import just_fix_windows_console + just_fix_windows_console() + +If you're on a recent version of Windows 10 or better, and your stdout/stderr +are pointing to a Windows console, then this will flip the magic configuration +switch to enable Windows' built-in ANSI support. + +If you're on an older version of Windows, and your stdout/stderr are pointing to +a Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a +magic file object that intercepts ANSI escape sequences and issues the +appropriate Win32 calls to emulate them. + +In all other circumstances, it does nothing whatsoever. Basically the idea is +that this makes Windows act like Unix with respect to ANSI escape handling. + +It's safe to call this function multiple times. It's safe to call this function +on non-Windows platforms, but it won't do anything. It's safe to call this +function when one or both of your stdout/stderr are redirected to a file – it +won't do anything to those streams. + +Alternatively, you can use the older interface with more features (but also more +potential footguns): + +.. code-block:: python + + from colorama import init + init() + +This does the same thing as ``just_fix_windows_console``, except for the +following differences: + +- It's not safe to call ``init`` multiple times; you can end up with multiple + layers of wrapping and broken ANSI support. + +- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI, + and if it thinks they don't, then it will wrap ``sys.stdout`` and + ``sys.stderr`` in a magic file object that strips out ANSI escape sequences + before printing them. This happens on all platforms, and can be convenient if + you want to write your code to emit ANSI escape sequences unconditionally, and + let Colorama decide whether they should actually be output. But note that + Colorama's heuristic is not particularly clever. + +- ``init`` also accepts explicit keyword args to enable/disable various + functionality – see below. + +To stop using Colorama before your program exits, simply call ``deinit()``. +This will restore ``stdout`` and ``stderr`` to their original values, so that +Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is +cheaper than calling ``init()`` again (but does the same thing). + +Most users should depend on ``colorama >= 0.4.6``, and use +``just_fix_windows_console``. The old ``init`` interface will be supported +indefinitely for backwards compatibility, but we don't plan to fix any issues +with it, also for backwards compatibility. + +Colored Output +.............. + +Cross-platform printing of colored text can then be done using Colorama's +constant shorthand for ANSI escape sequences. These are deliberately +rudimentary, see below. + +.. code-block:: python + + from colorama import Fore, Back, Style + print(Fore.RED + 'some red text') + print(Back.GREEN + 'and with a green background') + print(Style.DIM + 'and in dim text') + print(Style.RESET_ALL) + print('back to normal now') + +...or simply by manually printing ANSI sequences from your own code: + +.. code-block:: python + + print('\033[31m' + 'some red text') + print('\033[39m') # and reset to default color + +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +the fabulous `Blessings `_, +or the incredible `_Rich `_. + +If you wish Colorama's Fore, Back and Style constants were more capable, +then consider using one of the above highly capable libraries to generate +colors, etc, and use Colorama just for its primary purpose: to convert +those ANSI sequences to also work on Windows: + +SIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama. +We are only interested in converting ANSI codes to win32 API calls, not +shortcuts like the above to generate ANSI characters. + +.. code-block:: python + + from colorama import just_fix_windows_console + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + just_fix_windows_console() + + # then use Termcolor for all colored text output + print(colored('Hello, World!', 'green', 'on_red')) + +Available formatting constants are:: + + Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Style: DIM, NORMAL, BRIGHT, RESET_ALL + +``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will +perform this reset automatically on program exit. + +These are fairly well supported, but not part of the standard:: + + Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + +Cursor Positioning +.................. + +ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for +an example of how to generate them. + +Init Keyword Args +................. + +``init()`` accepts some ``**kwargs`` to override default behaviour. + +init(autoreset=False): + If you find yourself repeatedly sending reset sequences to turn off color + changes at the end of every print, then ``init(autoreset=True)`` will + automate that: + + .. code-block:: python + + from colorama import init + init(autoreset=True) + print(Fore.RED + 'some red text') + print('automatically back to default color again') + +init(strip=None): + Pass ``True`` or ``False`` to override whether ANSI codes should be + stripped from the output. The default behaviour is to strip if on Windows + or if output is redirected (not a tty). + +init(convert=None): + Pass ``True`` or ``False`` to override whether to convert ANSI codes in the + output into win32 calls. The default behaviour is to convert if on Windows + and output is to a tty (terminal). + +init(wrap=True): + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + with proxy objects, which override the ``.write()`` method to do their work. + If this wrapping causes you problems, then this can be disabled by passing + ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or + ``strip`` or ``convert`` are True. + + When wrapping is disabled, colored printing on non-Windows platforms will + continue to work as normal. To do cross-platform colored output, you can + use Colorama's ``AnsiToWin32`` proxy directly: + + .. code-block:: python + + import sys + from colorama import init, AnsiToWin32 + init(wrap=False) + stream = AnsiToWin32(sys.stderr).stream + + # Python 2 + print >>stream, Fore.BLUE + 'blue text on stderr' + + # Python 3 + print(Fore.BLUE + 'blue text on stderr', file=stream) + +Recognised ANSI Sequences +......................... + +ANSI sequences generally take the form:: + + ESC [ ; ... + +Where ```` is an integer, and ```` is a single letter. Zero or +more params are passed to a ````. If no params are passed, it is +generally synonymous with passing a single zero. No spaces exist in the +sequence; they have been inserted here simply to read more easily. + +The only ANSI sequences that Colorama converts into win32 calls are:: + + ESC [ 0 m # reset all (colors and brightness) + ESC [ 1 m # bright + ESC [ 2 m # dim (looks same as normal brightness) + ESC [ 22 m # normal brightness + + # FOREGROUND: + ESC [ 30 m # black + ESC [ 31 m # red + ESC [ 32 m # green + ESC [ 33 m # yellow + ESC [ 34 m # blue + ESC [ 35 m # magenta + ESC [ 36 m # cyan + ESC [ 37 m # white + ESC [ 39 m # reset + + # BACKGROUND + ESC [ 40 m # black + ESC [ 41 m # red + ESC [ 42 m # green + ESC [ 43 m # yellow + ESC [ 44 m # blue + ESC [ 45 m # magenta + ESC [ 46 m # cyan + ESC [ 47 m # white + ESC [ 49 m # reset + + # cursor positioning + ESC [ y;x H # position cursor at x across, y down + ESC [ y;x f # position cursor at x across, y down + ESC [ n A # move cursor n lines up + ESC [ n B # move cursor n lines down + ESC [ n C # move cursor n characters forward + ESC [ n D # move cursor n characters backward + + # clear the screen + ESC [ mode J # clear the screen + + # clear the line + ESC [ mode K # clear the line + +Multiple numeric params to the ``'m'`` command can be combined into a single +sequence:: + + ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background + +All other ANSI sequences of the form ``ESC [ ; ... `` +are silently stripped from the output on Windows. + +Any other form of ANSI sequence, such as single-character codes or alternative +initial characters, are not recognised or stripped. It would be cool to add +them though. Let me know if it would be useful for you, via the Issues on +GitHub. + +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some valid ANSI sequences aren't recognised. + +If you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the +explanation there of why we do not want PRs that allow Colorama to generate new +types of ANSI codes. + +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues + +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. + +.. _README-hacking.md: README-hacking.md + +License +------- + +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. + +Professional support +-------------------- + +.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for colorama is available as part of the + `Tidelift Subscription`_. + Tidelift gives software development teams a single source for purchasing + and maintaining their software, with professional grade assurances from + the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +Thanks +------ + +See the CHANGELOG for more thanks! + +* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. +* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, + providing a solution to issue #7's setuptools/distutils debate, + and other fixes. +* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``. +* Matthew McCormick for politely pointing out a longstanding crash on non-Win. +* Ben Hoyt, for a magnificent fix under 64-bit Windows. +* Jesse at Empty Square for submitting a fix for examples in the README. +* User 'jamessp', an observant documentation fix for cursor positioning. +* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 + fix. +* Julien Stuyck, for wisely suggesting Python3 compatible updates to README. +* Daniel Griffith for multiple fabulous patches. +* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty + output. +* Roger Binns, for many suggestions, valuable feedback, & bug reports. +* Tim Golden for thought and much appreciated feedback on the initial idea. +* User 'Zearin' for updates to the README file. +* John Szakmeister for adding support for light colors +* Charles Merriam for adding documentation to demos +* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes +* Florian Bruhin for a fix when stdout or stderr are None +* Thomas Weininger for fixing ValueError on Windows +* Remi Rampin for better Github integration and fixes to the README file +* Simeon Visser for closing a file handle using 'with' and updating classifiers + to include Python 3.3 and 3.4 +* Andy Neff for fixing RESET of LIGHT_EX colors. +* Jonathan Hartley for the initial idea and implementation. diff --git a/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD new file mode 100644 index 0000000..cd6b130 --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD @@ -0,0 +1,31 @@ +colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 +colorama-0.4.6.dist-info/RECORD,, +colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 +colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 +colorama/__pycache__/__init__.cpython-312.pyc,, +colorama/__pycache__/ansi.cpython-312.pyc,, +colorama/__pycache__/ansitowin32.cpython-312.pyc,, +colorama/__pycache__/initialise.cpython-312.pyc,, +colorama/__pycache__/win32.cpython-312.pyc,, +colorama/__pycache__/winterm.cpython-312.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-312.pyc,, +colorama/tests/__pycache__/ansi_test.cpython-312.pyc,, +colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc,, +colorama/tests/__pycache__/initialise_test.cpython-312.pyc,, +colorama/tests/__pycache__/isatty_test.cpython-312.pyc,, +colorama/tests/__pycache__/utils.cpython-312.pyc,, +colorama/tests/__pycache__/winterm_test.cpython-312.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/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL new file mode 100644 index 0000000..d79189f --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.11.1 +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..3105888 --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holders, nor those of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv/Lib/site-packages/colorama/__init__.py b/backend/venv/Lib/site-packages/colorama/__init__.py new file mode 100644 index 0000000..383101c --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text, just_fix_windows_console +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.4.6' + diff --git a/backend/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5102d8bbb81d065941cf0d36b405d7791dc6aaa1 GIT binary patch literal 485 zcmXv~%Ss$U6s?-B?s@dgEJVTVvuPxg;Djtf5L6Hs5`qtuqM>NJD?@2l)lk**a_3k0 z4Q~7qm*S=%B;X>r6WqD-mgC&Tx%ZyKecpCDEd=)KW?!^0LJvM!SnWM{-i6=_6{x@^ zl9*yyqcs`OKoUx1NJH$kS{cbYt;+^&$R=&d7KMhu2W2eVv<)$#omrSfk1z)%p(8?x z%0&gAdo%Z)T$kEpGGi5=R&ModWGnVtOxZ-JLQgEqwX(Y832|gc8}7(fmY=)upqiE3 zMcX4|wMnpxH!$t2FgE7K3auEsM$bT@my_-9>Cor_oFRo8q!X=kEhRTOXF`p+ zs8r2PQ! d6kv@1qoaFt^cSt&p|wBgqGZJsC5Td7Z{%*)+>Nw0MJlsv zyHpi`26TvFA5^PVi+j$f8=5zNZ|~8>uGOx$x}~#Z?g_ukCT zym|9`GxL2s9wG28{AJN$VM6|fO7~MbLhG*}+$9##i6!WQCF-Ij>5?UH6J53xK*dU1 z>b9V(P-{?YBAFppXq#AJJM>Tr#?iyv8Ubsx&l=&@7+B+WxYswztqHIu`>Zi;9Rllc zpEWKLJNmHWteyZZ*3*)p#e3QiXpx>a+(=~)Y&IiHYmS>)uUpruc4pPC+0^uGHIki==RO^(Rpnct`nN@czQnu}h%$nzIOpK4)wXqw{ zRcFJt9CNHrSI1Es$8inYt(Y6OfrCai#iO4>xx@smB6L=Pl?(+#*E$Jsmw14|=XC-~ z$QF6n`C}8BECI1hvSNt|>kmXG<;$~7ay^f z!QwcB;nfWcnoE&aF(|Er08R2Fn)oKYv-I`It+Tu3y=dla6yH0Oh4s#t^Gup76k)xJ=Xh1y?HSxkhe1z5aSs7- z-*yh%n%GtLqCdMY?M072l8;mLeZaZ@Za+Szm`)F1BYwR5;8du4>z8FTVnU`?hzx9J0HrV5oC*zRhVQslto<6q@H`j@z$8OYI~;VQKkWN zP~e<~CCaW{{hY})bKPdjb+dZScG2NXCKE6%WI!4@o?&dJdchd$+D4(Ldj_CM+97iA z$gcdS*{`M^rw`vf`^U5Qe(_`a%_m1*yC>hXemL^Zj`C#a@UFaT-JkpJjUP^Y_~Xz= z&opxIRnCi2R%S30dSMtWVi>^@26D_WzPM&qgBJP*%=I9k5_gXt1p^1%YZn8yOfOO9hO*ubXeJUxKM`&o$U}0qz0K5}}r%mY`OkmZ4Uy5Zn!L7c|stm_>LXu2Hv6 zE8X#Mf`2EedK-`VK5)q8f}|4Z>(Ii4nu|kscR^fU*o;4)c5Hb8BhfvMlBsXXyTf09 za%*e1vX?yeD0D1HwwLGJWRPrQFzJ9_^3?o=(q^*HGc>#j-RNlqp7Sryjr;S{kPXqFqs;k$*C0KGfT>46K$t-I4FcaKWJ{3NJX#1R zptzXinAU>wdP^RFHmIkARL9-}sop)6TMN+Am+F}2BBZzk=`BNQE4pT>ddSlBuocoH zR#=Z(5j|!_^|%$&6INVLS_yr~O6tSbke;%J^)x)T(kz4#o32yae-$S1Uqi?s97Dh? z_A!7yF2Toi^)U{G~0FnO}LTwvN$n@1*R+(%7rBsFV4=KTjE0)h2OF$S79hr zf;K)RstMi}42^oM^XqZ}wItU%Q$26SDNzf?;!}gVe`E8oG>U-7gL@HRn>;>rq**}7 z_oQi*rVwU&67N!Ys*=Ma%{jE5N8nNkr6R(7SGqYD&;sYGK|fvSBdBAnhi)Fx21N7KT{SB*A-s(msoj0W;(`=l(ScEW7} g)w39hq;8Kk<)6aCL6y3Fw5j|QPTzjzrpjaWPqh~|SpWb4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42a3e0296c7f6d9f6331e900b6f95731ff855778 GIT binary patch literal 16405 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..01a50eaf378c5cd9f0d9b89536d7be9642eec1cf GIT binary patch literal 8128 zcmb7ITWlLwdOkzWkR$OXQqxe@>#8Ezq z)A@8oh|_a)Snt!rn+fY9w2!8c4)HXvpOrbPOqBN%N_qPXKyLtgqt8eY9!99MJ~mS1 zD~c5RiX$eUi9)<_7G!z#@mX}}D&pAth%4fYp6D|it-N8j?p0cZW?irM`Ru^C`St!8 zinseq)qbF9SL@j~P?V{y0xNc@>hR+-W9701>;ljWe+fa0X}-%@F_ zZ(nu(^`ZBCmP)OG9MvbvQGKEu7gc`Qx39K<92Qu!_QW-7Ph9g-b}hB$t1qx-G4$s_ z0T1{BujC!mJjL+!CrVp?qO@038MAL+Ljh^?dMdw^-%*2x6E$c!QG@=h z2UmO_`P`fd$_^e)Q=Iuei+o=wKH@QE_pO7u>YOOf6!5S}K|l@qAF6$Gl_+`h&LvSTbJs4v$R^ zj0dy!LdcM59Q`R&))9~3h(SIb95s4Q$J5g~PA``<&&-;0Cn|LqXJEvdcf>$u&M-cf zGlFtOi>$jys_yfSO?XEJ{1biS0|R6J-W!911LOYTu|e-rsUXYj3PoL@P%swt-1bNY zZeb#{#7iaILf!ssigK|9sgzq74crSw<|9f6 znH|iWfU=lG4RU@R{RVpBWToP0_I3HutnT&B0+hr%uRK7hnl@*o0MC4s`FXNA%raG2 zDbJao&sha1^Ej^nWyyD5-I15l`Fd{wi{zusW07go64-76xpiYpjqNR5*BgIsw+R#H zOVkGv^&@P7DkjQf8|lbF;N?K87=VPX@MZg^@kgM z@7$Whu^AkQL_*P-TMMyRFcyjMILP}$(Yt(9jN!#wQ-RS2?`R+OB z4b1Sutzax10|tT9fcCR*dFB=+qu&pE!0%sbEWAxT85$P|BK!>$D`>y;!hVT!-Lz&} zx2#z<#I27vKi*p2T;6w-ryXrcM_bzAPCDFs=hB^5lATx5oxRD1c$?diPp) z+R>DBG;L4rez@~ty5&N$<-#wWzpDL*+VtC_$+t)UN&J`Pe_l>|r;^?&d1gn_(UEp^ zB^_ORT-r03^bDpwLrKrjp~>*B^>@hNv>qaZ#d-t+LeMIfSie6Si12>DRP6UhV%&U~ z)XjeXNArPjW(3sdVnOI;`n=xpehir}lIWXIm5L`udqzh5;{$z@z-l_ghdIHItAXG# z!l&Sct4Lu|iwdX+eNfy-&)J3pOWC9Ogt>O#Qomi6Ft_bnsyBwVMmI+j=8k;ZIl}iz8&$%5mg}P+3Q!7Gs`3n>@>uNXF$S zjzpr3Qm536=1C^TEbBxy-$!wsIy!+KQ)6ygR!TbMzsie!v8WIW^AkbL^U>b<>1iGh zN2g<$h$7Kbu~^uxmkhT9Q7+6&bWoTINk(Bl7~};(AfmWjF4<0Ccfed=F64*UDPod4 zhv6@@L9v3qvbj^X&Q8a9&RpZyT(nnYSd^y3^$VLeQz4j0d zWPAJxRC4XXQTI{S5~8+`RXuaYv`DCqP3!uRYEQLK-tWg;L0F!J{}IW;uOSMSkE0J^ zTZ0QUx5PEG{}r`PQRpx1G+IQz&@WK96{fi<*$!@koaa(F77T=i_dMFT0JDTzDEh z$|@*0vGsxIqGTcNoe;Sp#dn5@$$syRNr}7%#>a6pkY`~IM_-Qj$Xx=%UpNf~@t)&% z@~U4s8~(O6<#a#2{Ey`+*!ZPA#EE^>5u!@^D3GkEk5as-nFttYsP;i4*Nbta+CLZ9 zs&4?nIrz?pW)185xNZU|CZ{p+nzCyN_GBP~Ns0iJd?4ZvaoA0|J4n$9g={xKaR$cK zZ`c!W1NmJtg`gYEVz1j+OxfM5hBv_bz*f3yQf!iY`V(i#$R=0A0yfcQQ5@F+)H3r` zO?9%SQl)=F+r^XoJyFYG+)Ezv_?$`E z&L`OOic&-g^&#$(m5PJ=k10j{CG49xmG5Zgs5=mI1sjYKqrCDcqnKLE35Esu=$0U9 zDZoV@Qw_KbaKSgTfD*M7NQGm*^k
        +j{&AWr8?jg}x821Vn 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 I*b~mb0$0?R-T(jq literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/ansi.py b/backend/venv/Lib/site-packages/colorama/ansi.py new file mode 100644 index 0000000..11ec695 --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama/ansi.py @@ -0,0 +1,102 @@ +# 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/backend/venv/Lib/site-packages/colorama/ansitowin32.py b/backend/venv/Lib/site-packages/colorama/ansitowin32.py new file mode 100644 index 0000000..abf209e --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama/ansitowin32.py @@ -0,0 +1,277 @@ +# 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/backend/venv/Lib/site-packages/colorama/initialise.py b/backend/venv/Lib/site-packages/colorama/initialise.py new file mode 100644 index 0000000..d5fd4b7 --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama/initialise.py @@ -0,0 +1,121 @@ +# 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/backend/venv/Lib/site-packages/colorama/tests/__init__.py b/backend/venv/Lib/site-packages/colorama/tests/__init__.py new file mode 100644 index 0000000..8c5661e --- /dev/null +++ b/backend/venv/Lib/site-packages/colorama/tests/__init__.py @@ -0,0 +1 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. diff --git a/backend/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76f1e57baefc2fdeefb958718e7de76d62e12339 GIT binary patch literal 191 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 ANB{r; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2184be7fc7934d71b406e598729453a2cc4fb849 GIT binary patch literal 11647 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0df9a432186aef4ee7e872f305fe7214952bb2db GIT binary patch literal 4774 zcmd^D-*4O26}}WjiIONwwu4lTDc7!(IEoY7iJPQz+!k`2tX;RHSPZn*3#ASPdKP{(xaXj6St5QKdi`5g@?&Fyt+;3k2}f&bbuz zE3%WVd)h9bbMHO8JeNG*Ip00vH^HEvKzsX(pQnD}CFDDtI87)IHa~#DO`;N&OOpil zt~95+5-y!j@ElQj)tz?hLPF3z2@lK#)syz>VnWn?37_sy`1L>{pi2n}u6eJLM9@Wk zOjPkIQGJ?gmA7|Ev}hsKf9U`rRCE!IUoCIWksO!fVu43EKO1vd;)G_HrxZi8+`5v= zJaT~^)WP#6)fD|5s?5%6)C$BiMrtDaPAW5e^bv{n|@EBy5*sc3b<$$9}C*W^6S|% zTRN|Ho~&^2M$`jp%abw`)6B&<%VV%NG0VB`u>)!Tj>nPg57BjFhPzo&~KkqZw1v*>n~RD1#>W&KR_}O5$W- zHfM<`BdH`|bJ`AD`rv0oK>UV02t;n}Ufxv*>@Nil=L3fefx)}(!A-bErcpS}dGoR- zG?L&{l5nXUfX%BekZzR+DX4Cc9#sJ8RXrd@77)Ii81q^FH<{dzhd927_8Z zJAQnhyVBIprW3&A3b$H*MyKb93E^%x$Idark^jUJBt#A35U`||93cib@8ZZL*hI~* z`AIU*(Gctyb5jXA%dZ%QM$HL2r!mJ<^!$p;avNIumlh9r7#Kv|-LwstiwIW|f^ea| z>Zk!n*#b+9S3m%2EiYWZw8-BVr5mAZp(Sy-{o`O!-2WiB>vxm)rSOe&*Ul}yv3&mH zpB1HpPk7Su!i~vmlUthsxcSS@csqZmU5Lxx|8)q0=+l4=!5JkDNMP`nF`#?!syCC( zU|Q6{5MUmMD~QDIMkH+gF1Xux4FrJE*7b*hMK6F+5+ivrvJ_eFD|8$ziv12AB}vXp z^3uD@Gll3tQ5vj5LZe`!IS&7TE6q~jc|zF4gktTY=!~kplORt2?3Adn$Ig1o##4xgWBWEB>sv4!N&(4`E9K*~eO*>)245|5)`QF<$?=N&V!c}t- z5jReP0L?_h$|r)8Lk8yc^>}N1AAe_`5Fe;dBIFy!V_(Cd z8F=q=X63Y~<)mgjRtCDlVPLY{Or#Oknz3G^^Bd<+bJvG$Hh1mJX#(Rk8!3!}DqOS! zrgbUQ*$51z(z(k3W=ho-_V0jE&AJ!S=m`)NzGJ8@`Im?P6so{fWx0+6HzpS+KMCCm zZQ)>Rvj^_|qZIGpKkbYMg};h0x)T)QyM1@syg2R<;xGMQ;fI7+gC9EBro?U-)#2CG zh@V{?RUnM*0Ac;oy=eMX5EY_yP&{!j(ho2;A;*qG2w*AFe>c)^V@dnLLLEayk}ymPP9GaHCaL#w8_ ziA4o#+uLYN^JmSQ(7>MNH1J_pbA5fuBi2L~zA~+b7mGVa?#Q0B4@51C%T0n!tAtwL z&Y@OW7(=Ui_kPw@3=h?4)())> z6ncJC43B{FX6W~!+u~ZsYG)_Mz^7% zgHRoA7u(M&W1lX5op@_j6I`rBDZECxHOAVuaazfy?c?+Z?O8c8ohKutdSIGiM|%;A z=!W)RdFSWdAB)0<_QUsY%;Tr?wmuI7HMJBHlYMHp;s`xurzOisq-MGw#Xb~`X&G%y z%i6!+>cW8?^0IE_5EwT;0nt!)y|w0B4HV>;OY+IQe6l2u<>j%0JYJMeS5JjstjVig zh3G4#=!s+KeDq8q`bJTD(sbk|l{wtp_-sU|U^IKvvnNf5tnY8@Lq@Gph(m0lq$zRPWY5NM5(R(kUfKMBQ z9z<~%#UP3!AXW&)*kDB~-Hjs@NQMUb|0>yVyM_J@$t?_RNW5@#!_UJM#L$Lc5Ke5i z2*PR3Hi0+dQ{jh^WHJ_}h@vIVWl|>MMKM;X8+8E%zK@vMdHg=YK0r_m2TPbUQ)#1- ztQj%0s9^t**fSnQQ^!zL9^Mj1Z6~}&k?-(GHAX=^<~ff0j`$yv-hYypACifCWMad^ oaYNsGV%%x&qsaFJ`^WEc#4Rl@e9L$I-7Wt1%wwLo_b}`K0xsHljsO4v literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bd1d715442693691c5abc2e3c59e84113328dec GIT binary patch literal 2463 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 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + self._light = 0 + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + elif mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + elif mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) + + +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/backend/venv/Lib/site-packages/dotenv/__init__.py b/backend/venv/Lib/site-packages/dotenv/__init__.py new file mode 100644 index 0000000..dde24a0 --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/__init__.py @@ -0,0 +1,51 @@ +from typing import Any, Optional + +from .main import dotenv_values, find_dotenv, get_key, load_dotenv, set_key, unset_key + + +def load_ipython_extension(ipython: Any) -> 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/backend/venv/Lib/site-packages/dotenv/__main__.py b/backend/venv/Lib/site-packages/dotenv/__main__.py new file mode 100644 index 0000000..3977f55 --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/__main__.py @@ -0,0 +1,6 @@ +"""Entry point for cli, enables execution with `python -m dotenv`""" + +from .cli import cli + +if __name__ == "__main__": + cli() diff --git a/backend/venv/Lib/site-packages/dotenv/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/dotenv/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c98a8b1a547c1e1bdb4891b4813e791057f62cf GIT binary patch literal 1688 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 R`uooPKitdwLpu%S{{WY%-r4{F literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/dotenv/__pycache__/ipython.cpython-312.pyc b/backend/venv/Lib/site-packages/dotenv/__pycache__/ipython.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26464568203e9e4981326e55114805f549395cf7 GIT binary patch literal 1972 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/dotenv/__pycache__/variables.cpython-312.pyc b/backend/venv/Lib/site-packages/dotenv/__pycache__/variables.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4bc1e98cfa8892c504d656749aae37d969ddb843 GIT binary patch literal 5024 zcmb_gS!^5E6@9aENKvGy#j4~@-bF`tEXj#o)shoSUb4x7w;(iQV#FC)l)1=nMsmea zs2v!n+@`4979ou`u=HgKc3bBw?pO2QAIdUXbzmR?nveF6fK;IESMPl@Ly5E;pgH<&U<$`_YVJ5Tk9jx&i?LPqQgtb-*DkJ$(gKJFv*jPL?arPBoQ3>B$whNd`gH2 z9Il0=n35t=N{+}WPsEc_A__-%qLa~jSKQjDi9l~$Tf4J|ygiH5=!))dfrVbHNylL1 z$!Vg=w~6M_`A5n_!Ql%qx)X2blHEyPKb0njMMN4_h)TwG_sO5Q29UDueuUg94F*A`# zt4YiAzG}jDIy>TPgBIN#{g_Q~(SH2>V`(*|_g%gco$C2$e|X(aPtSq!%H`GcVRbxd zGWPY{;p4XKDK=Qa*jUC${4h45(u6vc)Z?~F>|S;jE2m(R2P;H4jYN2j(*=#!MYy{F zcb9Y-Ea3rNdv%5BgvTB@6yT6f%oV+n$;30MluqM%ERmi7 z2^l&W9a7`h^t2X*^+fdD#8A{onEHV+psH7OBdTRg*m%{|vT<;15>J!XW3g-v>f@lj zXn>a*d!f5YmP1YX&388!E-r<3P0PzQpuD+28QRkV-IfhFFAIb^A30`{%-W5*7xt0p~sK>{`7R7pD7w ze}QAJXP|V)>ELWsAET9Lvne}(%RsNeFxWmTKJd-?3c2~tV(>swIbb^r25W`B(81VY zlQ78>vwRWM+-MmfVAE-Co-kw+pJfdIgN(Yk=MrJeaT`&uwG#jr7F~etzJ!rT8>X6$ z>y|ebV}1sA48h~fN^bb!$=6$n)&ZfcI4}@`)NW)7LwA!r54IHc%r-vQHn;6r@Q{N5 z!G@n_?_>)X?_a)mc`?{tRN7xOUs)pqAg4kj8|njYj!#szVcrE=_oe`sBdRe%UjgI*4CyKxsg6l|!_A;fXg=0dzgV3^fba45-~bg-}s=Lbu& zAcYYDVL$|gq2%MFE_=HRSzD{25M{MK>0ZUb)+xR-4!?49J$)q&q-x~TMH|61K@*2% z2loVqfimEj3{{jz6Ihl<-1EZR2N>vuc@0!jfPb!pVY?#0XGN`sVW1fHTgoM;>aax2 z8~5zVG-x*D9;S?t zoj^9wu;3Vt-{{vLXr~+cE+AzN{*aCG!?)4xn(Ssn(Mka>4WsB28uu%a9 z40VI9t{vD#egpOU64}p!bd~V@;oOIh#V`F| z_=}CbOToUP(r5e23m{$gmn_J58A#vqZw%gPPUE1O=SJ5@KFGlaPoV6omgC(dJ|*OY zTYL_x5RHQ{;s-5^dJKL`xT>2B3&P@B{mZs!1MC|p7b<UfNzbUm`HfAAQ`v(95PzF03G> zq;S$n&dwhvIm|C-I6J|d;p_}^hQkzd+-5nB9EV>_F+ju=1B2}m>>yZ&G7zt*CNbIU zg5OFVVD&qMV?a5@nLx7J#&&o8dw_g&iV*zT8%4OSY7d=t6f(t>FeT=AjU}Ba31+Mi zpOSMzj=MGhM+=##aMp5ISPQM>k?6kXGcM0@#Kh9r=8$soBgyqMdp9Reai5+MiCI(T zBJT539+2p{2IrvlRqye<_?}7lJo~M1gA2=p6qDRq(z0t9#G3vpGIz;TK3e=$e;Y^d7!Cqa(3_hrs9@E z&jOuGN@qzRO7p)BbgfTLh$mz&TyODIw*+-4P7y}fcc&$rllWf?MaNlJoZ;;)4}8v# zC6Z8nTsnE~#M$#FnX*}_2Y-*m)O0#ys`w9$0mVGpdrj|5H&q|7mU7JgDDI=@fEmjY z;|6pkf#bO6#QQbb_cb}PM2>vZwttq#FPjqYk(5#$kvu^M96-i&h7^VWHa^HWN5QtgV^ afVO~~Rt$3a2WCb_#v6R1jod{nKrR6ORyxN3 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/dotenv/cli.py b/backend/venv/Lib/site-packages/dotenv/cli.py new file mode 100644 index 0000000..c548aa3 --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/cli.py @@ -0,0 +1,218 @@ +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.""" + 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.""" + 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={"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: List[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, 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/backend/venv/Lib/site-packages/dotenv/ipython.py b/backend/venv/Lib/site-packages/dotenv/ipython.py new file mode 100644 index 0000000..4e7edbb --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/ipython.py @@ -0,0 +1,50 @@ +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/backend/venv/Lib/site-packages/dotenv/main.py b/backend/venv/Lib/site-packages/dotenv/main.py new file mode 100644 index 0000000..1d6bf0b --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/main.py @@ -0,0 +1,435 @@ +import io +import logging +import os +import pathlib +import shutil +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 `shutil.move()`; `shutil.move()` +# only accepts string paths, not byte paths or file descriptors. See +# https://github.com/python/typeshed/pull/6832. +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], +) -> Iterator[Tuple[IO[str], IO[str]]]: + pathlib.Path(path).touch() + + with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as dest: + error = None + try: + with open(path, encoding=encoding) as source: + yield (source, dest) + except BaseException as err: + error = err + + if error is None: + shutil.move(dest.name, path) + else: + os.unlink(dest.name) + 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", +) -> Tuple[Optional[bool], str, str]: + """ + Adds or Updates a key/value to the given .env + + If the .env path given doesn't exist, fails instead of risking creating + an orphan .env somewhere in the filesystem + """ + 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) 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", +) -> 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. + """ + 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) 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/backend/venv/Lib/site-packages/dotenv/parser.py b/backend/venv/Lib/site-packages/dotenv/parser.py new file mode 100644 index 0000000..eb100b4 --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/parser.py @@ -0,0 +1,182 @@ +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/backend/venv/Lib/site-packages/dotenv/py.typed b/backend/venv/Lib/site-packages/dotenv/py.typed new file mode 100644 index 0000000..7632ecf --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 diff --git a/backend/venv/Lib/site-packages/dotenv/variables.py b/backend/venv/Lib/site-packages/dotenv/variables.py new file mode 100644 index 0000000..667f2f2 --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/variables.py @@ -0,0 +1,86 @@ +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/backend/venv/Lib/site-packages/dotenv/version.py b/backend/venv/Lib/site-packages/dotenv/version.py new file mode 100644 index 0000000..a955fda --- /dev/null +++ b/backend/venv/Lib/site-packages/dotenv/version.py @@ -0,0 +1 @@ +__version__ = "1.2.1" diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/INSTALLER b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/METADATA b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/METADATA new file mode 100644 index 0000000..f5f8bd9 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/METADATA @@ -0,0 +1,645 @@ +Metadata-Version: 2.4 +Name: fastapi +Version: 0.128.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.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 +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.9 +Requires-Dist: starlette<0.51.0,>=0.40.0 +Requires-Dist: pydantic>=2.7.0 +Requires-Dist: typing-extensions>=4.8.0 +Requires-Dist: annotated-doc>=0.0.2 +Provides-Extra: standard +Requires-Dist: fastapi-cli[standard]>=0.0.8; 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: ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1; extra == "all" +Requires-Dist: orjson>=3.2.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 framework, high performance, easy to learn, fast to code, ready for production +

        +

        + + Test + + + Coverage + + + Package version + + + Supported Python versions + +

        + +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: 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 (previously known as Swagger) and JSON Schema. + +* estimation based on tests conducted by an internal development team, building production applications. + +## Sponsors + + +### Keystone Sponsor + + + +### Gold and Silver Sponsors + + + + + + + + + + + + + + + + + + + + + + +Other 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)
        + +--- + +"_I’m over the moon excited about **FastAPI**. It’s so fun!_" + +
        Brian Okken - Python Bytes podcast host (ref)
        + +--- + +"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" + +
        Timothy Crosley - Hug creator (ref)
        + +--- + +"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" + +"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" + +
        Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (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 mini documentary + +There's a FastAPI mini documentary 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**. + +**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 for the web parts. +* Pydantic for the data parts. + +## Installation + +Create and activate a virtual environment 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 typing import Union + +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: Union[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="9 14" +from typing import Union + +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: Union[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. + +
        + +### Run it + +Run the server with: + +
        + +```console +$ fastapi dev main.py + + ╭────────── 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 main.py... + +The command `fastapi dev` reads your `main.py` file, detects the **FastAPI** app in it, and starts a server using Uvicorn. + +By default, `fastapi dev` will start with auto-reload enabled for local development. + +You can read more about it in the FastAPI CLI docs. + +
        + +### Check it + +Open your browser at 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. + +You will see the automatic interactive API documentation (provided by 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. + +You will see the alternative automatic documentation (provided by 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="4 9-12 25-27" +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[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. + +* 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. + +* 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 as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** 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 and other libraries. +* Many extra features (thanks to Starlette) 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, go and join the waiting list if you haven't. 🚀 + +If you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉), you can deploy your application with one command. + +Before deploying, make sure you are logged in: + +
        + +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
        + +Then deploy your app: + +
        + +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
        + +That's it! Now you can access your app at that URL. ✨ + +#### About FastAPI Cloud + +**FastAPI Cloud** 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, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section 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 - for email validation. + +Used by Starlette: + +* httpx - Required if you want to use the `TestClient`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. + +Used by FastAPI: + +* uvicorn - 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. + +### 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 - for settings management. +* pydantic-extra-types - for extra types to be used with Pydantic. + +Additional optional FastAPI dependencies: + +* orjson - Required if you want to use `ORJSONResponse`. +* ujson - Required if you want to use `UJSONResponse`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/RECORD b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/RECORD new file mode 100644 index 0000000..0bab849 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/RECORD @@ -0,0 +1,103 @@ +../../Scripts/fastapi.exe,sha256=eLSmbaHfEyim1V8CQCtfv_YNrUQUArOSjDnrXkNUoss,108414 +fastapi-0.128.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +fastapi-0.128.0.dist-info/METADATA,sha256=hKL7LtKoBl4ojHSJ_u5MsihJRMPBU5AsppXt75m24FY,30977 +fastapi-0.128.0.dist-info/RECORD,, +fastapi-0.128.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi-0.128.0.dist-info/WHEEL,sha256=tsUv_t7BDeJeRHaSrczbGeuK-TtDpGsWi_JfpzD255I,90 +fastapi-0.128.0.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61 +fastapi-0.128.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086 +fastapi/__init__.py,sha256=wlYVfo3p5m4F8JxyVpV1aFS5XKRzgCXBfB9s231GveY,1081 +fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37 +fastapi/__pycache__/__init__.cpython-312.pyc,, +fastapi/__pycache__/__main__.cpython-312.pyc,, +fastapi/__pycache__/applications.cpython-312.pyc,, +fastapi/__pycache__/background.cpython-312.pyc,, +fastapi/__pycache__/cli.cpython-312.pyc,, +fastapi/__pycache__/concurrency.cpython-312.pyc,, +fastapi/__pycache__/datastructures.cpython-312.pyc,, +fastapi/__pycache__/encoders.cpython-312.pyc,, +fastapi/__pycache__/exception_handlers.cpython-312.pyc,, +fastapi/__pycache__/exceptions.cpython-312.pyc,, +fastapi/__pycache__/logger.cpython-312.pyc,, +fastapi/__pycache__/param_functions.cpython-312.pyc,, +fastapi/__pycache__/params.cpython-312.pyc,, +fastapi/__pycache__/requests.cpython-312.pyc,, +fastapi/__pycache__/responses.cpython-312.pyc,, +fastapi/__pycache__/routing.cpython-312.pyc,, +fastapi/__pycache__/staticfiles.cpython-312.pyc,, +fastapi/__pycache__/templating.cpython-312.pyc,, +fastapi/__pycache__/testclient.cpython-312.pyc,, +fastapi/__pycache__/types.cpython-312.pyc,, +fastapi/__pycache__/utils.cpython-312.pyc,, +fastapi/__pycache__/websockets.cpython-312.pyc,, +fastapi/_compat/__init__.py,sha256=o3dg67W5LlwA52_1Y9Re_JhelcG0oj5ke_GdQHcwBnw,2226 +fastapi/_compat/__pycache__/__init__.cpython-312.pyc,, +fastapi/_compat/__pycache__/shared.cpython-312.pyc,, +fastapi/_compat/__pycache__/v2.cpython-312.pyc,, +fastapi/_compat/shared.py,sha256=yFZWOnzG1JRIPuLOk0eaBcrwP2bap8UkP5I0XBuVZck,6842 +fastapi/_compat/v2.py,sha256=B5OawqkcpTaaDLNZDHFlasGQyYFS7VFbwyDVwUTydE0,19597 +fastapi/applications.py,sha256=IO5F5FdRacBFXYxGPk7zPbwRCa-cxN74HHf0eMEp7xE,180536 +fastapi/background.py,sha256=fDNVXWBZniIQIxW3v-Sc99FT2p4RDKOOWW2fhOe4Nko,1793 +fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418 +fastapi/concurrency.py,sha256=xHGDEOQAA6cvFEDX46oq3r2t1Zd4sVvreaRgdIE4juM,1489 +fastapi/datastructures.py,sha256=41qs2ZhTzORMGn7JSAF9qsiPY9XP4uGyGOMKhfzg4i4,5205 +fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi/dependencies/__pycache__/__init__.cpython-312.pyc,, +fastapi/dependencies/__pycache__/models.cpython-312.pyc,, +fastapi/dependencies/__pycache__/utils.cpython-312.pyc,, +fastapi/dependencies/models.py,sha256=TjJB2l6m-vhFkau7ysLdgcymZ6SdIJmlrJjqMJs5TZc,7317 +fastapi/dependencies/utils.py,sha256=rJQFCFUC7q765yUcOoSV78GCyTGfS2ePLbMvJ2B-yLc,38549 +fastapi/encoders.py,sha256=uQfXjliV2O93wy7sng3pUuLZw9UOw8HNsAHb2B1ZfEs,11004 +fastapi/exception_handlers.py,sha256=YVcT8Zy021VYYeecgdyh5YEUjEIHKcLspbkSf4OfbJI,1275 +fastapi/exceptions.py,sha256=enNT5h_wDyzY90qA4a_VqMDRSUNHTd1LX_vihMNa-LE,6973 +fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54 +fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58 +fastapi/middleware/__pycache__/__init__.cpython-312.pyc,, +fastapi/middleware/__pycache__/asyncexitstack.cpython-312.pyc,, +fastapi/middleware/__pycache__/cors.cpython-312.pyc,, +fastapi/middleware/__pycache__/gzip.cpython-312.pyc,, +fastapi/middleware/__pycache__/httpsredirect.cpython-312.pyc,, +fastapi/middleware/__pycache__/trustedhost.cpython-312.pyc,, +fastapi/middleware/__pycache__/wsgi.cpython-312.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=Z3Ue-7wni4lUZMvH3G9ek__acgYdJstbnpZX_HQAboY,79 +fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi/openapi/__pycache__/__init__.cpython-312.pyc,, +fastapi/openapi/__pycache__/constants.cpython-312.pyc,, +fastapi/openapi/__pycache__/docs.cpython-312.pyc,, +fastapi/openapi/__pycache__/models.cpython-312.pyc,, +fastapi/openapi/__pycache__/utils.cpython-312.pyc,, +fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153 +fastapi/openapi/docs.py,sha256=wqcXZOhBdnf2pilVNyAIfjKAhfH9MXaQiitwZeJCR7I,10335 +fastapi/openapi/models.py,sha256=xJfPRE7DqNvtqgdouXbtMCCLBrZ-4Bd87QaA_WPUVTA,15419 +fastapi/openapi/utils.py,sha256=HsOqZ8uWSTUYL18jhYI0gU-A1nLHCNu3k3UEIAVzRyY,23795 +fastapi/param_functions.py,sha256=O8bsr2xM8XODE0wjtev8sZLl3Tt_glpdQteM2relVrU,64466 +fastapi/params.py,sha256=YS7z57t0N4H8Rdogx1sU6R-KZDcLn5y46SGz8z5lX-s,26982 +fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142 +fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761 +fastapi/routing.py,sha256=dHZW6NLzbvD7jZT2N-V6fj1Irbe8HR-FDeiBNSuTHHs,178746 +fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881 +fastapi/security/__pycache__/__init__.cpython-312.pyc,, +fastapi/security/__pycache__/api_key.cpython-312.pyc,, +fastapi/security/__pycache__/base.cpython-312.pyc,, +fastapi/security/__pycache__/http.cpython-312.pyc,, +fastapi/security/__pycache__/oauth2.cpython-312.pyc,, +fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc,, +fastapi/security/__pycache__/utils.cpython-312.pyc,, +fastapi/security/api_key.py,sha256=5AriUhrA_KgdtJRJ_BtCDgcTFOUlUUvDSultdIfdApc,9799 +fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141 +fastapi/security/http.py,sha256=gckOhSa1ubLpARU819pxKiZZnmnyg_co6AwQyNE8yxw,13518 +fastapi/security/oauth2.py,sha256=8sU0yRncO_1mK8rdUES1GRijPawi2ZGwLGWphWeS02w,22477 +fastapi/security/open_id_connect_url.py,sha256=pFvSVESThhjYXSDWPlFGtm9bN62JXHzuwnVfmtyNcZE,3158 +fastapi/security/utils.py,sha256=Gk6KGztJnYqvYFTmuQO7ow_icayiqP3HL762ZFRQjfU,286 +fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69 +fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76 +fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66 +fastapi/types.py,sha256=W0HOmfeZw_3PcMDOa6GA-Or9okP9hf_260UkbCfKHY4,455 +fastapi/utils.py,sha256=sl-ddHjWbQiLUNLFiG93IXStAZgp8NSFwJsjo41mb04,5230 +fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222 diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/REQUESTED b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/WHEEL b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/WHEEL new file mode 100644 index 0000000..2efd4ed --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: pdm-backend (2.4.6) +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/entry_points.txt b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/entry_points.txt new file mode 100644 index 0000000..b81849e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +fastapi = fastapi.cli:main + +[gui_scripts] + diff --git a/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..3e92463 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +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/backend/venv/Lib/site-packages/fastapi/__init__.py b/backend/venv/Lib/site-packages/fastapi/__init__.py new file mode 100644 index 0000000..6133787 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/__init__.py @@ -0,0 +1,25 @@ +"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" + +__version__ = "0.128.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/backend/venv/Lib/site-packages/fastapi/__main__.py b/backend/venv/Lib/site-packages/fastapi/__main__.py new file mode 100644 index 0000000..fc36465 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/__main__.py @@ -0,0 +1,3 @@ +from fastapi.cli import main + +main() diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db48a025afc0fe963a3015308136df4cac79633e GIT binary patch literal 1099 zcmYk5OHUL*5XXDi$LxDyUpz#ai;s=4fH6jiF$zc^F$Mv}bT*mv&NRzpXQs#Q9&kDN zE&L2#{33n=HyLAMIB+xJW;|HkJmMVw`>X1%>aMEZZ{>0U!T0{_j`t*u&@W|NePfq! z{ukggauG(Zfem-eP5EO%3a1R@rrnI64l+2SIqPQw6Pub%KNsY2UUSYb1VvoboChx9 zlIDV64l1~!xd>dvRm~;faXhZM3_O7+G*^IYxTd)ZT*r0IBv&^!U$#7)gL;1+Ia zuKSb06rR%D@TY?rJfpek-w0;$tmc+~Gq{CsX`Te0!*d22PPL~`-fa*eUu?LnDxz*B+dI*n-Ps*LH&T+Pu~4YQd1%-Ui=|GGzrGEu)USiCktp&#hp0LQ&nQ=+cikPHRgQ{F zB($GHpJPr1H}x)h)gHlf;NW@XtwscfY9GX*o{8Y&nc-VY+_78_G6eV$uuyys50hG3^OG62V*G;FBO<&^ajjv%j{|g{RSn%LEY7 zJ!Z^dK|r}fZ7)2cp=5m6RfWQ|x?mr5UwOT*@FZP`z)Sj6bk&<9k+*0=h$n5k6AeeX zrvW@TpFZPv;T-j}#1_c!lwla(QTJzM@>B5?-8n_`30g_e!vsA_(DMYf6SR<^MGY4W UdOtzS3A(2Nxbp+8^4pN@ALHIVs{jB1 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6305b582cb920285db6588a5e4b88491b85d8bce GIT binary patch literal 246 zcmX@j%ge<81QF|kGF5@}V-N=hn4pZ$azMs(h7^Vr#vF!R#wbQc1}277#??@1Mutiz zP3D&%o+jfhmfXb5JU>mQTij`h#U+UanR>}NnMKS%$(0PBL27=5J6pvR6y>KECFbU4 z=B3A!=jSKq=jNssC8x$`=9Q)9mE;#y#v~;sXQ$?+!~pqaF+Q0|F~ylBsk#L~(ZuxB z;uxsm`tk7~`{LvE3My}L*yQG?l;)(`6>$LVVFco0ULf&-nURt4E`!WN29{Q~A~v81 E0FfI(6aWAK literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/applications.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/applications.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e75c6620c969956bf838ee554cb3089424692cc8 GIT binary patch literal 86656 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 Mi2hXJ8*cdj51g^(9RL6T literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/background.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/background.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09ba3e96b1d4a6981d84dff2edc25814794b4976 GIT binary patch literal 2400 zcmcIm&5smC6tAA1Z)O-)76pV*4hLrVm`OY=W+H|Km5`7P0x>#{>89%_v-zARqs`Q zQ!W<~Ja2t{&NXrf{j55pCzCWbm!NSQImj_QOh$8qe7*3S>eS7sFdqa=5=ouN zoDT+3{v`1{vgFaa5t*+t8(x(Y#J<$ytRFZRh`1zRsBo5W;-3$x9T{is*l#TJNoR8% z8Xo`@irR*Q+9}6qn@)3cX4)VAZa>T zC)ds2KwZPhUoW+{+(2tayL2Aa3miyBsR&shC|)K4rfHyE3K~c(8CZgW=R&Vh)D!0@aj?%g#bk-~ zC3fK#C^bF%&g(?T`Ln07!)$@OjN=KzSX2CNZCT1tw3^K>sFKiaNS6dX=COv&{HE+n z#$DnyCm4=s49$8H!2bRCwKd|09*qN9TwDwXa+$?(cRBNM;u*Vs$he#eK}T>HCqc&c zBnwF|53dURr?ENvD@Mfx$^txm70S-hgHuD0-%WYw$H z@si4T;^C_N=IEhpt=T!E2fUi^&VyZ1%U6|T31!8nWrxK%j zRbz$2qu)`w+Yju^cmGDJa(@BNznapi1^J+oCrKTZ8sp?~g~YkZY;(YpD$@sR;_#kl;-c)fWCO2i~YfIcZ5al%ir`QI4% z_tK&G`hUyEXh-U)C?onI%l$YyFstB${3U`pK_a8Zm@*>zcP16ep{LQVr8Q; zcRxS32`Z>wj`Efj5T9CBRJ1H8LVZuQOP2LspLoek&a$9ZTNa1Q1aSqD7nFcAf_PSm zF&jF%sGLw@Q_r)ky1}=Dl28ZiI9HdLzMHgA-vq)2@%TD=nA)Am4`14mIr`()=e{e= z-g@IR^VXXir9I!5D#KKIW_HuembVVgT)FblEL4ia45$uwqHQxDuiRW2?oz$oX#4E# z+9$Q)^QyN86}SGe7g`Sy2)<*q^g_K9W#u4*ory7NBnntmCZjI`g;}GEX5kXz9+i?d zCPhkzAMHFpntEbGqM6vgMc1HY3%D2rS6>I3xi3*1i{c{6zZ}#43V#8*iX@?Oa%dWc q@dG-vfe!tO_C7#o9-sq1rOP+$_ZO}ikFqZsNAEw|_#MGp`}zw57Oz|Y literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/cli.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/cli.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7c280e5174e32bdf221819518e5af18b3526c50 GIT binary patch literal 660 zcmaJ<&1(}u6o0cH%_hwUG=YkzweeuUuY*u1;za}%$szP$<4V}@qWHOi_@a z&_lgi&)%fqKjKC3QkL}O$y+cUq$l5OSG@UPe)Hb@J%01vW4_dC6+nCZxyL>dfbTl^ zYgXYbZ=rJpWe6c85yYf#5D2Z%d}H;=)Mx`WFN3f#XY`F7IIK_Lg}DP0(y@PNi4MuE z*k`;O6oUC>BI>i;MmPeMCpE|mA$bK#bGf~QW9&>D0cD?i0ROTxq6!}1xS$D4p<{IS zhueuemef_xsr$^A%1@aaBysHX@T!|e)JKkS%tw*CQ4~DEkcYkqpKfebD&>@=|0}6< z%*+WQHqaAhb}ATGS+zIjipBJv5Q)I?OEHzwA5p0rbcr>o7A zwf%$A+^HRm4(s#!#Sfd`>g}&idu~Iy>*lYjO&Y%!WpJ85fsoco ZqdB{;D_Uo=ip8^)8oVp5oA1fG`3E@prWCanpQf>5kw4Mo9JN(pUUwhXhgH+GWwSnl4K zEKQ1NDGCMk#RS@i^rb4Pwe&A&%uAt9!H0ywg@P~jZDTC89}hiuvXfMN?OpcV-#zzt z&;2;RGrwfBDZuv8_wU;)8o)z2h+4b@HoiqL2Q{b>2V7DnL}KbtS1BtYRuHRYHN>i; zxv_FA#F`T?Cy*O+5^l1b41IAY<)+K&5GN34%9#)+5ogO;0u)%RmRcm6yO(vQ*3wL2 z`U~i&Wf)<4O&g|i7P2qF&>?~Cqf}55Y z_C3L-#k;0wo?~*RU`npF>2|l=@zG|TePHr4NXZSGbn9Uo)uza`fFu?+9j0V(lgBWLGl6zL?;^D1iauf=% z@gsUq1Hm+it@#>>9%+^&K`7x0G&3-+MtHlAxR)?_pCb2$GN*i@X>doqLFX`~A{KGS z6A{|($J5(5Lby*R!rMKj8-Fw8JGzL1l5J~8y165PCLDz?kK;dn0EE8D0(b?uIZH)X zH2%L%BnnZ)85+I944t9l#mK+iKX-0?$s4LX_fgOwT0N`GC=HBok(|Z5&eG3lv(rzJ zDVSEy!W6lqOp!k2%p;jD6h++W2q(>DUGXHEAZZv3wa5)4&`hss`$1Cp9Wez7sTe8D zAc3@LTOcd>&a}nq!uGvDt)kijRiH+LtYJuHv#M!L7)GDUWnO|zxTv#lKu~G^L_;cL zKeoTh!*5pV+&{-n*R{QKl_}pxNxF<%Qqkw}Tt07BWJKoGDmXr08L_LC2CDurmcj(q zPNOnrHiTKX2eEdnNzR#PH3#a=;H774>Dgl7d+`V|$&H`U{02`iz>^{r4=fzHUpRPS zq)oG0>Ot|~LiMKejdQ;^w5ku?PYfX?SG?+9@mKZU6}@*YqhCFJ<@9`UUM!6MaICFB z?$r&Txzry(lc{xS+TDkH8*&Da5dk*lJ8&Jk)KOn zPk%kS(DT)Y3+An^yZdhM`{{KISa=Ns7IX}l)!Wi+D5{>iOxIJeBfpj}Tt4|kLG*V! zi(&t1RPZtvGsC;c)!n6jxJgRA>a94UyGPKsw4am?sY^YY#JvRFONWTW{mJ2?vNTjm z4(F76$HT*uQ>E)t=xNk?0vwX*4mP~(Rz^qzamVA)vJho$3xy&w? zWf#Oy7?@Trt2)Sq;u_e}7SBtb)M3z#3FP=45^UfYALi{gY#;=_ z2ThPT=K8fshaKm=IFv$f7--rGA*2QUEjZkQQVU*u2s>NQ(}MR}aO!tT30+S>EPHwM z(#IEQI|j77O?Q#hT4L`!UrD^&R&emER=9RzUcGi|MceaOL&t`KymiUr2XT*o0T6AX ADgXcg literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/datastructures.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c737d54cf570bb7d71b0d22572eec0cac6b80344 GIT binary patch literal 7211 zcmd5hTWs9cmE>?Z!x?ErJ*}4?w5?R4Baf0eNw>;V@gugJ*sdROJ5iRV$U71p4mr8x zSe~h~5E?gifEJMZNK~{16ci{L7%kkd6pO{e`?LG8Kck%hQHdBx(f!!uVTG4k_9Oz6;inr!x8Lsp(WSC;JDpd$mB8%7VWlz zoRb-x0JuHZ&fp}#9k~t$O8|G~IvJb-xGUGi;55M9xo!rx0Nj(?!gDe1dCqLT%$XUo z<(d%ko$FzvZ7?cdi$!C-F^))P`!zo5_n94}&+H_9`MBA2IiBk;cdI?0;H1h2$rtrv z(Q;2i_0q|+d7 z=$;RhgafVtKi$t0f6{ZEQ^qVQ=!bR3vV8uq&QImHH^8f`e6x4n!=O#8z&M;;RwTu--9JKu+j~z#64Ka2&;urk?xsKHK;WA zO5cOkf>>rN@YKraWHw@$ZKj-$U*Yn+*?ze-mq~Hv4l@bZX@=c#H#TXFusbhja&2Z; z1GD>X%m&>apevgS+hYsB?WDu(C7os;{I!`}K4JD>j$Z>V@ym6=>;UN|Dbg8A)f^-} zW*gbk9Dx;E*RAM<7260r^>slKi;_sZoY! z=nmi!#h)e0xsX8(nayHzjC{wCl>J%c6VEv^ zZM(*+u=l6}o(l&mJBB)n+vH2O0t*;fhY%BFk%#j*uCte6DTZs3=pZM-^^}4O=g_C! zl8>SRxdESS^~;CAy(dl_QB2qH7?G2qJe5Phg7?bEtnU}S@v*Ty;ORvx>sz`rO-pd$)4%qFyN4Bvj71bLWced~EAHbqk7L#_*(Ag`!J+ zr4gb+e1;KiTt|uc9cBEDD$S@7E`e~TJf%cPBWgMveHMnZMc4C3c8!HB?ovaYpiIFI z@`^zT1R|!h5kwhpGV}6u*(YAOiW$1@-k! zb`MPh(Z}w`!aD1TIB6d8etSD$yRbFVWfq71*BP52bM{*qJq@P0shzpg=ZWDfBMtLW zvq2n5ReEs^Xm|!vg&i6tQqBevP9s>^&d9>a6*te!8E4SKn9zU_N~JQ0ShHags3X=L zH%LYkl}8ZEa2=mGK3YbDW`sJbgf`Qpl?_@Wd=2q~xCsfTGSN^FDhWR%%osx7o1<3f zgg%Tik==tIBtq35GorMM@sNW!#JvH3YfnS-bN(pDLq75W4!^fzm$)B8$#IFl7A5C5 zAV+-r>1q|Rfx`0(7!PCf;Bzmf!6jGVN{e;KWEInH5 z8Tn8isY)YNdF0ErRzP{9Ya9PIKNx>U+{Ra4Xq*%UhaVb~Qz}doil*E!D<qJp3iy1$aTi&F4MhSB^K%5^5&Y4Fr0NW&3&*LZ|l# zc@=-d+;<SFc0Nz~=Ts9UdEzcS_)8d}(IyHU9odTL|h>+lNEz}?hX=oSi`!^6Cy z%!l$)0p1X?82UdU+8{Jh#A=Nq)=#w$<)NxHRF#Lm^jNs++{*u)ABev#ZsmhMt?5`A zgwtZl*DmOGi3Gf6pqA=i0s!o<6`_GN))4t6-ftwm`mNLJ_3L+ONNIkuPNbRYe#!m1 zaRvK6@7J$woX>9Oh!40CT`28i$0|DxUMxc00kvzB<5946gIE`cIj*RQAZqY9Hb_l7yrhKwP#LNpFUOHcDmMirrLVu zBf0BmlS`SJoUKaPHCV<4Ed~_bn#V56P~(JGWc}_#>n%Lo?5EI99KMO(L=x@ugi)vs}&x9zOg3!F!<{iMh8A$Qgx0C+t0lAn@h3pj!$ddF-I2J|e*Q1=!`FAezxR)O zYx1*I=~*TzmH*`b-~%0^KOa-K29l;>`K)Ph0IlGfCAdFmL93>{R?_WgCaGy~E7LTJ zd{gvS+5$}=YnmRu<-koA3M(q%r~vj72$tj1cI=9*E@8zGOSlw+GQ~&(hKU6kTy|$& zlcHNQnNhSvik1jfv}O483GAcIQFM1Yfisz?nlp%PYnsZ3!5Z<+ek$_@R|_*TUh&Q&(SncVBh*`P%No)$YT~=_9rHk(JDrg}HZy>d-_@ zd9K>~+;V1rExv!Ha}ah~=z1%2)vFF3ul1g&N+)g!u`bvuhFf)t>c?%pE3F-WZk1PK zv5xLFA)aYl6~v5uOGwJ;RS_^&ySa4RogRe7Ihg2b7f0AC`M#?F16Rp+dJr1w6!(1G z-oMhi`GO9%&7Q_Kd+v-R#0OT}xkSfmOc2MGj8zcK*zdxh>-J~ZTNCQjtLX@Od}Uzg z((Wa1X=Hie!Bs&JA76QVlKp<1%3LuP_Fb8MYx`#+j5iiP9xWEd34W!ge{uKK@514+ zqdt6n-}MLn)O(}rhH;~B`CF6KM<$omqv7nwDG=&{vCy}i8u&~^d`9th3_)hV zzwy=meeEA$sQG?}uXkpQ#PbmI;Mr0%<0JvF2yoI&z!N9-<7N{2sj{S|f=+nb(Mz^} z!qyEk>)P<3Sb3kNZM+zHv-ezxn3*f41u4b1%k_61f7ru26JCwrwFmCCaG8R-5Rlv% z2k)_SvjpFj;86f~Q&{p;X5l$$n!p4UZxrh=xTB6L1TH6x11r4y;v}_9cv8A+`5Y{V zONu`WY+wWmL`HT)y@|<@WrI#8r%O=RXbmBjx%c>E@A32mjMVE0gu^-_if9m2EXVR8 zdJWzyt89JpH@FP*^E|iGGjJvT<8-Jv3{CeGUW}npnAuPvaOWEp0!&3;Gle+vt|4rt~%NU;kC-kH2QS(A5Er5#}k;@u50L|bDl z<8@*K%bOH67kS#xLs_y}M%p}2y*k3d9X>psK=;BP^f)%_wZbkkD4u$rNoX2*4UXBr zsZMa}J;3&ML4$|vU)=e@wy~Q0(0|F3*T4P#**~7W5&w_$zonNSo2*Kc?9|89G~JK; z9>C@xHixibvHUbbFJW^Q8n`O4*BzR}k#TG=b%(*4@s74FAgpm zYaINnCU{X<970$@_$a@aScT3}e(BNM>^G!{bb^-XjHj^_L#eQYx4BjI!Sn_daZL+S z`N}^tN4bw{*9(BZPw$4j$V7VzPPpFWlaX}jKf=UyoRpz~$A~trb^9WzwG36`Ly?9D z0@-kF_|Fi$$$D9R+F%JfNI;bfWnowoFomxi&+km?0t znCbhVxDJcz?8b)_nn5yc*dULrrl9DD6r&Rh@-&MOJLnWbc&NK9ERdcIYn!L33A5<^ z-fPf6=I8mF-0sg~5+D1VgXR`Cce*)#`%O;0$&KCQzIl`T7Hglm$?dzz9lD*Ei18DA wwPWZu$Dq#-$7TK~e~V-75GQY0DAd}9=37=1N&bO_CssN5S$g6&{xG5bKY+zfMF0Q* literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/encoders.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f142f006a22cf38ec0fd571f50942499205eb489 GIT binary patch literal 11059 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/exception_handlers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..193bafbdcfc9e384fd32a9bc42fd58efb3b4ef73 GIT binary patch literal 2026 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/logger.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/logger.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc66f41aa9710272d06a104411b6291ae87663b8 GIT binary patch literal 286 zcmX@j%ge<81QF|kGR=VWV-N=hn4yf%20+Gih7^Vr#vFzy1}277hAbwSA_Senw3-pZ zi(;x|)MS1M;`rTSPfIK=Ni4|JWWL3olb@cRnU{WxGd;D$2gpt>y2S<(OD$T-@EN51 zSE#d9OhHk8dQoC-E>LAmd47I!er|4RQF3a0W?orpUP*pYWlU0Ha&~H7N(_)+7UPqd z6jPj8lB!z(6irM|EslZOs1Gq(ub}c4hfQvNN@-52T@lE;AZHd!0f`UHjEs!88TcM> ZN_B`|=ajn0DK*3LGN)=ITM-9P8UPNZOzQvu literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/param_functions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63d229ad303b39cbb38b1e44147f97e322c3b774 GIT binary patch literal 36380 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/params.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/params.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c9fbeedd7a58b09333f9e65a38301e5655a0bff GIT binary patch literal 24339 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/requests.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/requests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68d72451c1c9c8587a40705e8fedfc9c6275a9df GIT binary patch literal 275 zcmX@j%ge<81QF|kGW&q^V-N=hn4pZ$GC;<3h7^Vr#vF!R#wbQc5St0eW{P5BWT<4; zWO)fvs>yhZ&m$xxz&SrJFEzO&Gd~X~!XA`bSejZ~;-|@cOQ^Ucu_!0Cq$E|Z2qIcs z#0=C}!~!H%GJFOZ@+;igDyE<)KfNe1H#ajcJ*GTAKRG`)H?=4^H9j-1EH$qrzo;@M zDKR-aH7_Lw$S;fW$xMnV&MZmQEdYuprl%Iiq$L8aD#+A_S)*4_d5gm)H$SB`C)KWq c6KD@35EpX;i4V+-jEr{~?C&uc7O?~Q0I}0e;{X5v literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/responses.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/responses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7045849b6b8e5e086ae730c94acf5cbdb6045b0 GIT binary patch literal 2403 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 C%12cI literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/templating.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/templating.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..551b871a26a1dddcfd860d05f51589f80a570165 GIT binary patch literal 249 zcmX@j%ge<81QF|kGJSybV-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zaN zUYU7WiAEu*xdl0iC8@=JnoPGuic1oUa#Bl5QuRt8;+c8rMa)1AD;Yk6^!*v_zmi1)2H?JM;=FZ*kb<=BJeAq}mm60BvFf;$jfv12ZEd<2?rFA~qlg E0Q%8L3jhEB literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/testclient.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ee748e3f221e4418357e9f0a43c84046efde3eb GIT binary patch literal 244 zcmX@j%ge<81QF|kGM#|*V-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zYX zA*sbB&N-Q>c_n_DOt(aeOA?E6QcFrw^-6#e$zX{hW}w=Y44*+-enmQ4#S|3frxzvW z=4R%l$CT&iC+FwprWPfq#%Jc00nN!Ts*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_pAi9mY_GW8L5=oM7n;;_lhPbtkwwJYKP+QbON#URE9W=2NFdkmIEY(NeGfv-k5 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/types.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..463cf7aa4a2b577a2f2be4ecc2c2c5a0ce651e33 GIT binary patch literal 853 zcmYjPO-vI(6rSzww%gi5DXm5zc%YXaEEfe+h!G2ks9+*!$fk*z?mo)K{mbkYyEl${ z<7TRC$$s|fda#j;JwU;m}4ZQkG(p=Ix;XC zc4QzO`XLxSoxm8l==ZO&VJdT)2-3mG9ZC!XWYM*n<^E2a}F0g60tHgMNxEvIe>8 z)NP%{LjZ>t&QaNC-lGz*afDw5jk1bi*NDUtB6AbvhCdBan4yXr=-BoRjl_A4zb1{< zz{kE%NRnrgZfHK0I5ibLpU`9|YZY6tf?ZYupNfX>V%kFjFa`d_hSIHzB!agJNUNG}Z6a?WjN`67Puc-79 zm42YfZ`tww#B`_86MJhtWiY$^A$zlrMm{A+cbA%TZTWq&xD!7d=2^ZO>`k{Xb)@}L zf9&!gJJS{W*}1{+{7&*vNj=tfr=Dyz#b$X=Y2{m9yWDC#D|Yf7uUqakUKRU8*9OYM vj(nIKYhG#HXs>mq+8cxX%wT-Bo9lYLa<}pN!rQ6-_{t!+IzSmR!4&@mjqdjs literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88a40c43550517d67b61c3d1f8813a809fef9c02 GIT binary patch literal 6429 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 F^uH%j2=xE} literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/shared.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/shared.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40e14a31987af4ae3c194239ab35bdef01c52602 GIT binary patch literal 9391 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 E2R@D9fB*mh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/v2.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/_compat/__pycache__/v2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c69aa7965a6f53bf32bd035d9e5e949e44813e54 GIT binary patch literal 23009 zcmc(H3vgT4dFH*q1&B95;z98JCIw0)C5ogZTed7p)LWD-QGOt@5sLRxrVKuE0m_yP zHguYHpj3^iq+KJe+tP{CP>H%>W-=S?ZfC0`ogH`5oxv4l1HPdfb(@);bapzhs5EtU zJKgU;7Z(62+DSV*yI115=kcF&&-u^!pXVI>$mz6kc%J?Drzd{*1jqdyCG^LgkF5QT ziR0ejL{8+RTv&VaVIFBi)G%ob8+pnzMukZsEKHihCYBbW=E<^f*`y_GVQEv;I%x~r zSlk@7PddU57B7oBCtYFJq&w`M^n^W=<>7LcZ;4h+dc$58w?=)F{;;3LZPCDFWw>%O z7!FQWg{xSeJz70k6Rw%84cAWAh3h8k!}XI5;RaUbKv`qBk;R>eH-(#6+=X~^xS7S> z(U!^9a4U;@qHUAy;dT};k9JIM32$NXifCxEGu+AI-sslJZQ*S!?nAsQ+{NPlX!m4K zxQE39h;I*XpWG4N!P1pT_lA2}JQ&?M*%$7c><{-(4ul7I&Po`pitd`+9p24z()RG9 z_}eS(2tOvZhaZ>R;e8XFSR>YcnHTFs9$`HT8(7%L!X_3rv#^DQtt@O~VLJ;uSh$6S zAr^MBa4QS9v9L?z*}v{Lg|GABC&V79Q`|1?mj)&GxSWS2r27T<4 zT4W(uoNHS0hSuf_h>z?%;G_e=_LF5(7IZmJg)5+^CyhEw59y4 zSj0p4(r^hj4tk$$QqeGKW-CF$cxpJDTVLUIGko#STlB=SZW%rMI{ zN^UkQX7LnC&WcZ>--BZ9rnnHqrvUS`Se%p7fZZ-VBh}>FID_(M#SuLRWzT7|hqZAQ zWnszjF{Mv`UMQ@nPe~r>8Sxov6D`?T+id>A=cMPQbCeFhAU?~!J&2Z{L(35{EWLp5 z?U&9;`I$t?r%>`~^f%uNln0S}4!NVCSc&?geMfvA-+V#j3*&wPxO(C9rto=@aQ8fG zoAM&4JI3%=%=orQIBzw0%p=5Op5qn_*ZN=PUNJt$z08Nke@65;9O6~W8R;{#($ts~GN{7X^vq?| zB1+N>#gJnaN8_Vo(a~5;bxgz}g%m0ZLsPSpcw3|LY-DV7>_sUgsMh^cQ`7O$xFo8^ z{Zp4!)7hzs=_xck8jAzg9D8w8mPEuHr-u$jMutv4d1C*_P{^p7j!umYy`nl!PK#1> zcyv-aIXa_SS?!U_Gg8Q;S_emC5-V112d1aSCoUYE7>lc>LlaU|RP6+{UmTr@OS0-1 zlO^;aGD(f$V|7nn7DuPz6Jux4%gNEh(v&2R#?i4MS)P^wP@@B!of4(-i783Uj{`6$ zc0WBDoxs>jYWNOI@nf;+DXqmLqf=s3qL#{~OQX?99G!_orKt&NiiTa0k47e9vDxzs zoyfJao*$hWpC*uer=((|$aNP}=)$aoER0>2w69`*${*^u>VGJUA&^&%XXPj`U3Ovu zI2w(rmJ3omGAdt)sWysD%M%wSXtd2QPsCr0OrT$pnds=mR0JcU(ND{f@!6>{!UCWg zFEA`dKNdzU11d*nqw#LlosUJvN5{|%mIYcIjj1m7ipdAizUx;WB-k2m$ zAbN!%Kc8uePsF2=>K~_>kFZ2U>kS%L?V=PLlP6}VpQ=TAWpr{TD#g??>6NkQtSG6r zd?Ye4t~$jDf}Nb0qT#7FQJRsZF}8fmFJg8hF}7eL(kpR!R5g#w(^sUaLN}#Ieq1A1 z`GSnPsxUD%5mzk~0&TKd_R`Cd>8a>t)uwfpu&SD6DLyMtjqyZ-`Nxbm3DC7KB6x$F z;O6*vzKG)va?dw$+?*kv7qJ|d;1Y(opabZlcg~nF7ISC$7=NuUVNCD|!(M=1YY|ZI zB7JGYgIvpoEF=?94Bj-J;X;OCEF0UXM%fIjlTv(?cmZda`o=TdJsn45VtCW39q$MLO`_=}xJFwbSnz4OO@;t3>$RZnHgws`PnXvNc)G-d6c zH?4QC#!ktuM%NJO%QYf20d#(z|e~WKFdM82_jD`QZgaN)~09-o24>QU_x9FO;jqH!xqUZ z*+jD@{s3FXYS~4LWEwY!))FPaAyKYXGU?DLx0RGTHz~K5l)G3tR9?|hlIvl)<;ZoG z}NT_w3*u}ySC1pCkrs^LN0Kf#UjV!2oW1=lN;i#{oUF{6~mDf*>K^f*XkVd+5r zZ9#rHN~%hs8AKiv8r--=to(dgxLOQ~X8fxXtJ%MrH_O)5s`kRTpb&0|b#%TEAg9rGjFFye2G7V8_tr10MOT+CY?rTKGwf`84B;LlK<0y`{1 zoZ)WpU|t%-*@k@iIRvEX#H8rB%8$mV(Z)uNjtJn2r#Q%NCW9uB8*4={&)su)UO#p9 zRL0SyIGU1t*5_Y1nfy%JvVAfBjmvLcMuZW{y0KBO*w~&${MecE{6>ADCHY2tsgT1U#Te>b8#{?X*&gg zSQ`Qi-&y{8{6UvNyDn$zi|G|mb>=)w|cW)fAVP7?R|LsgkU!QM-chfjX%M^ z!p96`L7&Nw(4fs^51J|rD7Jn;RCcAlWI*edqBf>kz{F}0l#FS+;@qAzWZmUoxUw*k zwp4w>NCr^zV@E<`-SFs^%KA~Lb|};`l#5Z_0Ju#vLZ8fSEz3hs&WHg0L0LJ_X zFa)>v_0L}YY{uQGxI0(e+tQY8pV0Yc)M1^cPi=TMc9d7`q#5S59Qh@Hm-JBXMEXia zN$2u_zd>;22w2}T?gqu(u;Ok?Tbds3SAq0tA$}}UHzED?$kfz}4INZXOb=g2(k$n5 z)WHh9gBtQeiaV6HgdXl8X+~@ThtbzJxOf3?n=vFEgZ&)O6*aNVbS{y9=^Xe`ooHaL zG}9c98pXC9`09p71i{}l>EsV+-C;+}&$9s-$#3Obn=>Q~qM0PY1!#g|8O6TJ$94J4 ziM9!7lcI(4-{!x_U+4eKJZFs4;$lxcpvMwMg2C5UKHOaRr zpd6~^i3?LOi2!RM&HVyY!=kduw9F7MGi8M|nUG7hysXuP{ecQ&FGlpV>;iyV`{Z*6 z_YaR8JrH?%==7PRr-maZj}D(Y9T_?Mt4((t{<+amUIDP`#zo;9?zh}4Roj!t?s=+Hdlk=?oY7qGx>sJ4I;NC&9esu5aI}rz+L0ctY9Anm1m({^|phvCow}c-K+?i>;ii zBjapWobA7i(Zv7$pmDIt_=6_XU}xDnK}s~p=04y2T=M$mLYILB#KAm#tmmc*G25Y{S=xLL@r*y zWM*Egkm5A#Q5(Ep<%B_Y#&U+H1 z2&)`n&JaRp5&)>pXq8Ya|0V^5SJeoYLX4C(7_WI{QnlzGSSP;q%s&NiOhhoxz>D#@iZ%*=8UIT@$@eDztfub^sabLWj(%}$>?+CIHS|`PY*1dr{O+lw7Rn1%DYuN zvz66vT)BQ_Nm{tFQrUOg`@m?Z2B^X3`Z;HCy8c(r2+&`~Xl$RWZ{psv?)MtMS-;<9 z{Jw=p^!qLoLRBDF$H<`@W%Ba?RLk;6l=~=UIe$6tc5&*Cli8`56jwcZGB5SvA=GoG zrl;Uel)p&z&3XJTAi-LcuT$(x6nvS2-$O8#UrKCI5~E}b^9UmU8bT*W2izS(!jv#4 z$`Y2F{I~LM4d%p z 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 bool: + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] + except TypeError: # pragma: no cover + if isinstance(cls, WithArgsTypes): + return False + raise # pragma: no cover + + +def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: + if lenient_issubclass(annotation, (str, bytes)): + return False + return lenient_issubclass(annotation, sequence_types) + + +def field_annotation_is_sequence(annotation: Union[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: Union[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: Union[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: Union[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: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", UserWarning) + from pydantic import v1 + return isinstance(obj, v1.BaseModel) + + +def is_pydantic_v1_model_class(cls: Any) -> bool: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", UserWarning) + from pydantic import v1 + 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/backend/venv/Lib/site-packages/fastapi/_compat/v2.py b/backend/venv/Lib/site-packages/fastapi/_compat/v2.py new file mode 100644 index 0000000..25b6814 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/_compat/v2.py @@ -0,0 +1,568 @@ +import re +import warnings +from collections.abc import Sequence +from copy import copy, deepcopy +from dataclasses import dataclass, is_dataclass +from enum import Enum +from functools import lru_cache +from typing import ( + Annotated, + Any, + Union, + cast, +) + +from fastapi._compat import 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._schema_generation_shared import ( # type: ignore[attr-defined] + GetJsonSchemaHandler as GetJsonSchemaHandler, +) +from pydantic._internal._typing_extra import eval_type_lenient +from pydantic._internal._utils import lenient_issubclass as lenient_issubclass +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, PydanticUndefinedType +from pydantic_core import Url as Url +from typing_extensions import Literal, get_args, get_origin + +try: + from pydantic_core.core_schema import ( + with_info_plain_validator_function as with_info_plain_validator_function, + ) +except ImportError: # pragma: no cover + from pydantic_core.core_schema import ( + general_plain_validator_function as with_info_plain_validator_function, # noqa: F401 + ) + +RequiredParam = PydanticUndefined +Undefined = PydanticUndefined +UndefinedType = PydanticUndefinedType +evaluate_forwardref = eval_type_lenient +Validator = Any + +# 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, + } + + +class BaseConfig: + pass + + +class ErrorWrapper(Exception): + pass + + +@dataclass +class ModelField: + field_info: FieldInfo + name: str + mode: Literal["validation", "serialization"] = "validation" + config: Union[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) -> Union[str, None]: + va = self.field_info.validation_alias + if isinstance(va, str) and va: + return va + return None + + @property + def serialization_alias(self) -> Union[str, None]: + sa = self.field_info.serialization_alias + return sa or None + + @property + def required(self) -> bool: + return self.field_info.is_required() + + @property + def default(self) -> Any: + return self.get_default() + + @property + def type_(self) -> Any: + return self.field_info.annotation + + 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 dropping support for Python 3.8 and + # setting the min Pydantic to v2.12.3 that adds asdict() + 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], + 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[Union[int, str], ...] = (), + ) -> tuple[Any, Union[list[dict[str, Any]], None]]: + try: + return ( + self._type_adapter.validate_python(value, from_attributes=True), + None, + ) + 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: Union[IncEx, None] = None, + exclude: Union[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 __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: Union[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.type_ for f in fields} + unique_flat_model_fields = { + f for f in flat_model_fields if f.type_ 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 + new_mapping, new_definitions = _remap_definitions_and_field_mappings( + model_name_map=model_name_map, + definitions=definitions, # type: ignore[arg-type] + field_mapping=field_mapping, + ) + return new_mapping, new_definitions + + +def _replace_refs( + *, + schema: dict[str, Any], + old_name_to_new_name_map: dict[str, str], +) -> dict[str, Any]: + new_schema = deepcopy(schema) + for key, value in new_schema.items(): + if key == "$ref": + value = schema["$ref"] + if isinstance(value, str): + ref_name = schema["$ref"].split("/")[-1] + if ref_name in old_name_to_new_name_map: + new_name = old_name_to_new_name_map[ref_name] + new_schema["$ref"] = REF_TEMPLATE.format(model=new_name) + continue + if isinstance(value, dict): + new_schema[key] = _replace_refs( + schema=value, + old_name_to_new_name_map=old_name_to_new_name_map, + ) + elif isinstance(value, list): + new_value = [] + for item in value: + if isinstance(item, dict): + new_item = _replace_refs( + schema=item, + old_name_to_new_name_map=old_name_to_new_name_map, + ) + new_value.append(new_item) + + else: + new_value.append(item) + new_schema[key] = new_value + return new_schema + + +def _remap_definitions_and_field_mappings( + *, + model_name_map: ModelNameMap, + definitions: dict[str, Any], + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], +) -> tuple[ + dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], + dict[str, Any], +]: + old_name_to_new_name_map = {} + for field_key, schema in field_mapping.items(): + model = field_key[0].type_ + if model not in model_name_map or "$ref" not in schema: + continue + new_name = model_name_map[model] + old_name = schema["$ref"].split("/")[-1] + if old_name in {f"{new_name}-Input", f"{new_name}-Output"}: + continue + old_name_to_new_name_map[old_name] = new_name + + new_field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ] = {} + for field_key, schema in field_mapping.items(): + new_schema = _replace_refs( + schema=schema, + old_name_to_new_name_map=old_name_to_new_name_map, + ) + new_field_mapping[field_key] = new_schema + + new_definitions = {} + for key, value in definitions.items(): + if key in old_name_to_new_name_map: + new_key = old_name_to_new_name_map[key] + else: + new_key = key + new_value = _replace_refs( + schema=value, + old_name_to_new_name_map=old_name_to_new_name_map, + ) + new_definitions[new_key] = new_value + return new_field_mapping, new_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 is_sequence_field(field: ModelField) -> bool: + return shared.field_annotation_is_sequence(field.field_info.annotation) + + +def is_scalar_sequence_field(field: ModelField) -> bool: + return shared.field_annotation_is_scalar_sequence(field.field_info.annotation) + + +def is_bytes_field(field: ModelField) -> bool: + return shared.is_bytes_or_nonable_bytes_annotation(field.type_) + + +def is_bytes_sequence_field(field: ModelField) -> bool: + return shared.is_bytes_sequence_annotation(field.type_) + + +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] + return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index] + + +def get_missing_field_error(loc: tuple[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] + + +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] + 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) # type: ignore[return-value] + + +# Duplicate of several schema functions from Pydantic v1 to make them compatible with +# Pydantic v2 and allow mixing the models + +TypeModelOrEnum = Union[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_compat_model_name_map(fields: list[ModelField]) -> ModelNameMap: + all_flat_models = set() + + v2_model_fields = [field for field in fields if isinstance(field, ModelField)] + v2_flat_models = get_flat_models_from_fields(v2_model_fields, known_models=set()) + all_flat_models = all_flat_models.union(v2_flat_models) # type: ignore[arg-type] + + model_name_map = get_model_name_map(all_flat_models) # type: ignore[arg-type] + return model_name_map + + +def get_flat_models_from_model( + model: type["BaseModel"], known_models: Union[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)) and arg not in known_models: + known_models.add(arg) + 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.type_ + 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[Union[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/backend/venv/Lib/site-packages/fastapi/applications.py b/backend/venv/Lib/site-packages/fastapi/applications.py new file mode 100644 index 0000000..54175cb --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/applications.py @@ -0,0 +1,4669 @@ +from collections.abc import Awaitable, Coroutine, Sequence +from enum import Enum +from typing import ( + Annotated, + Any, + Callable, + Optional, + TypeVar, + Union, +) + +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[ + Optional[list[BaseRoute]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[list[dict[str, Any]]], + 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[ + Optional[list[dict[str, Union[str, Any]]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[Sequence[Middleware]], + 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[ + Optional[ + dict[ + Union[int, type[Exception]], + Callable[[Request, Any], Coroutine[Any, Any, Response]], + ] + ], + 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[ + Optional[Sequence[Callable[[], Any]]], + 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[ + Optional[Sequence[Callable[[], Any]]], + 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[ + Optional[Lifespan[AppType]], + 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[ + Optional[str], + 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[ + Optional[dict[str, Union[str, Any]]], + 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[ + Optional[dict[str, Union[str, Any]]], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[list[BaseRoute]], + 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[ + Optional[routing.APIRouter], + 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[ + Optional[bool], + 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/). + """ + ), + ] = 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[ + Optional[dict[str, Any]], + 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. + """ + ), + ] = True, + openapi_external_docs: Annotated[ + Optional[dict[str, Any]], + 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, + **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: Optional[dict[str, Any]] = 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, + ) + self.exception_handlers: dict[ + Any, Callable[[Request, Any], Union[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 + ) + self.exception_handlers.setdefault( + WebSocketRequestValidationError, + # Starlette still has incorrect type specification for the handlers + websocket_request_validation_exception_handler, # type: ignore + ) + + self.user_middleware: list[Middleware] = ( + [] if middleware is None else list(middleware) + ) + self.middleware_stack: Union[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/). + """ + if not self.openapi_schema: + 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, + ) + return self.openapi_schema + + def setup(self) -> None: + if self.openapi_url: + urls = (server_data.get("url") for server_data in self.servers) + server_urls = {url for url in urls if url} + + async def openapi(req: Request) -> JSONResponse: + root_path = req.scope.get("root_path", "").rstrip("/") + if root_path not in server_urls: + if root_path and self.root_path_in_servers: + self.servers.insert(0, {"url": root_path}) + server_urls.add(root_path) + return JSONResponse(self.openapi()) + + 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: Optional[int] = None, + tags: Optional[list[Union[str, Enum]]] = None, + dependencies: Optional[Sequence[Depends]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + response_description: str = "Successful Response", + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + deprecated: Optional[bool] = None, + methods: Optional[list[str]] = None, + operation_id: Optional[str] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Union[type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), + name: Optional[str] = None, + openapi_extra: Optional[dict[str, Any]] = 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 api_route( + self, + path: str, + *, + response_model: Any = Default(None), + status_code: Optional[int] = None, + tags: Optional[list[Union[str, Enum]]] = None, + dependencies: Optional[Sequence[Depends]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + response_description: str = "Successful Response", + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + deprecated: Optional[bool] = None, + methods: Optional[list[str]] = None, + operation_id: Optional[str] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Optional[str] = None, + openapi_extra: Optional[dict[str, Any]] = 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: Optional[str] = None, + *, + dependencies: Optional[Sequence[Depends]] = 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[ + Optional[str], + Doc( + """ + A name for the WebSocket. Only used internally. + """ + ), + ] = None, + *, + dependencies: Annotated[ + Optional[Sequence[Depends]], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + 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[ + Optional[list[BaseRoute]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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: Union[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) + + 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[ + Union[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/backend/venv/Lib/site-packages/fastapi/background.py b/backend/venv/Lib/site-packages/fastapi/background.py new file mode 100644 index 0000000..20803ba --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/background.py @@ -0,0 +1,60 @@ +from typing import Annotated, Any, Callable + +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/backend/venv/Lib/site-packages/fastapi/cli.py b/backend/venv/Lib/site-packages/fastapi/cli.py new file mode 100644 index 0000000..8d3301e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/cli.py @@ -0,0 +1,13 @@ +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/backend/venv/Lib/site-packages/fastapi/concurrency.py b/backend/venv/Lib/site-packages/fastapi/concurrency.py new file mode 100644 index 0000000..76a5a2e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/concurrency.py @@ -0,0 +1,41 @@ +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/backend/venv/Lib/site-packages/fastapi/datastructures.py b/backend/venv/Lib/site-packages/fastapi/datastructures.py new file mode 100644 index 0000000..2bf5fdb --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/datastructures.py @@ -0,0 +1,183 @@ +from collections.abc import Mapping +from typing import ( + Annotated, + Any, + BinaryIO, + Callable, + Optional, + 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[Optional[str], Doc("The original file name.")] + size: Annotated[Optional[int], Doc("The size of the file in bytes.")] + headers: Annotated[Headers, Doc("The headers of the request.")] + content_type: Annotated[ + Optional[str], 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", "format": "binary"} + + @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 diff --git a/backend/venv/Lib/site-packages/fastapi/dependencies/__init__.py b/backend/venv/Lib/site-packages/fastapi/dependencies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15c710bfdeabfa26df5805720bb4d0d71311a3c2 GIT binary patch literal 197 zcmX@j%ge<81QF|kGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!N^!P|DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_pAiNz&}1)2IOsRck)sd>qnsm1#7K>e8|@$q^EmA5!-a`RJ4b5iY!Sb>%@0&y{j O@sXL4k+Fyw$N~V)a5sYh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c82830f73d7fdd8fd86c3370c1e532fb6cb6c919 GIT binary patch literal 9214 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/dependencies/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7ad3e26b1ce588a55180e034e5ddb7ccba0955d GIT binary patch literal 39922 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/dependencies/models.py b/backend/venv/Lib/site-packages/fastapi/dependencies/models.py new file mode 100644 index 0000000..5839232 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/dependencies/models.py @@ -0,0 +1,193 @@ +import inspect +import sys +from dataclasses import dataclass, field +from functools import cached_property, partial +from typing import Any, Callable, Optional, Union + +from fastapi._compat import ModelField +from fastapi.security.base import SecurityBase +from fastapi.types import DependencyCacheKey +from typing_extensions import Literal + +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: Optional[Callable[..., Any]]) -> 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: Optional[str] = None + call: Optional[Callable[..., Any]] = None + request_param_name: Optional[str] = None + websocket_param_name: Optional[str] = None + http_connection_param_name: Optional[str] = None + response_param_name: Optional[str] = None + background_tasks_param_name: Optional[str] = None + security_scopes_param_name: Optional[str] = None + own_oauth_scopes: Optional[list[str]] = None + parent_oauth_scopes: Optional[list[str]] = None + use_cache: bool = True + path: Optional[str] = None + scope: Union[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) -> Union[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/backend/venv/Lib/site-packages/fastapi/dependencies/utils.py b/backend/venv/Lib/site-packages/fastapi/dependencies/utils.py new file mode 100644 index 0000000..45e1ff3 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/dependencies/utils.py @@ -0,0 +1,1021 @@ +import dataclasses +import inspect +import sys +from collections.abc import Coroutine, Mapping, Sequence +from contextlib import AsyncExitStack, contextmanager +from copy import copy, deepcopy +from dataclasses import dataclass +from typing import ( + Annotated, + Any, + Callable, + ForwardRef, + Optional, + Union, + cast, +) + +import anyio +from fastapi import params +from fastapi._compat import ( + ModelField, + RequiredParam, + Undefined, + _regenerate_error_with_loc, + copy_field_info, + create_body_model, + evaluate_forwardref, + field_annotation_is_scalar, + get_cached_model_fields, + get_missing_field_error, + is_bytes_field, + is_bytes_sequence_field, + is_scalar_field, + is_scalar_sequence_field, + is_sequence_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 +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_extensions import Literal, get_args, get_origin + +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 __version__ # type: ignore[no-redef,import-untyped] + + 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: Optional[list[DependencyCacheKey]] = None, + parent_oauth_scopes: Optional[list[str]] = 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.type_, BaseModel): + fields_to_extract = get_cached_model_fields(first_field.type_) + 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: + if sys.version_info >= (3, 10): + 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 + signature = inspect.signature(call) + 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) + + +def get_dependant( + *, + path: str, + call: Callable[..., Any], + name: Optional[str] = None, + own_oauth_scopes: Optional[list[str]] = None, + parent_oauth_scopes: Optional[list[str]] = None, + use_cache: bool = True, + scope: Union[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 + raise DependencyScopeError( + f'The dependency "{dependant.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 +) -> Optional[bool]: + 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: Optional[params.Depends] + field: Optional[ModelField] + + +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 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: Union[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, # type: ignore[arg-type] + 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 # type: ignore[assignment] + 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 + if lenient_issubclass( + type_annotation, + ( + Request, + WebSocket, + HTTPConnection, + Response, + StarletteBackgroundTasks, + SecurityScopes, + ), + ): + assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}" + 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, + required=field_info.default in (RequiredParam, Undefined), + 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 is_scalar_sequence_field(field) + or ( + lenient_issubclass(field.type_, BaseModel) + # For Pydantic v1 + and getattr(field, "shape", 1) == 1 + ) + ) + + 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: Optional[StarletteBackgroundTasks] + response: Response + dependency_cache: dict[DependencyCacheKey, Any] + + +async def solve_dependencies( + *, + request: Union[Request, WebSocket], + dependant: Dependant, + body: Optional[Union[dict[str, Any], FormData]] = None, + background_tasks: Optional[StarletteBackgroundTasks] = None, + response: Optional[Response] = None, + dependency_overrides_provider: Optional[Any] = None, + dependency_cache: Optional[dict[DependencyCacheKey, Any]] = 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.required: + return None, [get_missing_field_error(loc=loc)] + else: + return deepcopy(field.default), [] + v_, errors_ = field.validate(value, values, loc=loc) + if isinstance(errors_, list): + new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=()) + return None, new_errors + else: + return v_, [] + + +def _get_multidict_value( + field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None +) -> Any: + alias = alias or get_validation_alias(field) + if is_sequence_field(field) 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 (is_sequence_field(field) and len(value) == 0) + ): + if field.required: + return + else: + return deepcopy(field.default) + return value + + +def request_params_to_args( + fields: Sequence[ModelField], + received_params: Union[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.type_, BaseModel): + fields_to_extract = get_cached_model_fields(first_field.type_) + 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 key in received_params.keys(): + if key not in processed_keys: + if hasattr(received_params, "getlist"): + 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.type_, BaseModel) + and not is_union_of_base_models(first_field.type_) + ): + 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_field(field) + and isinstance(value, UploadFile) + ): + value = await value.read() + elif ( + is_bytes_sequence_field(field) + and isinstance(field_info, params.File) + and value_is_sequence(value) + ): + # For types + assert isinstance(value, sequence_types) + results: list[Union[bytes, str]] = [] + + async def process_fn( + fn: Callable[[], Coroutine[Any, Any, Any]], + ) -> None: + result = await fn() + results.append(result) # noqa: B023 + + async with anyio.create_task_group() as tg: + for sub_value in value: + tg.start_soon(process_fn, 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: Optional[Union[dict[str, Any], FormData]], + 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.type_, BaseModel) + and isinstance(received_body, FormData) + ): + fields_to_extract = get_cached_model_fields(first_field.type_) + + 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: Optional[Any] = None + if body_to_process is not None: + 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 +) -> Optional[ModelField]: + """ + 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.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, + required=required, + 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/backend/venv/Lib/site-packages/fastapi/encoders.py b/backend/venv/Lib/site-packages/fastapi/encoders.py new file mode 100644 index 0000000..e8610c9 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/encoders.py @@ -0,0 +1,346 @@ +import dataclasses +import datetime +from collections import defaultdict, deque +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, Callable, Optional, Union +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.color import Color +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, +) + + +# Taken from Pydantic v1 as is +def isoformat(o: Union[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) -> Union[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, + 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[ + Optional[IncEx], + Doc( + """ + Pydantic's `include` parameter, passed to Pydantic models to set the + fields to include. + """ + ), + ] = None, + exclude: Annotated[ + Optional[IncEx], + 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[ + Optional[dict[Any, Callable[[Any], Any]]], + 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) + if exclude is not None and not isinstance(exclude, (set, dict)): + exclude = set(exclude) + 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/backend/venv/Lib/site-packages/fastapi/exception_handlers.py b/backend/venv/Lib/site-packages/fastapi/exception_handlers.py new file mode 100644 index 0000000..475dd7b --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/exception_handlers.py @@ -0,0 +1,34 @@ +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/backend/venv/Lib/site-packages/fastapi/exceptions.py b/backend/venv/Lib/site-packages/fastapi/exceptions.py new file mode 100644 index 0000000..1a3abd8 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/exceptions.py @@ -0,0 +1,246 @@ +from collections.abc import Sequence +from typing import Annotated, Any, Optional, TypedDict, Union + +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. + """ + ), + ], + detail: Annotated[ + Any, + Doc( + """ + Any data to be sent to the client in the `detail` key of the JSON + response. + """ + ), + ] = None, + headers: Annotated[ + Optional[dict[str, str]], + Doc( + """ + Any headers to send to the client in the response. + """ + ), + ] = 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[ + Union[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: Optional[EndpointContext] = 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: Optional[EndpointContext] = None, + ) -> None: + super().__init__(errors, endpoint_ctx=endpoint_ctx) + self.body = body + + +class WebSocketRequestValidationError(ValidationException): + def __init__( + self, + errors: Sequence[Any], + *, + endpoint_ctx: Optional[EndpointContext] = None, + ) -> None: + super().__init__(errors, endpoint_ctx=endpoint_ctx) + + +class ResponseValidationError(ValidationException): + def __init__( + self, + errors: Sequence[Any], + *, + body: Any = None, + endpoint_ctx: Optional[EndpointContext] = 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/backend/venv/Lib/site-packages/fastapi/logger.py b/backend/venv/Lib/site-packages/fastapi/logger.py new file mode 100644 index 0000000..5b2c4ad --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/logger.py @@ -0,0 +1,3 @@ +import logging + +logger = logging.getLogger("fastapi") diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/__init__.py b/backend/venv/Lib/site-packages/fastapi/middleware/__init__.py new file mode 100644 index 0000000..620296d --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/__init__.py @@ -0,0 +1 @@ +from starlette.middleware import Middleware as Middleware diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4181219f15779cfba16740448933613aa55575c GIT binary patch literal 253 zcmX@j%ge<81QF|kGOd90V-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zYX zzL_a0IjQA|MX7$8Ot(aeOA?E6QcFrw^>X17Ma)38D;Yk6wERkPwu&hz%1fFdkQl35q9Xu19fMX#K-FuRNmsS$<0qG%}KQ@;s9F72*kx8#s_9bM#g&#mPKqp F4ge+JNmT#< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/asyncexitstack.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/middleware/__pycache__/asyncexitstack.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..480ffc37785801e7c12120722134d9913700e3a8 GIT binary patch literal 1488 zcmah}U1%It6h3!;cQ>2HW)stjmJOTQjI`+nBBfH4p@tyUJTxM9Sr{fWH*xID?s{jE z&FU7436h6CSi#1}JX(U{yFQq=f-jaT2}6Z|59-_M3Jv0e=gjP;_CY-CJ@?%2-h1Yp z@0`8g4G!i2QF-p?iJF^o(9S94gF(ij)O6=Q1w45?5T=RhBeY-N1-kjccyXbvMH^37&DY z8%ibHQjCH4#FK%%;kmBQo3`MwY-2Ear(TQrT4dGifXABP(Tb?eJ90l1oGCwAcZ;aD zpv~G~p_NKo!WHYUT5y-m8Dz`HG&rWVCKW0vL5r$X| zld9>WS4GSZ%hzuqI-=uP$I*R=>IyIcbPg~)xk z*HG!XR8wQ(j{0vbweg13mUoC%lyz*_#HXD4Od1%mev__CPkxg@3ogK|S8$Bs$d+Il zk~5gkoy5llP$6VZiNQ6@gwC(Y*PzM1kef^#!%rHrppPfzPReYkVu%1@QH+opMTNXk zJwi$W%U>*trwGN`IJWQqPi@j8 zDV^-oI^y^ooa{BK^|(N1s`z$NYSyoVYSA4Sbmi69>?Wa3}`YV>hNQmQT z35^s{DX7`R2~>AM43kZ?3Top-(Nhv$MzsM43+IygAUoJq5%1(> zb$WZY12}y(mrUQzB-6cD|0FQ=Pp;>UOq}bz9KN@hG(bFr`3Rp!5ub`$4IU;jr$Hv+ xCXptAoucTDf{inm(xhJ&X17ddc}k#YN0OO)D8bgY^E2bGC{p zD9TSSO3cm8%uA0c&(BZJ&&^FON=}W>%qvUHE6Fdaj7dsN&Q8rsi2?GX17dg)b}1x3t2O)D8bgY^E2bGC{p zD9TSSO3cm8%uA0c&(BZJ&&^FON=}W>%qvUHE6Fdaj7dsN&Q8rsi2?GDrl2T4y(lp^H#09iraV7CIX^cywJ13?J~OW@HLoPUs4^xgF*!Rm zFC_-ZFN^WXOo}PaEJ@WZ0E#B2rxwSgB?4_N$ka#JsE=Z!UP0w84x8Nkl+v73yCM#t Zy^KIy3<`)3%#4hT-X17dgaCGnMKS%O)D8bgY^E2bGC{p zD9TSSO3cm8%uA0c&(BZJ&&^FON=}W>%qvUHE6Fdaj7dsN&Q8rsi2?G 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/backend/venv/Lib/site-packages/fastapi/middleware/cors.py b/backend/venv/Lib/site-packages/fastapi/middleware/cors.py new file mode 100644 index 0000000..8dfaad0 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/cors.py @@ -0,0 +1 @@ +from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/gzip.py b/backend/venv/Lib/site-packages/fastapi/middleware/gzip.py new file mode 100644 index 0000000..bbeb2cc --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/gzip.py @@ -0,0 +1 @@ +from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py b/backend/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py new file mode 100644 index 0000000..b7a3d8e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/httpsredirect.py @@ -0,0 +1,3 @@ +from starlette.middleware.httpsredirect import ( # noqa + HTTPSRedirectMiddleware as HTTPSRedirectMiddleware, +) diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/trustedhost.py b/backend/venv/Lib/site-packages/fastapi/middleware/trustedhost.py new file mode 100644 index 0000000..08d7e03 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/trustedhost.py @@ -0,0 +1,3 @@ +from starlette.middleware.trustedhost import ( # noqa + TrustedHostMiddleware as TrustedHostMiddleware, +) diff --git a/backend/venv/Lib/site-packages/fastapi/middleware/wsgi.py b/backend/venv/Lib/site-packages/fastapi/middleware/wsgi.py new file mode 100644 index 0000000..c4c6a79 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/middleware/wsgi.py @@ -0,0 +1 @@ +from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/__init__.py b/backend/venv/Lib/site-packages/fastapi/openapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b80dc6ed5950e4640cc0b6c1d35a8b8c1c5caf37 GIT binary patch literal 192 zcmX@j%ge<81QF|kGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!ig&h(DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_pAiNz&}1)2K!1*v%;Iv%Jsvm`!Vub}c4hfQvNN@-52T@fqLK1Lue1~EP|Gcqz3 HF#}lul~Xl? literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..064fd305b021599b216079f1d521eaeb5a3e76f8 GIT binary patch literal 362 zcmZur&r1S96rOQSLbMR{)~zlcZ0`|*xl=1>E;^CPz_#vAy5!C*J7#DE^;bmaPF?y( zx^$Ge_74Q!I`tOn)`R!n_v7$=@5N#s!3^Gd;WPZtl>ANR7p%(wp3npZ=mif^fQLB9 z3^NO(nyu%+(#8p)+HlUO&f275>8#W3Q@!CdXw%j?i?j(P%gV0l%P5wDiNylk7D0xNewDb36 z^MJ*P94B5Bg<{NZrG)H=Cq8#WF^2{+S+J4kUvm*K;B(dvM@)q?UW-BX#$2&0PtCkI zG-b?1`h6)tfb#qCLT?^I!<#9uCtDDRVO0grmw_?XW%7YatK!~6ezjeDEF=YRegKeU BZjk^0 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/docs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32524ab12415281691a544f2b2409714a4bafdf9 GIT binary patch literal 10796 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 W6|9Fp^}p})o&MX!Zv_12rv5(>xN#f+ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/openapi/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c7709bbbe6c0ee372808c420ddc5db49e023004 GIT binary patch literal 22799 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 z z`xt_l9WG55^Iw0%@Y#r z;M^!ERJv4?eUot_59i>o=>U591}bO696RRJmG&E=#Y@Z1XlB$%DC9q4_A6Z&EH|+k25w8vPZZ79N`{2@0^Dc0FM_+kxls9Nw^ny0DGO@NF z&UMcEZv@u|z7a&Z$g{@Ye!0-tBQ*AWV(H!XfNOmKFWQu^+gS8o+v@SpY!vMk_a71H zJ!{&W7jEy+Kex^qal5$+kwU2z_-cxL&oS|ZratFV0aGm?c!BqqH^UCcvWi8Yv zmR+QujlV=cn+xu4P*82YTn!L{<=FaQw%c+Bi#GAaK}i*)bIeetAL{? zD41ui&7wgjO-xBrpj@c@K?3+23B9E=0Uj)+hMExMQUSRMDO;XU8Xy-DC0c*-bnerGEpi&Q!C&FLskpDnIZ%KjP zfPKNkq~uUa%BLhQi1~F&KHfx3bLawC$&-ghEJetwxG>|X*r@g$mn3Sz~-@t0*{P_nM`y&h-z%6ClAlX{T7KB`sY)s?`BC}cJ zC=l~nl0C?Q!v*e+R9b*ZSk$Ogs%^^oca-h#DEp^Wnoj0Cr$9SOn}KgOv~Hdh z?8Csi?-~Vq?-RSxrT@%HIohB2>zdR#Do_klwpPIR*hq_>MuIT7KA-Cv6+)vq&jG;W zG8Z*^m;Q;t+yNCL#Rkgi2d7}sQZHH{0vA4-pVS$mQ0814TX(I`uGin1e2RlDx_zo4 z(cM_o!27YzygIa|S-Y@iym=7*B!qV3!e;BnD<9ZEWtg+{3A$ZRbpTd8s-n93KC>TJ zsl1Qv^+g>l)GLu)~(L3x93_82@QvHw!?z)$o-)QngaNJo*N16`lqyc$_euN_-`>t?T@^FMVEkY87mCc~=WV;V15(UGDK5~Wr# z_DeL1;BuQ7gC=dO%-Z0(W^K>S1wq&N)PdQ@RaVtSm1y%6Y$3rGDr!iw1AM$O@>pkl zs>4Vzq*3kK^c7-zh1gy&r>l0|A0)2_gP;ag?J8P*Do+&_Od%3{j~=?O`HPbz{#a*P zZCy>Tc6|BQkj9?k7@@J_O|`1;vBg=i1O!Wz`v*6N?rQE{xNH0ntZ91%-M*(TQZu6qs(dgf;T{^? zht)s=N6;zgJWsI%s7HaxrLkFTZhPE2Aa?bM`woiHPH||Dxc2~DJ{5ZhK5KeSrFud2 z*kUW{NDKyMa}*7794rI=qDhXMDVuj~_U7wFi=2j=c@68Ww;GFea@t1KdE}1RPCtl8O}@jn%2{|QbnJfu9xc#Zs;~` content, normally shown in the browser tab. + """ + ), + ], + swagger_js_url: Annotated[ + str, + Doc( + """ + The URL to use to load the Swagger UI JavaScript. + + It is normally set to a CDN URL. + """ + ), + ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js", + swagger_css_url: Annotated[ + str, + Doc( + """ + The URL to use to load the Swagger UI CSS. + + It is normally set to a CDN URL. + """ + ), + ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css", + swagger_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", + oauth2_redirect_url: Annotated[ + Optional[str], + Doc( + """ + The OAuth2 redirect URL, it is normally automatically handled by FastAPI. + """ + ), + ] = None, + init_oauth: Annotated[ + Optional[dict[str, Any]], + Doc( + """ + A dictionary with Swagger UI OAuth2 initialization configurations. + """ + ), + ] = None, + swagger_ui_parameters: Annotated[ + Optional[dict[str, Any]], + Doc( + """ + Configuration parameters for Swagger UI. + + It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters]. + """ + ), + ] = None, +) -> HTMLResponse: + """ + Generate and return the HTML that loads Swagger UI for the interactive + API docs (normally served at `/docs`). + + You would only call this function yourself if you needed to override some parts, + for example the URLs to use to load Swagger UI's JavaScript and CSS. + + Read more about it in the + [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/) + and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). + """ + current_swagger_ui_parameters = swagger_ui_default_parameters.copy() + if swagger_ui_parameters: + current_swagger_ui_parameters.update(swagger_ui_parameters) + + html = f""" + + + + + + {title} + + +

        + + + + + + """ + 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`. + """ + ), + ], + title: Annotated[ + str, + Doc( + """ + The HTML `` content, normally shown in the browser tab. + """ + ), + ], + redoc_js_url: Annotated[ + str, + Doc( + """ + The URL to use to load the ReDoc JavaScript. + + It is normally set to a CDN URL. + """ + ), + ] = "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/backend/venv/Lib/site-packages/fastapi/openapi/models.py b/backend/venv/Lib/site-packages/fastapi/openapi/models.py new file mode 100644 index 0000000..ac6a6d5 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/openapi/models.py @@ -0,0 +1,438 @@ +from collections.abc import Iterable, Mapping +from enum import Enum +from typing import Annotated, Any, Callable, 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 Literal, 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 + @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: Optional[str] = None + url: Optional[AnyUrl] = None + email: Optional[EmailStr] = None + + +class License(BaseModelWithConfig): + name: str + identifier: Optional[str] = None + url: Optional[AnyUrl] = None + + +class Info(BaseModelWithConfig): + title: str + summary: Optional[str] = None + description: Optional[str] = None + termsOfService: Optional[str] = None + contact: Optional[Contact] = None + license: Optional[License] = None + version: str + + +class ServerVariable(BaseModelWithConfig): + enum: Annotated[Optional[list[str]], Field(min_length=1)] = None + default: str + description: Optional[str] = None + + +class Server(BaseModelWithConfig): + url: Union[AnyUrl, str] + description: Optional[str] = None + variables: Optional[dict[str, ServerVariable]] = None + + +class Reference(BaseModel): + ref: str = Field(alias="$ref") + + +class Discriminator(BaseModel): + propertyName: str + mapping: Optional[dict[str, str]] = None + + +class XML(BaseModelWithConfig): + name: Optional[str] = None + namespace: Optional[str] = None + prefix: Optional[str] = None + attribute: Optional[bool] = None + wrapped: Optional[bool] = None + + +class ExternalDocumentation(BaseModelWithConfig): + description: Optional[str] = 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_: Optional[str] = Field(default=None, alias="$schema") + vocabulary: Optional[str] = Field(default=None, alias="$vocabulary") + id: Optional[str] = Field(default=None, alias="$id") + anchor: Optional[str] = Field(default=None, alias="$anchor") + dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") + ref: Optional[str] = Field(default=None, alias="$ref") + dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") + defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") + comment: Optional[str] = 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: Optional[list["SchemaOrBool"]] = None + anyOf: Optional[list["SchemaOrBool"]] = None + oneOf: Optional[list["SchemaOrBool"]] = 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: Optional[dict[str, "SchemaOrBool"]] = None + prefixItems: Optional[list["SchemaOrBool"]] = None + # TODO: uncomment and remove below when deprecating Pydantic v1 + # It generates a list of schemas for tuples, before prefixItems was available + # items: Optional["SchemaOrBool"] = None + items: Optional[Union["SchemaOrBool", list["SchemaOrBool"]]] = None + contains: Optional["SchemaOrBool"] = None + properties: Optional[dict[str, "SchemaOrBool"]] = None + patternProperties: Optional[dict[str, "SchemaOrBool"]] = 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: Optional[Union[SchemaType, list[SchemaType]]] = None + enum: Optional[list[Any]] = None + const: Optional[Any] = None + multipleOf: Optional[float] = Field(default=None, gt=0) + maximum: Optional[float] = None + exclusiveMaximum: Optional[float] = None + minimum: Optional[float] = None + exclusiveMinimum: Optional[float] = None + maxLength: Optional[int] = Field(default=None, ge=0) + minLength: Optional[int] = Field(default=None, ge=0) + pattern: Optional[str] = None + maxItems: Optional[int] = Field(default=None, ge=0) + minItems: Optional[int] = Field(default=None, ge=0) + uniqueItems: Optional[bool] = None + maxContains: Optional[int] = Field(default=None, ge=0) + minContains: Optional[int] = Field(default=None, ge=0) + maxProperties: Optional[int] = Field(default=None, ge=0) + minProperties: Optional[int] = Field(default=None, ge=0) + required: Optional[list[str]] = None + dependentRequired: Optional[dict[str, set[str]]] = 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: Optional[str] = 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: Optional[str] = None + contentMediaType: Optional[str] = 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: Optional[str] = None + description: Optional[str] = None + default: Optional[Any] = None + deprecated: Optional[bool] = None + readOnly: Optional[bool] = None + writeOnly: Optional[bool] = None + examples: Optional[list[Any]] = None + # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object + # Schema Object + discriminator: Optional[Discriminator] = None + xml: Optional[XML] = None + externalDocs: Optional[ExternalDocumentation] = None + example: Annotated[ + Optional[Any], + 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 = Union[Schema, bool] + + +class Example(TypedDict, total=False): + summary: Optional[str] + description: Optional[str] + value: Optional[Any] + externalValue: Optional[AnyUrl] + + __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] + + +class ParameterInType(Enum): + query = "query" + header = "header" + path = "path" + cookie = "cookie" + + +class Encoding(BaseModelWithConfig): + contentType: Optional[str] = None + headers: Optional[dict[str, Union["Header", Reference]]] = None + style: Optional[str] = None + explode: Optional[bool] = None + allowReserved: Optional[bool] = None + + +class MediaType(BaseModelWithConfig): + schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") + example: Optional[Any] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None + encoding: Optional[dict[str, Encoding]] = None + + +class ParameterBase(BaseModelWithConfig): + description: Optional[str] = None + required: Optional[bool] = None + deprecated: Optional[bool] = None + # Serialization rules for simple scenarios + style: Optional[str] = None + explode: Optional[bool] = None + allowReserved: Optional[bool] = None + schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") + example: Optional[Any] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None + # Serialization rules for more complex scenarios + content: Optional[dict[str, MediaType]] = None + + +class Parameter(ParameterBase): + name: str + in_: ParameterInType = Field(alias="in") + + +class Header(ParameterBase): + pass + + +class RequestBody(BaseModelWithConfig): + description: Optional[str] = None + content: dict[str, MediaType] + required: Optional[bool] = None + + +class Link(BaseModelWithConfig): + operationRef: Optional[str] = None + operationId: Optional[str] = None + parameters: Optional[dict[str, Union[Any, str]]] = None + requestBody: Optional[Union[Any, str]] = None + description: Optional[str] = None + server: Optional[Server] = None + + +class Response(BaseModelWithConfig): + description: str + headers: Optional[dict[str, Union[Header, Reference]]] = None + content: Optional[dict[str, MediaType]] = None + links: Optional[dict[str, Union[Link, Reference]]] = None + + +class Operation(BaseModelWithConfig): + tags: Optional[list[str]] = None + summary: Optional[str] = None + description: Optional[str] = None + externalDocs: Optional[ExternalDocumentation] = None + operationId: Optional[str] = None + parameters: Optional[list[Union[Parameter, Reference]]] = None + requestBody: Optional[Union[RequestBody, Reference]] = None + # Using Any for Specification Extensions + responses: Optional[dict[str, Union[Response, Any]]] = None + callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None + deprecated: Optional[bool] = None + security: Optional[list[dict[str, list[str]]]] = None + servers: Optional[list[Server]] = None + + +class PathItem(BaseModelWithConfig): + ref: Optional[str] = Field(default=None, alias="$ref") + summary: Optional[str] = None + description: Optional[str] = None + get: Optional[Operation] = None + put: Optional[Operation] = None + post: Optional[Operation] = None + delete: Optional[Operation] = None + options: Optional[Operation] = None + head: Optional[Operation] = None + patch: Optional[Operation] = None + trace: Optional[Operation] = None + servers: Optional[list[Server]] = None + parameters: Optional[list[Union[Parameter, Reference]]] = None + + +class SecuritySchemeType(Enum): + apiKey = "apiKey" + http = "http" + oauth2 = "oauth2" + openIdConnect = "openIdConnect" + + +class SecurityBase(BaseModelWithConfig): + type_: SecuritySchemeType = Field(alias="type") + description: Optional[str] = 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: Optional[str] = None + + +class OAuthFlow(BaseModelWithConfig): + refreshUrl: Optional[str] = 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: Optional[OAuthFlowImplicit] = None + password: Optional[OAuthFlowPassword] = None + clientCredentials: Optional[OAuthFlowClientCredentials] = None + authorizationCode: Optional[OAuthFlowAuthorizationCode] = 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 = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer] + + +class Components(BaseModelWithConfig): + schemas: Optional[dict[str, Union[Schema, Reference]]] = None + responses: Optional[dict[str, Union[Response, Reference]]] = None + parameters: Optional[dict[str, Union[Parameter, Reference]]] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None + requestBodies: Optional[dict[str, Union[RequestBody, Reference]]] = None + headers: Optional[dict[str, Union[Header, Reference]]] = None + securitySchemes: Optional[dict[str, Union[SecurityScheme, Reference]]] = None + links: Optional[dict[str, Union[Link, Reference]]] = None + # Using Any for Specification Extensions + callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None + pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None + + +class Tag(BaseModelWithConfig): + name: str + description: Optional[str] = None + externalDocs: Optional[ExternalDocumentation] = None + + +class OpenAPI(BaseModelWithConfig): + openapi: str + info: Info + jsonSchemaDialect: Optional[str] = None + servers: Optional[list[Server]] = None + # Using Any for Specification Extensions + paths: Optional[dict[str, Union[PathItem, Any]]] = None + webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None + components: Optional[Components] = None + security: Optional[list[dict[str, list[str]]]] = None + tags: Optional[list[Tag]] = None + externalDocs: Optional[ExternalDocumentation] = None + + +Schema.model_rebuild() +Operation.model_rebuild() +Encoding.model_rebuild() diff --git a/backend/venv/Lib/site-packages/fastapi/openapi/utils.py b/backend/venv/Lib/site-packages/fastapi/openapi/utils.py new file mode 100644 index 0000000..75ff261 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/openapi/utils.py @@ -0,0 +1,567 @@ +import http.client +import inspect +import warnings +from collections.abc import Sequence +from typing import Any, Optional, Union, cast + +from fastapi import routing +from fastapi._compat import ( + ModelField, + Undefined, + get_compat_model_name_map, + get_definitions, + get_schema_from_model_field, + lenient_issubclass, +) +from fastapi.datastructures import DefaultPlaceholder +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.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 +from typing_extensions import Literal + +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"}, + }, + "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.type_, 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.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 != Undefined: + 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: Optional[ModelField], + model_name_map: ModelNameMap, + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] + ], + separate_input_output_schemas: bool = True, +) -> Optional[dict[str, Any]]: + 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.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 != Undefined: + 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.APIRoute, 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.APIRoute, method: str) -> str: + if route.summary: + return route.summary + return route.name.replace("_", " ").title() + + +def get_openapi_operation_metadata( + *, route: routing.APIRoute, 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: + message = ( + f"Duplicate Operation ID {operation_id} for function " + + f"{route.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.APIRoute, + 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: Optional[str] = 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=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 route_response_media_type and is_body_allowed_for_status_code( + route.status_code + ): + 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 = additional_response.copy() + 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: Optional[dict[str, Any]] = 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: Optional[str] = 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_fields_from_routes( + routes: Sequence[BaseRoute], +) -> 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 in routes: + if getattr(route, "include_in_schema", None) and isinstance( + route, routing.APIRoute + ): + if route.body_field: + assert isinstance(route.body_field, ModelField), ( + "A request body must be a Pydantic Field" + ) + body_fields_from_routes.append(route.body_field) + if route.response_field: + responses_from_routes.append(route.response_field) + if route.response_fields: + responses_from_routes.extend(route.response_fields.values()) + if route.callbacks: + callback_flat_models.extend(get_fields_from_routes(route.callbacks)) + params = get_flat_params(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: Optional[str] = None, + description: Optional[str] = None, + routes: Sequence[BaseRoute], + webhooks: Optional[Sequence[BaseRoute]] = None, + tags: Optional[list[dict[str, Any]]] = None, + servers: Optional[list[dict[str, Union[str, Any]]]] = None, + terms_of_service: Optional[str] = None, + contact: Optional[dict[str, Union[str, Any]]] = None, + license_info: Optional[dict[str, Union[str, Any]]] = None, + separate_input_output_schemas: bool = True, + external_docs: Optional[dict[str, Any]] = 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 or []) + list(webhooks or [])) + model_name_map = get_compat_model_name_map(all_fields) + field_mapping, definitions = get_definitions( + fields=all_fields, + model_name_map=model_name_map, + separate_input_output_schemas=separate_input_output_schemas, + ) + for route in routes or []: + if isinstance(route, routing.APIRoute): + result = get_openapi_path( + route=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(route.path_format, {}).update(path) + if security_schemes: + components.setdefault("securitySchemes", {}).update( + security_schemes + ) + if path_definitions: + definitions.update(path_definitions) + for webhook in webhooks or []: + if isinstance(webhook, routing.APIRoute): + result = get_openapi_path( + route=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(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 diff --git a/backend/venv/Lib/site-packages/fastapi/param_functions.py b/backend/venv/Lib/site-packages/fastapi/param_functions.py new file mode 100644 index 0000000..0834fd7 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/param_functions.py @@ -0,0 +1,2369 @@ +from collections.abc import Sequence +from typing import Annotated, Any, Callable, Optional, Union + +from annotated_doc import Doc +from fastapi import params +from fastapi._compat import Undefined +from fastapi.openapi.models import Example +from pydantic import AliasChoices, AliasPath +from typing_extensions import Literal, deprecated + +_Unset: Any = Undefined + + +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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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. + """ + ), + ] = Undefined, + *, + default_factory: Annotated[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Union[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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Union[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[ + Optional[str], + 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[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, + validation_alias: Annotated[ + Union[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[ + Union[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[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, + regex: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[list[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Annotated[ + Optional[dict[str, Example]], + 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[ + Union[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[ + Union[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[ + Optional[Callable[..., Any]], + Doc( + """ + A "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you, just pass the object + directly. + """ + ), + ] = 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. + """ + ), + ] = True, + scope: Annotated[ + Union[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. + """ + ), + ] = 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[ + Optional[Callable[..., Any]], + Doc( + """ + A "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you, just pass the object + directly. + """ + ), + ] = None, + *, + scopes: Annotated[ + Optional[Sequence[str]], + 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. + ) + """ + ), + ] = 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. + """ + ), + ] = 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/backend/venv/Lib/site-packages/fastapi/params.py b/backend/venv/Lib/site-packages/fastapi/params.py new file mode 100644 index 0000000..72e797f --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/params.py @@ -0,0 +1,755 @@ +import warnings +from collections.abc import Sequence +from dataclasses import dataclass +from enum import Enum +from typing import Annotated, Any, Callable, Optional, Union + +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 Literal, deprecated + +from ._compat import ( + Undefined, +) + +_Unset: Any = Undefined + + +class ParamTypes(Enum): + query = "query" + header = "header" + path = "path" + cookie = "cookie" + + +class Param(FieldInfo): # type: ignore[misc] + in_: ParamTypes + + def __init__( + self, + default: Any = Undefined, + *, + default_factory: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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) + + 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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + convert_underscores: bool = True, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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] + def __init__( + self, + default: Any = Undefined, + *, + default_factory: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + embed: Union[bool, None] = None, + media_type: str = "application/json", + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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) + + 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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + media_type: str = "application/x-www-form-urlencoded", + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + media_type: str = "multipart/form-data", + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + validation_alias: Union[str, AliasPath, AliasChoices, None] = None, + serialization_alias: Union[str, None] = None, + title: Optional[str] = None, + description: Optional[str] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + pattern: Optional[str] = None, + regex: Annotated[ + Optional[str], + deprecated( + "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." + ), + ] = None, + discriminator: Union[str, None] = None, + strict: Union[bool, None] = _Unset, + multiple_of: Union[float, None] = _Unset, + allow_inf_nan: Union[bool, None] = _Unset, + max_digits: Union[int, None] = _Unset, + decimal_places: Union[int, None] = _Unset, + examples: Optional[list[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = _Unset, + openapi_examples: Optional[dict[str, Example]] = None, + deprecated: Union[deprecated, str, bool, None] = None, + include_in_schema: bool = True, + json_schema_extra: Union[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: Optional[Callable[..., Any]] = None + use_cache: bool = True + scope: Union[Literal["function", "request"], None] = None + + +@dataclass(frozen=True) +class Security(Depends): + scopes: Optional[Sequence[str]] = None diff --git a/backend/venv/Lib/site-packages/fastapi/py.typed b/backend/venv/Lib/site-packages/fastapi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/fastapi/requests.py b/backend/venv/Lib/site-packages/fastapi/requests.py new file mode 100644 index 0000000..d16552c --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/requests.py @@ -0,0 +1,2 @@ +from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401 +from starlette.requests import Request as Request # noqa: F401 diff --git a/backend/venv/Lib/site-packages/fastapi/responses.py b/backend/venv/Lib/site-packages/fastapi/responses.py new file mode 100644 index 0000000..6c8db6f --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/responses.py @@ -0,0 +1,48 @@ +from typing import Any + +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 + +try: + import ujson +except ImportError: # pragma: nocover + ujson = None # type: ignore + + +try: + import orjson +except ImportError: # pragma: nocover + orjson = None # type: ignore + + +class UJSONResponse(JSONResponse): + """ + JSON response using the high-performance ujson library to serialize data to JSON. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). + """ + + 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") + + +class ORJSONResponse(JSONResponse): + """ + JSON response using the high-performance orjson library to serialize data to JSON. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). + """ + + 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/backend/venv/Lib/site-packages/fastapi/routing.py b/backend/venv/Lib/site-packages/fastapi/routing.py new file mode 100644 index 0000000..9ca2f46 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/routing.py @@ -0,0 +1,4508 @@ +import email.message +import functools +import inspect +import json +from collections.abc import ( + AsyncIterator, + Awaitable, + Collection, + Coroutine, + Mapping, + Sequence, +) +from contextlib import AsyncExitStack, asynccontextmanager +from enum import Enum, IntEnum +from typing import ( + Annotated, + Any, + Callable, + Optional, + Union, +) + +from annotated_doc import Doc +from fastapi import params +from fastapi._compat import ( + ModelField, + Undefined, + annotation_is_pydantic_v1, + 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_typed_return_annotation, + solve_dependencies, +) +from fastapi.encoders import jsonable_encoder +from fastapi.exceptions import ( + EndpointContext, + FastAPIError, + PydanticV1NotSupportedError, + RequestValidationError, + ResponseValidationError, + WebSocketRequestValidationError, +) +from fastapi.types import DecoratedCallable, IncEx +from fastapi.utils import ( + create_cloned_field, + 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 is_async_callable +from starlette.concurrency import run_in_threadpool +from starlette.exceptions import HTTPException +from starlette.requests import Request +from starlette.responses import JSONResponse, Response +from starlette.routing import ( + BaseRoute, + Match, + compile_path, + get_name, +) +from starlette.routing import Mount as Mount # noqa +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], Union[Awaitable[Response], Response]], +) -> ASGIApp: + """ + Takes a function or coroutine `func(request) -> response`, + and returns an ASGI application. + """ + f: Callable[[Request], Awaitable[Response]] = ( + func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore + ) + + 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 + + +def _merge_lifespan_context( + original_context: Lifespan[Any], nested_context: Lifespan[Any] +) -> Lifespan[Any]: + @asynccontextmanager + async def merged_lifespan( + app: AppType, + ) -> AsyncIterator[Optional[Mapping[str, Any]]]: + 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] + + +# 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: Optional[ModelField] = None, + response_content: Any, + include: Optional[IncEx] = None, + exclude: Optional[IncEx] = None, + by_alias: bool = True, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + is_coroutine: bool = True, + endpoint_ctx: Optional[EndpointContext] = None, +) -> Any: + if field: + errors = [] + 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 isinstance(errors_, list): + errors.extend(errors_) + if errors: + ctx = endpoint_ctx or EndpointContext() + raise ResponseValidationError( + errors=errors, + body=response_content, + endpoint_ctx=ctx, + ) + + return field.serialize( + 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 get_request_handler( + dependant: Dependant, + body_field: Optional[ModelField] = None, + status_code: Optional[int] = None, + response_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse), + response_field: Optional[ModelField] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Optional[Any] = None, + embed_body_fields: 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 + + async def app(request: Request) -> Response: + response: Union[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: + 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=body, + dependency_overrides_provider=dependency_overrides_provider, + async_exit_stack=async_exit_stack, + embed_body_fields=embed_body_fields, + ) + errors = solved_result.errors + if not errors: + 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: 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 + 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, + ) + 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: Optional[Any] = 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: Optional[str] = None, + dependencies: Optional[Sequence[params.Depends]] = None, + dependency_overrides_provider: Optional[Any] = 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 + + +class APIRoute(routing.Route): + def __init__( + self, + path: str, + endpoint: Callable[..., Any], + *, + response_model: Any = Default(None), + status_code: Optional[int] = None, + tags: Optional[list[Union[str, Enum]]] = None, + dependencies: Optional[Sequence[params.Depends]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + response_description: str = "Successful Response", + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + deprecated: Optional[bool] = None, + name: Optional[str] = None, + methods: Optional[Union[set[str], list[str]]] = None, + operation_id: Optional[str] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Union[type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), + dependency_overrides_provider: Optional[Any] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = None, + generate_unique_id_function: Union[ + Callable[["APIRoute"], str], DefaultPlaceholder + ] = Default(generate_unique_id), + ) -> None: + self.path = path + self.endpoint = endpoint + if isinstance(response_model, DefaultPlaceholder): + return_annotation = get_typed_return_annotation(endpoint) + if lenient_issubclass(return_annotation, Response): + response_model = None + else: + response_model = return_annotation + self.response_model = response_model + self.summary = summary + self.response_description = response_description + self.deprecated = deprecated + self.operation_id = operation_id + self.response_model_include = response_model_include + self.response_model_exclude = response_model_exclude + self.response_model_by_alias = response_model_by_alias + self.response_model_exclude_unset = response_model_exclude_unset + self.response_model_exclude_defaults = response_model_exclude_defaults + self.response_model_exclude_none = response_model_exclude_none + self.include_in_schema = include_in_schema + self.response_class = response_class + self.dependency_overrides_provider = dependency_overrides_provider + self.callbacks = callbacks + self.openapi_extra = openapi_extra + self.generate_unique_id_function = generate_unique_id_function + self.tags = tags or [] + self.responses = responses or {} + self.name = get_name(endpoint) if name is None else name + self.path_regex, self.path_format, self.param_convertors = compile_path(path) + if methods is None: + methods = ["GET"] + self.methods: set[str] = {method.upper() for method in methods} + if isinstance(generate_unique_id_function, DefaultPlaceholder): + current_generate_unique_id: Callable[[APIRoute], str] = ( + generate_unique_id_function.value + ) + else: + current_generate_unique_id = generate_unique_id_function + self.unique_id = self.operation_id or current_generate_unique_id(self) + # normalize enums e.g. http.HTTPStatus + if isinstance(status_code, IntEnum): + status_code = int(status_code) + self.status_code = status_code + if self.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_" + self.unique_id + if annotation_is_pydantic_v1(self.response_model): + raise PydanticV1NotSupportedError( + "pydantic.v1 models are no longer supported by FastAPI." + f" Please update the response model {self.response_model!r}." + ) + self.response_field = create_model_field( + name=response_name, + type_=self.response_model, + mode="serialization", + ) + # Create a clone of the field, so that a Pydantic submodel is not returned + # as is just because it's an instance of a subclass of a more limited class + # e.g. UserInDB (containing hashed_password) could be a subclass of User + # that doesn't have the hashed_password. But because it's a subclass, it + # would pass the validation and be returned as is. + # By being a new field, no inheritance will be passed as is. A new model + # will always be created. + # TODO: remove when deprecating Pydantic v1 + self.secure_cloned_response_field: Optional[ModelField] = ( + create_cloned_field(self.response_field) + ) + else: + self.response_field = None # type: ignore + self.secure_cloned_response_field = None + self.dependencies = list(dependencies or []) + self.description = description or inspect.cleandoc(self.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" + self.description = self.description.split("\f")[0].strip() + response_fields = {} + for additional_status_code, response in self.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}_{self.unique_id}" + if annotation_is_pydantic_v1(model): + raise PydanticV1NotSupportedError( + "pydantic.v1 models are no longer supported by FastAPI." + f" In responses={{}}, please update {model}." + ) + response_field = create_model_field( + name=response_name, type_=model, mode="serialization" + ) + response_fields[additional_status_code] = response_field + if response_fields: + self.response_fields: dict[Union[int, str], ModelField] = response_fields + else: + self.response_fields = {} + + assert callable(endpoint), "An endpoint must be a callable" + 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.body_field = get_body_field( + flat_dependant=self._flat_dependant, + name=self.unique_id, + embed_body_fields=self._embed_body_fields, + ) + self.app = request_response(self.get_route_handler()) + + def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: + return get_request_handler( + dependant=self.dependant, + body_field=self.body_field, + status_code=self.status_code, + response_class=self.response_class, + response_field=self.secure_cloned_response_field, + response_model_include=self.response_model_include, + response_model_exclude=self.response_model_exclude, + response_model_by_alias=self.response_model_by_alias, + response_model_exclude_unset=self.response_model_exclude_unset, + response_model_exclude_defaults=self.response_model_exclude_defaults, + response_model_exclude_none=self.response_model_exclude_none, + dependency_overrides_provider=self.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 + + +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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[list[BaseRoute]], + 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[ + Optional[list[BaseRoute]], + 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[ + Optional[ASGIApp], + Doc( + """ + Default function handler for this router. Used to handle + 404 Not Found errors. + """ + ), + ] = None, + dependency_overrides_provider: Annotated[ + Optional[Any], + 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[ + Optional[Sequence[Callable[[], Any]]], + 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[ + Optional[Sequence[Callable[[], Any]]], + 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[ + Optional[Lifespan[Any]], + 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[ + Optional[bool], + 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), + ) -> None: + super().__init__( + routes=routes, + redirect_slashes=redirect_slashes, + default=default, + on_startup=on_startup, + on_shutdown=on_shutdown, + lifespan=lifespan, + ) + 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 '/'" + ) + self.prefix = prefix + self.tags: list[Union[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 + + def route( + self, + path: str, + methods: Optional[Collection[str]] = None, + name: Optional[str] = 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: Optional[int] = None, + tags: Optional[list[Union[str, Enum]]] = None, + dependencies: Optional[Sequence[params.Depends]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + response_description: str = "Successful Response", + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + deprecated: Optional[bool] = None, + methods: Optional[Union[set[str], list[str]]] = None, + operation_id: Optional[str] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Union[type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), + name: Optional[str] = None, + route_class_override: Optional[type[APIRoute]] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = None, + generate_unique_id_function: Union[ + Callable[[APIRoute], str], DefaultPlaceholder + ] = Default(generate_unique_id), + ) -> 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, + ) + self.routes.append(route) + + def api_route( + self, + path: str, + *, + response_model: Any = Default(None), + status_code: Optional[int] = None, + tags: Optional[list[Union[str, Enum]]] = None, + dependencies: Optional[Sequence[params.Depends]] = None, + summary: Optional[str] = None, + description: Optional[str] = None, + response_description: str = "Successful Response", + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + deprecated: Optional[bool] = None, + methods: Optional[list[str]] = None, + operation_id: Optional[str] = None, + response_model_include: Optional[IncEx] = None, + response_model_exclude: Optional[IncEx] = 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: Optional[str] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = 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: Optional[str] = None, + *, + dependencies: Optional[Sequence[params.Depends]] = 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) + + def websocket( + self, + path: Annotated[ + str, + Doc( + """ + WebSocket path. + """ + ), + ], + name: Annotated[ + Optional[str], + Doc( + """ + A name for the WebSocket. Only used internally. + """ + ), + ] = None, + *, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + 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: Union[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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[list[BaseRoute]], + 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[ + Optional[bool], + 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) + ``` + """ + 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 r in router.routes: + path = getattr(r, "path") # noqa: B009 + name = getattr(r, "name", "unknown") + if path is not None and not path: + raise FastAPIError( + f"Prefix and path cannot be both empty (path operation: {name})" + ) + if responses is None: + responses = {} + for route in router.routes: + if isinstance(route, APIRoute): + combined_responses = {**responses, **route.responses} + use_response_class = get_value_or_default( + route.response_class, + router.default_response_class, + default_response_class, + self.default_response_class, + ) + current_tags = [] + if tags: + current_tags.extend(tags) + if route.tags: + current_tags.extend(route.tags) + current_dependencies: list[params.Depends] = [] + if dependencies: + current_dependencies.extend(dependencies) + if route.dependencies: + current_dependencies.extend(route.dependencies) + current_callbacks = [] + if callbacks: + current_callbacks.extend(callbacks) + if route.callbacks: + current_callbacks.extend(route.callbacks) + current_generate_unique_id = get_value_or_default( + route.generate_unique_id_function, + router.generate_unique_id_function, + generate_unique_id_function, + self.generate_unique_id_function, + ) + self.add_api_route( + prefix + route.path, + route.endpoint, + response_model=route.response_model, + status_code=route.status_code, + tags=current_tags, + dependencies=current_dependencies, + summary=route.summary, + description=route.description, + response_description=route.response_description, + responses=combined_responses, + deprecated=route.deprecated or deprecated or self.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 self.include_in_schema + and include_in_schema, + response_class=use_response_class, + name=route.name, + route_class_override=type(route), + callbacks=current_callbacks, + openapi_extra=route.openapi_extra, + generate_unique_id_function=current_generate_unique_id, + ) + elif isinstance(route, routing.Route): + methods = list(route.methods or []) + self.add_route( + prefix + route.path, + route.endpoint, + methods=methods, + include_in_schema=route.include_in_schema, + name=route.name, + ) + elif isinstance(route, APIWebSocketRoute): + current_dependencies = [] + if dependencies: + current_dependencies.extend(dependencies) + if route.dependencies: + current_dependencies.extend(route.dependencies) + self.add_api_websocket_route( + prefix + route.path, + route.endpoint, + dependencies=current_dependencies, + name=route.name, + ) + elif isinstance(route, routing.WebSocketRoute): + self.add_websocket_route( + prefix + route.path, route.endpoint, name=route.name + ) + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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[ + Optional[int], + 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[ + Optional[list[Union[str, Enum]]], + 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[ + Optional[Sequence[params.Depends]], + 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[ + Optional[str], + 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[ + Optional[str], + 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[ + Optional[dict[Union[int, str], dict[str, Any]]], + 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[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + 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[ + Optional[IncEx], + 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[ + Optional[IncEx], + 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[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[list[BaseRoute]], + 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[ + Optional[dict[str, Any]], + 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, + ) + + @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/backend/venv/Lib/site-packages/fastapi/security/__init__.py b/backend/venv/Lib/site-packages/fastapi/security/__init__.py new file mode 100644 index 0000000..3aa6bf2 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/__init__.py @@ -0,0 +1,15 @@ +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/backend/venv/Lib/site-packages/fastapi/security/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e87fa3c4459c453bd013ff272f90d931460489a7 GIT binary patch literal 849 zcmZ{iO>fgM7{{HyBu&%wWt)U1fw*v>NKi3xLTIoRp$*Vh+6f^mQsyP5vzo-2<7^6F zgwMc*Gv9%45GhS^0C#a$vkTnAJF5Flyn2;>H;3B+Q?SyN|XI?%#(x$@?f}LS|nxuf))av2NDe> zO^~v2DrG86p&u+8`nib205V_D zB`ErHJbvn>g3kqsW0uUl3(f-`$5aH=XURGI4lWAsgaiwkgdX^F?=3s=GA8N66ruz^ zw)c@_5^gcdu5LT>p_WPCf0Pzw>sidhJfhoT6B??wl5K(ft{a9?p~rfTDs)hx`xV-* b&;vd1RcKnF7ZrM4q4yPf@&i2=x1j7VD(~_t literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/__pycache__/api_key.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/api_key.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5595be0d2fe126e2dca6250c4586b4a5ea1da2c5 GIT binary patch literal 10486 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 K*y0xuxSn5l+lJTx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/__pycache__/http.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/http.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..944a0e25cb5869dbdf969b269d822fe70ce9291a GIT binary patch literal 14539 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 Fe*y3nA_)Kh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/__pycache__/oauth2.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/oauth2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9be4381fa7112592cc25a63ebfa3c869ecc8907c GIT binary patch literal 19252 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2efae29dfbdf3ed0166957b098ea3ca5e9a009a GIT binary patch literal 3765 zcmcgv%WoUU8J}G)pCU!dmS{DW;yF0BC`)vc6it)53FJ6#ggUZe$yG}TSgm%4(%Sn_ zW_Bf0P!YrR!7WSW`M3udfET$hs0 z=0j-QCyX={i!@YAX{0O_J}FE4ZOTeBjipt>GFE0oiFY*BZ$ZP#!c3N>u`TCw`{wie z<_r7gdtg2%cNX`~G;>zzPNtE!dRd{VTID-hqsOYSBJ`8@H8rabMoTTVc7$g@0YiXp z1qwwv?E+1_MvX97VqRdI2D+D;jv+*yPI%PzL|}L(qkfax0bTV&$D#|2hJsnt5Y&*; zECw;Km}j=?1vxM}I%{yx_7+D+U!lR0Ehv0_&uLMEiXdE|fltjiVld61?JoNsXdvjS z9V|)pCaz4v>*+;91kfClau>n?)v$afywlKhmmTK9HYubTI!#AJ_wy`VIFMYtgSgK`Yd+NA^xfWj?51Pj3W}aBQ(P5 zi*>qU3wyy~)ClPOS<5%Yd~L5vD4Qdc*6x3!TDx5H|J1G*0rEFB0Z7*w_&ndD7Hb-z z6F~AbspnIq4LSj!@wvSgV`hmN7UP)b%iLeF!D(ZZ1JT$VyaoAp!0fMupv+Pk1 zUSS#zz{f-|Ix-e099ZmtT+B%UaEyWF*a#29qcXh?^JkOJ@8sV+8Xy<|%BS-e4M(u~ zF}e!eAf)px=(`c99dV^Q|~Jq00J!QMBkZFZz`gyz}R)%y{}xy(`8?Q z-P~=Q6=| z9*<7k)&80rY(I1IuJ-HlChR0phO;2#-gabh5aS>tI|_~6kqwfV!i_}1TZ^r{uXV3m z)8NFZwZ16?>`po}YppUnJ3BtHYbeT`X9j0n9%pbR3k8^Nu_$A)0FWMKV-^$;+#D#t z@pf5L_y9cc>Om++%cCLJxWRNF2z}4{;v;Zvbg$38ZtWEmJPg$>@=1Bt8^}n!{)hdM!(eed8h%e11glTSj0!GnSKZoDuZK!@k6!6))avj?H%XM72uUN`P zf{&l6>#7(&92>j>NUbV>i>QPS-#%Ar8h;iRMyW*>$eiXU zpj%5xpK^**C3NEU27!t~&c~jHOvHoZuuP1{XJNHC2i51~-?vD6@Wk)R@0Onoo_RcY z=E3EU2G89seOw-DmyiDDonOAwu0Hdm`qJa-OCMEVepGq+vt!5G<)KHpq5lX3`t2XQ zrqp_QKQyC)t^;;MhXH1by8d=(IC$BBURKxPegFVQHKUXWI7g6jln`kPzVGm3*q7;p zrt&;i&q4Jbk%5$k$?L4FdSFJhp}Ir9RCDQE=Nu{Zb^5Uyf$E=3`Cj@t0Mzl5?PB@k zV!5NLeU;6WR_g7f(xvj3sqFDWCyQ&Uq&I` z=r^xBgX>-;1JAaL6)CG1WmQmCAIds9P}qD8*91yBU3lPb5_oiav+3dAFLnq#J{)=Y z;-AL1uo)YTz@DmAqD;_Q2L6)ni=9?7x_^(*v(lSUHDRhc5)?32T{5YNz19b!qJi#; zE|=98;O`R0JdOH+<+#IwfYn*|f0K|AiH__{C2$flKv8990$M-}68roN$lHlplsgxv x#jE^9m_YD|5vV#TMNvK_r~W~PpOTADNnL(VJtZ$}Wu_Hn_}-;|5qwHX{{!4T=1~9u literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/fastapi/security/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..368449dbdfae53676dbfc6fdf7db501f8503f2aa GIT binary patch literal 595 zcmY*VziSjh6rS1HU1RhNV&sfMxJq0^qlh4hiW0Dr2--+kSth&h?nd_)GqWcvcM!p1 z%XF#j6v5j6!Ny?WF(3$5b|+_L<(u;qeK3#j`{sL(kN3XSS|nHx-`*Fil#s8M{3(A9 zrk4=xlY}HRB^lkOlq3#Na8^)H7%*_a>CRZ!P23mmwp)9F|ILmE)GXX9wJ36)n$x_} z{X&Xo+zL@2cmgsS@U#NsOVE|fV+`@P7$W)7_mkSJQyA$k0-XKqfMH*+<_i4h$+ zBQ~T%)^#3`fNceiA@UG<4eem0!zGtm*bsp$T`T)4?n4HKM#jTWo+&GLuzo(;Tn|fG z^ia%1-V2`=MO!$t!)8(EvF(!YJ~?`JymWHhzWk}ZanRm)xB0Ps z>%d*!z0=%os_~KIdsmwqAKX(@w3DsCGrq1%%q{ID4O3bgPgi9Mv(2xGTtZ#8?B~Mu ztVpU9Zpvk(_MR%hHer;~&*aR+_vy;GbMDoNm#qmy{KZ>ruI#bq+Vkj#hkUl`7mm7~ A4*&oF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/fastapi/security/api_key.py b/backend/venv/Lib/site-packages/fastapi/security/api_key.py new file mode 100644 index 0000000..18dfb8e --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/api_key.py @@ -0,0 +1,318 @@ +from typing import Annotated, Optional, Union + +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): + def __init__( + self, + location: APIKeyIn, + name: str, + description: Union[str, None], + scheme_name: Union[str, None], + auto_error: bool, + ): + self.auto_error = auto_error + + self.model: APIKey = APIKey( + **{"in": location}, + 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: Optional[str]) -> Optional[str]: + 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[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + 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[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + 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[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + api_key = request.cookies.get(self.model.name) + return self.check_api_key(api_key) diff --git a/backend/venv/Lib/site-packages/fastapi/security/base.py b/backend/venv/Lib/site-packages/fastapi/security/base.py new file mode 100644 index 0000000..c43555d --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/base.py @@ -0,0 +1,6 @@ +from fastapi.openapi.models import SecurityBase as SecurityBaseModel + + +class SecurityBase: + model: SecurityBaseModel + scheme_name: str diff --git a/backend/venv/Lib/site-packages/fastapi/security/http.py b/backend/venv/Lib/site-packages/fastapi/security/http.py new file mode 100644 index 0000000..b4c3bc6 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/http.py @@ -0,0 +1,423 @@ +import binascii +from base64 import b64decode +from typing import Annotated, Optional + +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): + def __init__( + self, + *, + scheme: str, + scheme_name: Optional[str] = None, + description: Optional[str] = None, + auto_error: bool = True, + ): + self.model: HTTPBaseModel = 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 + ) -> Optional[HTTPAuthorizationCredentials]: + 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[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + realm: Annotated[ + Optional[str], + Doc( + """ + HTTP Basic authentication realm. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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 + ) -> Optional[HTTPBasicCredentials]: + 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[Optional[str], Doc("Bearer token format.")] = None, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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 + ) -> Optional[HTTPAuthorizationCredentials]: + 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 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[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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 + ) -> Optional[HTTPAuthorizationCredentials]: + 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/backend/venv/Lib/site-packages/fastapi/security/oauth2.py b/backend/venv/Lib/site-packages/fastapi/security/oauth2.py new file mode 100644 index 0000000..fc49ba1 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/oauth2.py @@ -0,0 +1,663 @@ +from typing import Annotated, Any, Optional, Union, 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 that it is application specific, it's not part of the specification. + """ + + def __init__( + self, + *, + grant_type: Annotated[ + Union[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. + """ + ), + ] = None, + username: Annotated[ + str, + Form(), + Doc( + """ + `username` string. The OAuth2 spec requires the exact field name + `username`. + """ + ), + ], + password: Annotated[ + str, + Form(json_schema_extra={"format": "password"}), + Doc( + """ + `password` string. The OAuth2 spec requires the exact field name + `password`. + """ + ), + ], + 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` + """ + ), + ] = "", + client_id: Annotated[ + Union[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[ + Union[str, None], + Form(json_schema_extra={"format": "password"}), + Doc( + """ + If there's a `client_password` (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 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. + """ + ), + ], + username: Annotated[ + str, + Form(), + Doc( + """ + `username` string. The OAuth2 spec requires the exact field name + `username`. + """ + ), + ], + password: Annotated[ + str, + Form(), + Doc( + """ + `password` string. The OAuth2 spec requires the exact field name + `password`. + """ + ), + ], + 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` + """ + ), + ] = "", + client_id: Annotated[ + Union[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[ + Union[str, None], + Form(), + Doc( + """ + If there's a `client_password` (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[ + Union[OAuthFlowsModel, dict[str, dict[str, Any]]], + Doc( + """ + The dictionary of OAuth2 flows. + """ + ), + ] = OAuthFlowsModel(), + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + 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. + """ + ), + ], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + scopes: Annotated[ + Optional[dict[str, str]], + Doc( + """ + The OAuth2 scopes that would be required by the *path operations* that + use this dependency. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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[ + Optional[str], + 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) -> Optional[str]: + 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[ + Optional[str], + Doc( + """ + The URL to refresh the token and obtain a new one. + """ + ), + ] = None, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + scopes: Annotated[ + Optional[dict[str, str]], + Doc( + """ + The OAuth2 scopes that would be required by the *path operations* that + use this dependency. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + 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[ + Optional[list[str]], + 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/backend/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py b/backend/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py new file mode 100644 index 0000000..f4d9533 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/open_id_connect_url.py @@ -0,0 +1,94 @@ +from typing import Annotated, Optional + +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 to subclass it and implement it in your + code. + """ + + def __init__( + self, + *, + openIdConnectUrl: Annotated[ + str, + Doc( + """ + The OpenID Connect URL. + """ + ), + ], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + 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) -> Optional[str]: + 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/backend/venv/Lib/site-packages/fastapi/security/utils.py b/backend/venv/Lib/site-packages/fastapi/security/utils.py new file mode 100644 index 0000000..002e68b --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/security/utils.py @@ -0,0 +1,10 @@ +from typing import Optional + + +def get_authorization_scheme_param( + authorization_header_value: Optional[str], +) -> tuple[str, str]: + if not authorization_header_value: + return "", "" + scheme, _, param = authorization_header_value.partition(" ") + return scheme, param diff --git a/backend/venv/Lib/site-packages/fastapi/staticfiles.py b/backend/venv/Lib/site-packages/fastapi/staticfiles.py new file mode 100644 index 0000000..299015d --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/staticfiles.py @@ -0,0 +1 @@ +from starlette.staticfiles import StaticFiles as StaticFiles # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/templating.py b/backend/venv/Lib/site-packages/fastapi/templating.py new file mode 100644 index 0000000..0cb8684 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/templating.py @@ -0,0 +1 @@ +from starlette.templating import Jinja2Templates as Jinja2Templates # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/testclient.py b/backend/venv/Lib/site-packages/fastapi/testclient.py new file mode 100644 index 0000000..4012406 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/testclient.py @@ -0,0 +1 @@ +from starlette.testclient import TestClient as TestClient # noqa diff --git a/backend/venv/Lib/site-packages/fastapi/types.py b/backend/venv/Lib/site-packages/fastapi/types.py new file mode 100644 index 0000000..d3e980c --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/types.py @@ -0,0 +1,11 @@ +import types +from enum import Enum +from typing import Any, Callable, Optional, TypeVar, Union + +from pydantic import BaseModel + +DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any]) +UnionType = getattr(types, "UnionType", Union) +ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str] +IncEx = Union[set[int], set[str], dict[int, Any], dict[str, Any]] +DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str] diff --git a/backend/venv/Lib/site-packages/fastapi/utils.py b/backend/venv/Lib/site-packages/fastapi/utils.py new file mode 100644 index 0000000..78fdcbb --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/utils.py @@ -0,0 +1,164 @@ +import re +import warnings +from collections.abc import MutableMapping +from typing import ( + TYPE_CHECKING, + Any, + Optional, + Union, +) +from weakref import WeakKeyDictionary + +import fastapi +from fastapi._compat import ( + BaseConfig, + ModelField, + PydanticSchemaGenerationError, + Undefined, + UndefinedType, + Validator, + annotation_is_pydantic_v1, +) +from fastapi.datastructures import DefaultPlaceholder, DefaultType +from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError +from pydantic import BaseModel +from pydantic.fields import FieldInfo +from typing_extensions import Literal + +from ._compat import v2 + +if TYPE_CHECKING: # pragma: nocover + from .routing import APIRoute + +# Cache for `create_cloned_field` +_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = ( + WeakKeyDictionary() +) + + +def is_body_allowed_for_status_code(status_code: Union[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, + class_validators: Optional[dict[str, Validator]] = None, + default: Optional[Any] = Undefined, + required: Union[bool, UndefinedType] = Undefined, + model_config: Union[type[BaseConfig], None] = None, + field_info: Optional[FieldInfo] = None, + alias: Optional[str] = None, + mode: Literal["validation", "serialization"] = "validation", + version: Literal["1", "auto"] = "auto", +) -> 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}." + ) + class_validators = class_validators or {} + + field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias) + kwargs = {"mode": mode, "name": name, "field_info": field_info} + try: + return v2.ModelField(**kwargs) # type: ignore[return-value,arg-type] + except PydanticSchemaGenerationError: + raise fastapi.exceptions.FastAPIError( + _invalid_args_message.format(type_=type_) + ) from None + + +def create_cloned_field( + field: ModelField, + *, + cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None, +) -> ModelField: + return field + + +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: Union[DefaultPlaceholder, DefaultType], + *extra_items: Union[DefaultPlaceholder, DefaultType], +) -> Union[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/backend/venv/Lib/site-packages/fastapi/websockets.py b/backend/venv/Lib/site-packages/fastapi/websockets.py new file mode 100644 index 0000000..55a4ac4 --- /dev/null +++ b/backend/venv/Lib/site-packages/fastapi/websockets.py @@ -0,0 +1,3 @@ +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/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/INSTALLER b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/METADATA b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/METADATA new file mode 100644 index 0000000..8a2f639 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/METADATA @@ -0,0 +1,202 @@ +Metadata-Version: 2.4 +Name: h11 +Version: 0.16.0 +Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 +Home-page: https://github.com/python-hyper/h11 +Author: Nathaniel J. Smith +Author-email: njs@pobox.com +License: MIT +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 3 +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 :: Internet :: WWW/HTTP +Classifier: Topic :: System :: Networking +Requires-Python: >=3.8 +License-File: LICENSE.txt +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: requires-python +Dynamic: summary + +h11 +=== + +.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master + :target: https://travis-ci.org/python-hyper/h11 + :alt: Automated test status + +.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg + :target: https://codecov.io/gh/python-hyper/h11 + :alt: Test coverage + +.. image:: https://readthedocs.org/projects/h11/badge/?version=latest + :target: http://h11.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +This is a little HTTP/1.1 library written from scratch in Python, +heavily inspired by `hyper-h2 `_. + +It's a "bring-your-own-I/O" library; h11 contains no IO code +whatsoever. This means you can hook h11 up to your favorite network +API, and that could be anything you want: synchronous, threaded, +asynchronous, or your own implementation of `RFC 6214 +`_ -- h11 won't judge you. +(Compare this to the current state of the art, where every time a `new +network API `_ comes along then someone +gets to start over reimplementing the entire HTTP protocol from +scratch.) Cory Benfield made an `excellent blog post describing the +benefits of this approach +`_, or if you like video +then here's his `PyCon 2016 talk on the same theme +`_. + +This also means that h11 is not immediately useful out of the box: +it's a toolkit for building programs that speak HTTP, not something +that could directly replace ``requests`` or ``twisted.web`` or +whatever. But h11 makes it much easier to implement something like +``requests`` or ``twisted.web``. + +At a high level, working with h11 goes like this: + +1) First, create an ``h11.Connection`` object to track the state of a + single HTTP/1.1 connection. + +2) When you read data off the network, pass it to + ``conn.receive_data(...)``; you'll get back a list of objects + representing high-level HTTP "events". + +3) When you want to send a high-level HTTP event, create the + corresponding "event" object and pass it to ``conn.send(...)``; + this will give you back some bytes that you can then push out + through the network. + +For example, a client might instantiate and then send a +``h11.Request`` object, then zero or more ``h11.Data`` objects for the +request body (e.g., if this is a POST), and then a +``h11.EndOfMessage`` to indicate the end of the message. Then the +server would then send back a ``h11.Response``, some ``h11.Data``, and +its own ``h11.EndOfMessage``. If either side violates the protocol, +you'll get a ``h11.ProtocolError`` exception. + +h11 is suitable for implementing both servers and clients, and has a +pleasantly symmetric API: the events you send as a client are exactly +the ones that you receive as a server and vice-versa. + +`Here's an example of a tiny HTTP client +`_ + +It also has `a fine manual `_. + +FAQ +--- + +*Whyyyyy?* + +I wanted to play with HTTP in `Curio +`__ and `Trio +`__, which at the time didn't have any +HTTP libraries. So I thought, no big deal, Python has, like, a dozen +different implementations of HTTP, surely I can find one that's +reusable. I didn't find one, but I did find Cory's call-to-arms +blog-post. So I figured, well, fine, if I have to implement HTTP from +scratch, at least I can make sure no-one *else* has to ever again. + +*Should I use it?* + +Maybe. You should be aware that it's a very young project. But, it's +feature complete and has an exhaustive test-suite and complete docs, +so the next step is for people to try using it and see how it goes +:-). If you do then please let us know -- if nothing else we'll want +to talk to you before making any incompatible changes! + +*What are the features/limitations?* + +Roughly speaking, it's trying to be a robust, complete, and non-hacky +implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: +HTTP/1.1 Message Syntax and Routing +`_. That is, it mostly focuses on +implementing HTTP at the level of taking bytes on and off the wire, +and the headers related to that, and tries to be anal about spec +conformance. It doesn't know about higher-level concerns like URL +routing, conditional GETs, cross-origin cookie policies, or content +negotiation. But it does know how to take care of framing, +cross-version differences in keep-alive handling, and the "obsolete +line folding" rule, so you can focus your energies on the hard / +interesting parts for your application, and it tries to support the +full specification in the sense that any useful HTTP/1.1 conformant +application should be able to use h11. + +It's pure Python, and has no dependencies outside of the standard +library. + +It has a test suite with 100.0% coverage for both statements and +branches. + +Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3. +The last Python 2-compatible version was h11 0.11.x. +(Originally it had a Cython wrapper for `http-parser +`_ and a beautiful nested state +machine implemented with ``yield from`` to postprocess the output. But +I had to take these out -- the new *parser* needs fewer lines-of-code +than the old *parser wrapper*, is written in pure Python, uses no +exotic language syntax, and has more features. It's sad, really; that +old state machine was really slick. I just need a few sentences here +to mourn that.) + +I don't know how fast it is. I haven't benchmarked or profiled it yet, +so it's probably got a few pointless hot spots, and I've been trying +to err on the side of simplicity and robustness instead of +micro-optimization. But at the architectural level I tried hard to +avoid fundamentally bad decisions, e.g., I believe that all the +parsing algorithms remain linear-time even in the face of pathological +input like slowloris, and there are no byte-by-byte loops. (I also +believe that it maintains bounded memory usage in the face of +arbitrary/pathological input.) + +The whole library is ~800 lines-of-code. You can read and understand +the whole thing in less than an hour. Most of the energy invested in +this so far has been spent on trying to keep things simple by +minimizing special-cases and ad hoc state manipulation; even though it +is now quite small and simple, I'm still annoyed that I haven't +figured out how to make it even smaller and simpler. (Unfortunately, +HTTP does not lend itself to simplicity.) + +The API is ~feature complete and I don't expect the general outlines +to change much, but you can't judge an API's ergonomics until you +actually document and use it, so I'd expect some changes in the +details. + +*How do I try it?* + +.. code-block:: sh + + $ pip install h11 + $ git clone git@github.com:python-hyper/h11 + $ cd h11/examples + $ python basic-client.py + +and go from there. + +*License?* + +MIT + +*Code of conduct?* + +Contributors are requested to follow our `code of conduct +`_ in +all project spaces. diff --git a/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/RECORD b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/RECORD new file mode 100644 index 0000000..fa60234 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/RECORD @@ -0,0 +1,29 @@ +h11-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348 +h11-0.16.0.dist-info/RECORD,, +h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91 +h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 +h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 +h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 +h11/__pycache__/__init__.cpython-312.pyc,, +h11/__pycache__/_abnf.cpython-312.pyc,, +h11/__pycache__/_connection.cpython-312.pyc,, +h11/__pycache__/_events.cpython-312.pyc,, +h11/__pycache__/_headers.cpython-312.pyc,, +h11/__pycache__/_readers.cpython-312.pyc,, +h11/__pycache__/_receivebuffer.cpython-312.pyc,, +h11/__pycache__/_state.cpython-312.pyc,, +h11/__pycache__/_util.cpython-312.pyc,, +h11/__pycache__/_version.cpython-312.pyc,, +h11/__pycache__/_writers.cpython-312.pyc,, +h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 +h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863 +h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792 +h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412 +h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590 +h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 +h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231 +h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 +h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686 +h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 +h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/WHEEL b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/WHEEL new file mode 100644 index 0000000..1eb3c49 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (78.1.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..8f080ea --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Nathaniel J. Smith and other 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/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/top_level.txt b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/top_level.txt new file mode 100644 index 0000000..0d24def --- /dev/null +++ b/backend/venv/Lib/site-packages/h11-0.16.0.dist-info/top_level.txt @@ -0,0 +1 @@ +h11 diff --git a/backend/venv/Lib/site-packages/h11/__init__.py b/backend/venv/Lib/site-packages/h11/__init__.py new file mode 100644 index 0000000..989e92c --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/__init__.py @@ -0,0 +1,62 @@ +# A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230), +# containing no networking code at all, loosely modelled on hyper-h2's generic +# implementation of HTTP/2 (and in particular the h2.connection.H2Connection +# class). There's still a bunch of subtle details you need to get right if you +# want to make this actually useful, because it doesn't implement all the +# semantics to check that what you're asking to write to the wire is sensible, +# but at least it gets you out of dealing with the wire itself. + +from h11._connection import Connection, NEED_DATA, PAUSED +from h11._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from h11._state import ( + CLIENT, + CLOSED, + DONE, + ERROR, + IDLE, + MIGHT_SWITCH_PROTOCOL, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, + SWITCHED_PROTOCOL, +) +from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError +from h11._version import __version__ + +PRODUCT_ID = "python-h11/" + __version__ + + +__all__ = ( + "Connection", + "NEED_DATA", + "PAUSED", + "ConnectionClosed", + "Data", + "EndOfMessage", + "Event", + "InformationalResponse", + "Request", + "Response", + "CLIENT", + "CLOSED", + "DONE", + "ERROR", + "IDLE", + "MUST_CLOSE", + "SEND_BODY", + "SEND_RESPONSE", + "SERVER", + "SWITCHED_PROTOCOL", + "ProtocolError", + "LocalProtocolError", + "RemoteProtocolError", +) diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..721763c549cd32e21c86f254bc09091d8b8ac2b8 GIT binary patch literal 1071 zcma))&u`N(6vvbPNZO=Xf354*G2k#Edf28NnGn)wB37wws-y#9Dp^_UZ4q%?oNTB& z!CwIDtE;-mk?@z1i7bS5S@ zBXwC%V0V2WrI6- z1*~veK`SR*6}UTA!M$m&ng1cgHq%UNkuXG~*e4;&_bkhV=JsHlDgEtT*D{+bEBy&* z1tdaamNC89V+AW5+xuMT#G5LR=(QKPj-`lAG^{aBQNMv5|a@LEJ_Jw#_eg< zL72qoma{1{9l~QoBYr>#PxQ$&J|yAV;pXN>vrg0ePH9GfzYU2h0;)hxATJ=E57h+< z0*1hxKvAG1P!^~P%nQ^676j@7O9G1m4US&(J}dI->u~hDkAKNvda{m0gQEY?#Iz(n zioF>9TVF*e_?JkQPf{GkesCo<5iRtxLb7swgLGNAG~O3;w>5xmlc^ATK>*=r>5?x= zKi$^Wa6-ue^)U9sgW+4k`-L&0BLw|W9Es5BaL*gPM&WqK=f}g2zc-Bh7_CjXm%q(u z$V+ZO9`45wu1}^c_ZXA$QGlM%2fT*Nzo^S`o|a{KR*~ebQ|Zwxm6KC5iQ__GRw;<- l4K5O^A<13&RO)<_R=*pKkFQRRhwrp=Wl>MPSLrIx_zRq#79s!u literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_abnf.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_abnf.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3aea8258744b31a7ee754772d3bf3e89b05a1655 GIT binary patch literal 1777 zcma)6Pi)&%7=KRe)cNDYNlV+U3_3b!osu@)L?=pVDck5Op;E!bz;$Na_%$(0>|(p6 zb!Ox%LPAU&cHo5IQdQc86XJw8B0+m<ACY&*&te6Fs9-&{-N7eLXWWDl2lpNcPOgswpuCjC9Wo9?+Sd z(Rq~<3&6`RW7}$ zl$@oKSebOv>(cJ^nUb`76IYz%`U7dVT$ZegGv3EZz0fl87u(pf zL^$rFr~}zBWn;sVZM+Nf6`j?Kys(C4EB3Y}R}B@0>Dssg zXcr<(tXR-AbV01VRW}t2^Z>omr0!DbJ*Bi+A%fn$^U3X%WsspY^ZNC&>pJnbri#&g z)%v#nP_{G&s+{|z$l83ghaOKuVY`c=n35^!tNTb8^y47E&)CL8toy0+OY)geY(F2G z?uq?$*QekoHVw0>*nVHFVQeT3%jcqK=lajU z^qTagVN{J~6Pr~mYx)j+(1y7uZ75ZcOO;^1BfYO}NS0>f(iWU5HEc=snVD%>+0Zwq zw)T8>zG{L&FwtG_S*u>!{9fRUR#%#Iyri$`SL+`oVDDHtyuurxCeAe!Nx zL)L+>KW-;!=4zWoLoa==g?XAk-5V}ACCtXsbh{dNfqbV{>KIY2BU zJm*odyg%5^v&`FV9^IJxMF@S8B@+yz)UcNbGALU-Y=z<@Xz#Pxg0 lfQ~W40g5sCfAd3+2ipwIB-#m-E_@@j`-o45GcSSI{{vtR@Bjb+ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_connection.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_connection.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74fa8cefcdab8466826f6042d9f8c1c9875e63cc GIT binary patch literal 23127 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_events.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_events.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a0257fa812c8c325591190c5031631afecd7239 GIT binary patch literal 13217 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_readers.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_readers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fee83e8ed7f221e927be4fd4f30b921b447af5c2 GIT binary patch literal 9644 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_receivebuffer.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_receivebuffer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..856221b04cd3fa7daeb9a3641d40e6e2d3e4b188 GIT binary patch literal 4695 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_state.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_state.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da1c1f7a4c29f0c56a8b004ce430f714cb3eb45d GIT binary patch literal 8459 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 J@r>#_{tv%9>k0q> literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/h11/__pycache__/_util.cpython-312.pyc b/backend/venv/Lib/site-packages/h11/__pycache__/_util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..caa9920d0a84d5102cf089dbfe806dae441df315 GIT binary patch literal 4715 zcma)9U2Gf25#Hn7k;i{ge^y*8JymrQDwYz*ZtALu>VXjpivQ=A(E zu5y5zjuUg(j8lnb9)aa%f@aJl&6+7Hm}wfJS(+(E@J%scX4d6GUxd(@nKk=l)3yg$dk;$b*XTqHk3c|cNCFVeDTFf&6i%b z49{0)oGa9;vWg$Ota~1XjyzXgvZ*i4)t0CqL;8l!eEBC8%cCOtq=3dcgT2R~bDL075KK~tm_k7` zV`hX(rbuN|GUZ~_jDl^VH94=aBuv(SED>_yhC!D+P*Jrire)}!RasPZb=h)k=mXm+ zs$Pkzug=X~e(L1ZNp-1njHyIIg=em0xvCET6;)qwJ*FF;x}dvMHEi8=PpB)FS5mzd zM>U*^!KgT*qGj83QMXTkqNW;b_z-J{J90rCgM_=H6&QDrx4G%xdNK&!Ae&H3wpt<(65WuGMrvl z-Rj~Zb-5BC7xY*`Hw4STu_o-Jx|A)0Rm#?4$y2KU0ISH44YI&DZm^Z=7)F&b@Epil z(wT?w(!s26S3!Q~%&_7|UY%i{Kuh{EVjq1ACM@Eb#~BT!SY-(AGOcvtBRK8D6@Dm?xxNNO$pTe9{W=A| z-e=hdRb~Ou0>wc+#2?o>K>h@1IDwj$PM!pZgH3JQS%G&vKAcc<2s}`_N_)!A0g6mo z)T_3Kp>g`@r`4BW`IW#65F+X#tx#qeD&zyBGzoG!G{evjC3llVh*n=LyNiDA0aW=> zhPv-AAv$1%wV z={(*IL|@S~t73VY#`-~xyy#0VwTmnV1I}^r%z*KKUp_xQ4<=n?dbte9n_qF@dMKAE zGbl({2CO-(Hou@7fEIHe#>?}Utc7{k^62CeaCL~udGP&HTGg}csihhl0m-YwhcuoF zwaLRf_Zc8-WH*^@O7Bj8G`f|1Y`6bgo5x<;?!UO1y11+4zEqBGDMwqU?+kpQ9N!sx zrXl@Vd2|m}k-T6v!7KR~9+z_LSH5lM(j>BWn0UQDi9>7X>UY)!nd?L)`BMgfn zKdx!~g44851co((i!)VzFn>&AlN(s8LA6Hq zGvw%GLwYaM9wga;MuHn=CNDEQ0~Cdc&8X z=+SxD_({l(W!=+sw&(`_Lw|)2_OS}uTLW^N)XB9_OBja_WPuL%rc{^QV|9^bBajcS zh1dxvLR%N#CpRO#Y*UYfYu^#-(zUSSIkHKMuE&4LTboKN@Jy(dWk( znNwYYO3MRhO~73CBodw-PC(C>`66x@ND^uQDTWT>WDYv+IUsAK9VO}hTd!}t-gE*;W6kl~6CX^pu5b2FG|um4)H?&)nd6%f&&j@9FKoQ9ojkTF9peV~ zliHj%%WpMm`%2i$3%hxsd;$)V{uAcJP3AN%-J>fGJ`RZS^Yw5E1FcbWykt;owFtLOgq26m3N7_((%|FS(QLYXqTnDC1!y;EDDy5A%qD_Wmb4 zrw|16{fpfH&w2T~5{l{I1c!g7$>9#Z1;ilLi_ zCGZb=*q(GHB)#xc9zM-`Nv#(Mz0wPUP@M5)-8C$0b)4QMUFX z-U;|1fikk<0qD_h5UBW>>L)BWD5DJcDnNdeR`64SjlqBo0|EEF1kC|Zu`Iqr@-uvK z5y%?(TP)dl@#iZa9^Z-`;dtJS<(gw3&VCVlWG9ur_3Fl}&7W?kMjJwpzneL-Ir98= z=Io|&b~oAA%)NVN?RD;^nY^%?fzKyQ$#5FHV)7$?6lyxCzyh>!-0^!86G;F_4pKBd zLz`l-Lrn|;a0FSHYl6~(-)$Fgs3PG>n?sue8nNle(K4 zA77SQRGgWg7azZp;WJ3XuV81Zn1Z7G^rFPv+|0c6nDYGmPO4oI d8_*7r%Zhn`#0O?ZM#c{c4E*Aa+(j%v0RU^ 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" + r":" + r"{OWS}" + r"(?P{field_value})" + r"{OWS}".format(**globals()) +) + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line +# +# request-line = method SP request-target SP HTTP-version CRLF +# method = token +# HTTP-version = HTTP-name "/" DIGIT "." DIGIT +# HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive +# +# request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full +# URL, host+port (for connect), or even "*", but in any case we are guaranteed +# that it contists of the visible printing characters. +method = token +request_target = r"{vchar}+".format(**globals()) +http_version = r"HTTP/(?P[0-9]\.[0-9])" +request_line = ( + r"(?P{method})" + r" " + r"(?P{request_target})" + r" " + r"{http_version}".format(**globals()) +) + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line +# +# status-line = HTTP-version SP status-code SP reason-phrase CRLF +# status-code = 3DIGIT +# reason-phrase = *( HTAB / SP / VCHAR / obs-text ) +status_code = r"[0-9]{3}" +reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals()) +status_line = ( + r"{http_version}" + r" " + r"(?P{status_code})" + # However, there are apparently a few too many servers out there that just + # leave out the reason phrase: + # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036 + # https://github.com/seanmonstar/httparse/issues/29 + # so make it optional. ?: is a non-capturing group. + r"(?: (?P{reason_phrase}))?".format(**globals()) +) + +HEXDIG = r"[0-9A-Fa-f]" +# Actually +# +# chunk-size = 1*HEXDIG +# +# but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20 +chunk_size = r"({HEXDIG}){{1,20}}".format(**globals()) +# Actually +# +# chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) +# +# but we aren't parsing the things so we don't really care. +chunk_ext = r";.*" +chunk_header = ( + r"(?P{chunk_size})" + r"(?P{chunk_ext})?" + r"{OWS}\r\n".format( + **globals() + ) # Even though the specification does not allow for extra whitespaces, + # we are lenient with trailing whitespaces because some servers on the wild use it. +) diff --git a/backend/venv/Lib/site-packages/h11/_connection.py b/backend/venv/Lib/site-packages/h11/_connection.py new file mode 100644 index 0000000..e37d82a --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_connection.py @@ -0,0 +1,659 @@ +# This contains the main Connection class. Everything in h11 revolves around +# this. +from typing import ( + Any, + Callable, + cast, + Dict, + List, + Optional, + overload, + Tuple, + Type, + Union, +) + +from ._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from ._headers import get_comma_header, has_expect_100_continue, set_comma_header +from ._readers import READERS, ReadersType +from ._receivebuffer import ReceiveBuffer +from ._state import ( + _SWITCH_CONNECT, + _SWITCH_UPGRADE, + CLIENT, + ConnectionState, + DONE, + ERROR, + MIGHT_SWITCH_PROTOCOL, + SEND_BODY, + SERVER, + SWITCHED_PROTOCOL, +) +from ._util import ( # Import the internal things we need + LocalProtocolError, + RemoteProtocolError, + Sentinel, +) +from ._writers import WRITERS, WritersType + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = ["Connection", "NEED_DATA", "PAUSED"] + + +class NEED_DATA(Sentinel, metaclass=Sentinel): + pass + + +class PAUSED(Sentinel, metaclass=Sentinel): + pass + + +# If we ever have this much buffered without it making a complete parseable +# event, we error out. The only time we really buffer is when reading the +# request/response line + headers together, so this is effectively the limit on +# the size of that. +# +# Some precedents for defaults: +# - node.js: 80 * 1024 +# - tomcat: 8 * 1024 +# - IIS: 16 * 1024 +# - Apache: <8 KiB per line> +DEFAULT_MAX_INCOMPLETE_EVENT_SIZE = 16 * 1024 + + +# RFC 7230's rules for connection lifecycles: +# - If either side says they want to close the connection, then the connection +# must close. +# - HTTP/1.1 defaults to keep-alive unless someone says Connection: close +# - HTTP/1.0 defaults to close unless both sides say Connection: keep-alive +# (and even this is a mess -- e.g. if you're implementing a proxy then +# sending Connection: keep-alive is forbidden). +# +# We simplify life by simply not supporting keep-alive with HTTP/1.0 peers. So +# our rule is: +# - If someone says Connection: close, we will close +# - If someone uses HTTP/1.0, we will close. +def _keep_alive(event: Union[Request, Response]) -> bool: + connection = get_comma_header(event.headers, b"connection") + if b"close" in connection: + return False + if getattr(event, "http_version", b"1.1") < b"1.1": + return False + return True + + +def _body_framing( + request_method: bytes, event: Union[Request, Response] +) -> Tuple[str, Union[Tuple[()], Tuple[int]]]: + # Called when we enter SEND_BODY to figure out framing information for + # this body. + # + # These are the only two events that can trigger a SEND_BODY state: + assert type(event) in (Request, Response) + # Returns one of: + # + # ("content-length", count) + # ("chunked", ()) + # ("http/1.0", ()) + # + # which are (lookup key, *args) for constructing body reader/writer + # objects. + # + # Reference: https://tools.ietf.org/html/rfc7230#section-3.3.3 + # + # Step 1: some responses always have an empty body, regardless of what the + # headers say. + if type(event) is Response: + if ( + event.status_code in (204, 304) + or request_method == b"HEAD" + or (request_method == b"CONNECT" and 200 <= event.status_code < 300) + ): + return ("content-length", (0,)) + # Section 3.3.3 also lists another case -- responses with status_code + # < 200. For us these are InformationalResponses, not Responses, so + # they can't get into this function in the first place. + assert event.status_code >= 200 + + # Step 2: check for Transfer-Encoding (T-E beats C-L): + transfer_encodings = get_comma_header(event.headers, b"transfer-encoding") + if transfer_encodings: + assert transfer_encodings == [b"chunked"] + return ("chunked", ()) + + # Step 3: check for Content-Length + content_lengths = get_comma_header(event.headers, b"content-length") + if content_lengths: + return ("content-length", (int(content_lengths[0]),)) + + # Step 4: no applicable headers; fallback/default depends on type + if type(event) is Request: + return ("content-length", (0,)) + else: + return ("http/1.0", ()) + + +################################################################ +# +# The main Connection class +# +################################################################ + + +class Connection: + """An object encapsulating the state of an HTTP connection. + + Args: + our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If + you're implementing a server, pass :data:`h11.SERVER`. + + max_incomplete_event_size (int): + The maximum number of bytes we're willing to buffer of an + incomplete event. In practice this mostly sets a limit on the + maximum size of the request/response line + headers. If this is + exceeded, then :meth:`next_event` will raise + :exc:`RemoteProtocolError`. + + """ + + def __init__( + self, + our_role: Type[Sentinel], + max_incomplete_event_size: int = DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, + ) -> None: + self._max_incomplete_event_size = max_incomplete_event_size + # State and role tracking + if our_role not in (CLIENT, SERVER): + raise ValueError(f"expected CLIENT or SERVER, not {our_role!r}") + self.our_role = our_role + self.their_role: Type[Sentinel] + if our_role is CLIENT: + self.their_role = SERVER + else: + self.their_role = CLIENT + self._cstate = ConnectionState() + + # Callables for converting data->events or vice-versa given the + # current state + self._writer = self._get_io_object(self.our_role, None, WRITERS) + self._reader = self._get_io_object(self.their_role, None, READERS) + + # Holds any unprocessed received data + self._receive_buffer = ReceiveBuffer() + # If this is true, then it indicates that the incoming connection was + # closed *after* the end of whatever's in self._receive_buffer: + self._receive_buffer_closed = False + + # Extra bits of state that don't fit into the state machine. + # + # These two are only used to interpret framing headers for figuring + # out how to read/write response bodies. their_http_version is also + # made available as a convenient public API. + self.their_http_version: Optional[bytes] = None + self._request_method: Optional[bytes] = None + # This is pure flow-control and doesn't at all affect the set of legal + # transitions, so no need to bother ConnectionState with it: + self.client_is_waiting_for_100_continue = False + + @property + def states(self) -> Dict[Type[Sentinel], Type[Sentinel]]: + """A dictionary like:: + + {CLIENT: , SERVER: } + + See :ref:`state-machine` for details. + + """ + return dict(self._cstate.states) + + @property + def our_state(self) -> Type[Sentinel]: + """The current state of whichever role we are playing. See + :ref:`state-machine` for details. + """ + return self._cstate.states[self.our_role] + + @property + def their_state(self) -> Type[Sentinel]: + """The current state of whichever role we are NOT playing. See + :ref:`state-machine` for details. + """ + return self._cstate.states[self.their_role] + + @property + def they_are_waiting_for_100_continue(self) -> bool: + return self.their_role is CLIENT and self.client_is_waiting_for_100_continue + + def start_next_cycle(self) -> None: + """Attempt to reset our connection state for a new request/response + cycle. + + If both client and server are in :data:`DONE` state, then resets them + both to :data:`IDLE` state in preparation for a new request/response + cycle on this same connection. Otherwise, raises a + :exc:`LocalProtocolError`. + + See :ref:`keepalive-and-pipelining`. + + """ + old_states = dict(self._cstate.states) + self._cstate.start_next_cycle() + self._request_method = None + # self.their_http_version gets left alone, since it presumably lasts + # beyond a single request/response cycle + assert not self.client_is_waiting_for_100_continue + self._respond_to_state_changes(old_states) + + def _process_error(self, role: Type[Sentinel]) -> None: + old_states = dict(self._cstate.states) + self._cstate.process_error(role) + self._respond_to_state_changes(old_states) + + def _server_switch_event(self, event: Event) -> Optional[Type[Sentinel]]: + if type(event) is InformationalResponse and event.status_code == 101: + return _SWITCH_UPGRADE + if type(event) is Response: + if ( + _SWITCH_CONNECT in self._cstate.pending_switch_proposals + and 200 <= event.status_code < 300 + ): + return _SWITCH_CONNECT + return None + + # All events go through here + def _process_event(self, role: Type[Sentinel], event: Event) -> None: + # First, pass the event through the state machine to make sure it + # succeeds. + old_states = dict(self._cstate.states) + if role is CLIENT and type(event) is Request: + if event.method == b"CONNECT": + self._cstate.process_client_switch_proposal(_SWITCH_CONNECT) + if get_comma_header(event.headers, b"upgrade"): + self._cstate.process_client_switch_proposal(_SWITCH_UPGRADE) + server_switch_event = None + if role is SERVER: + server_switch_event = self._server_switch_event(event) + self._cstate.process_event(role, type(event), server_switch_event) + + # Then perform the updates triggered by it. + + if type(event) is Request: + self._request_method = event.method + + if role is self.their_role and type(event) in ( + Request, + Response, + InformationalResponse, + ): + event = cast(Union[Request, Response, InformationalResponse], event) + self.their_http_version = event.http_version + + # Keep alive handling + # + # RFC 7230 doesn't really say what one should do if Connection: close + # shows up on a 1xx InformationalResponse. I think the idea is that + # this is not supposed to happen. In any case, if it does happen, we + # ignore it. + if type(event) in (Request, Response) and not _keep_alive( + cast(Union[Request, Response], event) + ): + self._cstate.process_keep_alive_disabled() + + # 100-continue + if type(event) is Request and has_expect_100_continue(event): + self.client_is_waiting_for_100_continue = True + if type(event) in (InformationalResponse, Response): + self.client_is_waiting_for_100_continue = False + if role is CLIENT and type(event) in (Data, EndOfMessage): + self.client_is_waiting_for_100_continue = False + + self._respond_to_state_changes(old_states, event) + + def _get_io_object( + self, + role: Type[Sentinel], + event: Optional[Event], + io_dict: Union[ReadersType, WritersType], + ) -> Optional[Callable[..., Any]]: + # event may be None; it's only used when entering SEND_BODY + state = self._cstate.states[role] + if state is SEND_BODY: + # Special case: the io_dict has a dict of reader/writer factories + # that depend on the request/response framing. + framing_type, args = _body_framing( + cast(bytes, self._request_method), cast(Union[Request, Response], event) + ) + return io_dict[SEND_BODY][framing_type](*args) # type: ignore[index] + else: + # General case: the io_dict just has the appropriate reader/writer + # for this state + return io_dict.get((role, state)) # type: ignore[return-value] + + # This must be called after any action that might have caused + # self._cstate.states to change. + def _respond_to_state_changes( + self, + old_states: Dict[Type[Sentinel], Type[Sentinel]], + event: Optional[Event] = None, + ) -> None: + # Update reader/writer + if self.our_state != old_states[self.our_role]: + self._writer = self._get_io_object(self.our_role, event, WRITERS) + if self.their_state != old_states[self.their_role]: + self._reader = self._get_io_object(self.their_role, event, READERS) + + @property + def trailing_data(self) -> Tuple[bytes, bool]: + """Data that has been received, but not yet processed, represented as + a tuple with two elements, where the first is a byte-string containing + the unprocessed data itself, and the second is a bool that is True if + the receive connection was closed. + + See :ref:`switching-protocols` for discussion of why you'd want this. + """ + return (bytes(self._receive_buffer), self._receive_buffer_closed) + + def receive_data(self, data: bytes) -> None: + """Add data to our internal receive buffer. + + This does not actually do any processing on the data, just stores + it. To trigger processing, you have to call :meth:`next_event`. + + Args: + data (:term:`bytes-like object`): + The new data that was just received. + + Special case: If *data* is an empty byte-string like ``b""``, + then this indicates that the remote side has closed the + connection (end of file). Normally this is convenient, because + standard Python APIs like :meth:`file.read` or + :meth:`socket.recv` use ``b""`` to indicate end-of-file, while + other failures to read are indicated using other mechanisms + like raising :exc:`TimeoutError`. When using such an API you + can just blindly pass through whatever you get from ``read`` + to :meth:`receive_data`, and everything will work. + + But, if you have an API where reading an empty string is a + valid non-EOF condition, then you need to be aware of this and + make sure to check for such strings and avoid passing them to + :meth:`receive_data`. + + Returns: + Nothing, but after calling this you should call :meth:`next_event` + to parse the newly received data. + + Raises: + RuntimeError: + Raised if you pass an empty *data*, indicating EOF, and then + pass a non-empty *data*, indicating more data that somehow + arrived after the EOF. + + (Calling ``receive_data(b"")`` multiple times is fine, + and equivalent to calling it once.) + + """ + if data: + if self._receive_buffer_closed: + raise RuntimeError("received close, then received more data?") + self._receive_buffer += data + else: + self._receive_buffer_closed = True + + def _extract_next_receive_event( + self, + ) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: + state = self.their_state + # We don't pause immediately when they enter DONE, because even in + # DONE state we can still process a ConnectionClosed() event. But + # if we have data in our buffer, then we definitely aren't getting + # a ConnectionClosed() immediately and we need to pause. + if state is DONE and self._receive_buffer: + return PAUSED + if state is MIGHT_SWITCH_PROTOCOL or state is SWITCHED_PROTOCOL: + return PAUSED + assert self._reader is not None + event = self._reader(self._receive_buffer) + if event is None: + if not self._receive_buffer and self._receive_buffer_closed: + # In some unusual cases (basically just HTTP/1.0 bodies), EOF + # triggers an actual protocol event; in that case, we want to + # return that event, and then the state will change and we'll + # get called again to generate the actual ConnectionClosed(). + if hasattr(self._reader, "read_eof"): + event = self._reader.read_eof() + else: + event = ConnectionClosed() + if event is None: + event = NEED_DATA + return event # type: ignore[no-any-return] + + def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: + """Parse the next event out of our receive buffer, update our internal + state, and return it. + + This is a mutating operation -- think of it like calling :func:`next` + on an iterator. + + Returns: + : One of three things: + + 1) An event object -- see :ref:`events`. + + 2) The special constant :data:`NEED_DATA`, which indicates that + you need to read more data from your socket and pass it to + :meth:`receive_data` before this method will be able to return + any more events. + + 3) The special constant :data:`PAUSED`, which indicates that we + are not in a state where we can process incoming data (usually + because the peer has finished their part of the current + request/response cycle, and you have not yet called + :meth:`start_next_cycle`). See :ref:`flow-control` for details. + + Raises: + RemoteProtocolError: + The peer has misbehaved. You should close the connection + (possibly after sending some kind of 4xx response). + + Once this method returns :class:`ConnectionClosed` once, then all + subsequent calls will also return :class:`ConnectionClosed`. + + If this method raises any exception besides :exc:`RemoteProtocolError` + then that's a bug -- if it happens please file a bug report! + + If this method raises any exception then it also sets + :attr:`Connection.their_state` to :data:`ERROR` -- see + :ref:`error-handling` for discussion. + + """ + + if self.their_state is ERROR: + raise RemoteProtocolError("Can't receive data when peer state is ERROR") + try: + event = self._extract_next_receive_event() + if event not in [NEED_DATA, PAUSED]: + self._process_event(self.their_role, cast(Event, event)) + if event is NEED_DATA: + if len(self._receive_buffer) > self._max_incomplete_event_size: + # 431 is "Request header fields too large" which is pretty + # much the only situation where we can get here + raise RemoteProtocolError( + "Receive buffer too long", error_status_hint=431 + ) + if self._receive_buffer_closed: + # We're still trying to complete some event, but that's + # never going to happen because no more data is coming + raise RemoteProtocolError("peer unexpectedly closed connection") + return event + except BaseException as exc: + self._process_error(self.their_role) + if isinstance(exc, LocalProtocolError): + exc._reraise_as_remote_protocol_error() + else: + raise + + @overload + def send(self, event: ConnectionClosed) -> None: + ... + + @overload + def send( + self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] + ) -> bytes: + ... + + @overload + def send(self, event: Event) -> Optional[bytes]: + ... + + def send(self, event: Event) -> Optional[bytes]: + """Convert a high-level event into bytes that can be sent to the peer, + while updating our internal state machine. + + Args: + event: The :ref:`event ` to send. + + Returns: + If ``type(event) is ConnectionClosed``, then returns + ``None``. Otherwise, returns a :term:`bytes-like object`. + + Raises: + LocalProtocolError: + Sending this event at this time would violate our + understanding of the HTTP/1.1 protocol. + + If this method raises any exception then it also sets + :attr:`Connection.our_state` to :data:`ERROR` -- see + :ref:`error-handling` for discussion. + + """ + data_list = self.send_with_data_passthrough(event) + if data_list is None: + return None + else: + return b"".join(data_list) + + def send_with_data_passthrough(self, event: Event) -> Optional[List[bytes]]: + """Identical to :meth:`send`, except that in situations where + :meth:`send` returns a single :term:`bytes-like object`, this instead + returns a list of them -- and when sending a :class:`Data` event, this + list is guaranteed to contain the exact object you passed in as + :attr:`Data.data`. See :ref:`sendfile` for discussion. + + """ + if self.our_state is ERROR: + raise LocalProtocolError("Can't send data when our state is ERROR") + try: + if type(event) is Response: + event = self._clean_up_response_headers_for_sending(event) + # We want to call _process_event before calling the writer, + # because if someone tries to do something invalid then this will + # give a sensible error message, while our writers all just assume + # they will only receive valid events. But, _process_event might + # change self._writer. So we have to do a little dance: + writer = self._writer + self._process_event(self.our_role, event) + if type(event) is ConnectionClosed: + return None + else: + # In any situation where writer is None, process_event should + # have raised ProtocolError + assert writer is not None + data_list: List[bytes] = [] + writer(event, data_list.append) + return data_list + except: + self._process_error(self.our_role) + raise + + def send_failed(self) -> None: + """Notify the state machine that we failed to send the data it gave + us. + + This causes :attr:`Connection.our_state` to immediately become + :data:`ERROR` -- see :ref:`error-handling` for discussion. + + """ + self._process_error(self.our_role) + + # When sending a Response, we take responsibility for a few things: + # + # - Sometimes you MUST set Connection: close. We take care of those + # times. (You can also set it yourself if you want, and if you do then + # we'll respect that and close the connection at the right time. But you + # don't have to worry about that unless you want to.) + # + # - The user has to set Content-Length if they want it. Otherwise, for + # responses that have bodies (e.g. not HEAD), then we will automatically + # select the right mechanism for streaming a body of unknown length, + # which depends on depending on the peer's HTTP version. + # + # This function's *only* responsibility is making sure headers are set up + # right -- everything downstream just looks at the headers. There are no + # side channels. + def _clean_up_response_headers_for_sending(self, response: Response) -> Response: + assert type(response) is Response + + headers = response.headers + need_close = False + + # HEAD requests need some special handling: they always act like they + # have Content-Length: 0, and that's how _body_framing treats + # them. But their headers are supposed to match what we would send if + # the request was a GET. (Technically there is one deviation allowed: + # we're allowed to leave out the framing headers -- see + # https://tools.ietf.org/html/rfc7231#section-4.3.2 . But it's just as + # easy to get them right.) + method_for_choosing_headers = cast(bytes, self._request_method) + if method_for_choosing_headers == b"HEAD": + method_for_choosing_headers = b"GET" + framing_type, _ = _body_framing(method_for_choosing_headers, response) + if framing_type in ("chunked", "http/1.0"): + # This response has a body of unknown length. + # If our peer is HTTP/1.1, we use Transfer-Encoding: chunked + # If our peer is HTTP/1.0, we use no framing headers, and close the + # connection afterwards. + # + # Make sure to clear Content-Length (in principle user could have + # set both and then we ignored Content-Length b/c + # Transfer-Encoding overwrote it -- this would be naughty of them, + # but the HTTP spec says that if our peer does this then we have + # to fix it instead of erroring out, so we'll accord the user the + # same respect). + headers = set_comma_header(headers, b"content-length", []) + if self.their_http_version is None or self.their_http_version < b"1.1": + # Either we never got a valid request and are sending back an + # error (their_http_version is None), so we assume the worst; + # or else we did get a valid HTTP/1.0 request, so we know that + # they don't understand chunked encoding. + headers = set_comma_header(headers, b"transfer-encoding", []) + # This is actually redundant ATM, since currently we + # unconditionally disable keep-alive when talking to HTTP/1.0 + # peers. But let's be defensive just in case we add + # Connection: keep-alive support later: + if self._request_method != b"HEAD": + need_close = True + else: + headers = set_comma_header(headers, b"transfer-encoding", [b"chunked"]) + + if not self._cstate.keep_alive or need_close: + # Make sure Connection: close is set + connection = set(get_comma_header(headers, b"connection")) + connection.discard(b"keep-alive") + connection.add(b"close") + headers = set_comma_header(headers, b"connection", sorted(connection)) + + return Response( + headers=headers, + status_code=response.status_code, + http_version=response.http_version, + reason=response.reason, + ) diff --git a/backend/venv/Lib/site-packages/h11/_events.py b/backend/venv/Lib/site-packages/h11/_events.py new file mode 100644 index 0000000..ca1c3ad --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_events.py @@ -0,0 +1,369 @@ +# High level events that make up HTTP/1.1 conversations. Loosely inspired by +# the corresponding events in hyper-h2: +# +# http://python-hyper.org/h2/en/stable/api.html#events +# +# Don't subclass these. Stuff will break. + +import re +from abc import ABC +from dataclasses import dataclass +from typing import List, Tuple, Union + +from ._abnf import method, request_target +from ._headers import Headers, normalize_and_validate +from ._util import bytesify, LocalProtocolError, validate + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = [ + "Event", + "Request", + "InformationalResponse", + "Response", + "Data", + "EndOfMessage", + "ConnectionClosed", +] + +method_re = re.compile(method.encode("ascii")) +request_target_re = re.compile(request_target.encode("ascii")) + + +class Event(ABC): + """ + Base class for h11 events. + """ + + __slots__ = () + + +@dataclass(init=False, frozen=True) +class Request(Event): + """The beginning of an HTTP request. + + Fields: + + .. attribute:: method + + An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte + string. :term:`Bytes-like objects ` and native + strings containing only ascii characters will be automatically + converted to byte strings. + + .. attribute:: target + + The target of an HTTP request, e.g. ``b"/index.html"``, or one of the + more exotic formats described in `RFC 7320, section 5.3 + `_. Always a byte + string. :term:`Bytes-like objects ` and native + strings containing only ascii characters will be automatically + converted to byte strings. + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + """ + + __slots__ = ("method", "headers", "target", "http_version") + + method: bytes + headers: Headers + target: bytes + http_version: bytes + + def __init__( + self, + *, + method: Union[bytes, str], + headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], + target: Union[bytes, str], + http_version: Union[bytes, str] = b"1.1", + _parsed: bool = False, + ) -> None: + super().__init__() + if isinstance(headers, Headers): + object.__setattr__(self, "headers", headers) + else: + object.__setattr__( + self, "headers", normalize_and_validate(headers, _parsed=_parsed) + ) + if not _parsed: + object.__setattr__(self, "method", bytesify(method)) + object.__setattr__(self, "target", bytesify(target)) + object.__setattr__(self, "http_version", bytesify(http_version)) + else: + object.__setattr__(self, "method", method) + object.__setattr__(self, "target", target) + object.__setattr__(self, "http_version", http_version) + + # "A server MUST respond with a 400 (Bad Request) status code to any + # HTTP/1.1 request message that lacks a Host header field and to any + # request message that contains more than one Host header field or a + # Host header field with an invalid field-value." + # -- https://tools.ietf.org/html/rfc7230#section-5.4 + host_count = 0 + for name, value in self.headers: + if name == b"host": + host_count += 1 + if self.http_version == b"1.1" and host_count == 0: + raise LocalProtocolError("Missing mandatory Host: header") + if host_count > 1: + raise LocalProtocolError("Found multiple Host: headers") + + validate(method_re, self.method, "Illegal method characters") + validate(request_target_re, self.target, "Illegal target characters") + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class _ResponseBase(Event): + __slots__ = ("headers", "http_version", "reason", "status_code") + + headers: Headers + http_version: bytes + reason: bytes + status_code: int + + def __init__( + self, + *, + headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], + status_code: int, + http_version: Union[bytes, str] = b"1.1", + reason: Union[bytes, str] = b"", + _parsed: bool = False, + ) -> None: + super().__init__() + if isinstance(headers, Headers): + object.__setattr__(self, "headers", headers) + else: + object.__setattr__( + self, "headers", normalize_and_validate(headers, _parsed=_parsed) + ) + if not _parsed: + object.__setattr__(self, "reason", bytesify(reason)) + object.__setattr__(self, "http_version", bytesify(http_version)) + if not isinstance(status_code, int): + raise LocalProtocolError("status code must be integer") + # Because IntEnum objects are instances of int, but aren't + # duck-compatible (sigh), see gh-72. + object.__setattr__(self, "status_code", int(status_code)) + else: + object.__setattr__(self, "reason", reason) + object.__setattr__(self, "http_version", http_version) + object.__setattr__(self, "status_code", status_code) + + self.__post_init__() + + def __post_init__(self) -> None: + pass + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class InformationalResponse(_ResponseBase): + """An HTTP informational response. + + Fields: + + .. attribute:: status_code + + The status code of this response, as an integer. For an + :class:`InformationalResponse`, this is always in the range [100, + 200). + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for + details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + .. attribute:: reason + + The reason phrase of this response, as a byte string. For example: + ``b"OK"``, or ``b"Not Found"``. + + """ + + def __post_init__(self) -> None: + if not (100 <= self.status_code < 200): + raise LocalProtocolError( + "InformationalResponse status_code should be in range " + "[100, 200), not {}".format(self.status_code) + ) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class Response(_ResponseBase): + """The beginning of an HTTP response. + + Fields: + + .. attribute:: status_code + + The status code of this response, as an integer. For an + :class:`Response`, this is always in the range [200, + 1000). + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + .. attribute:: reason + + The reason phrase of this response, as a byte string. For example: + ``b"OK"``, or ``b"Not Found"``. + + """ + + def __post_init__(self) -> None: + if not (200 <= self.status_code < 1000): + raise LocalProtocolError( + "Response status_code should be in range [200, 1000), not {}".format( + self.status_code + ) + ) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class Data(Event): + """Part of an HTTP message body. + + Fields: + + .. attribute:: data + + A :term:`bytes-like object` containing part of a message body. Or, if + using the ``combine=False`` argument to :meth:`Connection.send`, then + any object that your socket writing code knows what to do with, and for + which calling :func:`len` returns the number of bytes that will be + written -- see :ref:`sendfile` for details. + + .. attribute:: chunk_start + + A marker that indicates whether this data object is from the start of a + chunked transfer encoding chunk. This field is ignored when when a Data + event is provided to :meth:`Connection.send`: it is only valid on + events emitted from :meth:`Connection.next_event`. You probably + shouldn't use this attribute at all; see + :ref:`chunk-delimiters-are-bad` for details. + + .. attribute:: chunk_end + + A marker that indicates whether this data object is the last for a + given chunked transfer encoding chunk. This field is ignored when when + a Data event is provided to :meth:`Connection.send`: it is only valid + on events emitted from :meth:`Connection.next_event`. You probably + shouldn't use this attribute at all; see + :ref:`chunk-delimiters-are-bad` for details. + + """ + + __slots__ = ("data", "chunk_start", "chunk_end") + + data: bytes + chunk_start: bool + chunk_end: bool + + def __init__( + self, data: bytes, chunk_start: bool = False, chunk_end: bool = False + ) -> None: + object.__setattr__(self, "data", data) + object.__setattr__(self, "chunk_start", chunk_start) + object.__setattr__(self, "chunk_end", chunk_end) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +# XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that +# are forbidden to be sent in a trailer, since processing them as if they were +# present in the header section might bypass external security filters." +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part +# Unfortunately, the list of forbidden fields is long and vague :-/ +@dataclass(init=False, frozen=True) +class EndOfMessage(Event): + """The end of an HTTP message. + + Fields: + + .. attribute:: headers + + Default value: ``[]`` + + Any trailing headers attached to this message, represented as a list of + (name, value) pairs. See :ref:`the header normalization rules + ` for details. + + Must be empty unless ``Transfer-Encoding: chunked`` is in use. + + """ + + __slots__ = ("headers",) + + headers: Headers + + def __init__( + self, + *, + headers: Union[ + Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]], None + ] = None, + _parsed: bool = False, + ) -> None: + super().__init__() + if headers is None: + headers = Headers([]) + elif not isinstance(headers, Headers): + headers = normalize_and_validate(headers, _parsed=_parsed) + + object.__setattr__(self, "headers", headers) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(frozen=True) +class ConnectionClosed(Event): + """This event indicates that the sender has closed their outgoing + connection. + + Note that this does not necessarily mean that they can't *receive* further + data, because TCP connections are composed to two one-way channels which + can be closed independently. See :ref:`closing` for details. + + No fields. + """ + + pass diff --git a/backend/venv/Lib/site-packages/h11/_headers.py b/backend/venv/Lib/site-packages/h11/_headers.py new file mode 100644 index 0000000..31da3e2 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_headers.py @@ -0,0 +1,282 @@ +import re +from typing import AnyStr, cast, List, overload, Sequence, Tuple, TYPE_CHECKING, Union + +from ._abnf import field_name, field_value +from ._util import bytesify, LocalProtocolError, validate + +if TYPE_CHECKING: + from ._events import Request + +try: + from typing import Literal +except ImportError: + from typing_extensions import Literal # type: ignore + +CONTENT_LENGTH_MAX_DIGITS = 20 # allow up to 1 billion TB - 1 + + +# Facts +# ----- +# +# Headers are: +# keys: case-insensitive ascii +# values: mixture of ascii and raw bytes +# +# "Historically, HTTP has allowed field content with text in the ISO-8859-1 +# charset [ISO-8859-1], supporting other charsets only through use of +# [RFC2047] encoding. In practice, most HTTP header field values use only a +# subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD +# limit their field values to US-ASCII octets. A recipient SHOULD treat other +# octets in field content (obs-text) as opaque data." +# And it deprecates all non-ascii values +# +# Leading/trailing whitespace in header names is forbidden +# +# Values get leading/trailing whitespace stripped +# +# Content-Disposition actually needs to contain unicode semantically; to +# accomplish this it has a terrifically weird way of encoding the filename +# itself as ascii (and even this still has lots of cross-browser +# incompatibilities) +# +# Order is important: +# "a proxy MUST NOT change the order of these field values when forwarding a +# message" +# (and there are several headers where the order indicates a preference) +# +# Multiple occurences of the same header: +# "A sender MUST NOT generate multiple header fields with the same field name +# in a message unless either the entire field value for that header field is +# defined as a comma-separated list [or the header is Set-Cookie which gets a +# special exception]" - RFC 7230. (cookies are in RFC 6265) +# +# So every header aside from Set-Cookie can be merged by b", ".join if it +# occurs repeatedly. But, of course, they can't necessarily be split by +# .split(b","), because quoting. +# +# Given all this mess (case insensitive, duplicates allowed, order is +# important, ...), there doesn't appear to be any standard way to handle +# headers in Python -- they're almost like dicts, but... actually just +# aren't. For now we punt and just use a super simple representation: headers +# are a list of pairs +# +# [(name1, value1), (name2, value2), ...] +# +# where all entries are bytestrings, names are lowercase and have no +# leading/trailing whitespace, and values are bytestrings with no +# leading/trailing whitespace. Searching and updating are done via naive O(n) +# methods. +# +# Maybe a dict-of-lists would be better? + +_content_length_re = re.compile(rb"[0-9]+") +_field_name_re = re.compile(field_name.encode("ascii")) +_field_value_re = re.compile(field_value.encode("ascii")) + + +class Headers(Sequence[Tuple[bytes, bytes]]): + """ + A list-like interface that allows iterating over headers as byte-pairs + of (lowercased-name, value). + + Internally we actually store the representation as three-tuples, + including both the raw original casing, in order to preserve casing + over-the-wire, and the lowercased name, for case-insensitive comparisions. + + r = Request( + method="GET", + target="/", + headers=[("Host", "example.org"), ("Connection", "keep-alive")], + http_version="1.1", + ) + assert r.headers == [ + (b"host", b"example.org"), + (b"connection", b"keep-alive") + ] + assert r.headers.raw_items() == [ + (b"Host", b"example.org"), + (b"Connection", b"keep-alive") + ] + """ + + __slots__ = "_full_items" + + def __init__(self, full_items: List[Tuple[bytes, bytes, bytes]]) -> None: + self._full_items = full_items + + def __bool__(self) -> bool: + return bool(self._full_items) + + def __eq__(self, other: object) -> bool: + return list(self) == list(other) # type: ignore + + def __len__(self) -> int: + return len(self._full_items) + + def __repr__(self) -> str: + return "" % repr(list(self)) + + def __getitem__(self, idx: int) -> Tuple[bytes, bytes]: # type: ignore[override] + _, name, value = self._full_items[idx] + return (name, value) + + def raw_items(self) -> List[Tuple[bytes, bytes]]: + return [(raw_name, value) for raw_name, _, value in self._full_items] + + +HeaderTypes = Union[ + List[Tuple[bytes, bytes]], + List[Tuple[bytes, str]], + List[Tuple[str, bytes]], + List[Tuple[str, str]], +] + + +@overload +def normalize_and_validate(headers: Headers, _parsed: Literal[True]) -> Headers: + ... + + +@overload +def normalize_and_validate(headers: HeaderTypes, _parsed: Literal[False]) -> Headers: + ... + + +@overload +def normalize_and_validate( + headers: Union[Headers, HeaderTypes], _parsed: bool = False +) -> Headers: + ... + + +def normalize_and_validate( + headers: Union[Headers, HeaderTypes], _parsed: bool = False +) -> Headers: + new_headers = [] + seen_content_length = None + saw_transfer_encoding = False + for name, value in headers: + # For headers coming out of the parser, we can safely skip some steps, + # because it always returns bytes and has already run these regexes + # over the data: + if not _parsed: + name = bytesify(name) + value = bytesify(value) + validate(_field_name_re, name, "Illegal header name {!r}", name) + validate(_field_value_re, value, "Illegal header value {!r}", value) + assert isinstance(name, bytes) + assert isinstance(value, bytes) + + raw_name = name + name = name.lower() + if name == b"content-length": + lengths = {length.strip() for length in value.split(b",")} + if len(lengths) != 1: + raise LocalProtocolError("conflicting Content-Length headers") + value = lengths.pop() + validate(_content_length_re, value, "bad Content-Length") + if len(value) > CONTENT_LENGTH_MAX_DIGITS: + raise LocalProtocolError("bad Content-Length") + if seen_content_length is None: + seen_content_length = value + new_headers.append((raw_name, name, value)) + elif seen_content_length != value: + raise LocalProtocolError("conflicting Content-Length headers") + elif name == b"transfer-encoding": + # "A server that receives a request message with a transfer coding + # it does not understand SHOULD respond with 501 (Not + # Implemented)." + # https://tools.ietf.org/html/rfc7230#section-3.3.1 + if saw_transfer_encoding: + raise LocalProtocolError( + "multiple Transfer-Encoding headers", error_status_hint=501 + ) + # "All transfer-coding names are case-insensitive" + # -- https://tools.ietf.org/html/rfc7230#section-4 + value = value.lower() + if value != b"chunked": + raise LocalProtocolError( + "Only Transfer-Encoding: chunked is supported", + error_status_hint=501, + ) + saw_transfer_encoding = True + new_headers.append((raw_name, name, value)) + else: + new_headers.append((raw_name, name, value)) + return Headers(new_headers) + + +def get_comma_header(headers: Headers, name: bytes) -> List[bytes]: + # Should only be used for headers whose value is a list of + # comma-separated, case-insensitive values. + # + # The header name `name` is expected to be lower-case bytes. + # + # Connection: meets these criteria (including cast insensitivity). + # + # Content-Length: technically is just a single value (1*DIGIT), but the + # standard makes reference to implementations that do multiple values, and + # using this doesn't hurt. Ditto, case insensitivity doesn't things either + # way. + # + # Transfer-Encoding: is more complex (allows for quoted strings), so + # splitting on , is actually wrong. For example, this is legal: + # + # Transfer-Encoding: foo; options="1,2", chunked + # + # and should be parsed as + # + # foo; options="1,2" + # chunked + # + # but this naive function will parse it as + # + # foo; options="1 + # 2" + # chunked + # + # However, this is okay because the only thing we are going to do with + # any Transfer-Encoding is reject ones that aren't just "chunked", so + # both of these will be treated the same anyway. + # + # Expect: the only legal value is the literal string + # "100-continue". Splitting on commas is harmless. Case insensitive. + # + out: List[bytes] = [] + for _, found_name, found_raw_value in headers._full_items: + if found_name == name: + found_raw_value = found_raw_value.lower() + for found_split_value in found_raw_value.split(b","): + found_split_value = found_split_value.strip() + if found_split_value: + out.append(found_split_value) + return out + + +def set_comma_header(headers: Headers, name: bytes, new_values: List[bytes]) -> Headers: + # The header name `name` is expected to be lower-case bytes. + # + # Note that when we store the header we use title casing for the header + # names, in order to match the conventional HTTP header style. + # + # Simply calling `.title()` is a blunt approach, but it's correct + # here given the cases where we're using `set_comma_header`... + # + # Connection, Content-Length, Transfer-Encoding. + new_headers: List[Tuple[bytes, bytes]] = [] + for found_raw_name, found_name, found_raw_value in headers._full_items: + if found_name != name: + new_headers.append((found_raw_name, found_raw_value)) + for new_value in new_values: + new_headers.append((name.title(), new_value)) + return normalize_and_validate(new_headers) + + +def has_expect_100_continue(request: "Request") -> bool: + # https://tools.ietf.org/html/rfc7231#section-5.1.1 + # "A server that receives a 100-continue expectation in an HTTP/1.0 request + # MUST ignore that expectation." + if request.http_version < b"1.1": + return False + expect = get_comma_header(request.headers, b"expect") + return b"100-continue" in expect diff --git a/backend/venv/Lib/site-packages/h11/_readers.py b/backend/venv/Lib/site-packages/h11/_readers.py new file mode 100644 index 0000000..576804c --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_readers.py @@ -0,0 +1,250 @@ +# Code to read HTTP data +# +# Strategy: each reader is a callable which takes a ReceiveBuffer object, and +# either: +# 1) consumes some of it and returns an Event +# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() +# and it might raise a LocalProtocolError, so simpler just to always use +# this) +# 3) returns None, meaning "I need more data" +# +# If they have a .read_eof attribute, then this will be called if an EOF is +# received -- but this is optional. Either way, the actual ConnectionClosed +# event will be generated afterwards. +# +# READERS is a dict describing how to pick a reader. It maps states to either: +# - a reader +# - or, for body readers, a dict of per-framing reader factories + +import re +from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union + +from ._abnf import chunk_header, header_field, request_line, status_line +from ._events import Data, EndOfMessage, InformationalResponse, Request, Response +from ._receivebuffer import ReceiveBuffer +from ._state import ( + CLIENT, + CLOSED, + DONE, + IDLE, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, +) +from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate + +__all__ = ["READERS"] + +header_field_re = re.compile(header_field.encode("ascii")) +obs_fold_re = re.compile(rb"[ \t]+") + + +def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: + it = iter(lines) + last: Optional[bytes] = None + for line in it: + match = obs_fold_re.match(line) + if match: + if last is None: + raise LocalProtocolError("continuation line at start of headers") + if not isinstance(last, bytearray): + # Cast to a mutable type, avoiding copy on append to ensure O(n) time + last = bytearray(last) + last += b" " + last += line[match.end() :] + else: + if last is not None: + yield last + last = line + if last is not None: + yield last + + +def _decode_header_lines( + lines: Iterable[bytes], +) -> Iterable[Tuple[bytes, bytes]]: + for line in _obsolete_line_fold(lines): + matches = validate(header_field_re, line, "illegal header line: {!r}", line) + yield (matches["field_name"], matches["field_value"]) + + +request_line_re = re.compile(request_line.encode("ascii")) + + +def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: + lines = buf.maybe_extract_lines() + if lines is None: + if buf.is_next_line_obviously_invalid_request_line(): + raise LocalProtocolError("illegal request line") + return None + if not lines: + raise LocalProtocolError("no request line received") + matches = validate( + request_line_re, lines[0], "illegal request line: {!r}", lines[0] + ) + return Request( + headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches + ) + + +status_line_re = re.compile(status_line.encode("ascii")) + + +def maybe_read_from_SEND_RESPONSE_server( + buf: ReceiveBuffer, +) -> Union[InformationalResponse, Response, None]: + lines = buf.maybe_extract_lines() + if lines is None: + if buf.is_next_line_obviously_invalid_request_line(): + raise LocalProtocolError("illegal request line") + return None + if not lines: + raise LocalProtocolError("no response line received") + matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) + http_version = ( + b"1.1" if matches["http_version"] is None else matches["http_version"] + ) + reason = b"" if matches["reason"] is None else matches["reason"] + status_code = int(matches["status_code"]) + class_: Union[Type[InformationalResponse], Type[Response]] = ( + InformationalResponse if status_code < 200 else Response + ) + return class_( + headers=list(_decode_header_lines(lines[1:])), + _parsed=True, + status_code=status_code, + reason=reason, + http_version=http_version, + ) + + +class ContentLengthReader: + def __init__(self, length: int) -> None: + self._length = length + self._remaining = length + + def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: + if self._remaining == 0: + return EndOfMessage() + data = buf.maybe_extract_at_most(self._remaining) + if data is None: + return None + self._remaining -= len(data) + return Data(data=data) + + def read_eof(self) -> NoReturn: + raise RemoteProtocolError( + "peer closed connection without sending complete message body " + "(received {} bytes, expected {})".format( + self._length - self._remaining, self._length + ) + ) + + +chunk_header_re = re.compile(chunk_header.encode("ascii")) + + +class ChunkedReader: + def __init__(self) -> None: + self._bytes_in_chunk = 0 + # After reading a chunk, we have to throw away the trailing \r\n. + # This tracks the bytes that we need to match and throw away. + self._bytes_to_discard = b"" + self._reading_trailer = False + + def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: + if self._reading_trailer: + lines = buf.maybe_extract_lines() + if lines is None: + return None + return EndOfMessage(headers=list(_decode_header_lines(lines))) + if self._bytes_to_discard: + data = buf.maybe_extract_at_most(len(self._bytes_to_discard)) + if data is None: + return None + if data != self._bytes_to_discard[: len(data)]: + raise LocalProtocolError( + f"malformed chunk footer: {data!r} (expected {self._bytes_to_discard!r})" + ) + self._bytes_to_discard = self._bytes_to_discard[len(data) :] + if self._bytes_to_discard: + return None + # else, fall through and read some more + assert self._bytes_to_discard == b"" + if self._bytes_in_chunk == 0: + # We need to refill our chunk count + chunk_header = buf.maybe_extract_next_line() + if chunk_header is None: + return None + matches = validate( + chunk_header_re, + chunk_header, + "illegal chunk header: {!r}", + chunk_header, + ) + # XX FIXME: we discard chunk extensions. Does anyone care? + self._bytes_in_chunk = int(matches["chunk_size"], base=16) + if self._bytes_in_chunk == 0: + self._reading_trailer = True + return self(buf) + chunk_start = True + else: + chunk_start = False + assert self._bytes_in_chunk > 0 + data = buf.maybe_extract_at_most(self._bytes_in_chunk) + if data is None: + return None + self._bytes_in_chunk -= len(data) + if self._bytes_in_chunk == 0: + self._bytes_to_discard = b"\r\n" + chunk_end = True + else: + chunk_end = False + return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) + + def read_eof(self) -> NoReturn: + raise RemoteProtocolError( + "peer closed connection without sending complete message body " + "(incomplete chunked read)" + ) + + +class Http10Reader: + def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: + data = buf.maybe_extract_at_most(999999999) + if data is None: + return None + return Data(data=data) + + def read_eof(self) -> EndOfMessage: + return EndOfMessage() + + +def expect_nothing(buf: ReceiveBuffer) -> None: + if buf: + raise LocalProtocolError("Got data when expecting EOF") + return None + + +ReadersType = Dict[ + Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], + Union[Callable[..., Any], Dict[str, Callable[..., Any]]], +] + +READERS: ReadersType = { + (CLIENT, IDLE): maybe_read_from_IDLE_client, + (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, + (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, + (CLIENT, DONE): expect_nothing, + (CLIENT, MUST_CLOSE): expect_nothing, + (CLIENT, CLOSED): expect_nothing, + (SERVER, DONE): expect_nothing, + (SERVER, MUST_CLOSE): expect_nothing, + (SERVER, CLOSED): expect_nothing, + SEND_BODY: { + "chunked": ChunkedReader, + "content-length": ContentLengthReader, + "http/1.0": Http10Reader, + }, +} diff --git a/backend/venv/Lib/site-packages/h11/_receivebuffer.py b/backend/venv/Lib/site-packages/h11/_receivebuffer.py new file mode 100644 index 0000000..e5c4e08 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_receivebuffer.py @@ -0,0 +1,153 @@ +import re +import sys +from typing import List, Optional, Union + +__all__ = ["ReceiveBuffer"] + + +# Operations we want to support: +# - find next \r\n or \r\n\r\n (\n or \n\n are also acceptable), +# or wait until there is one +# - read at-most-N bytes +# Goals: +# - on average, do this fast +# - worst case, do this in O(n) where n is the number of bytes processed +# Plan: +# - store bytearray, offset, how far we've searched for a separator token +# - use the how-far-we've-searched data to avoid rescanning +# - while doing a stream of uninterrupted processing, advance offset instead +# of constantly copying +# WARNING: +# - I haven't benchmarked or profiled any of this yet. +# +# Note that starting in Python 3.4, deleting the initial n bytes from a +# bytearray is amortized O(n), thanks to some excellent work by Antoine +# Martin: +# +# https://bugs.python.org/issue19087 +# +# This means that if we only supported 3.4+, we could get rid of the code here +# involving self._start and self.compress, because it's doing exactly the same +# thing that bytearray now does internally. +# +# BUT unfortunately, we still support 2.7, and reading short segments out of a +# long buffer MUST be O(bytes read) to avoid DoS issues, so we can't actually +# delete this code. Yet: +# +# https://pythonclock.org/ +# +# (Two things to double-check first though: make sure PyPy also has the +# optimization, and benchmark to make sure it's a win, since we do have a +# slightly clever thing where we delay calling compress() until we've +# processed a whole event, which could in theory be slightly more efficient +# than the internal bytearray support.) +blank_line_regex = re.compile(b"\n\r?\n", re.MULTILINE) + + +class ReceiveBuffer: + def __init__(self) -> None: + self._data = bytearray() + self._next_line_search = 0 + self._multiple_lines_search = 0 + + def __iadd__(self, byteslike: Union[bytes, bytearray]) -> "ReceiveBuffer": + self._data += byteslike + return self + + def __bool__(self) -> bool: + return bool(len(self)) + + def __len__(self) -> int: + return len(self._data) + + # for @property unprocessed_data + def __bytes__(self) -> bytes: + return bytes(self._data) + + def _extract(self, count: int) -> bytearray: + # extracting an initial slice of the data buffer and return it + out = self._data[:count] + del self._data[:count] + + self._next_line_search = 0 + self._multiple_lines_search = 0 + + return out + + def maybe_extract_at_most(self, count: int) -> Optional[bytearray]: + """ + Extract a fixed number of bytes from the buffer. + """ + out = self._data[:count] + if not out: + return None + + return self._extract(count) + + def maybe_extract_next_line(self) -> Optional[bytearray]: + """ + Extract the first line, if it is completed in the buffer. + """ + # Only search in buffer space that we've not already looked at. + search_start_index = max(0, self._next_line_search - 1) + partial_idx = self._data.find(b"\r\n", search_start_index) + + if partial_idx == -1: + self._next_line_search = len(self._data) + return None + + # + 2 is to compensate len(b"\r\n") + idx = partial_idx + 2 + + return self._extract(idx) + + def maybe_extract_lines(self) -> Optional[List[bytearray]]: + """ + Extract everything up to the first blank line, and return a list of lines. + """ + # Handle the case where we have an immediate empty line. + if self._data[:1] == b"\n": + self._extract(1) + return [] + + if self._data[:2] == b"\r\n": + self._extract(2) + return [] + + # Only search in buffer space that we've not already looked at. + match = blank_line_regex.search(self._data, self._multiple_lines_search) + if match is None: + self._multiple_lines_search = max(0, len(self._data) - 2) + return None + + # Truncate the buffer and return it. + idx = match.span(0)[-1] + out = self._extract(idx) + lines = out.split(b"\n") + + for line in lines: + if line.endswith(b"\r"): + del line[-1] + + assert lines[-2] == lines[-1] == b"" + + del lines[-2:] + + return lines + + # In theory we should wait until `\r\n` before starting to validate + # incoming data. However it's interesting to detect (very) invalid data + # early given they might not even contain `\r\n` at all (hence only + # timeout will get rid of them). + # This is not a 100% effective detection but more of a cheap sanity check + # allowing for early abort in some useful cases. + # This is especially interesting when peer is messing up with HTTPS and + # sent us a TLS stream where we were expecting plain HTTP given all + # versions of TLS so far start handshake with a 0x16 message type code. + def is_next_line_obviously_invalid_request_line(self) -> bool: + try: + # HTTP header line must not contain non-printable characters + # and should not start with a space + return self._data[0] < 0x21 + except IndexError: + return False diff --git a/backend/venv/Lib/site-packages/h11/_state.py b/backend/venv/Lib/site-packages/h11/_state.py new file mode 100644 index 0000000..3ad444b --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_state.py @@ -0,0 +1,365 @@ +################################################################ +# The core state machine +################################################################ +# +# Rule 1: everything that affects the state machine and state transitions must +# live here in this file. As much as possible goes into the table-based +# representation, but for the bits that don't quite fit, the actual code and +# state must nonetheless live here. +# +# Rule 2: this file does not know about what role we're playing; it only knows +# about HTTP request/response cycles in the abstract. This ensures that we +# don't cheat and apply different rules to local and remote parties. +# +# +# Theory of operation +# =================== +# +# Possibly the simplest way to think about this is that we actually have 5 +# different state machines here. Yes, 5. These are: +# +# 1) The client state, with its complicated automaton (see the docs) +# 2) The server state, with its complicated automaton (see the docs) +# 3) The keep-alive state, with possible states {True, False} +# 4) The SWITCH_CONNECT state, with possible states {False, True} +# 5) The SWITCH_UPGRADE state, with possible states {False, True} +# +# For (3)-(5), the first state listed is the initial state. +# +# (1)-(3) are stored explicitly in member variables. The last +# two are stored implicitly in the pending_switch_proposals set as: +# (state of 4) == (_SWITCH_CONNECT in pending_switch_proposals) +# (state of 5) == (_SWITCH_UPGRADE in pending_switch_proposals) +# +# And each of these machines has two different kinds of transitions: +# +# a) Event-triggered +# b) State-triggered +# +# Event triggered is the obvious thing that you'd think it is: some event +# happens, and if it's the right event at the right time then a transition +# happens. But there are somewhat complicated rules for which machines can +# "see" which events. (As a rule of thumb, if a machine "sees" an event, this +# means two things: the event can affect the machine, and if the machine is +# not in a state where it expects that event then it's an error.) These rules +# are: +# +# 1) The client machine sees all h11.events objects emitted by the client. +# +# 2) The server machine sees all h11.events objects emitted by the server. +# +# It also sees the client's Request event. +# +# And sometimes, server events are annotated with a _SWITCH_* event. For +# example, we can have a (Response, _SWITCH_CONNECT) event, which is +# different from a regular Response event. +# +# 3) The keep-alive machine sees the process_keep_alive_disabled() event +# (which is derived from Request/Response events), and this event +# transitions it from True -> False, or from False -> False. There's no way +# to transition back. +# +# 4&5) The _SWITCH_* machines transition from False->True when we get a +# Request that proposes the relevant type of switch (via +# process_client_switch_proposals), and they go from True->False when we +# get a Response that has no _SWITCH_* annotation. +# +# So that's event-triggered transitions. +# +# State-triggered transitions are less standard. What they do here is couple +# the machines together. The way this works is, when certain *joint* +# configurations of states are achieved, then we automatically transition to a +# new *joint* state. So, for example, if we're ever in a joint state with +# +# client: DONE +# keep-alive: False +# +# then the client state immediately transitions to: +# +# client: MUST_CLOSE +# +# This is fundamentally different from an event-based transition, because it +# doesn't matter how we arrived at the {client: DONE, keep-alive: False} state +# -- maybe the client transitioned SEND_BODY -> DONE, or keep-alive +# transitioned True -> False. Either way, once this precondition is satisfied, +# this transition is immediately triggered. +# +# What if two conflicting state-based transitions get enabled at the same +# time? In practice there's only one case where this arises (client DONE -> +# MIGHT_SWITCH_PROTOCOL versus DONE -> MUST_CLOSE), and we resolve it by +# explicitly prioritizing the DONE -> MIGHT_SWITCH_PROTOCOL transition. +# +# Implementation +# -------------- +# +# The event-triggered transitions for the server and client machines are all +# stored explicitly in a table. Ditto for the state-triggered transitions that +# involve just the server and client state. +# +# The transitions for the other machines, and the state-triggered transitions +# that involve the other machines, are written out as explicit Python code. +# +# It'd be nice if there were some cleaner way to do all this. This isn't +# *too* terrible, but I feel like it could probably be better. +# +# WARNING +# ------- +# +# The script that generates the state machine diagrams for the docs knows how +# to read out the EVENT_TRIGGERED_TRANSITIONS and STATE_TRIGGERED_TRANSITIONS +# tables. But it can't automatically read the transitions that are written +# directly in Python code. So if you touch those, you need to also update the +# script to keep it in sync! +from typing import cast, Dict, Optional, Set, Tuple, Type, Union + +from ._events import * +from ._util import LocalProtocolError, Sentinel + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = [ + "CLIENT", + "SERVER", + "IDLE", + "SEND_RESPONSE", + "SEND_BODY", + "DONE", + "MUST_CLOSE", + "CLOSED", + "MIGHT_SWITCH_PROTOCOL", + "SWITCHED_PROTOCOL", + "ERROR", +] + + +class CLIENT(Sentinel, metaclass=Sentinel): + pass + + +class SERVER(Sentinel, metaclass=Sentinel): + pass + + +# States +class IDLE(Sentinel, metaclass=Sentinel): + pass + + +class SEND_RESPONSE(Sentinel, metaclass=Sentinel): + pass + + +class SEND_BODY(Sentinel, metaclass=Sentinel): + pass + + +class DONE(Sentinel, metaclass=Sentinel): + pass + + +class MUST_CLOSE(Sentinel, metaclass=Sentinel): + pass + + +class CLOSED(Sentinel, metaclass=Sentinel): + pass + + +class ERROR(Sentinel, metaclass=Sentinel): + pass + + +# Switch types +class MIGHT_SWITCH_PROTOCOL(Sentinel, metaclass=Sentinel): + pass + + +class SWITCHED_PROTOCOL(Sentinel, metaclass=Sentinel): + pass + + +class _SWITCH_UPGRADE(Sentinel, metaclass=Sentinel): + pass + + +class _SWITCH_CONNECT(Sentinel, metaclass=Sentinel): + pass + + +EventTransitionType = Dict[ + Type[Sentinel], + Dict[ + Type[Sentinel], + Dict[Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], Type[Sentinel]], + ], +] + +EVENT_TRIGGERED_TRANSITIONS: EventTransitionType = { + CLIENT: { + IDLE: {Request: SEND_BODY, ConnectionClosed: CLOSED}, + SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, + DONE: {ConnectionClosed: CLOSED}, + MUST_CLOSE: {ConnectionClosed: CLOSED}, + CLOSED: {ConnectionClosed: CLOSED}, + MIGHT_SWITCH_PROTOCOL: {}, + SWITCHED_PROTOCOL: {}, + ERROR: {}, + }, + SERVER: { + IDLE: { + ConnectionClosed: CLOSED, + Response: SEND_BODY, + # Special case: server sees client Request events, in this form + (Request, CLIENT): SEND_RESPONSE, + }, + SEND_RESPONSE: { + InformationalResponse: SEND_RESPONSE, + Response: SEND_BODY, + (InformationalResponse, _SWITCH_UPGRADE): SWITCHED_PROTOCOL, + (Response, _SWITCH_CONNECT): SWITCHED_PROTOCOL, + }, + SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, + DONE: {ConnectionClosed: CLOSED}, + MUST_CLOSE: {ConnectionClosed: CLOSED}, + CLOSED: {ConnectionClosed: CLOSED}, + SWITCHED_PROTOCOL: {}, + ERROR: {}, + }, +} + +StateTransitionType = Dict[ + Tuple[Type[Sentinel], Type[Sentinel]], Dict[Type[Sentinel], Type[Sentinel]] +] + +# NB: there are also some special-case state-triggered transitions hard-coded +# into _fire_state_triggered_transitions below. +STATE_TRIGGERED_TRANSITIONS: StateTransitionType = { + # (Client state, Server state) -> new states + # Protocol negotiation + (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL}, + # Socket shutdown + (CLOSED, DONE): {SERVER: MUST_CLOSE}, + (CLOSED, IDLE): {SERVER: MUST_CLOSE}, + (ERROR, DONE): {SERVER: MUST_CLOSE}, + (DONE, CLOSED): {CLIENT: MUST_CLOSE}, + (IDLE, CLOSED): {CLIENT: MUST_CLOSE}, + (DONE, ERROR): {CLIENT: MUST_CLOSE}, +} + + +class ConnectionState: + def __init__(self) -> None: + # Extra bits of state that don't quite fit into the state model. + + # If this is False then it enables the automatic DONE -> MUST_CLOSE + # transition. Don't set this directly; call .keep_alive_disabled() + self.keep_alive = True + + # This is a subset of {UPGRADE, CONNECT}, containing the proposals + # made by the client for switching protocols. + self.pending_switch_proposals: Set[Type[Sentinel]] = set() + + self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE} + + def process_error(self, role: Type[Sentinel]) -> None: + self.states[role] = ERROR + self._fire_state_triggered_transitions() + + def process_keep_alive_disabled(self) -> None: + self.keep_alive = False + self._fire_state_triggered_transitions() + + def process_client_switch_proposal(self, switch_event: Type[Sentinel]) -> None: + self.pending_switch_proposals.add(switch_event) + self._fire_state_triggered_transitions() + + def process_event( + self, + role: Type[Sentinel], + event_type: Type[Event], + server_switch_event: Optional[Type[Sentinel]] = None, + ) -> None: + _event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]] = event_type + if server_switch_event is not None: + assert role is SERVER + if server_switch_event not in self.pending_switch_proposals: + raise LocalProtocolError( + "Received server _SWITCH_UPGRADE event without a pending proposal" + ) + _event_type = (event_type, server_switch_event) + if server_switch_event is None and _event_type is Response: + self.pending_switch_proposals = set() + self._fire_event_triggered_transitions(role, _event_type) + # Special case: the server state does get to see Request + # events. + if _event_type is Request: + assert role is CLIENT + self._fire_event_triggered_transitions(SERVER, (Request, CLIENT)) + self._fire_state_triggered_transitions() + + def _fire_event_triggered_transitions( + self, + role: Type[Sentinel], + event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], + ) -> None: + state = self.states[role] + try: + new_state = EVENT_TRIGGERED_TRANSITIONS[role][state][event_type] + except KeyError: + event_type = cast(Type[Event], event_type) + raise LocalProtocolError( + "can't handle event type {} when role={} and state={}".format( + event_type.__name__, role, self.states[role] + ) + ) from None + self.states[role] = new_state + + def _fire_state_triggered_transitions(self) -> None: + # We apply these rules repeatedly until converging on a fixed point + while True: + start_states = dict(self.states) + + # It could happen that both these special-case transitions are + # enabled at the same time: + # + # DONE -> MIGHT_SWITCH_PROTOCOL + # DONE -> MUST_CLOSE + # + # For example, this will always be true of a HTTP/1.0 client + # requesting CONNECT. If this happens, the protocol switch takes + # priority. From there the client will either go to + # SWITCHED_PROTOCOL, in which case it's none of our business when + # they close the connection, or else the server will deny the + # request, in which case the client will go back to DONE and then + # from there to MUST_CLOSE. + if self.pending_switch_proposals: + if self.states[CLIENT] is DONE: + self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL + + if not self.pending_switch_proposals: + if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL: + self.states[CLIENT] = DONE + + if not self.keep_alive: + for role in (CLIENT, SERVER): + if self.states[role] is DONE: + self.states[role] = MUST_CLOSE + + # Tabular state-triggered transitions + joint_state = (self.states[CLIENT], self.states[SERVER]) + changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {}) + self.states.update(changes) + + if self.states == start_states: + # Fixed point reached + return + + def start_next_cycle(self) -> None: + if self.states != {CLIENT: DONE, SERVER: DONE}: + raise LocalProtocolError( + f"not in a reusable state. self.states={self.states}" + ) + # Can't reach DONE/DONE with any of these active, but still, let's be + # sure. + assert self.keep_alive + assert not self.pending_switch_proposals + self.states = {CLIENT: IDLE, SERVER: IDLE} diff --git a/backend/venv/Lib/site-packages/h11/_util.py b/backend/venv/Lib/site-packages/h11/_util.py new file mode 100644 index 0000000..6718445 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_util.py @@ -0,0 +1,135 @@ +from typing import Any, Dict, NoReturn, Pattern, Tuple, Type, TypeVar, Union + +__all__ = [ + "ProtocolError", + "LocalProtocolError", + "RemoteProtocolError", + "validate", + "bytesify", +] + + +class ProtocolError(Exception): + """Exception indicating a violation of the HTTP/1.1 protocol. + + This as an abstract base class, with two concrete base classes: + :exc:`LocalProtocolError`, which indicates that you tried to do something + that HTTP/1.1 says is illegal, and :exc:`RemoteProtocolError`, which + indicates that the remote peer tried to do something that HTTP/1.1 says is + illegal. See :ref:`error-handling` for details. + + In addition to the normal :exc:`Exception` features, it has one attribute: + + .. attribute:: error_status_hint + + This gives a suggestion as to what status code a server might use if + this error occurred as part of a request. + + For a :exc:`RemoteProtocolError`, this is useful as a suggestion for + how you might want to respond to a misbehaving peer, if you're + implementing a server. + + For a :exc:`LocalProtocolError`, this can be taken as a suggestion for + how your peer might have responded to *you* if h11 had allowed you to + continue. + + The default is 400 Bad Request, a generic catch-all for protocol + violations. + + """ + + def __init__(self, msg: str, error_status_hint: int = 400) -> None: + if type(self) is ProtocolError: + raise TypeError("tried to directly instantiate ProtocolError") + Exception.__init__(self, msg) + self.error_status_hint = error_status_hint + + +# Strategy: there are a number of public APIs where a LocalProtocolError can +# be raised (send(), all the different event constructors, ...), and only one +# public API where RemoteProtocolError can be raised +# (receive_data()). Therefore we always raise LocalProtocolError internally, +# and then receive_data will translate this into a RemoteProtocolError. +# +# Internally: +# LocalProtocolError is the generic "ProtocolError". +# Externally: +# LocalProtocolError is for local errors and RemoteProtocolError is for +# remote errors. +class LocalProtocolError(ProtocolError): + def _reraise_as_remote_protocol_error(self) -> NoReturn: + # After catching a LocalProtocolError, use this method to re-raise it + # as a RemoteProtocolError. This method must be called from inside an + # except: block. + # + # An easy way to get an equivalent RemoteProtocolError is just to + # modify 'self' in place. + self.__class__ = RemoteProtocolError # type: ignore + # But the re-raising is somewhat non-trivial -- you might think that + # now that we've modified the in-flight exception object, that just + # doing 'raise' to re-raise it would be enough. But it turns out that + # this doesn't work, because Python tracks the exception type + # (exc_info[0]) separately from the exception object (exc_info[1]), + # and we only modified the latter. So we really do need to re-raise + # the new type explicitly. + # On py3, the traceback is part of the exception object, so our + # in-place modification preserved it and we can just re-raise: + raise self + + +class RemoteProtocolError(ProtocolError): + pass + + +def validate( + regex: Pattern[bytes], data: bytes, msg: str = "malformed data", *format_args: Any +) -> Dict[str, bytes]: + match = regex.fullmatch(data) + if not match: + if format_args: + msg = msg.format(*format_args) + raise LocalProtocolError(msg) + return match.groupdict() + + +# Sentinel values +# +# - Inherit identity-based comparison and hashing from object +# - Have a nice repr +# - Have a *bonus property*: type(sentinel) is sentinel +# +# The bonus property is useful if you want to take the return value from +# next_event() and do some sort of dispatch based on type(event). + +_T_Sentinel = TypeVar("_T_Sentinel", bound="Sentinel") + + +class Sentinel(type): + def __new__( + cls: Type[_T_Sentinel], + name: str, + bases: Tuple[type, ...], + namespace: Dict[str, Any], + **kwds: Any + ) -> _T_Sentinel: + assert bases == (Sentinel,) + v = super().__new__(cls, name, bases, namespace, **kwds) + v.__class__ = v # type: ignore + return v + + def __repr__(self) -> str: + return self.__name__ + + +# Used for methods, request targets, HTTP versions, header names, and header +# values. Accepts ascii-strings, or bytes/bytearray/memoryview/..., and always +# returns bytes. +def bytesify(s: Union[bytes, bytearray, memoryview, int, str]) -> bytes: + # Fast-path: + if type(s) is bytes: + return s + if isinstance(s, str): + s = s.encode("ascii") + if isinstance(s, int): + raise TypeError("expected bytes-like object, not int") + return bytes(s) diff --git a/backend/venv/Lib/site-packages/h11/_version.py b/backend/venv/Lib/site-packages/h11/_version.py new file mode 100644 index 0000000..76e7327 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_version.py @@ -0,0 +1,16 @@ +# This file must be kept very simple, because it is consumed from several +# places -- it is imported by h11/__init__.py, execfile'd by setup.py, etc. + +# We use a simple scheme: +# 1.0.0 -> 1.0.0+dev -> 1.1.0 -> 1.1.0+dev +# where the +dev versions are never released into the wild, they're just what +# we stick into the VCS in between releases. +# +# This is compatible with PEP 440: +# http://legacy.python.org/dev/peps/pep-0440/ +# via the use of the "local suffix" "+dev", which is disallowed on index +# servers and causes 1.0.0+dev to sort after plain 1.0.0, which is what we +# want. (Contrast with the special suffix 1.0.0.dev, which sorts *before* +# 1.0.0.) + +__version__ = "0.16.0" diff --git a/backend/venv/Lib/site-packages/h11/_writers.py b/backend/venv/Lib/site-packages/h11/_writers.py new file mode 100644 index 0000000..939cdb9 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/_writers.py @@ -0,0 +1,145 @@ +# Code to read HTTP data +# +# Strategy: each writer takes an event + a write-some-bytes function, which is +# calls. +# +# WRITERS is a dict describing how to pick a reader. It maps states to either: +# - a writer +# - or, for body writers, a dict of framin-dependent writer factories + +from typing import Any, Callable, Dict, List, Tuple, Type, Union + +from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response +from ._headers import Headers +from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER +from ._util import LocalProtocolError, Sentinel + +__all__ = ["WRITERS"] + +Writer = Callable[[bytes], Any] + + +def write_headers(headers: Headers, write: Writer) -> None: + # "Since the Host field-value is critical information for handling a + # request, a user agent SHOULD generate Host as the first header field + # following the request-line." - RFC 7230 + raw_items = headers._full_items + for raw_name, name, value in raw_items: + if name == b"host": + write(b"%s: %s\r\n" % (raw_name, value)) + for raw_name, name, value in raw_items: + if name != b"host": + write(b"%s: %s\r\n" % (raw_name, value)) + write(b"\r\n") + + +def write_request(request: Request, write: Writer) -> None: + if request.http_version != b"1.1": + raise LocalProtocolError("I only send HTTP/1.1") + write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target)) + write_headers(request.headers, write) + + +# Shared between InformationalResponse and Response +def write_any_response( + response: Union[InformationalResponse, Response], write: Writer +) -> None: + if response.http_version != b"1.1": + raise LocalProtocolError("I only send HTTP/1.1") + status_bytes = str(response.status_code).encode("ascii") + # We don't bother sending ascii status messages like "OK"; they're + # optional and ignored by the protocol. (But the space after the numeric + # status code is mandatory.) + # + # XX FIXME: could at least make an effort to pull out the status message + # from stdlib's http.HTTPStatus table. Or maybe just steal their enums + # (either by import or copy/paste). We already accept them as status codes + # since they're of type IntEnum < int. + write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason)) + write_headers(response.headers, write) + + +class BodyWriter: + def __call__(self, event: Event, write: Writer) -> None: + if type(event) is Data: + self.send_data(event.data, write) + elif type(event) is EndOfMessage: + self.send_eom(event.headers, write) + else: # pragma: no cover + assert False + + def send_data(self, data: bytes, write: Writer) -> None: + pass + + def send_eom(self, headers: Headers, write: Writer) -> None: + pass + + +# +# These are all careful not to do anything to 'data' except call len(data) and +# write(data). This allows us to transparently pass-through funny objects, +# like placeholder objects referring to files on disk that will be sent via +# sendfile(2). +# +class ContentLengthWriter(BodyWriter): + def __init__(self, length: int) -> None: + self._length = length + + def send_data(self, data: bytes, write: Writer) -> None: + self._length -= len(data) + if self._length < 0: + raise LocalProtocolError("Too much data for declared Content-Length") + write(data) + + def send_eom(self, headers: Headers, write: Writer) -> None: + if self._length != 0: + raise LocalProtocolError("Too little data for declared Content-Length") + if headers: + raise LocalProtocolError("Content-Length and trailers don't mix") + + +class ChunkedWriter(BodyWriter): + def send_data(self, data: bytes, write: Writer) -> None: + # if we encoded 0-length data in the naive way, it would look like an + # end-of-message. + if not data: + return + write(b"%x\r\n" % len(data)) + write(data) + write(b"\r\n") + + def send_eom(self, headers: Headers, write: Writer) -> None: + write(b"0\r\n") + write_headers(headers, write) + + +class Http10Writer(BodyWriter): + def send_data(self, data: bytes, write: Writer) -> None: + write(data) + + def send_eom(self, headers: Headers, write: Writer) -> None: + if headers: + raise LocalProtocolError("can't send trailers to HTTP/1.0 client") + # no need to close the socket ourselves, that will be taken care of by + # Connection: close machinery + + +WritersType = Dict[ + Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]], + Union[ + Dict[str, Type[BodyWriter]], + Callable[[Union[InformationalResponse, Response], Writer], None], + Callable[[Request, Writer], None], + ], +] + +WRITERS: WritersType = { + (CLIENT, IDLE): write_request, + (SERVER, IDLE): write_any_response, + (SERVER, SEND_RESPONSE): write_any_response, + SEND_BODY: { + "chunked": ChunkedWriter, + "content-length": ContentLengthWriter, + "http/1.0": Http10Writer, + }, +} diff --git a/backend/venv/Lib/site-packages/h11/py.typed b/backend/venv/Lib/site-packages/h11/py.typed new file mode 100644 index 0000000..f5642f7 --- /dev/null +++ b/backend/venv/Lib/site-packages/h11/py.typed @@ -0,0 +1 @@ +Marker diff --git a/backend/venv/Lib/site-packages/idna-3.11.dist-info/INSTALLER b/backend/venv/Lib/site-packages/idna-3.11.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/idna-3.11.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/idna-3.11.dist-info/METADATA b/backend/venv/Lib/site-packages/idna-3.11.dist-info/METADATA new file mode 100644 index 0000000..7a4a4b7 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna-3.11.dist-info/METADATA @@ -0,0 +1,209 @@ +Metadata-Version: 2.4 +Name: idna +Version: 3.11 +Summary: Internationalized Domain Names in Applications (IDNA) +Author-email: Kim Davies +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: Name Service (DNS) +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +License-File: LICENSE.md +Requires-Dist: ruff >= 0.6.2 ; extra == "all" +Requires-Dist: mypy >= 1.11.2 ; extra == "all" +Requires-Dist: pytest >= 8.3.2 ; extra == "all" +Requires-Dist: flake8 >= 7.1.1 ; extra == "all" +Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst +Project-URL: Issue tracker, https://github.com/kjd/idna/issues +Project-URL: Source, https://github.com/kjd/idna +Provides-Extra: all + +Internationalized Domain Names in Applications (IDNA) +===================================================== + +Support for `Internationalized Domain Names in +Applications (IDNA) `_ +and `Unicode IDNA Compatibility Processing +`_. + +The latest versions of these standards supplied here provide +more comprehensive language coverage and reduce the potential of +allowing domains with known security vulnerabilities. This library +is a suitable replacement for the “encodings.idna” +module that comes with the Python standard library, but which +only supports an older superseded IDNA specification from 2003. + +Basic functions are simply executed: + +.. code-block:: pycon + + >>> import idna + >>> idna.encode('ドメイン.テスト') + b'xn--eckwd4c7c.xn--zckzah' + >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) + ドメイン.テスト + + +Installation +------------ + +This package is available for installation from PyPI via the +typical mechanisms, such as: + +.. code-block:: bash + + $ python3 -m pip install idna + + +Usage +----- + +For typical usage, the ``encode`` and ``decode`` functions will take a +domain name argument and perform a conversion to ASCII compatible encoding +(known as A-labels), or to Unicode strings (known as U-labels) +respectively. + +.. code-block:: pycon + + >>> import idna + >>> idna.encode('ドメイン.テスト') + b'xn--eckwd4c7c.xn--zckzah' + >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) + ドメイン.テスト + +Conversions can be applied at a per-label basis using the ``ulabel`` or +``alabel`` functions if necessary: + +.. code-block:: pycon + + >>> idna.alabel('测试') + b'xn--0zwm56d' + + +Compatibility Mapping (UTS #46) ++++++++++++++++++++++++++++++++ + +This library provides support for `Unicode IDNA Compatibility +Processing `_ which normalizes input from +different potential ways a user may input a domain prior to performing the IDNA +conversion operations. This functionality, known as a +`mapping `_, is considered by the +specification to be a local user-interface issue distinct from IDNA +conversion functionality. + +For example, “Königsgäßchen” is not a permissible label as *LATIN +CAPITAL LETTER K* is not allowed (nor are capital letters in general). +UTS 46 will convert this into lower case prior to applying the IDNA +conversion. + +.. code-block:: pycon + + >>> import idna + >>> idna.encode('Königsgäßchen') + ... + idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed + >>> idna.encode('Königsgäßchen', uts46=True) + b'xn--knigsgchen-b4a3dun' + >>> print(idna.decode('xn--knigsgchen-b4a3dun')) + königsgäßchen + + +Exceptions +---------- + +All errors raised during the conversion following the specification +should raise an exception derived from the ``idna.IDNAError`` base +class. + +More specific exceptions that may be generated as ``idna.IDNABidiError`` +when the error reflects an illegal combination of left-to-right and +right-to-left characters in a label; ``idna.InvalidCodepoint`` when +a specific codepoint is an illegal character in an IDN label (i.e. +INVALID); and ``idna.InvalidCodepointContext`` when the codepoint is +illegal based on its position in the string (i.e. it is CONTEXTO or CONTEXTJ +but the contextual requirements are not satisfied.) + +Building and Diagnostics +------------------------ + +The IDNA and UTS 46 functionality relies upon pre-calculated lookup +tables for performance. These tables are derived from computing against +eligibility criteria in the respective standards using the command-line +script ``tools/idna-data``. + +This tool will fetch relevant codepoint data from the Unicode repository +and perform the required calculations to identify eligibility. There are +three main modes: + +* ``idna-data make-libdata``. Generates ``idnadata.py`` and + ``uts46data.py``, the pre-calculated lookup tables used for IDNA and + UTS 46 conversions. Implementers who wish to track this library against + a different Unicode version may use this tool to manually generate a + different version of the ``idnadata.py`` and ``uts46data.py`` files. + +* ``idna-data make-table``. Generate a table of the IDNA disposition + (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix + B.1 of RFC 5892 and the pre-computed tables published by `IANA + `_. + +* ``idna-data U+0061``. Prints debugging output on the various + properties associated with an individual Unicode codepoint (in this + case, U+0061), that are used to assess the IDNA and UTS 46 status of a + codepoint. This is helpful in debugging or analysis. + +The tool accepts a number of arguments, described using ``idna-data +-h``. Most notably, the ``--version`` argument allows the specification +of the version of Unicode to be used in computing the table data. For +example, ``idna-data --version 9.0.0 make-libdata`` will generate +library data against Unicode 9.0.0. + + +Additional Notes +---------------- + +* **Packages**. The latest tagged release version is published in the + `Python Package Index `_. + +* **Version support**. This library supports Python 3.8 and higher. + As this library serves as a low-level toolkit for a variety of + applications, many of which strive for broad compatibility with older + Python versions, there is no rush to remove older interpreter support. + Support for older versions are likely to be removed from new releases + as automated tests can no longer easily be run, i.e. once the Python + version is officially end-of-life. + +* **Testing**. The library has a test suite based on each rule of the + IDNA specification, as well as tests that are provided as part of the + Unicode Technical Standard 46, `Unicode IDNA Compatibility Processing + `_. + +* **Emoji**. It is an occasional request to support emoji domains in + this library. Encoding of symbols like emoji is expressly prohibited by + the technical standard IDNA 2008 and emoji domains are broadly phased + out across the domain industry due to associated security risks. For + now, applications that need to support these non-compliant labels + may wish to consider trying the encode/decode operation in this library + first, and then falling back to using `encodings.idna`. See `the Github + project `_ for more discussion. + +* **Transitional processing**. Unicode 16.0.0 removed transitional + processing so the `transitional` argument for the encode() method + no longer has any effect and will be removed at a later date. + diff --git a/backend/venv/Lib/site-packages/idna-3.11.dist-info/RECORD b/backend/venv/Lib/site-packages/idna-3.11.dist-info/RECORD new file mode 100644 index 0000000..1203f10 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna-3.11.dist-info/RECORD @@ -0,0 +1,22 @@ +idna-3.11.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +idna-3.11.dist-info/METADATA,sha256=fCwSww9SuiN8TIHllFSASUQCW55hAs8dzKnr9RaEEbA,8378 +idna-3.11.dist-info/RECORD,, +idna-3.11.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +idna-3.11.dist-info/licenses/LICENSE.md,sha256=t6M2q_OwThgOwGXN0W5wXQeeHMehT5EKpukYfza5zYc,1541 +idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 +idna/__pycache__/__init__.cpython-312.pyc,, +idna/__pycache__/codec.cpython-312.pyc,, +idna/__pycache__/compat.cpython-312.pyc,, +idna/__pycache__/core.cpython-312.pyc,, +idna/__pycache__/idnadata.cpython-312.pyc,, +idna/__pycache__/intranges.cpython-312.pyc,, +idna/__pycache__/package_data.cpython-312.pyc,, +idna/__pycache__/uts46data.cpython-312.pyc,, +idna/codec.py,sha256=M2SGWN7cs_6B32QmKTyTN6xQGZeYQgQ2wiX3_DR6loE,3438 +idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 +idna/core.py,sha256=P26_XVycuMTZ1R2mNK1ZREVzM5mvTzdabBXfyZVU1Lc,13246 +idna/idnadata.py,sha256=SG8jhaGE53iiD6B49pt2pwTv_UvClciWE-N54oR2p4U,79623 +idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 +idna/package_data.py,sha256=_CUavOxobnbyNG2FLyHoN8QHP3QM9W1tKuw7eq9QwBk,21 +idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +idna/uts46data.py,sha256=H9J35VkD0F9L9mKOqjeNGd2A-Va6FlPoz6Jz4K7h-ps,243725 diff --git a/backend/venv/Lib/site-packages/idna-3.11.dist-info/WHEEL b/backend/venv/Lib/site-packages/idna-3.11.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna-3.11.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/idna-3.11.dist-info/licenses/LICENSE.md b/backend/venv/Lib/site-packages/idna-3.11.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..256ba90 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna-3.11.dist-info/licenses/LICENSE.md @@ -0,0 +1,31 @@ +BSD 3-Clause License + +Copyright (c) 2013-2025, Kim Davies and contributors. +All rights reserved. + +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/backend/venv/Lib/site-packages/idna/__init__.py b/backend/venv/Lib/site-packages/idna/__init__.py new file mode 100644 index 0000000..cfdc030 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/__init__.py @@ -0,0 +1,45 @@ +from .core import ( + IDNABidiError, + IDNAError, + InvalidCodepoint, + InvalidCodepointContext, + alabel, + check_bidi, + check_hyphen_ok, + check_initial_combiner, + check_label, + check_nfc, + decode, + encode, + ulabel, + uts46_remap, + valid_contextj, + valid_contexto, + valid_label_length, + valid_string_length, +) +from .intranges import intranges_contain +from .package_data import __version__ + +__all__ = [ + "__version__", + "IDNABidiError", + "IDNAError", + "InvalidCodepoint", + "InvalidCodepointContext", + "alabel", + "check_bidi", + "check_hyphen_ok", + "check_initial_combiner", + "check_label", + "check_nfc", + "decode", + "encode", + "intranges_contain", + "ulabel", + "uts46_remap", + "valid_contextj", + "valid_contexto", + "valid_label_length", + "valid_string_length", +] diff --git a/backend/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..748e48cb6e61706163946d7d8ec921e2763efc70 GIT binary patch literal 879 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 vs@ss$clxC zolUx=v<-szf7qPZErNxGq&qk(E8pzpf~5}3`HYnpHM;S$P&<(0tyS_Qk$XQgRrm= zvLVKOb!)bCGSr^TlQ?AA8TN{OIJLLgF?St~6}oZEu}Ugcko|jW{hpVg9H1XXK|JtY zNZFTB1lWgXLA(!fCNcMVe*Zbd!Xtm*+X#AI8f37P(5XLw)C)xH-=eU@&u%7pQQ47e z+v}YUo}&~N?a3U8*X=%QI_eaM3gnah@O<;qkA!kdWH3%_?CwBsMXa z5pSWxihc_(kCRwI_La5YyV{S*y4QQ;LezlI$D`1HLj|o-J_NF&gklmFP9ff@Kfsyboqg< N&Rl+E{3>Y-wc_#9o+bQZ7m{C5voLHIF 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 C;SkFJ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc b/backend/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c00dcbf9f25e59fd58c4014d20d7ef4e71a562d GIT binary patch literal 100908 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc b/backend/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..803a94e164e4786d44b397d3b2e1c0c942d7e8fa GIT binary patch literal 2626 zcmZuyO>7&-6`uX0Xi}6!36|xbSR*S5v>#>r82WyaZt$RTew^E?# zd)^PMI{@qYL7S+``ha;rA|!Fa{*1ZQq>k+e)GJWi4Oo$JKSN8V#b~9B!ijmW%nB99 zsp??rmrTc@ZlyHGIBFfwEmB@_{RA+1&-Gcp5`f$1eC54Txe_o~%vqT;pSgh<*q)2a zgLy^^9xo*(Cj7wU!O09|u60t+(1<@J_)|K~X0v*h-k8UDU4Ica$ECL`%onasESf&O zLp$yhwky;gw~MxGI^uvIoPd~UV3!#Ec*60D6XPOoUC$<-;zeE2v_1%)%r1 zwp(=eu-*YJot&h(Q?!P@AVk*-&^AC&`B~xZ=`$El5hxsUtH;8a@9}_Hp(gSWDh_kQ zm{~4^i!fzCl3+_C(rLnz9^(k6Fc~d0FvEaV5oVZhOn~kpw*wYRc9_anIES)}9QfFm zFwKQjLy=2eL`r!DD zGDuChvsv46%{L+2(dOB5H5}UIi~{#cA~-$_+xEieH{iEIej6Y|hwBIb{>IA1R;qvH zd@DV)^3jvj;J3N;&$oxh|CxGuRca-BS8uPq-4Q)bj<@=c)K9McrEzrQYBT*{dTT7# zG`GgiJnlc!8W?Gfj5j`Nrte>AUVW7QetL7{538wGyziUTTI$*dqU(hnbQ zy>sEmv8{J5ZVzAjIexiyaCj}zPLaM>Afn#%`taY*ZmJ_Y5F-gS0gh0C!{<9ifO3Mg zDE~nq?vWbw^(EkI(h`&x6o7o?DFw{~p!f(79E-`vRh06BDCq0{PM{_YzZKGg-LI`( ztmn3p$2ZmE{18Y(iSKJXxU1M1v)S1h$`>M#mjF)%8Fp8$@S~u0(C*n6&%RIyKL(^O z@t0uo5q41&fGmscA&ZZK=2bL7=NM0FeQ@o<`tADVtwXPECSTuFUyp)P;eHK{QSVC& z0#XF`D-ip;q9t{^$g;fG4?k7G@Pz@LOWw6rpo>Wh=OAHY!EWd3^fu^rnAV4Q9vHKb z-enbfoLYmZ?#K&AV3k(WM9-9~3Un>yxlXs+e}(?ge(%5IH->(r?pjrcIx3dea6npA3&T z&Tr(P_Rie@czgKtT5?rgWvyiY`stsOqxDxFCr4XDhuRA1rDDz9>rhXBe%v$iWN@?* zYxwt*+k=_49#~|GMSq|z)DYsJ%(XN$O4?k^25cj<;h&(&2j0 znEI~TCO~dXH*=4a=DQD!9c0@XNgAyWwFyj(oR~IpJIJ-;l9XA$j-pI`x{=#Z8t;Aw ii-2v%`=xY!s!d?pIJn_Ar#9|97!~ZJ8^57cMEZZQwV|2- literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc b/backend/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5240c2c0429b62b968e2d4496ad49733d3dd518 GIT binary patch literal 210 zcmX@j%ge<81Oe-UGDU&(V-N=h7@>^M96-i&h7^V^^2=g;GLvG8GfPr+3xJ}D>8ZsrnJIaR`cPhcN@7W(UP0w84x8Nkl+v73 dyCOEAMIgr&gWUdsnURt42A@bHcM%Ja3jmSAJ7xd? literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc b/backend/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..398ca427311f963dc37668cce25e7c9878421ab9 GIT binary patch literal 161838 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 Tuple[bytes, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return b"", 0 + + return encode(data), len(data) + + def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return "", 0 + + return decode(data), len(data) + + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return b"", 0 + + labels = _unicode_dots_re.split(data) + trailing_dot = b"" + if labels: + if not labels[-1]: + trailing_dot = b"." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = b"." + + result = [] + size = 0 + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + # Join with U+002E + result_bytes = b".".join(result) + trailing_dot + size += len(trailing_dot) + return result_bytes, size + + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return ("", 0) + + if not isinstance(data, str): + data = str(data, "ascii") + + labels = _unicode_dots_re.split(data) + trailing_dot = "" + if labels: + if not labels[-1]: + trailing_dot = "." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = "." + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result_str = ".".join(result) + trailing_dot + size += len(trailing_dot) + return (result_str, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + + +class StreamReader(Codec, codecs.StreamReader): + pass + + +def search_function(name: str) -> Optional[codecs.CodecInfo]: + if name != "idna2008": + return None + return codecs.CodecInfo( + name=name, + encode=Codec().encode, + decode=Codec().decode, # type: ignore + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) + + +codecs.register(search_function) diff --git a/backend/venv/Lib/site-packages/idna/compat.py b/backend/venv/Lib/site-packages/idna/compat.py new file mode 100644 index 0000000..1df9f2a --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/compat.py @@ -0,0 +1,15 @@ +from typing import Any, Union + +from .core import decode, encode + + +def ToASCII(label: str) -> bytes: + return encode(label) + + +def ToUnicode(label: Union[bytes, bytearray]) -> str: + return decode(label) + + +def nameprep(s: Any) -> None: + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/backend/venv/Lib/site-packages/idna/core.py b/backend/venv/Lib/site-packages/idna/core.py new file mode 100644 index 0000000..8177bf7 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/core.py @@ -0,0 +1,437 @@ +import bisect +import re +import unicodedata +from typing import Optional, Union + +from . import idnadata +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b"xn--" +_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") + + +class IDNAError(UnicodeError): + """Base exception for all IDNA-encoding related problems""" + + pass + + +class IDNABidiError(IDNAError): + """Exception when bidirectional requirements are not satisfied""" + + pass + + +class InvalidCodepoint(IDNAError): + """Exception when a disallowed or unallocated codepoint is used""" + + pass + + +class InvalidCodepointContext(IDNAError): + """Exception when the codepoint is not valid in the context it is used""" + + pass + + +def _combining_class(cp: int) -> int: + v = unicodedata.combining(chr(cp)) + if v == 0: + if not unicodedata.name(chr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + + +def _is_script(cp: str, script: str) -> bool: + return intranges_contain(ord(cp), idnadata.scripts[script]) + + +def _punycode(s: str) -> bytes: + return s.encode("punycode") + + +def _unot(s: int) -> str: + return "U+{:04X}".format(s) + + +def valid_label_length(label: Union[bytes, str]) -> bool: + if len(label) > 63: + return False + return True + + +def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool: + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label: str, check_ltr: bool = False) -> bool: + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == "": + # String likely comes from a newer version of Unicode + raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx)) + if direction in ["R", "AL", "AN"]: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ["R", "AL"]: + rtl = True + elif direction == "L": + rtl = False + else: + raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label))) + + valid_ending = False + number_type: Optional[str] = None + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if direction not in [ + "R", + "AL", + "AN", + "EN", + "ES", + "CS", + "ET", + "ON", + "BN", + "NSM", + ]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx)) + # Bidi rule 3 + if direction in ["R", "AL", "EN", "AN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + # Bidi rule 4 + if direction in ["AN", "EN"]: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError("Can not mix numeral types in a right-to-left label") + else: + # Bidi rule 5 + if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx)) + # Bidi rule 6 + if direction in ["L", "EN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + + if not valid_ending: + raise IDNABidiError("Label ends with illegal codepoint directionality") + + return True + + +def check_initial_combiner(label: str) -> bool: + if unicodedata.category(label[0])[0] == "M": + raise IDNAError("Label begins with an illegal combining character") + return True + + +def check_hyphen_ok(label: str) -> bool: + if label[2:4] == "--": + raise IDNAError("Label has disallowed hyphens in 3rd and 4th position") + if label[0] == "-" or label[-1] == "-": + raise IDNAError("Label must not start or end with a hyphen") + return True + + +def check_nfc(label: str) -> None: + if unicodedata.normalize("NFC", label) != label: + raise IDNAError("Label must be in Normalization Form C") + + +def valid_contextj(label: str, pos: int) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x200C: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos - 1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("L"), ord("D")]: + ok = True + break + else: + break + + if not ok: + return False + + ok = False + for i in range(pos + 1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("R"), ord("D")]: + ok = True + break + else: + break + return ok + + if cp_value == 0x200D: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + return False + + +def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x00B7: + if 0 < pos < len(label) - 1: + if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label) - 1 and len(label) > 1: + return _is_script(label[pos + 1], "Greek") + return False + + elif cp_value == 0x05F3 or cp_value == 0x05F4: + if pos > 0: + return _is_script(label[pos - 1], "Hebrew") + return False + + elif cp_value == 0x30FB: + for cp in label: + if cp == "\u30fb": + continue + if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): + return True + return False + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6F0 <= ord(cp) <= 0x06F9: + return False + return True + + elif 0x6F0 <= cp_value <= 0x6F9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + return False + + +def check_label(label: Union[str, bytes, bytearray]) -> None: + if isinstance(label, (bytes, bytearray)): + label = label.decode("utf-8") + if len(label) == 0: + raise IDNAError("Empty Label") + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for pos, cp in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): + try: + if not valid_contextj(label, pos): + raise InvalidCodepointContext( + "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + except ValueError: + raise IDNAError( + "Unknown codepoint adjacent to joiner {} at position {} in {}".format( + _unot(cp_value), pos + 1, repr(label) + ) + ) + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): + if not valid_contexto(label, pos): + raise InvalidCodepointContext( + "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + else: + raise InvalidCodepoint( + "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label)) + ) + + check_bidi(label) + + +def alabel(label: str) -> bytes: + try: + label_bytes = label.encode("ascii") + ulabel(label_bytes) + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + return label_bytes + except UnicodeEncodeError: + pass + + check_label(label) + label_bytes = _alabel_prefix + _punycode(label) + + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + + return label_bytes + + +def ulabel(label: Union[str, bytes, bytearray]) -> str: + if not isinstance(label, (bytes, bytearray)): + try: + label_bytes = label.encode("ascii") + except UnicodeEncodeError: + check_label(label) + return label + else: + label_bytes = bytes(label) + + label_bytes = label_bytes.lower() + if label_bytes.startswith(_alabel_prefix): + label_bytes = label_bytes[len(_alabel_prefix) :] + if not label_bytes: + raise IDNAError("Malformed A-label, no Punycode eligible content found") + if label_bytes.decode("ascii")[-1] == "-": + raise IDNAError("A-label must not end with a hyphen") + else: + check_label(label_bytes) + return label_bytes.decode("ascii") + + try: + label = label_bytes.decode("punycode") + except UnicodeError: + raise IDNAError("Invalid A-label") + check_label(label) + return label + + +def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + + output = "" + + for pos, char in enumerate(domain): + code_point = ord(char) + try: + uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement: Optional[str] = None + if len(uts46row) == 3: + replacement = uts46row[2] + if ( + status == "V" + or (status == "D" and not transitional) + or (status == "3" and not std3_rules and replacement is None) + ): + output += char + elif replacement is not None and ( + status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional) + ): + output += replacement + elif status != "I": + raise IndexError() + except IndexError: + raise InvalidCodepoint( + "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain)) + ) + + return unicodedata.normalize("NFC", output) + + +def encode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, + transitional: bool = False, +) -> bytes: + if not isinstance(s, str): + try: + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("should pass a unicode string to the function rather than a byte string.") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split(".") + else: + labels = _unicode_dots_re.split(s) + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if labels[-1] == "": + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append(b"") + s = b".".join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError("Domain too long") + return s + + +def decode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, +) -> str: + try: + if not isinstance(s, str): + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("Invalid ASCII in A-label") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(".") + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + s = ulabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append("") + return ".".join(result) diff --git a/backend/venv/Lib/site-packages/idna/idnadata.py b/backend/venv/Lib/site-packages/idna/idnadata.py new file mode 100644 index 0000000..ded47ca --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/idnadata.py @@ -0,0 +1,4309 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "16.0.0" + +scripts = { + "Greek": ( + 0x37000000374, + 0x37500000378, + 0x37A0000037E, + 0x37F00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038B, + 0x38C0000038D, + 0x38E000003A2, + 0x3A3000003E2, + 0x3F000000400, + 0x1D2600001D2B, + 0x1D5D00001D62, + 0x1D6600001D6B, + 0x1DBF00001DC0, + 0x1F0000001F16, + 0x1F1800001F1E, + 0x1F2000001F46, + 0x1F4800001F4E, + 0x1F5000001F58, + 0x1F5900001F5A, + 0x1F5B00001F5C, + 0x1F5D00001F5E, + 0x1F5F00001F7E, + 0x1F8000001FB5, + 0x1FB600001FC5, + 0x1FC600001FD4, + 0x1FD600001FDC, + 0x1FDD00001FF0, + 0x1FF200001FF5, + 0x1FF600001FFF, + 0x212600002127, + 0xAB650000AB66, + 0x101400001018F, + 0x101A0000101A1, + 0x1D2000001D246, + ), + "Han": ( + 0x2E8000002E9A, + 0x2E9B00002EF4, + 0x2F0000002FD6, + 0x300500003006, + 0x300700003008, + 0x30210000302A, + 0x30380000303C, + 0x340000004DC0, + 0x4E000000A000, + 0xF9000000FA6E, + 0xFA700000FADA, + 0x16FE200016FE4, + 0x16FF000016FF2, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x2F8000002FA1E, + 0x300000003134B, + 0x31350000323B0, + ), + "Hebrew": ( + 0x591000005C8, + 0x5D0000005EB, + 0x5EF000005F5, + 0xFB1D0000FB37, + 0xFB380000FB3D, + 0xFB3E0000FB3F, + 0xFB400000FB42, + 0xFB430000FB45, + 0xFB460000FB50, + ), + "Hiragana": ( + 0x304100003097, + 0x309D000030A0, + 0x1B0010001B120, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1F2000001F201, + ), + "Katakana": ( + 0x30A1000030FB, + 0x30FD00003100, + 0x31F000003200, + 0x32D0000032FF, + 0x330000003358, + 0xFF660000FF70, + 0xFF710000FF9E, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B001, + 0x1B1200001B123, + 0x1B1550001B156, + 0x1B1640001B168, + ), +} +joining_types = { + 0xAD: 84, + 0x300: 84, + 0x301: 84, + 0x302: 84, + 0x303: 84, + 0x304: 84, + 0x305: 84, + 0x306: 84, + 0x307: 84, + 0x308: 84, + 0x309: 84, + 0x30A: 84, + 0x30B: 84, + 0x30C: 84, + 0x30D: 84, + 0x30E: 84, + 0x30F: 84, + 0x310: 84, + 0x311: 84, + 0x312: 84, + 0x313: 84, + 0x314: 84, + 0x315: 84, + 0x316: 84, + 0x317: 84, + 0x318: 84, + 0x319: 84, + 0x31A: 84, + 0x31B: 84, + 0x31C: 84, + 0x31D: 84, + 0x31E: 84, + 0x31F: 84, + 0x320: 84, + 0x321: 84, + 0x322: 84, + 0x323: 84, + 0x324: 84, + 0x325: 84, + 0x326: 84, + 0x327: 84, + 0x328: 84, + 0x329: 84, + 0x32A: 84, + 0x32B: 84, + 0x32C: 84, + 0x32D: 84, + 0x32E: 84, + 0x32F: 84, + 0x330: 84, + 0x331: 84, + 0x332: 84, + 0x333: 84, + 0x334: 84, + 0x335: 84, + 0x336: 84, + 0x337: 84, + 0x338: 84, + 0x339: 84, + 0x33A: 84, + 0x33B: 84, + 0x33C: 84, + 0x33D: 84, + 0x33E: 84, + 0x33F: 84, + 0x340: 84, + 0x341: 84, + 0x342: 84, + 0x343: 84, + 0x344: 84, + 0x345: 84, + 0x346: 84, + 0x347: 84, + 0x348: 84, + 0x349: 84, + 0x34A: 84, + 0x34B: 84, + 0x34C: 84, + 0x34D: 84, + 0x34E: 84, + 0x34F: 84, + 0x350: 84, + 0x351: 84, + 0x352: 84, + 0x353: 84, + 0x354: 84, + 0x355: 84, + 0x356: 84, + 0x357: 84, + 0x358: 84, + 0x359: 84, + 0x35A: 84, + 0x35B: 84, + 0x35C: 84, + 0x35D: 84, + 0x35E: 84, + 0x35F: 84, + 0x360: 84, + 0x361: 84, + 0x362: 84, + 0x363: 84, + 0x364: 84, + 0x365: 84, + 0x366: 84, + 0x367: 84, + 0x368: 84, + 0x369: 84, + 0x36A: 84, + 0x36B: 84, + 0x36C: 84, + 0x36D: 84, + 0x36E: 84, + 0x36F: 84, + 0x483: 84, + 0x484: 84, + 0x485: 84, + 0x486: 84, + 0x487: 84, + 0x488: 84, + 0x489: 84, + 0x591: 84, + 0x592: 84, + 0x593: 84, + 0x594: 84, + 0x595: 84, + 0x596: 84, + 0x597: 84, + 0x598: 84, + 0x599: 84, + 0x59A: 84, + 0x59B: 84, + 0x59C: 84, + 0x59D: 84, + 0x59E: 84, + 0x59F: 84, + 0x5A0: 84, + 0x5A1: 84, + 0x5A2: 84, + 0x5A3: 84, + 0x5A4: 84, + 0x5A5: 84, + 0x5A6: 84, + 0x5A7: 84, + 0x5A8: 84, + 0x5A9: 84, + 0x5AA: 84, + 0x5AB: 84, + 0x5AC: 84, + 0x5AD: 84, + 0x5AE: 84, + 0x5AF: 84, + 0x5B0: 84, + 0x5B1: 84, + 0x5B2: 84, + 0x5B3: 84, + 0x5B4: 84, + 0x5B5: 84, + 0x5B6: 84, + 0x5B7: 84, + 0x5B8: 84, + 0x5B9: 84, + 0x5BA: 84, + 0x5BB: 84, + 0x5BC: 84, + 0x5BD: 84, + 0x5BF: 84, + 0x5C1: 84, + 0x5C2: 84, + 0x5C4: 84, + 0x5C5: 84, + 0x5C7: 84, + 0x610: 84, + 0x611: 84, + 0x612: 84, + 0x613: 84, + 0x614: 84, + 0x615: 84, + 0x616: 84, + 0x617: 84, + 0x618: 84, + 0x619: 84, + 0x61A: 84, + 0x61C: 84, + 0x620: 68, + 0x622: 82, + 0x623: 82, + 0x624: 82, + 0x625: 82, + 0x626: 68, + 0x627: 82, + 0x628: 68, + 0x629: 82, + 0x62A: 68, + 0x62B: 68, + 0x62C: 68, + 0x62D: 68, + 0x62E: 68, + 0x62F: 82, + 0x630: 82, + 0x631: 82, + 0x632: 82, + 0x633: 68, + 0x634: 68, + 0x635: 68, + 0x636: 68, + 0x637: 68, + 0x638: 68, + 0x639: 68, + 0x63A: 68, + 0x63B: 68, + 0x63C: 68, + 0x63D: 68, + 0x63E: 68, + 0x63F: 68, + 0x640: 67, + 0x641: 68, + 0x642: 68, + 0x643: 68, + 0x644: 68, + 0x645: 68, + 0x646: 68, + 0x647: 68, + 0x648: 82, + 0x649: 68, + 0x64A: 68, + 0x64B: 84, + 0x64C: 84, + 0x64D: 84, + 0x64E: 84, + 0x64F: 84, + 0x650: 84, + 0x651: 84, + 0x652: 84, + 0x653: 84, + 0x654: 84, + 0x655: 84, + 0x656: 84, + 0x657: 84, + 0x658: 84, + 0x659: 84, + 0x65A: 84, + 0x65B: 84, + 0x65C: 84, + 0x65D: 84, + 0x65E: 84, + 0x65F: 84, + 0x66E: 68, + 0x66F: 68, + 0x670: 84, + 0x671: 82, + 0x672: 82, + 0x673: 82, + 0x675: 82, + 0x676: 82, + 0x677: 82, + 0x678: 68, + 0x679: 68, + 0x67A: 68, + 0x67B: 68, + 0x67C: 68, + 0x67D: 68, + 0x67E: 68, + 0x67F: 68, + 0x680: 68, + 0x681: 68, + 0x682: 68, + 0x683: 68, + 0x684: 68, + 0x685: 68, + 0x686: 68, + 0x687: 68, + 0x688: 82, + 0x689: 82, + 0x68A: 82, + 0x68B: 82, + 0x68C: 82, + 0x68D: 82, + 0x68E: 82, + 0x68F: 82, + 0x690: 82, + 0x691: 82, + 0x692: 82, + 0x693: 82, + 0x694: 82, + 0x695: 82, + 0x696: 82, + 0x697: 82, + 0x698: 82, + 0x699: 82, + 0x69A: 68, + 0x69B: 68, + 0x69C: 68, + 0x69D: 68, + 0x69E: 68, + 0x69F: 68, + 0x6A0: 68, + 0x6A1: 68, + 0x6A2: 68, + 0x6A3: 68, + 0x6A4: 68, + 0x6A5: 68, + 0x6A6: 68, + 0x6A7: 68, + 0x6A8: 68, + 0x6A9: 68, + 0x6AA: 68, + 0x6AB: 68, + 0x6AC: 68, + 0x6AD: 68, + 0x6AE: 68, + 0x6AF: 68, + 0x6B0: 68, + 0x6B1: 68, + 0x6B2: 68, + 0x6B3: 68, + 0x6B4: 68, + 0x6B5: 68, + 0x6B6: 68, + 0x6B7: 68, + 0x6B8: 68, + 0x6B9: 68, + 0x6BA: 68, + 0x6BB: 68, + 0x6BC: 68, + 0x6BD: 68, + 0x6BE: 68, + 0x6BF: 68, + 0x6C0: 82, + 0x6C1: 68, + 0x6C2: 68, + 0x6C3: 82, + 0x6C4: 82, + 0x6C5: 82, + 0x6C6: 82, + 0x6C7: 82, + 0x6C8: 82, + 0x6C9: 82, + 0x6CA: 82, + 0x6CB: 82, + 0x6CC: 68, + 0x6CD: 82, + 0x6CE: 68, + 0x6CF: 82, + 0x6D0: 68, + 0x6D1: 68, + 0x6D2: 82, + 0x6D3: 82, + 0x6D5: 82, + 0x6D6: 84, + 0x6D7: 84, + 0x6D8: 84, + 0x6D9: 84, + 0x6DA: 84, + 0x6DB: 84, + 0x6DC: 84, + 0x6DF: 84, + 0x6E0: 84, + 0x6E1: 84, + 0x6E2: 84, + 0x6E3: 84, + 0x6E4: 84, + 0x6E7: 84, + 0x6E8: 84, + 0x6EA: 84, + 0x6EB: 84, + 0x6EC: 84, + 0x6ED: 84, + 0x6EE: 82, + 0x6EF: 82, + 0x6FA: 68, + 0x6FB: 68, + 0x6FC: 68, + 0x6FF: 68, + 0x70F: 84, + 0x710: 82, + 0x711: 84, + 0x712: 68, + 0x713: 68, + 0x714: 68, + 0x715: 82, + 0x716: 82, + 0x717: 82, + 0x718: 82, + 0x719: 82, + 0x71A: 68, + 0x71B: 68, + 0x71C: 68, + 0x71D: 68, + 0x71E: 82, + 0x71F: 68, + 0x720: 68, + 0x721: 68, + 0x722: 68, + 0x723: 68, + 0x724: 68, + 0x725: 68, + 0x726: 68, + 0x727: 68, + 0x728: 82, + 0x729: 68, + 0x72A: 82, + 0x72B: 68, + 0x72C: 82, + 0x72D: 68, + 0x72E: 68, + 0x72F: 82, + 0x730: 84, + 0x731: 84, + 0x732: 84, + 0x733: 84, + 0x734: 84, + 0x735: 84, + 0x736: 84, + 0x737: 84, + 0x738: 84, + 0x739: 84, + 0x73A: 84, + 0x73B: 84, + 0x73C: 84, + 0x73D: 84, + 0x73E: 84, + 0x73F: 84, + 0x740: 84, + 0x741: 84, + 0x742: 84, + 0x743: 84, + 0x744: 84, + 0x745: 84, + 0x746: 84, + 0x747: 84, + 0x748: 84, + 0x749: 84, + 0x74A: 84, + 0x74D: 82, + 0x74E: 68, + 0x74F: 68, + 0x750: 68, + 0x751: 68, + 0x752: 68, + 0x753: 68, + 0x754: 68, + 0x755: 68, + 0x756: 68, + 0x757: 68, + 0x758: 68, + 0x759: 82, + 0x75A: 82, + 0x75B: 82, + 0x75C: 68, + 0x75D: 68, + 0x75E: 68, + 0x75F: 68, + 0x760: 68, + 0x761: 68, + 0x762: 68, + 0x763: 68, + 0x764: 68, + 0x765: 68, + 0x766: 68, + 0x767: 68, + 0x768: 68, + 0x769: 68, + 0x76A: 68, + 0x76B: 82, + 0x76C: 82, + 0x76D: 68, + 0x76E: 68, + 0x76F: 68, + 0x770: 68, + 0x771: 82, + 0x772: 68, + 0x773: 82, + 0x774: 82, + 0x775: 68, + 0x776: 68, + 0x777: 68, + 0x778: 82, + 0x779: 82, + 0x77A: 68, + 0x77B: 68, + 0x77C: 68, + 0x77D: 68, + 0x77E: 68, + 0x77F: 68, + 0x7A6: 84, + 0x7A7: 84, + 0x7A8: 84, + 0x7A9: 84, + 0x7AA: 84, + 0x7AB: 84, + 0x7AC: 84, + 0x7AD: 84, + 0x7AE: 84, + 0x7AF: 84, + 0x7B0: 84, + 0x7CA: 68, + 0x7CB: 68, + 0x7CC: 68, + 0x7CD: 68, + 0x7CE: 68, + 0x7CF: 68, + 0x7D0: 68, + 0x7D1: 68, + 0x7D2: 68, + 0x7D3: 68, + 0x7D4: 68, + 0x7D5: 68, + 0x7D6: 68, + 0x7D7: 68, + 0x7D8: 68, + 0x7D9: 68, + 0x7DA: 68, + 0x7DB: 68, + 0x7DC: 68, + 0x7DD: 68, + 0x7DE: 68, + 0x7DF: 68, + 0x7E0: 68, + 0x7E1: 68, + 0x7E2: 68, + 0x7E3: 68, + 0x7E4: 68, + 0x7E5: 68, + 0x7E6: 68, + 0x7E7: 68, + 0x7E8: 68, + 0x7E9: 68, + 0x7EA: 68, + 0x7EB: 84, + 0x7EC: 84, + 0x7ED: 84, + 0x7EE: 84, + 0x7EF: 84, + 0x7F0: 84, + 0x7F1: 84, + 0x7F2: 84, + 0x7F3: 84, + 0x7FA: 67, + 0x7FD: 84, + 0x816: 84, + 0x817: 84, + 0x818: 84, + 0x819: 84, + 0x81B: 84, + 0x81C: 84, + 0x81D: 84, + 0x81E: 84, + 0x81F: 84, + 0x820: 84, + 0x821: 84, + 0x822: 84, + 0x823: 84, + 0x825: 84, + 0x826: 84, + 0x827: 84, + 0x829: 84, + 0x82A: 84, + 0x82B: 84, + 0x82C: 84, + 0x82D: 84, + 0x840: 82, + 0x841: 68, + 0x842: 68, + 0x843: 68, + 0x844: 68, + 0x845: 68, + 0x846: 82, + 0x847: 82, + 0x848: 68, + 0x849: 82, + 0x84A: 68, + 0x84B: 68, + 0x84C: 68, + 0x84D: 68, + 0x84E: 68, + 0x84F: 68, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 82, + 0x857: 82, + 0x858: 82, + 0x859: 84, + 0x85A: 84, + 0x85B: 84, + 0x860: 68, + 0x862: 68, + 0x863: 68, + 0x864: 68, + 0x865: 68, + 0x867: 82, + 0x868: 68, + 0x869: 82, + 0x86A: 82, + 0x870: 82, + 0x871: 82, + 0x872: 82, + 0x873: 82, + 0x874: 82, + 0x875: 82, + 0x876: 82, + 0x877: 82, + 0x878: 82, + 0x879: 82, + 0x87A: 82, + 0x87B: 82, + 0x87C: 82, + 0x87D: 82, + 0x87E: 82, + 0x87F: 82, + 0x880: 82, + 0x881: 82, + 0x882: 82, + 0x883: 67, + 0x884: 67, + 0x885: 67, + 0x886: 68, + 0x889: 68, + 0x88A: 68, + 0x88B: 68, + 0x88C: 68, + 0x88D: 68, + 0x88E: 82, + 0x897: 84, + 0x898: 84, + 0x899: 84, + 0x89A: 84, + 0x89B: 84, + 0x89C: 84, + 0x89D: 84, + 0x89E: 84, + 0x89F: 84, + 0x8A0: 68, + 0x8A1: 68, + 0x8A2: 68, + 0x8A3: 68, + 0x8A4: 68, + 0x8A5: 68, + 0x8A6: 68, + 0x8A7: 68, + 0x8A8: 68, + 0x8A9: 68, + 0x8AA: 82, + 0x8AB: 82, + 0x8AC: 82, + 0x8AE: 82, + 0x8AF: 68, + 0x8B0: 68, + 0x8B1: 82, + 0x8B2: 82, + 0x8B3: 68, + 0x8B4: 68, + 0x8B5: 68, + 0x8B6: 68, + 0x8B7: 68, + 0x8B8: 68, + 0x8B9: 82, + 0x8BA: 68, + 0x8BB: 68, + 0x8BC: 68, + 0x8BD: 68, + 0x8BE: 68, + 0x8BF: 68, + 0x8C0: 68, + 0x8C1: 68, + 0x8C2: 68, + 0x8C3: 68, + 0x8C4: 68, + 0x8C5: 68, + 0x8C6: 68, + 0x8C7: 68, + 0x8C8: 68, + 0x8CA: 84, + 0x8CB: 84, + 0x8CC: 84, + 0x8CD: 84, + 0x8CE: 84, + 0x8CF: 84, + 0x8D0: 84, + 0x8D1: 84, + 0x8D2: 84, + 0x8D3: 84, + 0x8D4: 84, + 0x8D5: 84, + 0x8D6: 84, + 0x8D7: 84, + 0x8D8: 84, + 0x8D9: 84, + 0x8DA: 84, + 0x8DB: 84, + 0x8DC: 84, + 0x8DD: 84, + 0x8DE: 84, + 0x8DF: 84, + 0x8E0: 84, + 0x8E1: 84, + 0x8E3: 84, + 0x8E4: 84, + 0x8E5: 84, + 0x8E6: 84, + 0x8E7: 84, + 0x8E8: 84, + 0x8E9: 84, + 0x8EA: 84, + 0x8EB: 84, + 0x8EC: 84, + 0x8ED: 84, + 0x8EE: 84, + 0x8EF: 84, + 0x8F0: 84, + 0x8F1: 84, + 0x8F2: 84, + 0x8F3: 84, + 0x8F4: 84, + 0x8F5: 84, + 0x8F6: 84, + 0x8F7: 84, + 0x8F8: 84, + 0x8F9: 84, + 0x8FA: 84, + 0x8FB: 84, + 0x8FC: 84, + 0x8FD: 84, + 0x8FE: 84, + 0x8FF: 84, + 0x900: 84, + 0x901: 84, + 0x902: 84, + 0x93A: 84, + 0x93C: 84, + 0x941: 84, + 0x942: 84, + 0x943: 84, + 0x944: 84, + 0x945: 84, + 0x946: 84, + 0x947: 84, + 0x948: 84, + 0x94D: 84, + 0x951: 84, + 0x952: 84, + 0x953: 84, + 0x954: 84, + 0x955: 84, + 0x956: 84, + 0x957: 84, + 0x962: 84, + 0x963: 84, + 0x981: 84, + 0x9BC: 84, + 0x9C1: 84, + 0x9C2: 84, + 0x9C3: 84, + 0x9C4: 84, + 0x9CD: 84, + 0x9E2: 84, + 0x9E3: 84, + 0x9FE: 84, + 0xA01: 84, + 0xA02: 84, + 0xA3C: 84, + 0xA41: 84, + 0xA42: 84, + 0xA47: 84, + 0xA48: 84, + 0xA4B: 84, + 0xA4C: 84, + 0xA4D: 84, + 0xA51: 84, + 0xA70: 84, + 0xA71: 84, + 0xA75: 84, + 0xA81: 84, + 0xA82: 84, + 0xABC: 84, + 0xAC1: 84, + 0xAC2: 84, + 0xAC3: 84, + 0xAC4: 84, + 0xAC5: 84, + 0xAC7: 84, + 0xAC8: 84, + 0xACD: 84, + 0xAE2: 84, + 0xAE3: 84, + 0xAFA: 84, + 0xAFB: 84, + 0xAFC: 84, + 0xAFD: 84, + 0xAFE: 84, + 0xAFF: 84, + 0xB01: 84, + 0xB3C: 84, + 0xB3F: 84, + 0xB41: 84, + 0xB42: 84, + 0xB43: 84, + 0xB44: 84, + 0xB4D: 84, + 0xB55: 84, + 0xB56: 84, + 0xB62: 84, + 0xB63: 84, + 0xB82: 84, + 0xBC0: 84, + 0xBCD: 84, + 0xC00: 84, + 0xC04: 84, + 0xC3C: 84, + 0xC3E: 84, + 0xC3F: 84, + 0xC40: 84, + 0xC46: 84, + 0xC47: 84, + 0xC48: 84, + 0xC4A: 84, + 0xC4B: 84, + 0xC4C: 84, + 0xC4D: 84, + 0xC55: 84, + 0xC56: 84, + 0xC62: 84, + 0xC63: 84, + 0xC81: 84, + 0xCBC: 84, + 0xCBF: 84, + 0xCC6: 84, + 0xCCC: 84, + 0xCCD: 84, + 0xCE2: 84, + 0xCE3: 84, + 0xD00: 84, + 0xD01: 84, + 0xD3B: 84, + 0xD3C: 84, + 0xD41: 84, + 0xD42: 84, + 0xD43: 84, + 0xD44: 84, + 0xD4D: 84, + 0xD62: 84, + 0xD63: 84, + 0xD81: 84, + 0xDCA: 84, + 0xDD2: 84, + 0xDD3: 84, + 0xDD4: 84, + 0xDD6: 84, + 0xE31: 84, + 0xE34: 84, + 0xE35: 84, + 0xE36: 84, + 0xE37: 84, + 0xE38: 84, + 0xE39: 84, + 0xE3A: 84, + 0xE47: 84, + 0xE48: 84, + 0xE49: 84, + 0xE4A: 84, + 0xE4B: 84, + 0xE4C: 84, + 0xE4D: 84, + 0xE4E: 84, + 0xEB1: 84, + 0xEB4: 84, + 0xEB5: 84, + 0xEB6: 84, + 0xEB7: 84, + 0xEB8: 84, + 0xEB9: 84, + 0xEBA: 84, + 0xEBB: 84, + 0xEBC: 84, + 0xEC8: 84, + 0xEC9: 84, + 0xECA: 84, + 0xECB: 84, + 0xECC: 84, + 0xECD: 84, + 0xECE: 84, + 0xF18: 84, + 0xF19: 84, + 0xF35: 84, + 0xF37: 84, + 0xF39: 84, + 0xF71: 84, + 0xF72: 84, + 0xF73: 84, + 0xF74: 84, + 0xF75: 84, + 0xF76: 84, + 0xF77: 84, + 0xF78: 84, + 0xF79: 84, + 0xF7A: 84, + 0xF7B: 84, + 0xF7C: 84, + 0xF7D: 84, + 0xF7E: 84, + 0xF80: 84, + 0xF81: 84, + 0xF82: 84, + 0xF83: 84, + 0xF84: 84, + 0xF86: 84, + 0xF87: 84, + 0xF8D: 84, + 0xF8E: 84, + 0xF8F: 84, + 0xF90: 84, + 0xF91: 84, + 0xF92: 84, + 0xF93: 84, + 0xF94: 84, + 0xF95: 84, + 0xF96: 84, + 0xF97: 84, + 0xF99: 84, + 0xF9A: 84, + 0xF9B: 84, + 0xF9C: 84, + 0xF9D: 84, + 0xF9E: 84, + 0xF9F: 84, + 0xFA0: 84, + 0xFA1: 84, + 0xFA2: 84, + 0xFA3: 84, + 0xFA4: 84, + 0xFA5: 84, + 0xFA6: 84, + 0xFA7: 84, + 0xFA8: 84, + 0xFA9: 84, + 0xFAA: 84, + 0xFAB: 84, + 0xFAC: 84, + 0xFAD: 84, + 0xFAE: 84, + 0xFAF: 84, + 0xFB0: 84, + 0xFB1: 84, + 0xFB2: 84, + 0xFB3: 84, + 0xFB4: 84, + 0xFB5: 84, + 0xFB6: 84, + 0xFB7: 84, + 0xFB8: 84, + 0xFB9: 84, + 0xFBA: 84, + 0xFBB: 84, + 0xFBC: 84, + 0xFC6: 84, + 0x102D: 84, + 0x102E: 84, + 0x102F: 84, + 0x1030: 84, + 0x1032: 84, + 0x1033: 84, + 0x1034: 84, + 0x1035: 84, + 0x1036: 84, + 0x1037: 84, + 0x1039: 84, + 0x103A: 84, + 0x103D: 84, + 0x103E: 84, + 0x1058: 84, + 0x1059: 84, + 0x105E: 84, + 0x105F: 84, + 0x1060: 84, + 0x1071: 84, + 0x1072: 84, + 0x1073: 84, + 0x1074: 84, + 0x1082: 84, + 0x1085: 84, + 0x1086: 84, + 0x108D: 84, + 0x109D: 84, + 0x135D: 84, + 0x135E: 84, + 0x135F: 84, + 0x1712: 84, + 0x1713: 84, + 0x1714: 84, + 0x1732: 84, + 0x1733: 84, + 0x1752: 84, + 0x1753: 84, + 0x1772: 84, + 0x1773: 84, + 0x17B4: 84, + 0x17B5: 84, + 0x17B7: 84, + 0x17B8: 84, + 0x17B9: 84, + 0x17BA: 84, + 0x17BB: 84, + 0x17BC: 84, + 0x17BD: 84, + 0x17C6: 84, + 0x17C9: 84, + 0x17CA: 84, + 0x17CB: 84, + 0x17CC: 84, + 0x17CD: 84, + 0x17CE: 84, + 0x17CF: 84, + 0x17D0: 84, + 0x17D1: 84, + 0x17D2: 84, + 0x17D3: 84, + 0x17DD: 84, + 0x1807: 68, + 0x180A: 67, + 0x180B: 84, + 0x180C: 84, + 0x180D: 84, + 0x180F: 84, + 0x1820: 68, + 0x1821: 68, + 0x1822: 68, + 0x1823: 68, + 0x1824: 68, + 0x1825: 68, + 0x1826: 68, + 0x1827: 68, + 0x1828: 68, + 0x1829: 68, + 0x182A: 68, + 0x182B: 68, + 0x182C: 68, + 0x182D: 68, + 0x182E: 68, + 0x182F: 68, + 0x1830: 68, + 0x1831: 68, + 0x1832: 68, + 0x1833: 68, + 0x1834: 68, + 0x1835: 68, + 0x1836: 68, + 0x1837: 68, + 0x1838: 68, + 0x1839: 68, + 0x183A: 68, + 0x183B: 68, + 0x183C: 68, + 0x183D: 68, + 0x183E: 68, + 0x183F: 68, + 0x1840: 68, + 0x1841: 68, + 0x1842: 68, + 0x1843: 68, + 0x1844: 68, + 0x1845: 68, + 0x1846: 68, + 0x1847: 68, + 0x1848: 68, + 0x1849: 68, + 0x184A: 68, + 0x184B: 68, + 0x184C: 68, + 0x184D: 68, + 0x184E: 68, + 0x184F: 68, + 0x1850: 68, + 0x1851: 68, + 0x1852: 68, + 0x1853: 68, + 0x1854: 68, + 0x1855: 68, + 0x1856: 68, + 0x1857: 68, + 0x1858: 68, + 0x1859: 68, + 0x185A: 68, + 0x185B: 68, + 0x185C: 68, + 0x185D: 68, + 0x185E: 68, + 0x185F: 68, + 0x1860: 68, + 0x1861: 68, + 0x1862: 68, + 0x1863: 68, + 0x1864: 68, + 0x1865: 68, + 0x1866: 68, + 0x1867: 68, + 0x1868: 68, + 0x1869: 68, + 0x186A: 68, + 0x186B: 68, + 0x186C: 68, + 0x186D: 68, + 0x186E: 68, + 0x186F: 68, + 0x1870: 68, + 0x1871: 68, + 0x1872: 68, + 0x1873: 68, + 0x1874: 68, + 0x1875: 68, + 0x1876: 68, + 0x1877: 68, + 0x1878: 68, + 0x1885: 84, + 0x1886: 84, + 0x1887: 68, + 0x1888: 68, + 0x1889: 68, + 0x188A: 68, + 0x188B: 68, + 0x188C: 68, + 0x188D: 68, + 0x188E: 68, + 0x188F: 68, + 0x1890: 68, + 0x1891: 68, + 0x1892: 68, + 0x1893: 68, + 0x1894: 68, + 0x1895: 68, + 0x1896: 68, + 0x1897: 68, + 0x1898: 68, + 0x1899: 68, + 0x189A: 68, + 0x189B: 68, + 0x189C: 68, + 0x189D: 68, + 0x189E: 68, + 0x189F: 68, + 0x18A0: 68, + 0x18A1: 68, + 0x18A2: 68, + 0x18A3: 68, + 0x18A4: 68, + 0x18A5: 68, + 0x18A6: 68, + 0x18A7: 68, + 0x18A8: 68, + 0x18A9: 84, + 0x18AA: 68, + 0x1920: 84, + 0x1921: 84, + 0x1922: 84, + 0x1927: 84, + 0x1928: 84, + 0x1932: 84, + 0x1939: 84, + 0x193A: 84, + 0x193B: 84, + 0x1A17: 84, + 0x1A18: 84, + 0x1A1B: 84, + 0x1A56: 84, + 0x1A58: 84, + 0x1A59: 84, + 0x1A5A: 84, + 0x1A5B: 84, + 0x1A5C: 84, + 0x1A5D: 84, + 0x1A5E: 84, + 0x1A60: 84, + 0x1A62: 84, + 0x1A65: 84, + 0x1A66: 84, + 0x1A67: 84, + 0x1A68: 84, + 0x1A69: 84, + 0x1A6A: 84, + 0x1A6B: 84, + 0x1A6C: 84, + 0x1A73: 84, + 0x1A74: 84, + 0x1A75: 84, + 0x1A76: 84, + 0x1A77: 84, + 0x1A78: 84, + 0x1A79: 84, + 0x1A7A: 84, + 0x1A7B: 84, + 0x1A7C: 84, + 0x1A7F: 84, + 0x1AB0: 84, + 0x1AB1: 84, + 0x1AB2: 84, + 0x1AB3: 84, + 0x1AB4: 84, + 0x1AB5: 84, + 0x1AB6: 84, + 0x1AB7: 84, + 0x1AB8: 84, + 0x1AB9: 84, + 0x1ABA: 84, + 0x1ABB: 84, + 0x1ABC: 84, + 0x1ABD: 84, + 0x1ABE: 84, + 0x1ABF: 84, + 0x1AC0: 84, + 0x1AC1: 84, + 0x1AC2: 84, + 0x1AC3: 84, + 0x1AC4: 84, + 0x1AC5: 84, + 0x1AC6: 84, + 0x1AC7: 84, + 0x1AC8: 84, + 0x1AC9: 84, + 0x1ACA: 84, + 0x1ACB: 84, + 0x1ACC: 84, + 0x1ACD: 84, + 0x1ACE: 84, + 0x1B00: 84, + 0x1B01: 84, + 0x1B02: 84, + 0x1B03: 84, + 0x1B34: 84, + 0x1B36: 84, + 0x1B37: 84, + 0x1B38: 84, + 0x1B39: 84, + 0x1B3A: 84, + 0x1B3C: 84, + 0x1B42: 84, + 0x1B6B: 84, + 0x1B6C: 84, + 0x1B6D: 84, + 0x1B6E: 84, + 0x1B6F: 84, + 0x1B70: 84, + 0x1B71: 84, + 0x1B72: 84, + 0x1B73: 84, + 0x1B80: 84, + 0x1B81: 84, + 0x1BA2: 84, + 0x1BA3: 84, + 0x1BA4: 84, + 0x1BA5: 84, + 0x1BA8: 84, + 0x1BA9: 84, + 0x1BAB: 84, + 0x1BAC: 84, + 0x1BAD: 84, + 0x1BE6: 84, + 0x1BE8: 84, + 0x1BE9: 84, + 0x1BED: 84, + 0x1BEF: 84, + 0x1BF0: 84, + 0x1BF1: 84, + 0x1C2C: 84, + 0x1C2D: 84, + 0x1C2E: 84, + 0x1C2F: 84, + 0x1C30: 84, + 0x1C31: 84, + 0x1C32: 84, + 0x1C33: 84, + 0x1C36: 84, + 0x1C37: 84, + 0x1CD0: 84, + 0x1CD1: 84, + 0x1CD2: 84, + 0x1CD4: 84, + 0x1CD5: 84, + 0x1CD6: 84, + 0x1CD7: 84, + 0x1CD8: 84, + 0x1CD9: 84, + 0x1CDA: 84, + 0x1CDB: 84, + 0x1CDC: 84, + 0x1CDD: 84, + 0x1CDE: 84, + 0x1CDF: 84, + 0x1CE0: 84, + 0x1CE2: 84, + 0x1CE3: 84, + 0x1CE4: 84, + 0x1CE5: 84, + 0x1CE6: 84, + 0x1CE7: 84, + 0x1CE8: 84, + 0x1CED: 84, + 0x1CF4: 84, + 0x1CF8: 84, + 0x1CF9: 84, + 0x1DC0: 84, + 0x1DC1: 84, + 0x1DC2: 84, + 0x1DC3: 84, + 0x1DC4: 84, + 0x1DC5: 84, + 0x1DC6: 84, + 0x1DC7: 84, + 0x1DC8: 84, + 0x1DC9: 84, + 0x1DCA: 84, + 0x1DCB: 84, + 0x1DCC: 84, + 0x1DCD: 84, + 0x1DCE: 84, + 0x1DCF: 84, + 0x1DD0: 84, + 0x1DD1: 84, + 0x1DD2: 84, + 0x1DD3: 84, + 0x1DD4: 84, + 0x1DD5: 84, + 0x1DD6: 84, + 0x1DD7: 84, + 0x1DD8: 84, + 0x1DD9: 84, + 0x1DDA: 84, + 0x1DDB: 84, + 0x1DDC: 84, + 0x1DDD: 84, + 0x1DDE: 84, + 0x1DDF: 84, + 0x1DE0: 84, + 0x1DE1: 84, + 0x1DE2: 84, + 0x1DE3: 84, + 0x1DE4: 84, + 0x1DE5: 84, + 0x1DE6: 84, + 0x1DE7: 84, + 0x1DE8: 84, + 0x1DE9: 84, + 0x1DEA: 84, + 0x1DEB: 84, + 0x1DEC: 84, + 0x1DED: 84, + 0x1DEE: 84, + 0x1DEF: 84, + 0x1DF0: 84, + 0x1DF1: 84, + 0x1DF2: 84, + 0x1DF3: 84, + 0x1DF4: 84, + 0x1DF5: 84, + 0x1DF6: 84, + 0x1DF7: 84, + 0x1DF8: 84, + 0x1DF9: 84, + 0x1DFA: 84, + 0x1DFB: 84, + 0x1DFC: 84, + 0x1DFD: 84, + 0x1DFE: 84, + 0x1DFF: 84, + 0x200B: 84, + 0x200D: 67, + 0x200E: 84, + 0x200F: 84, + 0x202A: 84, + 0x202B: 84, + 0x202C: 84, + 0x202D: 84, + 0x202E: 84, + 0x2060: 84, + 0x2061: 84, + 0x2062: 84, + 0x2063: 84, + 0x2064: 84, + 0x206A: 84, + 0x206B: 84, + 0x206C: 84, + 0x206D: 84, + 0x206E: 84, + 0x206F: 84, + 0x20D0: 84, + 0x20D1: 84, + 0x20D2: 84, + 0x20D3: 84, + 0x20D4: 84, + 0x20D5: 84, + 0x20D6: 84, + 0x20D7: 84, + 0x20D8: 84, + 0x20D9: 84, + 0x20DA: 84, + 0x20DB: 84, + 0x20DC: 84, + 0x20DD: 84, + 0x20DE: 84, + 0x20DF: 84, + 0x20E0: 84, + 0x20E1: 84, + 0x20E2: 84, + 0x20E3: 84, + 0x20E4: 84, + 0x20E5: 84, + 0x20E6: 84, + 0x20E7: 84, + 0x20E8: 84, + 0x20E9: 84, + 0x20EA: 84, + 0x20EB: 84, + 0x20EC: 84, + 0x20ED: 84, + 0x20EE: 84, + 0x20EF: 84, + 0x20F0: 84, + 0x2CEF: 84, + 0x2CF0: 84, + 0x2CF1: 84, + 0x2D7F: 84, + 0x2DE0: 84, + 0x2DE1: 84, + 0x2DE2: 84, + 0x2DE3: 84, + 0x2DE4: 84, + 0x2DE5: 84, + 0x2DE6: 84, + 0x2DE7: 84, + 0x2DE8: 84, + 0x2DE9: 84, + 0x2DEA: 84, + 0x2DEB: 84, + 0x2DEC: 84, + 0x2DED: 84, + 0x2DEE: 84, + 0x2DEF: 84, + 0x2DF0: 84, + 0x2DF1: 84, + 0x2DF2: 84, + 0x2DF3: 84, + 0x2DF4: 84, + 0x2DF5: 84, + 0x2DF6: 84, + 0x2DF7: 84, + 0x2DF8: 84, + 0x2DF9: 84, + 0x2DFA: 84, + 0x2DFB: 84, + 0x2DFC: 84, + 0x2DFD: 84, + 0x2DFE: 84, + 0x2DFF: 84, + 0x302A: 84, + 0x302B: 84, + 0x302C: 84, + 0x302D: 84, + 0x3099: 84, + 0x309A: 84, + 0xA66F: 84, + 0xA670: 84, + 0xA671: 84, + 0xA672: 84, + 0xA674: 84, + 0xA675: 84, + 0xA676: 84, + 0xA677: 84, + 0xA678: 84, + 0xA679: 84, + 0xA67A: 84, + 0xA67B: 84, + 0xA67C: 84, + 0xA67D: 84, + 0xA69E: 84, + 0xA69F: 84, + 0xA6F0: 84, + 0xA6F1: 84, + 0xA802: 84, + 0xA806: 84, + 0xA80B: 84, + 0xA825: 84, + 0xA826: 84, + 0xA82C: 84, + 0xA840: 68, + 0xA841: 68, + 0xA842: 68, + 0xA843: 68, + 0xA844: 68, + 0xA845: 68, + 0xA846: 68, + 0xA847: 68, + 0xA848: 68, + 0xA849: 68, + 0xA84A: 68, + 0xA84B: 68, + 0xA84C: 68, + 0xA84D: 68, + 0xA84E: 68, + 0xA84F: 68, + 0xA850: 68, + 0xA851: 68, + 0xA852: 68, + 0xA853: 68, + 0xA854: 68, + 0xA855: 68, + 0xA856: 68, + 0xA857: 68, + 0xA858: 68, + 0xA859: 68, + 0xA85A: 68, + 0xA85B: 68, + 0xA85C: 68, + 0xA85D: 68, + 0xA85E: 68, + 0xA85F: 68, + 0xA860: 68, + 0xA861: 68, + 0xA862: 68, + 0xA863: 68, + 0xA864: 68, + 0xA865: 68, + 0xA866: 68, + 0xA867: 68, + 0xA868: 68, + 0xA869: 68, + 0xA86A: 68, + 0xA86B: 68, + 0xA86C: 68, + 0xA86D: 68, + 0xA86E: 68, + 0xA86F: 68, + 0xA870: 68, + 0xA871: 68, + 0xA872: 76, + 0xA8C4: 84, + 0xA8C5: 84, + 0xA8E0: 84, + 0xA8E1: 84, + 0xA8E2: 84, + 0xA8E3: 84, + 0xA8E4: 84, + 0xA8E5: 84, + 0xA8E6: 84, + 0xA8E7: 84, + 0xA8E8: 84, + 0xA8E9: 84, + 0xA8EA: 84, + 0xA8EB: 84, + 0xA8EC: 84, + 0xA8ED: 84, + 0xA8EE: 84, + 0xA8EF: 84, + 0xA8F0: 84, + 0xA8F1: 84, + 0xA8FF: 84, + 0xA926: 84, + 0xA927: 84, + 0xA928: 84, + 0xA929: 84, + 0xA92A: 84, + 0xA92B: 84, + 0xA92C: 84, + 0xA92D: 84, + 0xA947: 84, + 0xA948: 84, + 0xA949: 84, + 0xA94A: 84, + 0xA94B: 84, + 0xA94C: 84, + 0xA94D: 84, + 0xA94E: 84, + 0xA94F: 84, + 0xA950: 84, + 0xA951: 84, + 0xA980: 84, + 0xA981: 84, + 0xA982: 84, + 0xA9B3: 84, + 0xA9B6: 84, + 0xA9B7: 84, + 0xA9B8: 84, + 0xA9B9: 84, + 0xA9BC: 84, + 0xA9BD: 84, + 0xA9E5: 84, + 0xAA29: 84, + 0xAA2A: 84, + 0xAA2B: 84, + 0xAA2C: 84, + 0xAA2D: 84, + 0xAA2E: 84, + 0xAA31: 84, + 0xAA32: 84, + 0xAA35: 84, + 0xAA36: 84, + 0xAA43: 84, + 0xAA4C: 84, + 0xAA7C: 84, + 0xAAB0: 84, + 0xAAB2: 84, + 0xAAB3: 84, + 0xAAB4: 84, + 0xAAB7: 84, + 0xAAB8: 84, + 0xAABE: 84, + 0xAABF: 84, + 0xAAC1: 84, + 0xAAEC: 84, + 0xAAED: 84, + 0xAAF6: 84, + 0xABE5: 84, + 0xABE8: 84, + 0xABED: 84, + 0xFB1E: 84, + 0xFE00: 84, + 0xFE01: 84, + 0xFE02: 84, + 0xFE03: 84, + 0xFE04: 84, + 0xFE05: 84, + 0xFE06: 84, + 0xFE07: 84, + 0xFE08: 84, + 0xFE09: 84, + 0xFE0A: 84, + 0xFE0B: 84, + 0xFE0C: 84, + 0xFE0D: 84, + 0xFE0E: 84, + 0xFE0F: 84, + 0xFE20: 84, + 0xFE21: 84, + 0xFE22: 84, + 0xFE23: 84, + 0xFE24: 84, + 0xFE25: 84, + 0xFE26: 84, + 0xFE27: 84, + 0xFE28: 84, + 0xFE29: 84, + 0xFE2A: 84, + 0xFE2B: 84, + 0xFE2C: 84, + 0xFE2D: 84, + 0xFE2E: 84, + 0xFE2F: 84, + 0xFEFF: 84, + 0xFFF9: 84, + 0xFFFA: 84, + 0xFFFB: 84, + 0x101FD: 84, + 0x102E0: 84, + 0x10376: 84, + 0x10377: 84, + 0x10378: 84, + 0x10379: 84, + 0x1037A: 84, + 0x10A01: 84, + 0x10A02: 84, + 0x10A03: 84, + 0x10A05: 84, + 0x10A06: 84, + 0x10A0C: 84, + 0x10A0D: 84, + 0x10A0E: 84, + 0x10A0F: 84, + 0x10A38: 84, + 0x10A39: 84, + 0x10A3A: 84, + 0x10A3F: 84, + 0x10AC0: 68, + 0x10AC1: 68, + 0x10AC2: 68, + 0x10AC3: 68, + 0x10AC4: 68, + 0x10AC5: 82, + 0x10AC7: 82, + 0x10AC9: 82, + 0x10ACA: 82, + 0x10ACD: 76, + 0x10ACE: 82, + 0x10ACF: 82, + 0x10AD0: 82, + 0x10AD1: 82, + 0x10AD2: 82, + 0x10AD3: 68, + 0x10AD4: 68, + 0x10AD5: 68, + 0x10AD6: 68, + 0x10AD7: 76, + 0x10AD8: 68, + 0x10AD9: 68, + 0x10ADA: 68, + 0x10ADB: 68, + 0x10ADC: 68, + 0x10ADD: 82, + 0x10ADE: 68, + 0x10ADF: 68, + 0x10AE0: 68, + 0x10AE1: 82, + 0x10AE4: 82, + 0x10AE5: 84, + 0x10AE6: 84, + 0x10AEB: 68, + 0x10AEC: 68, + 0x10AED: 68, + 0x10AEE: 68, + 0x10AEF: 82, + 0x10B80: 68, + 0x10B81: 82, + 0x10B82: 68, + 0x10B83: 82, + 0x10B84: 82, + 0x10B85: 82, + 0x10B86: 68, + 0x10B87: 68, + 0x10B88: 68, + 0x10B89: 82, + 0x10B8A: 68, + 0x10B8B: 68, + 0x10B8C: 82, + 0x10B8D: 68, + 0x10B8E: 82, + 0x10B8F: 82, + 0x10B90: 68, + 0x10B91: 82, + 0x10BA9: 82, + 0x10BAA: 82, + 0x10BAB: 82, + 0x10BAC: 82, + 0x10BAD: 68, + 0x10BAE: 68, + 0x10D00: 76, + 0x10D01: 68, + 0x10D02: 68, + 0x10D03: 68, + 0x10D04: 68, + 0x10D05: 68, + 0x10D06: 68, + 0x10D07: 68, + 0x10D08: 68, + 0x10D09: 68, + 0x10D0A: 68, + 0x10D0B: 68, + 0x10D0C: 68, + 0x10D0D: 68, + 0x10D0E: 68, + 0x10D0F: 68, + 0x10D10: 68, + 0x10D11: 68, + 0x10D12: 68, + 0x10D13: 68, + 0x10D14: 68, + 0x10D15: 68, + 0x10D16: 68, + 0x10D17: 68, + 0x10D18: 68, + 0x10D19: 68, + 0x10D1A: 68, + 0x10D1B: 68, + 0x10D1C: 68, + 0x10D1D: 68, + 0x10D1E: 68, + 0x10D1F: 68, + 0x10D20: 68, + 0x10D21: 68, + 0x10D22: 82, + 0x10D23: 68, + 0x10D24: 84, + 0x10D25: 84, + 0x10D26: 84, + 0x10D27: 84, + 0x10D69: 84, + 0x10D6A: 84, + 0x10D6B: 84, + 0x10D6C: 84, + 0x10D6D: 84, + 0x10EAB: 84, + 0x10EAC: 84, + 0x10EC2: 82, + 0x10EC3: 68, + 0x10EC4: 68, + 0x10EFC: 84, + 0x10EFD: 84, + 0x10EFE: 84, + 0x10EFF: 84, + 0x10F30: 68, + 0x10F31: 68, + 0x10F32: 68, + 0x10F33: 82, + 0x10F34: 68, + 0x10F35: 68, + 0x10F36: 68, + 0x10F37: 68, + 0x10F38: 68, + 0x10F39: 68, + 0x10F3A: 68, + 0x10F3B: 68, + 0x10F3C: 68, + 0x10F3D: 68, + 0x10F3E: 68, + 0x10F3F: 68, + 0x10F40: 68, + 0x10F41: 68, + 0x10F42: 68, + 0x10F43: 68, + 0x10F44: 68, + 0x10F46: 84, + 0x10F47: 84, + 0x10F48: 84, + 0x10F49: 84, + 0x10F4A: 84, + 0x10F4B: 84, + 0x10F4C: 84, + 0x10F4D: 84, + 0x10F4E: 84, + 0x10F4F: 84, + 0x10F50: 84, + 0x10F51: 68, + 0x10F52: 68, + 0x10F53: 68, + 0x10F54: 82, + 0x10F70: 68, + 0x10F71: 68, + 0x10F72: 68, + 0x10F73: 68, + 0x10F74: 82, + 0x10F75: 82, + 0x10F76: 68, + 0x10F77: 68, + 0x10F78: 68, + 0x10F79: 68, + 0x10F7A: 68, + 0x10F7B: 68, + 0x10F7C: 68, + 0x10F7D: 68, + 0x10F7E: 68, + 0x10F7F: 68, + 0x10F80: 68, + 0x10F81: 68, + 0x10F82: 84, + 0x10F83: 84, + 0x10F84: 84, + 0x10F85: 84, + 0x10FB0: 68, + 0x10FB2: 68, + 0x10FB3: 68, + 0x10FB4: 82, + 0x10FB5: 82, + 0x10FB6: 82, + 0x10FB8: 68, + 0x10FB9: 82, + 0x10FBA: 82, + 0x10FBB: 68, + 0x10FBC: 68, + 0x10FBD: 82, + 0x10FBE: 68, + 0x10FBF: 68, + 0x10FC1: 68, + 0x10FC2: 82, + 0x10FC3: 82, + 0x10FC4: 68, + 0x10FC9: 82, + 0x10FCA: 68, + 0x10FCB: 76, + 0x11001: 84, + 0x11038: 84, + 0x11039: 84, + 0x1103A: 84, + 0x1103B: 84, + 0x1103C: 84, + 0x1103D: 84, + 0x1103E: 84, + 0x1103F: 84, + 0x11040: 84, + 0x11041: 84, + 0x11042: 84, + 0x11043: 84, + 0x11044: 84, + 0x11045: 84, + 0x11046: 84, + 0x11070: 84, + 0x11073: 84, + 0x11074: 84, + 0x1107F: 84, + 0x11080: 84, + 0x11081: 84, + 0x110B3: 84, + 0x110B4: 84, + 0x110B5: 84, + 0x110B6: 84, + 0x110B9: 84, + 0x110BA: 84, + 0x110C2: 84, + 0x11100: 84, + 0x11101: 84, + 0x11102: 84, + 0x11127: 84, + 0x11128: 84, + 0x11129: 84, + 0x1112A: 84, + 0x1112B: 84, + 0x1112D: 84, + 0x1112E: 84, + 0x1112F: 84, + 0x11130: 84, + 0x11131: 84, + 0x11132: 84, + 0x11133: 84, + 0x11134: 84, + 0x11173: 84, + 0x11180: 84, + 0x11181: 84, + 0x111B6: 84, + 0x111B7: 84, + 0x111B8: 84, + 0x111B9: 84, + 0x111BA: 84, + 0x111BB: 84, + 0x111BC: 84, + 0x111BD: 84, + 0x111BE: 84, + 0x111C9: 84, + 0x111CA: 84, + 0x111CB: 84, + 0x111CC: 84, + 0x111CF: 84, + 0x1122F: 84, + 0x11230: 84, + 0x11231: 84, + 0x11234: 84, + 0x11236: 84, + 0x11237: 84, + 0x1123E: 84, + 0x11241: 84, + 0x112DF: 84, + 0x112E3: 84, + 0x112E4: 84, + 0x112E5: 84, + 0x112E6: 84, + 0x112E7: 84, + 0x112E8: 84, + 0x112E9: 84, + 0x112EA: 84, + 0x11300: 84, + 0x11301: 84, + 0x1133B: 84, + 0x1133C: 84, + 0x11340: 84, + 0x11366: 84, + 0x11367: 84, + 0x11368: 84, + 0x11369: 84, + 0x1136A: 84, + 0x1136B: 84, + 0x1136C: 84, + 0x11370: 84, + 0x11371: 84, + 0x11372: 84, + 0x11373: 84, + 0x11374: 84, + 0x113BB: 84, + 0x113BC: 84, + 0x113BD: 84, + 0x113BE: 84, + 0x113BF: 84, + 0x113C0: 84, + 0x113CE: 84, + 0x113D0: 84, + 0x113D2: 84, + 0x113E1: 84, + 0x113E2: 84, + 0x11438: 84, + 0x11439: 84, + 0x1143A: 84, + 0x1143B: 84, + 0x1143C: 84, + 0x1143D: 84, + 0x1143E: 84, + 0x1143F: 84, + 0x11442: 84, + 0x11443: 84, + 0x11444: 84, + 0x11446: 84, + 0x1145E: 84, + 0x114B3: 84, + 0x114B4: 84, + 0x114B5: 84, + 0x114B6: 84, + 0x114B7: 84, + 0x114B8: 84, + 0x114BA: 84, + 0x114BF: 84, + 0x114C0: 84, + 0x114C2: 84, + 0x114C3: 84, + 0x115B2: 84, + 0x115B3: 84, + 0x115B4: 84, + 0x115B5: 84, + 0x115BC: 84, + 0x115BD: 84, + 0x115BF: 84, + 0x115C0: 84, + 0x115DC: 84, + 0x115DD: 84, + 0x11633: 84, + 0x11634: 84, + 0x11635: 84, + 0x11636: 84, + 0x11637: 84, + 0x11638: 84, + 0x11639: 84, + 0x1163A: 84, + 0x1163D: 84, + 0x1163F: 84, + 0x11640: 84, + 0x116AB: 84, + 0x116AD: 84, + 0x116B0: 84, + 0x116B1: 84, + 0x116B2: 84, + 0x116B3: 84, + 0x116B4: 84, + 0x116B5: 84, + 0x116B7: 84, + 0x1171D: 84, + 0x1171F: 84, + 0x11722: 84, + 0x11723: 84, + 0x11724: 84, + 0x11725: 84, + 0x11727: 84, + 0x11728: 84, + 0x11729: 84, + 0x1172A: 84, + 0x1172B: 84, + 0x1182F: 84, + 0x11830: 84, + 0x11831: 84, + 0x11832: 84, + 0x11833: 84, + 0x11834: 84, + 0x11835: 84, + 0x11836: 84, + 0x11837: 84, + 0x11839: 84, + 0x1183A: 84, + 0x1193B: 84, + 0x1193C: 84, + 0x1193E: 84, + 0x11943: 84, + 0x119D4: 84, + 0x119D5: 84, + 0x119D6: 84, + 0x119D7: 84, + 0x119DA: 84, + 0x119DB: 84, + 0x119E0: 84, + 0x11A01: 84, + 0x11A02: 84, + 0x11A03: 84, + 0x11A04: 84, + 0x11A05: 84, + 0x11A06: 84, + 0x11A07: 84, + 0x11A08: 84, + 0x11A09: 84, + 0x11A0A: 84, + 0x11A33: 84, + 0x11A34: 84, + 0x11A35: 84, + 0x11A36: 84, + 0x11A37: 84, + 0x11A38: 84, + 0x11A3B: 84, + 0x11A3C: 84, + 0x11A3D: 84, + 0x11A3E: 84, + 0x11A47: 84, + 0x11A51: 84, + 0x11A52: 84, + 0x11A53: 84, + 0x11A54: 84, + 0x11A55: 84, + 0x11A56: 84, + 0x11A59: 84, + 0x11A5A: 84, + 0x11A5B: 84, + 0x11A8A: 84, + 0x11A8B: 84, + 0x11A8C: 84, + 0x11A8D: 84, + 0x11A8E: 84, + 0x11A8F: 84, + 0x11A90: 84, + 0x11A91: 84, + 0x11A92: 84, + 0x11A93: 84, + 0x11A94: 84, + 0x11A95: 84, + 0x11A96: 84, + 0x11A98: 84, + 0x11A99: 84, + 0x11C30: 84, + 0x11C31: 84, + 0x11C32: 84, + 0x11C33: 84, + 0x11C34: 84, + 0x11C35: 84, + 0x11C36: 84, + 0x11C38: 84, + 0x11C39: 84, + 0x11C3A: 84, + 0x11C3B: 84, + 0x11C3C: 84, + 0x11C3D: 84, + 0x11C3F: 84, + 0x11C92: 84, + 0x11C93: 84, + 0x11C94: 84, + 0x11C95: 84, + 0x11C96: 84, + 0x11C97: 84, + 0x11C98: 84, + 0x11C99: 84, + 0x11C9A: 84, + 0x11C9B: 84, + 0x11C9C: 84, + 0x11C9D: 84, + 0x11C9E: 84, + 0x11C9F: 84, + 0x11CA0: 84, + 0x11CA1: 84, + 0x11CA2: 84, + 0x11CA3: 84, + 0x11CA4: 84, + 0x11CA5: 84, + 0x11CA6: 84, + 0x11CA7: 84, + 0x11CAA: 84, + 0x11CAB: 84, + 0x11CAC: 84, + 0x11CAD: 84, + 0x11CAE: 84, + 0x11CAF: 84, + 0x11CB0: 84, + 0x11CB2: 84, + 0x11CB3: 84, + 0x11CB5: 84, + 0x11CB6: 84, + 0x11D31: 84, + 0x11D32: 84, + 0x11D33: 84, + 0x11D34: 84, + 0x11D35: 84, + 0x11D36: 84, + 0x11D3A: 84, + 0x11D3C: 84, + 0x11D3D: 84, + 0x11D3F: 84, + 0x11D40: 84, + 0x11D41: 84, + 0x11D42: 84, + 0x11D43: 84, + 0x11D44: 84, + 0x11D45: 84, + 0x11D47: 84, + 0x11D90: 84, + 0x11D91: 84, + 0x11D95: 84, + 0x11D97: 84, + 0x11EF3: 84, + 0x11EF4: 84, + 0x11F00: 84, + 0x11F01: 84, + 0x11F36: 84, + 0x11F37: 84, + 0x11F38: 84, + 0x11F39: 84, + 0x11F3A: 84, + 0x11F40: 84, + 0x11F42: 84, + 0x11F5A: 84, + 0x13430: 84, + 0x13431: 84, + 0x13432: 84, + 0x13433: 84, + 0x13434: 84, + 0x13435: 84, + 0x13436: 84, + 0x13437: 84, + 0x13438: 84, + 0x13439: 84, + 0x1343A: 84, + 0x1343B: 84, + 0x1343C: 84, + 0x1343D: 84, + 0x1343E: 84, + 0x1343F: 84, + 0x13440: 84, + 0x13447: 84, + 0x13448: 84, + 0x13449: 84, + 0x1344A: 84, + 0x1344B: 84, + 0x1344C: 84, + 0x1344D: 84, + 0x1344E: 84, + 0x1344F: 84, + 0x13450: 84, + 0x13451: 84, + 0x13452: 84, + 0x13453: 84, + 0x13454: 84, + 0x13455: 84, + 0x1611E: 84, + 0x1611F: 84, + 0x16120: 84, + 0x16121: 84, + 0x16122: 84, + 0x16123: 84, + 0x16124: 84, + 0x16125: 84, + 0x16126: 84, + 0x16127: 84, + 0x16128: 84, + 0x16129: 84, + 0x1612D: 84, + 0x1612E: 84, + 0x1612F: 84, + 0x16AF0: 84, + 0x16AF1: 84, + 0x16AF2: 84, + 0x16AF3: 84, + 0x16AF4: 84, + 0x16B30: 84, + 0x16B31: 84, + 0x16B32: 84, + 0x16B33: 84, + 0x16B34: 84, + 0x16B35: 84, + 0x16B36: 84, + 0x16F4F: 84, + 0x16F8F: 84, + 0x16F90: 84, + 0x16F91: 84, + 0x16F92: 84, + 0x16FE4: 84, + 0x1BC9D: 84, + 0x1BC9E: 84, + 0x1BCA0: 84, + 0x1BCA1: 84, + 0x1BCA2: 84, + 0x1BCA3: 84, + 0x1CF00: 84, + 0x1CF01: 84, + 0x1CF02: 84, + 0x1CF03: 84, + 0x1CF04: 84, + 0x1CF05: 84, + 0x1CF06: 84, + 0x1CF07: 84, + 0x1CF08: 84, + 0x1CF09: 84, + 0x1CF0A: 84, + 0x1CF0B: 84, + 0x1CF0C: 84, + 0x1CF0D: 84, + 0x1CF0E: 84, + 0x1CF0F: 84, + 0x1CF10: 84, + 0x1CF11: 84, + 0x1CF12: 84, + 0x1CF13: 84, + 0x1CF14: 84, + 0x1CF15: 84, + 0x1CF16: 84, + 0x1CF17: 84, + 0x1CF18: 84, + 0x1CF19: 84, + 0x1CF1A: 84, + 0x1CF1B: 84, + 0x1CF1C: 84, + 0x1CF1D: 84, + 0x1CF1E: 84, + 0x1CF1F: 84, + 0x1CF20: 84, + 0x1CF21: 84, + 0x1CF22: 84, + 0x1CF23: 84, + 0x1CF24: 84, + 0x1CF25: 84, + 0x1CF26: 84, + 0x1CF27: 84, + 0x1CF28: 84, + 0x1CF29: 84, + 0x1CF2A: 84, + 0x1CF2B: 84, + 0x1CF2C: 84, + 0x1CF2D: 84, + 0x1CF30: 84, + 0x1CF31: 84, + 0x1CF32: 84, + 0x1CF33: 84, + 0x1CF34: 84, + 0x1CF35: 84, + 0x1CF36: 84, + 0x1CF37: 84, + 0x1CF38: 84, + 0x1CF39: 84, + 0x1CF3A: 84, + 0x1CF3B: 84, + 0x1CF3C: 84, + 0x1CF3D: 84, + 0x1CF3E: 84, + 0x1CF3F: 84, + 0x1CF40: 84, + 0x1CF41: 84, + 0x1CF42: 84, + 0x1CF43: 84, + 0x1CF44: 84, + 0x1CF45: 84, + 0x1CF46: 84, + 0x1D167: 84, + 0x1D168: 84, + 0x1D169: 84, + 0x1D173: 84, + 0x1D174: 84, + 0x1D175: 84, + 0x1D176: 84, + 0x1D177: 84, + 0x1D178: 84, + 0x1D179: 84, + 0x1D17A: 84, + 0x1D17B: 84, + 0x1D17C: 84, + 0x1D17D: 84, + 0x1D17E: 84, + 0x1D17F: 84, + 0x1D180: 84, + 0x1D181: 84, + 0x1D182: 84, + 0x1D185: 84, + 0x1D186: 84, + 0x1D187: 84, + 0x1D188: 84, + 0x1D189: 84, + 0x1D18A: 84, + 0x1D18B: 84, + 0x1D1AA: 84, + 0x1D1AB: 84, + 0x1D1AC: 84, + 0x1D1AD: 84, + 0x1D242: 84, + 0x1D243: 84, + 0x1D244: 84, + 0x1DA00: 84, + 0x1DA01: 84, + 0x1DA02: 84, + 0x1DA03: 84, + 0x1DA04: 84, + 0x1DA05: 84, + 0x1DA06: 84, + 0x1DA07: 84, + 0x1DA08: 84, + 0x1DA09: 84, + 0x1DA0A: 84, + 0x1DA0B: 84, + 0x1DA0C: 84, + 0x1DA0D: 84, + 0x1DA0E: 84, + 0x1DA0F: 84, + 0x1DA10: 84, + 0x1DA11: 84, + 0x1DA12: 84, + 0x1DA13: 84, + 0x1DA14: 84, + 0x1DA15: 84, + 0x1DA16: 84, + 0x1DA17: 84, + 0x1DA18: 84, + 0x1DA19: 84, + 0x1DA1A: 84, + 0x1DA1B: 84, + 0x1DA1C: 84, + 0x1DA1D: 84, + 0x1DA1E: 84, + 0x1DA1F: 84, + 0x1DA20: 84, + 0x1DA21: 84, + 0x1DA22: 84, + 0x1DA23: 84, + 0x1DA24: 84, + 0x1DA25: 84, + 0x1DA26: 84, + 0x1DA27: 84, + 0x1DA28: 84, + 0x1DA29: 84, + 0x1DA2A: 84, + 0x1DA2B: 84, + 0x1DA2C: 84, + 0x1DA2D: 84, + 0x1DA2E: 84, + 0x1DA2F: 84, + 0x1DA30: 84, + 0x1DA31: 84, + 0x1DA32: 84, + 0x1DA33: 84, + 0x1DA34: 84, + 0x1DA35: 84, + 0x1DA36: 84, + 0x1DA3B: 84, + 0x1DA3C: 84, + 0x1DA3D: 84, + 0x1DA3E: 84, + 0x1DA3F: 84, + 0x1DA40: 84, + 0x1DA41: 84, + 0x1DA42: 84, + 0x1DA43: 84, + 0x1DA44: 84, + 0x1DA45: 84, + 0x1DA46: 84, + 0x1DA47: 84, + 0x1DA48: 84, + 0x1DA49: 84, + 0x1DA4A: 84, + 0x1DA4B: 84, + 0x1DA4C: 84, + 0x1DA4D: 84, + 0x1DA4E: 84, + 0x1DA4F: 84, + 0x1DA50: 84, + 0x1DA51: 84, + 0x1DA52: 84, + 0x1DA53: 84, + 0x1DA54: 84, + 0x1DA55: 84, + 0x1DA56: 84, + 0x1DA57: 84, + 0x1DA58: 84, + 0x1DA59: 84, + 0x1DA5A: 84, + 0x1DA5B: 84, + 0x1DA5C: 84, + 0x1DA5D: 84, + 0x1DA5E: 84, + 0x1DA5F: 84, + 0x1DA60: 84, + 0x1DA61: 84, + 0x1DA62: 84, + 0x1DA63: 84, + 0x1DA64: 84, + 0x1DA65: 84, + 0x1DA66: 84, + 0x1DA67: 84, + 0x1DA68: 84, + 0x1DA69: 84, + 0x1DA6A: 84, + 0x1DA6B: 84, + 0x1DA6C: 84, + 0x1DA75: 84, + 0x1DA84: 84, + 0x1DA9B: 84, + 0x1DA9C: 84, + 0x1DA9D: 84, + 0x1DA9E: 84, + 0x1DA9F: 84, + 0x1DAA1: 84, + 0x1DAA2: 84, + 0x1DAA3: 84, + 0x1DAA4: 84, + 0x1DAA5: 84, + 0x1DAA6: 84, + 0x1DAA7: 84, + 0x1DAA8: 84, + 0x1DAA9: 84, + 0x1DAAA: 84, + 0x1DAAB: 84, + 0x1DAAC: 84, + 0x1DAAD: 84, + 0x1DAAE: 84, + 0x1DAAF: 84, + 0x1E000: 84, + 0x1E001: 84, + 0x1E002: 84, + 0x1E003: 84, + 0x1E004: 84, + 0x1E005: 84, + 0x1E006: 84, + 0x1E008: 84, + 0x1E009: 84, + 0x1E00A: 84, + 0x1E00B: 84, + 0x1E00C: 84, + 0x1E00D: 84, + 0x1E00E: 84, + 0x1E00F: 84, + 0x1E010: 84, + 0x1E011: 84, + 0x1E012: 84, + 0x1E013: 84, + 0x1E014: 84, + 0x1E015: 84, + 0x1E016: 84, + 0x1E017: 84, + 0x1E018: 84, + 0x1E01B: 84, + 0x1E01C: 84, + 0x1E01D: 84, + 0x1E01E: 84, + 0x1E01F: 84, + 0x1E020: 84, + 0x1E021: 84, + 0x1E023: 84, + 0x1E024: 84, + 0x1E026: 84, + 0x1E027: 84, + 0x1E028: 84, + 0x1E029: 84, + 0x1E02A: 84, + 0x1E08F: 84, + 0x1E130: 84, + 0x1E131: 84, + 0x1E132: 84, + 0x1E133: 84, + 0x1E134: 84, + 0x1E135: 84, + 0x1E136: 84, + 0x1E2AE: 84, + 0x1E2EC: 84, + 0x1E2ED: 84, + 0x1E2EE: 84, + 0x1E2EF: 84, + 0x1E4EC: 84, + 0x1E4ED: 84, + 0x1E4EE: 84, + 0x1E4EF: 84, + 0x1E5EE: 84, + 0x1E5EF: 84, + 0x1E8D0: 84, + 0x1E8D1: 84, + 0x1E8D2: 84, + 0x1E8D3: 84, + 0x1E8D4: 84, + 0x1E8D5: 84, + 0x1E8D6: 84, + 0x1E900: 68, + 0x1E901: 68, + 0x1E902: 68, + 0x1E903: 68, + 0x1E904: 68, + 0x1E905: 68, + 0x1E906: 68, + 0x1E907: 68, + 0x1E908: 68, + 0x1E909: 68, + 0x1E90A: 68, + 0x1E90B: 68, + 0x1E90C: 68, + 0x1E90D: 68, + 0x1E90E: 68, + 0x1E90F: 68, + 0x1E910: 68, + 0x1E911: 68, + 0x1E912: 68, + 0x1E913: 68, + 0x1E914: 68, + 0x1E915: 68, + 0x1E916: 68, + 0x1E917: 68, + 0x1E918: 68, + 0x1E919: 68, + 0x1E91A: 68, + 0x1E91B: 68, + 0x1E91C: 68, + 0x1E91D: 68, + 0x1E91E: 68, + 0x1E91F: 68, + 0x1E920: 68, + 0x1E921: 68, + 0x1E922: 68, + 0x1E923: 68, + 0x1E924: 68, + 0x1E925: 68, + 0x1E926: 68, + 0x1E927: 68, + 0x1E928: 68, + 0x1E929: 68, + 0x1E92A: 68, + 0x1E92B: 68, + 0x1E92C: 68, + 0x1E92D: 68, + 0x1E92E: 68, + 0x1E92F: 68, + 0x1E930: 68, + 0x1E931: 68, + 0x1E932: 68, + 0x1E933: 68, + 0x1E934: 68, + 0x1E935: 68, + 0x1E936: 68, + 0x1E937: 68, + 0x1E938: 68, + 0x1E939: 68, + 0x1E93A: 68, + 0x1E93B: 68, + 0x1E93C: 68, + 0x1E93D: 68, + 0x1E93E: 68, + 0x1E93F: 68, + 0x1E940: 68, + 0x1E941: 68, + 0x1E942: 68, + 0x1E943: 68, + 0x1E944: 84, + 0x1E945: 84, + 0x1E946: 84, + 0x1E947: 84, + 0x1E948: 84, + 0x1E949: 84, + 0x1E94A: 84, + 0x1E94B: 84, + 0xE0001: 84, + 0xE0020: 84, + 0xE0021: 84, + 0xE0022: 84, + 0xE0023: 84, + 0xE0024: 84, + 0xE0025: 84, + 0xE0026: 84, + 0xE0027: 84, + 0xE0028: 84, + 0xE0029: 84, + 0xE002A: 84, + 0xE002B: 84, + 0xE002C: 84, + 0xE002D: 84, + 0xE002E: 84, + 0xE002F: 84, + 0xE0030: 84, + 0xE0031: 84, + 0xE0032: 84, + 0xE0033: 84, + 0xE0034: 84, + 0xE0035: 84, + 0xE0036: 84, + 0xE0037: 84, + 0xE0038: 84, + 0xE0039: 84, + 0xE003A: 84, + 0xE003B: 84, + 0xE003C: 84, + 0xE003D: 84, + 0xE003E: 84, + 0xE003F: 84, + 0xE0040: 84, + 0xE0041: 84, + 0xE0042: 84, + 0xE0043: 84, + 0xE0044: 84, + 0xE0045: 84, + 0xE0046: 84, + 0xE0047: 84, + 0xE0048: 84, + 0xE0049: 84, + 0xE004A: 84, + 0xE004B: 84, + 0xE004C: 84, + 0xE004D: 84, + 0xE004E: 84, + 0xE004F: 84, + 0xE0050: 84, + 0xE0051: 84, + 0xE0052: 84, + 0xE0053: 84, + 0xE0054: 84, + 0xE0055: 84, + 0xE0056: 84, + 0xE0057: 84, + 0xE0058: 84, + 0xE0059: 84, + 0xE005A: 84, + 0xE005B: 84, + 0xE005C: 84, + 0xE005D: 84, + 0xE005E: 84, + 0xE005F: 84, + 0xE0060: 84, + 0xE0061: 84, + 0xE0062: 84, + 0xE0063: 84, + 0xE0064: 84, + 0xE0065: 84, + 0xE0066: 84, + 0xE0067: 84, + 0xE0068: 84, + 0xE0069: 84, + 0xE006A: 84, + 0xE006B: 84, + 0xE006C: 84, + 0xE006D: 84, + 0xE006E: 84, + 0xE006F: 84, + 0xE0070: 84, + 0xE0071: 84, + 0xE0072: 84, + 0xE0073: 84, + 0xE0074: 84, + 0xE0075: 84, + 0xE0076: 84, + 0xE0077: 84, + 0xE0078: 84, + 0xE0079: 84, + 0xE007A: 84, + 0xE007B: 84, + 0xE007C: 84, + 0xE007D: 84, + 0xE007E: 84, + 0xE007F: 84, + 0xE0100: 84, + 0xE0101: 84, + 0xE0102: 84, + 0xE0103: 84, + 0xE0104: 84, + 0xE0105: 84, + 0xE0106: 84, + 0xE0107: 84, + 0xE0108: 84, + 0xE0109: 84, + 0xE010A: 84, + 0xE010B: 84, + 0xE010C: 84, + 0xE010D: 84, + 0xE010E: 84, + 0xE010F: 84, + 0xE0110: 84, + 0xE0111: 84, + 0xE0112: 84, + 0xE0113: 84, + 0xE0114: 84, + 0xE0115: 84, + 0xE0116: 84, + 0xE0117: 84, + 0xE0118: 84, + 0xE0119: 84, + 0xE011A: 84, + 0xE011B: 84, + 0xE011C: 84, + 0xE011D: 84, + 0xE011E: 84, + 0xE011F: 84, + 0xE0120: 84, + 0xE0121: 84, + 0xE0122: 84, + 0xE0123: 84, + 0xE0124: 84, + 0xE0125: 84, + 0xE0126: 84, + 0xE0127: 84, + 0xE0128: 84, + 0xE0129: 84, + 0xE012A: 84, + 0xE012B: 84, + 0xE012C: 84, + 0xE012D: 84, + 0xE012E: 84, + 0xE012F: 84, + 0xE0130: 84, + 0xE0131: 84, + 0xE0132: 84, + 0xE0133: 84, + 0xE0134: 84, + 0xE0135: 84, + 0xE0136: 84, + 0xE0137: 84, + 0xE0138: 84, + 0xE0139: 84, + 0xE013A: 84, + 0xE013B: 84, + 0xE013C: 84, + 0xE013D: 84, + 0xE013E: 84, + 0xE013F: 84, + 0xE0140: 84, + 0xE0141: 84, + 0xE0142: 84, + 0xE0143: 84, + 0xE0144: 84, + 0xE0145: 84, + 0xE0146: 84, + 0xE0147: 84, + 0xE0148: 84, + 0xE0149: 84, + 0xE014A: 84, + 0xE014B: 84, + 0xE014C: 84, + 0xE014D: 84, + 0xE014E: 84, + 0xE014F: 84, + 0xE0150: 84, + 0xE0151: 84, + 0xE0152: 84, + 0xE0153: 84, + 0xE0154: 84, + 0xE0155: 84, + 0xE0156: 84, + 0xE0157: 84, + 0xE0158: 84, + 0xE0159: 84, + 0xE015A: 84, + 0xE015B: 84, + 0xE015C: 84, + 0xE015D: 84, + 0xE015E: 84, + 0xE015F: 84, + 0xE0160: 84, + 0xE0161: 84, + 0xE0162: 84, + 0xE0163: 84, + 0xE0164: 84, + 0xE0165: 84, + 0xE0166: 84, + 0xE0167: 84, + 0xE0168: 84, + 0xE0169: 84, + 0xE016A: 84, + 0xE016B: 84, + 0xE016C: 84, + 0xE016D: 84, + 0xE016E: 84, + 0xE016F: 84, + 0xE0170: 84, + 0xE0171: 84, + 0xE0172: 84, + 0xE0173: 84, + 0xE0174: 84, + 0xE0175: 84, + 0xE0176: 84, + 0xE0177: 84, + 0xE0178: 84, + 0xE0179: 84, + 0xE017A: 84, + 0xE017B: 84, + 0xE017C: 84, + 0xE017D: 84, + 0xE017E: 84, + 0xE017F: 84, + 0xE0180: 84, + 0xE0181: 84, + 0xE0182: 84, + 0xE0183: 84, + 0xE0184: 84, + 0xE0185: 84, + 0xE0186: 84, + 0xE0187: 84, + 0xE0188: 84, + 0xE0189: 84, + 0xE018A: 84, + 0xE018B: 84, + 0xE018C: 84, + 0xE018D: 84, + 0xE018E: 84, + 0xE018F: 84, + 0xE0190: 84, + 0xE0191: 84, + 0xE0192: 84, + 0xE0193: 84, + 0xE0194: 84, + 0xE0195: 84, + 0xE0196: 84, + 0xE0197: 84, + 0xE0198: 84, + 0xE0199: 84, + 0xE019A: 84, + 0xE019B: 84, + 0xE019C: 84, + 0xE019D: 84, + 0xE019E: 84, + 0xE019F: 84, + 0xE01A0: 84, + 0xE01A1: 84, + 0xE01A2: 84, + 0xE01A3: 84, + 0xE01A4: 84, + 0xE01A5: 84, + 0xE01A6: 84, + 0xE01A7: 84, + 0xE01A8: 84, + 0xE01A9: 84, + 0xE01AA: 84, + 0xE01AB: 84, + 0xE01AC: 84, + 0xE01AD: 84, + 0xE01AE: 84, + 0xE01AF: 84, + 0xE01B0: 84, + 0xE01B1: 84, + 0xE01B2: 84, + 0xE01B3: 84, + 0xE01B4: 84, + 0xE01B5: 84, + 0xE01B6: 84, + 0xE01B7: 84, + 0xE01B8: 84, + 0xE01B9: 84, + 0xE01BA: 84, + 0xE01BB: 84, + 0xE01BC: 84, + 0xE01BD: 84, + 0xE01BE: 84, + 0xE01BF: 84, + 0xE01C0: 84, + 0xE01C1: 84, + 0xE01C2: 84, + 0xE01C3: 84, + 0xE01C4: 84, + 0xE01C5: 84, + 0xE01C6: 84, + 0xE01C7: 84, + 0xE01C8: 84, + 0xE01C9: 84, + 0xE01CA: 84, + 0xE01CB: 84, + 0xE01CC: 84, + 0xE01CD: 84, + 0xE01CE: 84, + 0xE01CF: 84, + 0xE01D0: 84, + 0xE01D1: 84, + 0xE01D2: 84, + 0xE01D3: 84, + 0xE01D4: 84, + 0xE01D5: 84, + 0xE01D6: 84, + 0xE01D7: 84, + 0xE01D8: 84, + 0xE01D9: 84, + 0xE01DA: 84, + 0xE01DB: 84, + 0xE01DC: 84, + 0xE01DD: 84, + 0xE01DE: 84, + 0xE01DF: 84, + 0xE01E0: 84, + 0xE01E1: 84, + 0xE01E2: 84, + 0xE01E3: 84, + 0xE01E4: 84, + 0xE01E5: 84, + 0xE01E6: 84, + 0xE01E7: 84, + 0xE01E8: 84, + 0xE01E9: 84, + 0xE01EA: 84, + 0xE01EB: 84, + 0xE01EC: 84, + 0xE01ED: 84, + 0xE01EE: 84, + 0xE01EF: 84, +} +codepoint_classes = { + "PVALID": ( + 0x2D0000002E, + 0x300000003A, + 0x610000007B, + 0xDF000000F7, + 0xF800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010A, + 0x10B0000010C, + 0x10D0000010E, + 0x10F00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011A, + 0x11B0000011C, + 0x11D0000011E, + 0x11F00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012A, + 0x12B0000012C, + 0x12D0000012E, + 0x12F00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13A0000013B, + 0x13C0000013D, + 0x13E0000013F, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14B0000014C, + 0x14D0000014E, + 0x14F00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015A, + 0x15B0000015C, + 0x15D0000015E, + 0x15F00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016A, + 0x16B0000016C, + 0x16D0000016E, + 0x16F00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17A0000017B, + 0x17C0000017D, + 0x17E0000017F, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18C0000018E, + 0x19200000193, + 0x19500000196, + 0x1990000019C, + 0x19E0000019F, + 0x1A1000001A2, + 0x1A3000001A4, + 0x1A5000001A6, + 0x1A8000001A9, + 0x1AA000001AC, + 0x1AD000001AE, + 0x1B0000001B1, + 0x1B4000001B5, + 0x1B6000001B7, + 0x1B9000001BC, + 0x1BD000001C4, + 0x1CE000001CF, + 0x1D0000001D1, + 0x1D2000001D3, + 0x1D4000001D5, + 0x1D6000001D7, + 0x1D8000001D9, + 0x1DA000001DB, + 0x1DC000001DE, + 0x1DF000001E0, + 0x1E1000001E2, + 0x1E3000001E4, + 0x1E5000001E6, + 0x1E7000001E8, + 0x1E9000001EA, + 0x1EB000001EC, + 0x1ED000001EE, + 0x1EF000001F1, + 0x1F5000001F6, + 0x1F9000001FA, + 0x1FB000001FC, + 0x1FD000001FE, + 0x1FF00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020A, + 0x20B0000020C, + 0x20D0000020E, + 0x20F00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021A, + 0x21B0000021C, + 0x21D0000021E, + 0x21F00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022A, + 0x22B0000022C, + 0x22D0000022E, + 0x22F00000230, + 0x23100000232, + 0x2330000023A, + 0x23C0000023D, + 0x23F00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024A, + 0x24B0000024C, + 0x24D0000024E, + 0x24F000002B0, + 0x2B9000002C2, + 0x2C6000002D2, + 0x2EC000002ED, + 0x2EE000002EF, + 0x30000000340, + 0x34200000343, + 0x3460000034F, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37B0000037E, + 0x39000000391, + 0x3AC000003CF, + 0x3D7000003D8, + 0x3D9000003DA, + 0x3DB000003DC, + 0x3DD000003DE, + 0x3DF000003E0, + 0x3E1000003E2, + 0x3E3000003E4, + 0x3E5000003E6, + 0x3E7000003E8, + 0x3E9000003EA, + 0x3EB000003EC, + 0x3ED000003EE, + 0x3EF000003F0, + 0x3F3000003F4, + 0x3F8000003F9, + 0x3FB000003FD, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046A, + 0x46B0000046C, + 0x46D0000046E, + 0x46F00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047A, + 0x47B0000047C, + 0x47D0000047E, + 0x47F00000480, + 0x48100000482, + 0x48300000488, + 0x48B0000048C, + 0x48D0000048E, + 0x48F00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049A, + 0x49B0000049C, + 0x49D0000049E, + 0x49F000004A0, + 0x4A1000004A2, + 0x4A3000004A4, + 0x4A5000004A6, + 0x4A7000004A8, + 0x4A9000004AA, + 0x4AB000004AC, + 0x4AD000004AE, + 0x4AF000004B0, + 0x4B1000004B2, + 0x4B3000004B4, + 0x4B5000004B6, + 0x4B7000004B8, + 0x4B9000004BA, + 0x4BB000004BC, + 0x4BD000004BE, + 0x4BF000004C0, + 0x4C2000004C3, + 0x4C4000004C5, + 0x4C6000004C7, + 0x4C8000004C9, + 0x4CA000004CB, + 0x4CC000004CD, + 0x4CE000004D0, + 0x4D1000004D2, + 0x4D3000004D4, + 0x4D5000004D6, + 0x4D7000004D8, + 0x4D9000004DA, + 0x4DB000004DC, + 0x4DD000004DE, + 0x4DF000004E0, + 0x4E1000004E2, + 0x4E3000004E4, + 0x4E5000004E6, + 0x4E7000004E8, + 0x4E9000004EA, + 0x4EB000004EC, + 0x4ED000004EE, + 0x4EF000004F0, + 0x4F1000004F2, + 0x4F3000004F4, + 0x4F5000004F6, + 0x4F7000004F8, + 0x4F9000004FA, + 0x4FB000004FC, + 0x4FD000004FE, + 0x4FF00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050A, + 0x50B0000050C, + 0x50D0000050E, + 0x50F00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051A, + 0x51B0000051C, + 0x51D0000051E, + 0x51F00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052A, + 0x52B0000052C, + 0x52D0000052E, + 0x52F00000530, + 0x5590000055A, + 0x56000000587, + 0x58800000589, + 0x591000005BE, + 0x5BF000005C0, + 0x5C1000005C3, + 0x5C4000005C6, + 0x5C7000005C8, + 0x5D0000005EB, + 0x5EF000005F3, + 0x6100000061B, + 0x62000000640, + 0x64100000660, + 0x66E00000675, + 0x679000006D4, + 0x6D5000006DD, + 0x6DF000006E9, + 0x6EA000006F0, + 0x6FA00000700, + 0x7100000074B, + 0x74D000007B2, + 0x7C0000007F6, + 0x7FD000007FE, + 0x8000000082E, + 0x8400000085C, + 0x8600000086B, + 0x87000000888, + 0x8890000088F, + 0x897000008E2, + 0x8E300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098D, + 0x98F00000991, + 0x993000009A9, + 0x9AA000009B1, + 0x9B2000009B3, + 0x9B6000009BA, + 0x9BC000009C5, + 0x9C7000009C9, + 0x9CB000009CF, + 0x9D7000009D8, + 0x9E0000009E4, + 0x9E6000009F2, + 0x9FC000009FD, + 0x9FE000009FF, + 0xA0100000A04, + 0xA0500000A0B, + 0xA0F00000A11, + 0xA1300000A29, + 0xA2A00000A31, + 0xA3200000A33, + 0xA3500000A36, + 0xA3800000A3A, + 0xA3C00000A3D, + 0xA3E00000A43, + 0xA4700000A49, + 0xA4B00000A4E, + 0xA5100000A52, + 0xA5C00000A5D, + 0xA6600000A76, + 0xA8100000A84, + 0xA8500000A8E, + 0xA8F00000A92, + 0xA9300000AA9, + 0xAAA00000AB1, + 0xAB200000AB4, + 0xAB500000ABA, + 0xABC00000AC6, + 0xAC700000ACA, + 0xACB00000ACE, + 0xAD000000AD1, + 0xAE000000AE4, + 0xAE600000AF0, + 0xAF900000B00, + 0xB0100000B04, + 0xB0500000B0D, + 0xB0F00000B11, + 0xB1300000B29, + 0xB2A00000B31, + 0xB3200000B34, + 0xB3500000B3A, + 0xB3C00000B45, + 0xB4700000B49, + 0xB4B00000B4E, + 0xB5500000B58, + 0xB5F00000B64, + 0xB6600000B70, + 0xB7100000B72, + 0xB8200000B84, + 0xB8500000B8B, + 0xB8E00000B91, + 0xB9200000B96, + 0xB9900000B9B, + 0xB9C00000B9D, + 0xB9E00000BA0, + 0xBA300000BA5, + 0xBA800000BAB, + 0xBAE00000BBA, + 0xBBE00000BC3, + 0xBC600000BC9, + 0xBCA00000BCE, + 0xBD000000BD1, + 0xBD700000BD8, + 0xBE600000BF0, + 0xC0000000C0D, + 0xC0E00000C11, + 0xC1200000C29, + 0xC2A00000C3A, + 0xC3C00000C45, + 0xC4600000C49, + 0xC4A00000C4E, + 0xC5500000C57, + 0xC5800000C5B, + 0xC5D00000C5E, + 0xC6000000C64, + 0xC6600000C70, + 0xC8000000C84, + 0xC8500000C8D, + 0xC8E00000C91, + 0xC9200000CA9, + 0xCAA00000CB4, + 0xCB500000CBA, + 0xCBC00000CC5, + 0xCC600000CC9, + 0xCCA00000CCE, + 0xCD500000CD7, + 0xCDD00000CDF, + 0xCE000000CE4, + 0xCE600000CF0, + 0xCF100000CF4, + 0xD0000000D0D, + 0xD0E00000D11, + 0xD1200000D45, + 0xD4600000D49, + 0xD4A00000D4F, + 0xD5400000D58, + 0xD5F00000D64, + 0xD6600000D70, + 0xD7A00000D80, + 0xD8100000D84, + 0xD8500000D97, + 0xD9A00000DB2, + 0xDB300000DBC, + 0xDBD00000DBE, + 0xDC000000DC7, + 0xDCA00000DCB, + 0xDCF00000DD5, + 0xDD600000DD7, + 0xDD800000DE0, + 0xDE600000DF0, + 0xDF200000DF4, + 0xE0100000E33, + 0xE3400000E3B, + 0xE4000000E4F, + 0xE5000000E5A, + 0xE8100000E83, + 0xE8400000E85, + 0xE8600000E8B, + 0xE8C00000EA4, + 0xEA500000EA6, + 0xEA700000EB3, + 0xEB400000EBE, + 0xEC000000EC5, + 0xEC600000EC7, + 0xEC800000ECF, + 0xED000000EDA, + 0xEDE00000EE0, + 0xF0000000F01, + 0xF0B00000F0C, + 0xF1800000F1A, + 0xF2000000F2A, + 0xF3500000F36, + 0xF3700000F38, + 0xF3900000F3A, + 0xF3E00000F43, + 0xF4400000F48, + 0xF4900000F4D, + 0xF4E00000F52, + 0xF5300000F57, + 0xF5800000F5C, + 0xF5D00000F69, + 0xF6A00000F6D, + 0xF7100000F73, + 0xF7400000F75, + 0xF7A00000F81, + 0xF8200000F85, + 0xF8600000F93, + 0xF9400000F98, + 0xF9900000F9D, + 0xF9E00000FA2, + 0xFA300000FA7, + 0xFA800000FAC, + 0xFAD00000FB9, + 0xFBA00000FBD, + 0xFC600000FC7, + 0x10000000104A, + 0x10500000109E, + 0x10D0000010FB, + 0x10FD00001100, + 0x120000001249, + 0x124A0000124E, + 0x125000001257, + 0x125800001259, + 0x125A0000125E, + 0x126000001289, + 0x128A0000128E, + 0x1290000012B1, + 0x12B2000012B6, + 0x12B8000012BF, + 0x12C0000012C1, + 0x12C2000012C6, + 0x12C8000012D7, + 0x12D800001311, + 0x131200001316, + 0x13180000135B, + 0x135D00001360, + 0x138000001390, + 0x13A0000013F6, + 0x14010000166D, + 0x166F00001680, + 0x16810000169B, + 0x16A0000016EB, + 0x16F1000016F9, + 0x170000001716, + 0x171F00001735, + 0x174000001754, + 0x17600000176D, + 0x176E00001771, + 0x177200001774, + 0x1780000017B4, + 0x17B6000017D4, + 0x17D7000017D8, + 0x17DC000017DE, + 0x17E0000017EA, + 0x18100000181A, + 0x182000001879, + 0x1880000018AB, + 0x18B0000018F6, + 0x19000000191F, + 0x19200000192C, + 0x19300000193C, + 0x19460000196E, + 0x197000001975, + 0x1980000019AC, + 0x19B0000019CA, + 0x19D0000019DA, + 0x1A0000001A1C, + 0x1A2000001A5F, + 0x1A6000001A7D, + 0x1A7F00001A8A, + 0x1A9000001A9A, + 0x1AA700001AA8, + 0x1AB000001ABE, + 0x1ABF00001ACF, + 0x1B0000001B4D, + 0x1B5000001B5A, + 0x1B6B00001B74, + 0x1B8000001BF4, + 0x1C0000001C38, + 0x1C4000001C4A, + 0x1C4D00001C7E, + 0x1C8A00001C8B, + 0x1CD000001CD3, + 0x1CD400001CFB, + 0x1D0000001D2C, + 0x1D2F00001D30, + 0x1D3B00001D3C, + 0x1D4E00001D4F, + 0x1D6B00001D78, + 0x1D7900001D9B, + 0x1DC000001E00, + 0x1E0100001E02, + 0x1E0300001E04, + 0x1E0500001E06, + 0x1E0700001E08, + 0x1E0900001E0A, + 0x1E0B00001E0C, + 0x1E0D00001E0E, + 0x1E0F00001E10, + 0x1E1100001E12, + 0x1E1300001E14, + 0x1E1500001E16, + 0x1E1700001E18, + 0x1E1900001E1A, + 0x1E1B00001E1C, + 0x1E1D00001E1E, + 0x1E1F00001E20, + 0x1E2100001E22, + 0x1E2300001E24, + 0x1E2500001E26, + 0x1E2700001E28, + 0x1E2900001E2A, + 0x1E2B00001E2C, + 0x1E2D00001E2E, + 0x1E2F00001E30, + 0x1E3100001E32, + 0x1E3300001E34, + 0x1E3500001E36, + 0x1E3700001E38, + 0x1E3900001E3A, + 0x1E3B00001E3C, + 0x1E3D00001E3E, + 0x1E3F00001E40, + 0x1E4100001E42, + 0x1E4300001E44, + 0x1E4500001E46, + 0x1E4700001E48, + 0x1E4900001E4A, + 0x1E4B00001E4C, + 0x1E4D00001E4E, + 0x1E4F00001E50, + 0x1E5100001E52, + 0x1E5300001E54, + 0x1E5500001E56, + 0x1E5700001E58, + 0x1E5900001E5A, + 0x1E5B00001E5C, + 0x1E5D00001E5E, + 0x1E5F00001E60, + 0x1E6100001E62, + 0x1E6300001E64, + 0x1E6500001E66, + 0x1E6700001E68, + 0x1E6900001E6A, + 0x1E6B00001E6C, + 0x1E6D00001E6E, + 0x1E6F00001E70, + 0x1E7100001E72, + 0x1E7300001E74, + 0x1E7500001E76, + 0x1E7700001E78, + 0x1E7900001E7A, + 0x1E7B00001E7C, + 0x1E7D00001E7E, + 0x1E7F00001E80, + 0x1E8100001E82, + 0x1E8300001E84, + 0x1E8500001E86, + 0x1E8700001E88, + 0x1E8900001E8A, + 0x1E8B00001E8C, + 0x1E8D00001E8E, + 0x1E8F00001E90, + 0x1E9100001E92, + 0x1E9300001E94, + 0x1E9500001E9A, + 0x1E9C00001E9E, + 0x1E9F00001EA0, + 0x1EA100001EA2, + 0x1EA300001EA4, + 0x1EA500001EA6, + 0x1EA700001EA8, + 0x1EA900001EAA, + 0x1EAB00001EAC, + 0x1EAD00001EAE, + 0x1EAF00001EB0, + 0x1EB100001EB2, + 0x1EB300001EB4, + 0x1EB500001EB6, + 0x1EB700001EB8, + 0x1EB900001EBA, + 0x1EBB00001EBC, + 0x1EBD00001EBE, + 0x1EBF00001EC0, + 0x1EC100001EC2, + 0x1EC300001EC4, + 0x1EC500001EC6, + 0x1EC700001EC8, + 0x1EC900001ECA, + 0x1ECB00001ECC, + 0x1ECD00001ECE, + 0x1ECF00001ED0, + 0x1ED100001ED2, + 0x1ED300001ED4, + 0x1ED500001ED6, + 0x1ED700001ED8, + 0x1ED900001EDA, + 0x1EDB00001EDC, + 0x1EDD00001EDE, + 0x1EDF00001EE0, + 0x1EE100001EE2, + 0x1EE300001EE4, + 0x1EE500001EE6, + 0x1EE700001EE8, + 0x1EE900001EEA, + 0x1EEB00001EEC, + 0x1EED00001EEE, + 0x1EEF00001EF0, + 0x1EF100001EF2, + 0x1EF300001EF4, + 0x1EF500001EF6, + 0x1EF700001EF8, + 0x1EF900001EFA, + 0x1EFB00001EFC, + 0x1EFD00001EFE, + 0x1EFF00001F08, + 0x1F1000001F16, + 0x1F2000001F28, + 0x1F3000001F38, + 0x1F4000001F46, + 0x1F5000001F58, + 0x1F6000001F68, + 0x1F7000001F71, + 0x1F7200001F73, + 0x1F7400001F75, + 0x1F7600001F77, + 0x1F7800001F79, + 0x1F7A00001F7B, + 0x1F7C00001F7D, + 0x1FB000001FB2, + 0x1FB600001FB7, + 0x1FC600001FC7, + 0x1FD000001FD3, + 0x1FD600001FD8, + 0x1FE000001FE3, + 0x1FE400001FE8, + 0x1FF600001FF7, + 0x214E0000214F, + 0x218400002185, + 0x2C3000002C60, + 0x2C6100002C62, + 0x2C6500002C67, + 0x2C6800002C69, + 0x2C6A00002C6B, + 0x2C6C00002C6D, + 0x2C7100002C72, + 0x2C7300002C75, + 0x2C7600002C7C, + 0x2C8100002C82, + 0x2C8300002C84, + 0x2C8500002C86, + 0x2C8700002C88, + 0x2C8900002C8A, + 0x2C8B00002C8C, + 0x2C8D00002C8E, + 0x2C8F00002C90, + 0x2C9100002C92, + 0x2C9300002C94, + 0x2C9500002C96, + 0x2C9700002C98, + 0x2C9900002C9A, + 0x2C9B00002C9C, + 0x2C9D00002C9E, + 0x2C9F00002CA0, + 0x2CA100002CA2, + 0x2CA300002CA4, + 0x2CA500002CA6, + 0x2CA700002CA8, + 0x2CA900002CAA, + 0x2CAB00002CAC, + 0x2CAD00002CAE, + 0x2CAF00002CB0, + 0x2CB100002CB2, + 0x2CB300002CB4, + 0x2CB500002CB6, + 0x2CB700002CB8, + 0x2CB900002CBA, + 0x2CBB00002CBC, + 0x2CBD00002CBE, + 0x2CBF00002CC0, + 0x2CC100002CC2, + 0x2CC300002CC4, + 0x2CC500002CC6, + 0x2CC700002CC8, + 0x2CC900002CCA, + 0x2CCB00002CCC, + 0x2CCD00002CCE, + 0x2CCF00002CD0, + 0x2CD100002CD2, + 0x2CD300002CD4, + 0x2CD500002CD6, + 0x2CD700002CD8, + 0x2CD900002CDA, + 0x2CDB00002CDC, + 0x2CDD00002CDE, + 0x2CDF00002CE0, + 0x2CE100002CE2, + 0x2CE300002CE5, + 0x2CEC00002CED, + 0x2CEE00002CF2, + 0x2CF300002CF4, + 0x2D0000002D26, + 0x2D2700002D28, + 0x2D2D00002D2E, + 0x2D3000002D68, + 0x2D7F00002D97, + 0x2DA000002DA7, + 0x2DA800002DAF, + 0x2DB000002DB7, + 0x2DB800002DBF, + 0x2DC000002DC7, + 0x2DC800002DCF, + 0x2DD000002DD7, + 0x2DD800002DDF, + 0x2DE000002E00, + 0x2E2F00002E30, + 0x300500003008, + 0x302A0000302E, + 0x303C0000303D, + 0x304100003097, + 0x30990000309B, + 0x309D0000309F, + 0x30A1000030FB, + 0x30FC000030FF, + 0x310500003130, + 0x31A0000031C0, + 0x31F000003200, + 0x340000004DC0, + 0x4E000000A48D, + 0xA4D00000A4FE, + 0xA5000000A60D, + 0xA6100000A62C, + 0xA6410000A642, + 0xA6430000A644, + 0xA6450000A646, + 0xA6470000A648, + 0xA6490000A64A, + 0xA64B0000A64C, + 0xA64D0000A64E, + 0xA64F0000A650, + 0xA6510000A652, + 0xA6530000A654, + 0xA6550000A656, + 0xA6570000A658, + 0xA6590000A65A, + 0xA65B0000A65C, + 0xA65D0000A65E, + 0xA65F0000A660, + 0xA6610000A662, + 0xA6630000A664, + 0xA6650000A666, + 0xA6670000A668, + 0xA6690000A66A, + 0xA66B0000A66C, + 0xA66D0000A670, + 0xA6740000A67E, + 0xA67F0000A680, + 0xA6810000A682, + 0xA6830000A684, + 0xA6850000A686, + 0xA6870000A688, + 0xA6890000A68A, + 0xA68B0000A68C, + 0xA68D0000A68E, + 0xA68F0000A690, + 0xA6910000A692, + 0xA6930000A694, + 0xA6950000A696, + 0xA6970000A698, + 0xA6990000A69A, + 0xA69B0000A69C, + 0xA69E0000A6E6, + 0xA6F00000A6F2, + 0xA7170000A720, + 0xA7230000A724, + 0xA7250000A726, + 0xA7270000A728, + 0xA7290000A72A, + 0xA72B0000A72C, + 0xA72D0000A72E, + 0xA72F0000A732, + 0xA7330000A734, + 0xA7350000A736, + 0xA7370000A738, + 0xA7390000A73A, + 0xA73B0000A73C, + 0xA73D0000A73E, + 0xA73F0000A740, + 0xA7410000A742, + 0xA7430000A744, + 0xA7450000A746, + 0xA7470000A748, + 0xA7490000A74A, + 0xA74B0000A74C, + 0xA74D0000A74E, + 0xA74F0000A750, + 0xA7510000A752, + 0xA7530000A754, + 0xA7550000A756, + 0xA7570000A758, + 0xA7590000A75A, + 0xA75B0000A75C, + 0xA75D0000A75E, + 0xA75F0000A760, + 0xA7610000A762, + 0xA7630000A764, + 0xA7650000A766, + 0xA7670000A768, + 0xA7690000A76A, + 0xA76B0000A76C, + 0xA76D0000A76E, + 0xA76F0000A770, + 0xA7710000A779, + 0xA77A0000A77B, + 0xA77C0000A77D, + 0xA77F0000A780, + 0xA7810000A782, + 0xA7830000A784, + 0xA7850000A786, + 0xA7870000A789, + 0xA78C0000A78D, + 0xA78E0000A790, + 0xA7910000A792, + 0xA7930000A796, + 0xA7970000A798, + 0xA7990000A79A, + 0xA79B0000A79C, + 0xA79D0000A79E, + 0xA79F0000A7A0, + 0xA7A10000A7A2, + 0xA7A30000A7A4, + 0xA7A50000A7A6, + 0xA7A70000A7A8, + 0xA7A90000A7AA, + 0xA7AF0000A7B0, + 0xA7B50000A7B6, + 0xA7B70000A7B8, + 0xA7B90000A7BA, + 0xA7BB0000A7BC, + 0xA7BD0000A7BE, + 0xA7BF0000A7C0, + 0xA7C10000A7C2, + 0xA7C30000A7C4, + 0xA7C80000A7C9, + 0xA7CA0000A7CB, + 0xA7CD0000A7CE, + 0xA7D10000A7D2, + 0xA7D30000A7D4, + 0xA7D50000A7D6, + 0xA7D70000A7D8, + 0xA7D90000A7DA, + 0xA7DB0000A7DC, + 0xA7F60000A7F8, + 0xA7FA0000A828, + 0xA82C0000A82D, + 0xA8400000A874, + 0xA8800000A8C6, + 0xA8D00000A8DA, + 0xA8E00000A8F8, + 0xA8FB0000A8FC, + 0xA8FD0000A92E, + 0xA9300000A954, + 0xA9800000A9C1, + 0xA9CF0000A9DA, + 0xA9E00000A9FF, + 0xAA000000AA37, + 0xAA400000AA4E, + 0xAA500000AA5A, + 0xAA600000AA77, + 0xAA7A0000AAC3, + 0xAADB0000AADE, + 0xAAE00000AAF0, + 0xAAF20000AAF7, + 0xAB010000AB07, + 0xAB090000AB0F, + 0xAB110000AB17, + 0xAB200000AB27, + 0xAB280000AB2F, + 0xAB300000AB5B, + 0xAB600000AB69, + 0xABC00000ABEB, + 0xABEC0000ABEE, + 0xABF00000ABFA, + 0xAC000000D7A4, + 0xFA0E0000FA10, + 0xFA110000FA12, + 0xFA130000FA15, + 0xFA1F0000FA20, + 0xFA210000FA22, + 0xFA230000FA25, + 0xFA270000FA2A, + 0xFB1E0000FB1F, + 0xFE200000FE30, + 0xFE730000FE74, + 0x100000001000C, + 0x1000D00010027, + 0x100280001003B, + 0x1003C0001003E, + 0x1003F0001004E, + 0x100500001005E, + 0x10080000100FB, + 0x101FD000101FE, + 0x102800001029D, + 0x102A0000102D1, + 0x102E0000102E1, + 0x1030000010320, + 0x1032D00010341, + 0x103420001034A, + 0x103500001037B, + 0x103800001039E, + 0x103A0000103C4, + 0x103C8000103D0, + 0x104280001049E, + 0x104A0000104AA, + 0x104D8000104FC, + 0x1050000010528, + 0x1053000010564, + 0x10597000105A2, + 0x105A3000105B2, + 0x105B3000105BA, + 0x105BB000105BD, + 0x105C0000105F4, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1078000010781, + 0x1080000010806, + 0x1080800010809, + 0x1080A00010836, + 0x1083700010839, + 0x1083C0001083D, + 0x1083F00010856, + 0x1086000010877, + 0x108800001089F, + 0x108E0000108F3, + 0x108F4000108F6, + 0x1090000010916, + 0x109200001093A, + 0x10980000109B8, + 0x109BE000109C0, + 0x10A0000010A04, + 0x10A0500010A07, + 0x10A0C00010A14, + 0x10A1500010A18, + 0x10A1900010A36, + 0x10A3800010A3B, + 0x10A3F00010A40, + 0x10A6000010A7D, + 0x10A8000010A9D, + 0x10AC000010AC8, + 0x10AC900010AE7, + 0x10B0000010B36, + 0x10B4000010B56, + 0x10B6000010B73, + 0x10B8000010B92, + 0x10C0000010C49, + 0x10CC000010CF3, + 0x10D0000010D28, + 0x10D3000010D3A, + 0x10D4000010D50, + 0x10D6900010D6E, + 0x10D6F00010D86, + 0x10E8000010EAA, + 0x10EAB00010EAD, + 0x10EB000010EB2, + 0x10EC200010EC5, + 0x10EFC00010F1D, + 0x10F2700010F28, + 0x10F3000010F51, + 0x10F7000010F86, + 0x10FB000010FC5, + 0x10FE000010FF7, + 0x1100000011047, + 0x1106600011076, + 0x1107F000110BB, + 0x110C2000110C3, + 0x110D0000110E9, + 0x110F0000110FA, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111C5, + 0x111C9000111CD, + 0x111CE000111DB, + 0x111DC000111DD, + 0x1120000011212, + 0x1121300011238, + 0x1123E00011242, + 0x1128000011287, + 0x1128800011289, + 0x1128A0001128E, + 0x1128F0001129E, + 0x1129F000112A9, + 0x112B0000112EB, + 0x112F0000112FA, + 0x1130000011304, + 0x113050001130D, + 0x1130F00011311, + 0x1131300011329, + 0x1132A00011331, + 0x1133200011334, + 0x113350001133A, + 0x1133B00011345, + 0x1134700011349, + 0x1134B0001134E, + 0x1135000011351, + 0x1135700011358, + 0x1135D00011364, + 0x113660001136D, + 0x1137000011375, + 0x113800001138A, + 0x1138B0001138C, + 0x1138E0001138F, + 0x11390000113B6, + 0x113B7000113C1, + 0x113C2000113C3, + 0x113C5000113C6, + 0x113C7000113CB, + 0x113CC000113D4, + 0x113E1000113E3, + 0x114000001144B, + 0x114500001145A, + 0x1145E00011462, + 0x11480000114C6, + 0x114C7000114C8, + 0x114D0000114DA, + 0x11580000115B6, + 0x115B8000115C1, + 0x115D8000115DE, + 0x1160000011641, + 0x1164400011645, + 0x116500001165A, + 0x11680000116B9, + 0x116C0000116CA, + 0x116D0000116E4, + 0x117000001171B, + 0x1171D0001172C, + 0x117300001173A, + 0x1174000011747, + 0x118000001183B, + 0x118C0000118EA, + 0x118FF00011907, + 0x119090001190A, + 0x1190C00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193B00011944, + 0x119500001195A, + 0x119A0000119A8, + 0x119AA000119D8, + 0x119DA000119E2, + 0x119E3000119E5, + 0x11A0000011A3F, + 0x11A4700011A48, + 0x11A5000011A9A, + 0x11A9D00011A9E, + 0x11AB000011AF9, + 0x11BC000011BE1, + 0x11BF000011BFA, + 0x11C0000011C09, + 0x11C0A00011C37, + 0x11C3800011C41, + 0x11C5000011C5A, + 0x11C7200011C90, + 0x11C9200011CA8, + 0x11CA900011CB7, + 0x11D0000011D07, + 0x11D0800011D0A, + 0x11D0B00011D37, + 0x11D3A00011D3B, + 0x11D3C00011D3E, + 0x11D3F00011D48, + 0x11D5000011D5A, + 0x11D6000011D66, + 0x11D6700011D69, + 0x11D6A00011D8F, + 0x11D9000011D92, + 0x11D9300011D99, + 0x11DA000011DAA, + 0x11EE000011EF7, + 0x11F0000011F11, + 0x11F1200011F3B, + 0x11F3E00011F43, + 0x11F5000011F5B, + 0x11FB000011FB1, + 0x120000001239A, + 0x1248000012544, + 0x12F9000012FF1, + 0x1300000013430, + 0x1344000013456, + 0x13460000143FB, + 0x1440000014647, + 0x161000001613A, + 0x1680000016A39, + 0x16A4000016A5F, + 0x16A6000016A6A, + 0x16A7000016ABF, + 0x16AC000016ACA, + 0x16AD000016AEE, + 0x16AF000016AF5, + 0x16B0000016B37, + 0x16B4000016B44, + 0x16B5000016B5A, + 0x16B6300016B78, + 0x16B7D00016B90, + 0x16D4000016D6D, + 0x16D7000016D7A, + 0x16E6000016E80, + 0x16F0000016F4B, + 0x16F4F00016F88, + 0x16F8F00016FA0, + 0x16FE000016FE2, + 0x16FE300016FE5, + 0x16FF000016FF2, + 0x17000000187F8, + 0x1880000018CD6, + 0x18CFF00018D09, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B123, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1B1550001B156, + 0x1B1640001B168, + 0x1B1700001B2FC, + 0x1BC000001BC6B, + 0x1BC700001BC7D, + 0x1BC800001BC89, + 0x1BC900001BC9A, + 0x1BC9D0001BC9F, + 0x1CCF00001CCFA, + 0x1CF000001CF2E, + 0x1CF300001CF47, + 0x1DA000001DA37, + 0x1DA3B0001DA6D, + 0x1DA750001DA76, + 0x1DA840001DA85, + 0x1DA9B0001DAA0, + 0x1DAA10001DAB0, + 0x1DF000001DF1F, + 0x1DF250001DF2B, + 0x1E0000001E007, + 0x1E0080001E019, + 0x1E01B0001E022, + 0x1E0230001E025, + 0x1E0260001E02B, + 0x1E08F0001E090, + 0x1E1000001E12D, + 0x1E1300001E13E, + 0x1E1400001E14A, + 0x1E14E0001E14F, + 0x1E2900001E2AF, + 0x1E2C00001E2FA, + 0x1E4D00001E4FA, + 0x1E5D00001E5FB, + 0x1E7E00001E7E7, + 0x1E7E80001E7EC, + 0x1E7ED0001E7EF, + 0x1E7F00001E7FF, + 0x1E8000001E8C5, + 0x1E8D00001E8D7, + 0x1E9220001E94C, + 0x1E9500001E95A, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x300000003134B, + 0x31350000323B0, + ), + "CONTEXTJ": (0x200C0000200E,), + "CONTEXTO": ( + 0xB7000000B8, + 0x37500000376, + 0x5F3000005F5, + 0x6600000066A, + 0x6F0000006FA, + 0x30FB000030FC, + ), +} diff --git a/backend/venv/Lib/site-packages/idna/intranges.py b/backend/venv/Lib/site-packages/idna/intranges.py new file mode 100644 index 0000000..7bfaa8d --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/intranges.py @@ -0,0 +1,57 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect +from typing import List, Tuple + + +def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i + 1 < len(sorted_list): + if sorted_list[i] == sorted_list[i + 1] - 1: + continue + current_range = sorted_list[last_write + 1 : i + 1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + + +def _encode_range(start: int, end: int) -> int: + return (start << 32) | end + + +def _decode_range(r: int) -> Tuple[int, int]: + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos - 1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/backend/venv/Lib/site-packages/idna/package_data.py b/backend/venv/Lib/site-packages/idna/package_data.py new file mode 100644 index 0000000..7272c8d --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/package_data.py @@ -0,0 +1 @@ +__version__ = "3.11" diff --git a/backend/venv/Lib/site-packages/idna/py.typed b/backend/venv/Lib/site-packages/idna/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/idna/uts46data.py b/backend/venv/Lib/site-packages/idna/uts46data.py new file mode 100644 index 0000000..4610b71 --- /dev/null +++ b/backend/venv/Lib/site-packages/idna/uts46data.py @@ -0,0 +1,8841 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +from typing import List, Tuple, Union + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "16.0.0" + + +def _seg_0() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x0, "V"), + (0x1, "V"), + (0x2, "V"), + (0x3, "V"), + (0x4, "V"), + (0x5, "V"), + (0x6, "V"), + (0x7, "V"), + (0x8, "V"), + (0x9, "V"), + (0xA, "V"), + (0xB, "V"), + (0xC, "V"), + (0xD, "V"), + (0xE, "V"), + (0xF, "V"), + (0x10, "V"), + (0x11, "V"), + (0x12, "V"), + (0x13, "V"), + (0x14, "V"), + (0x15, "V"), + (0x16, "V"), + (0x17, "V"), + (0x18, "V"), + (0x19, "V"), + (0x1A, "V"), + (0x1B, "V"), + (0x1C, "V"), + (0x1D, "V"), + (0x1E, "V"), + (0x1F, "V"), + (0x20, "V"), + (0x21, "V"), + (0x22, "V"), + (0x23, "V"), + (0x24, "V"), + (0x25, "V"), + (0x26, "V"), + (0x27, "V"), + (0x28, "V"), + (0x29, "V"), + (0x2A, "V"), + (0x2B, "V"), + (0x2C, "V"), + (0x2D, "V"), + (0x2E, "V"), + (0x2F, "V"), + (0x30, "V"), + (0x31, "V"), + (0x32, "V"), + (0x33, "V"), + (0x34, "V"), + (0x35, "V"), + (0x36, "V"), + (0x37, "V"), + (0x38, "V"), + (0x39, "V"), + (0x3A, "V"), + (0x3B, "V"), + (0x3C, "V"), + (0x3D, "V"), + (0x3E, "V"), + (0x3F, "V"), + (0x40, "V"), + (0x41, "M", "a"), + (0x42, "M", "b"), + (0x43, "M", "c"), + (0x44, "M", "d"), + (0x45, "M", "e"), + (0x46, "M", "f"), + (0x47, "M", "g"), + (0x48, "M", "h"), + (0x49, "M", "i"), + (0x4A, "M", "j"), + (0x4B, "M", "k"), + (0x4C, "M", "l"), + (0x4D, "M", "m"), + (0x4E, "M", "n"), + (0x4F, "M", "o"), + (0x50, "M", "p"), + (0x51, "M", "q"), + (0x52, "M", "r"), + (0x53, "M", "s"), + (0x54, "M", "t"), + (0x55, "M", "u"), + (0x56, "M", "v"), + (0x57, "M", "w"), + (0x58, "M", "x"), + (0x59, "M", "y"), + (0x5A, "M", "z"), + (0x5B, "V"), + (0x5C, "V"), + (0x5D, "V"), + (0x5E, "V"), + (0x5F, "V"), + (0x60, "V"), + (0x61, "V"), + (0x62, "V"), + (0x63, "V"), + ] + + +def _seg_1() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x64, "V"), + (0x65, "V"), + (0x66, "V"), + (0x67, "V"), + (0x68, "V"), + (0x69, "V"), + (0x6A, "V"), + (0x6B, "V"), + (0x6C, "V"), + (0x6D, "V"), + (0x6E, "V"), + (0x6F, "V"), + (0x70, "V"), + (0x71, "V"), + (0x72, "V"), + (0x73, "V"), + (0x74, "V"), + (0x75, "V"), + (0x76, "V"), + (0x77, "V"), + (0x78, "V"), + (0x79, "V"), + (0x7A, "V"), + (0x7B, "V"), + (0x7C, "V"), + (0x7D, "V"), + (0x7E, "V"), + (0x7F, "V"), + (0x80, "X"), + (0x81, "X"), + (0x82, "X"), + (0x83, "X"), + (0x84, "X"), + (0x85, "X"), + (0x86, "X"), + (0x87, "X"), + (0x88, "X"), + (0x89, "X"), + (0x8A, "X"), + (0x8B, "X"), + (0x8C, "X"), + (0x8D, "X"), + (0x8E, "X"), + (0x8F, "X"), + (0x90, "X"), + (0x91, "X"), + (0x92, "X"), + (0x93, "X"), + (0x94, "X"), + (0x95, "X"), + (0x96, "X"), + (0x97, "X"), + (0x98, "X"), + (0x99, "X"), + (0x9A, "X"), + (0x9B, "X"), + (0x9C, "X"), + (0x9D, "X"), + (0x9E, "X"), + (0x9F, "X"), + (0xA0, "M", " "), + (0xA1, "V"), + (0xA2, "V"), + (0xA3, "V"), + (0xA4, "V"), + (0xA5, "V"), + (0xA6, "V"), + (0xA7, "V"), + (0xA8, "M", " ̈"), + (0xA9, "V"), + (0xAA, "M", "a"), + (0xAB, "V"), + (0xAC, "V"), + (0xAD, "I"), + (0xAE, "V"), + (0xAF, "M", " ̄"), + (0xB0, "V"), + (0xB1, "V"), + (0xB2, "M", "2"), + (0xB3, "M", "3"), + (0xB4, "M", " ́"), + (0xB5, "M", "μ"), + (0xB6, "V"), + (0xB7, "V"), + (0xB8, "M", " ̧"), + (0xB9, "M", "1"), + (0xBA, "M", "o"), + (0xBB, "V"), + (0xBC, "M", "1⁄4"), + (0xBD, "M", "1⁄2"), + (0xBE, "M", "3⁄4"), + (0xBF, "V"), + (0xC0, "M", "à"), + (0xC1, "M", "á"), + (0xC2, "M", "â"), + (0xC3, "M", "ã"), + (0xC4, "M", "ä"), + (0xC5, "M", "å"), + (0xC6, "M", "æ"), + (0xC7, "M", "ç"), + ] + + +def _seg_2() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC8, "M", "è"), + (0xC9, "M", "é"), + (0xCA, "M", "ê"), + (0xCB, "M", "ë"), + (0xCC, "M", "ì"), + (0xCD, "M", "í"), + (0xCE, "M", "î"), + (0xCF, "M", "ï"), + (0xD0, "M", "ð"), + (0xD1, "M", "ñ"), + (0xD2, "M", "ò"), + (0xD3, "M", "ó"), + (0xD4, "M", "ô"), + (0xD5, "M", "õ"), + (0xD6, "M", "ö"), + (0xD7, "V"), + (0xD8, "M", "ø"), + (0xD9, "M", "ù"), + (0xDA, "M", "ú"), + (0xDB, "M", "û"), + (0xDC, "M", "ü"), + (0xDD, "M", "ý"), + (0xDE, "M", "þ"), + (0xDF, "D", "ss"), + (0xE0, "V"), + (0xE1, "V"), + (0xE2, "V"), + (0xE3, "V"), + (0xE4, "V"), + (0xE5, "V"), + (0xE6, "V"), + (0xE7, "V"), + (0xE8, "V"), + (0xE9, "V"), + (0xEA, "V"), + (0xEB, "V"), + (0xEC, "V"), + (0xED, "V"), + (0xEE, "V"), + (0xEF, "V"), + (0xF0, "V"), + (0xF1, "V"), + (0xF2, "V"), + (0xF3, "V"), + (0xF4, "V"), + (0xF5, "V"), + (0xF6, "V"), + (0xF7, "V"), + (0xF8, "V"), + (0xF9, "V"), + (0xFA, "V"), + (0xFB, "V"), + (0xFC, "V"), + (0xFD, "V"), + (0xFE, "V"), + (0xFF, "V"), + (0x100, "M", "ā"), + (0x101, "V"), + (0x102, "M", "ă"), + (0x103, "V"), + (0x104, "M", "ą"), + (0x105, "V"), + (0x106, "M", "ć"), + (0x107, "V"), + (0x108, "M", "ĉ"), + (0x109, "V"), + (0x10A, "M", "ċ"), + (0x10B, "V"), + (0x10C, "M", "č"), + (0x10D, "V"), + (0x10E, "M", "ď"), + (0x10F, "V"), + (0x110, "M", "đ"), + (0x111, "V"), + (0x112, "M", "ē"), + (0x113, "V"), + (0x114, "M", "ĕ"), + (0x115, "V"), + (0x116, "M", "ė"), + (0x117, "V"), + (0x118, "M", "ę"), + (0x119, "V"), + (0x11A, "M", "ě"), + (0x11B, "V"), + (0x11C, "M", "ĝ"), + (0x11D, "V"), + (0x11E, "M", "ğ"), + (0x11F, "V"), + (0x120, "M", "ġ"), + (0x121, "V"), + (0x122, "M", "ģ"), + (0x123, "V"), + (0x124, "M", "ĥ"), + (0x125, "V"), + (0x126, "M", "ħ"), + (0x127, "V"), + (0x128, "M", "ĩ"), + (0x129, "V"), + (0x12A, "M", "ī"), + (0x12B, "V"), + ] + + +def _seg_3() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x12C, "M", "ĭ"), + (0x12D, "V"), + (0x12E, "M", "į"), + (0x12F, "V"), + (0x130, "M", "i̇"), + (0x131, "V"), + (0x132, "M", "ij"), + (0x134, "M", "ĵ"), + (0x135, "V"), + (0x136, "M", "ķ"), + (0x137, "V"), + (0x139, "M", "ĺ"), + (0x13A, "V"), + (0x13B, "M", "ļ"), + (0x13C, "V"), + (0x13D, "M", "ľ"), + (0x13E, "V"), + (0x13F, "M", "l·"), + (0x141, "M", "ł"), + (0x142, "V"), + (0x143, "M", "ń"), + (0x144, "V"), + (0x145, "M", "ņ"), + (0x146, "V"), + (0x147, "M", "ň"), + (0x148, "V"), + (0x149, "M", "ʼn"), + (0x14A, "M", "ŋ"), + (0x14B, "V"), + (0x14C, "M", "ō"), + (0x14D, "V"), + (0x14E, "M", "ŏ"), + (0x14F, "V"), + (0x150, "M", "ő"), + (0x151, "V"), + (0x152, "M", "œ"), + (0x153, "V"), + (0x154, "M", "ŕ"), + (0x155, "V"), + (0x156, "M", "ŗ"), + (0x157, "V"), + (0x158, "M", "ř"), + (0x159, "V"), + (0x15A, "M", "ś"), + (0x15B, "V"), + (0x15C, "M", "ŝ"), + (0x15D, "V"), + (0x15E, "M", "ş"), + (0x15F, "V"), + (0x160, "M", "š"), + (0x161, "V"), + (0x162, "M", "ţ"), + (0x163, "V"), + (0x164, "M", "ť"), + (0x165, "V"), + (0x166, "M", "ŧ"), + (0x167, "V"), + (0x168, "M", "ũ"), + (0x169, "V"), + (0x16A, "M", "ū"), + (0x16B, "V"), + (0x16C, "M", "ŭ"), + (0x16D, "V"), + (0x16E, "M", "ů"), + (0x16F, "V"), + (0x170, "M", "ű"), + (0x171, "V"), + (0x172, "M", "ų"), + (0x173, "V"), + (0x174, "M", "ŵ"), + (0x175, "V"), + (0x176, "M", "ŷ"), + (0x177, "V"), + (0x178, "M", "ÿ"), + (0x179, "M", "ź"), + (0x17A, "V"), + (0x17B, "M", "ż"), + (0x17C, "V"), + (0x17D, "M", "ž"), + (0x17E, "V"), + (0x17F, "M", "s"), + (0x180, "V"), + (0x181, "M", "ɓ"), + (0x182, "M", "ƃ"), + (0x183, "V"), + (0x184, "M", "ƅ"), + (0x185, "V"), + (0x186, "M", "ɔ"), + (0x187, "M", "ƈ"), + (0x188, "V"), + (0x189, "M", "ɖ"), + (0x18A, "M", "ɗ"), + (0x18B, "M", "ƌ"), + (0x18C, "V"), + (0x18E, "M", "ǝ"), + (0x18F, "M", "ə"), + (0x190, "M", "ɛ"), + (0x191, "M", "ƒ"), + (0x192, "V"), + (0x193, "M", "ɠ"), + ] + + +def _seg_4() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x194, "M", "ɣ"), + (0x195, "V"), + (0x196, "M", "ɩ"), + (0x197, "M", "ɨ"), + (0x198, "M", "ƙ"), + (0x199, "V"), + (0x19C, "M", "ɯ"), + (0x19D, "M", "ɲ"), + (0x19E, "V"), + (0x19F, "M", "ɵ"), + (0x1A0, "M", "ơ"), + (0x1A1, "V"), + (0x1A2, "M", "ƣ"), + (0x1A3, "V"), + (0x1A4, "M", "ƥ"), + (0x1A5, "V"), + (0x1A6, "M", "ʀ"), + (0x1A7, "M", "ƨ"), + (0x1A8, "V"), + (0x1A9, "M", "ʃ"), + (0x1AA, "V"), + (0x1AC, "M", "ƭ"), + (0x1AD, "V"), + (0x1AE, "M", "ʈ"), + (0x1AF, "M", "ư"), + (0x1B0, "V"), + (0x1B1, "M", "ʊ"), + (0x1B2, "M", "ʋ"), + (0x1B3, "M", "ƴ"), + (0x1B4, "V"), + (0x1B5, "M", "ƶ"), + (0x1B6, "V"), + (0x1B7, "M", "ʒ"), + (0x1B8, "M", "ƹ"), + (0x1B9, "V"), + (0x1BC, "M", "ƽ"), + (0x1BD, "V"), + (0x1C4, "M", "dž"), + (0x1C7, "M", "lj"), + (0x1CA, "M", "nj"), + (0x1CD, "M", "ǎ"), + (0x1CE, "V"), + (0x1CF, "M", "ǐ"), + (0x1D0, "V"), + (0x1D1, "M", "ǒ"), + (0x1D2, "V"), + (0x1D3, "M", "ǔ"), + (0x1D4, "V"), + (0x1D5, "M", "ǖ"), + (0x1D6, "V"), + (0x1D7, "M", "ǘ"), + (0x1D8, "V"), + (0x1D9, "M", "ǚ"), + (0x1DA, "V"), + (0x1DB, "M", "ǜ"), + (0x1DC, "V"), + (0x1DE, "M", "ǟ"), + (0x1DF, "V"), + (0x1E0, "M", "ǡ"), + (0x1E1, "V"), + (0x1E2, "M", "ǣ"), + (0x1E3, "V"), + (0x1E4, "M", "ǥ"), + (0x1E5, "V"), + (0x1E6, "M", "ǧ"), + (0x1E7, "V"), + (0x1E8, "M", "ǩ"), + (0x1E9, "V"), + (0x1EA, "M", "ǫ"), + (0x1EB, "V"), + (0x1EC, "M", "ǭ"), + (0x1ED, "V"), + (0x1EE, "M", "ǯ"), + (0x1EF, "V"), + (0x1F1, "M", "dz"), + (0x1F4, "M", "ǵ"), + (0x1F5, "V"), + (0x1F6, "M", "ƕ"), + (0x1F7, "M", "ƿ"), + (0x1F8, "M", "ǹ"), + (0x1F9, "V"), + (0x1FA, "M", "ǻ"), + (0x1FB, "V"), + (0x1FC, "M", "ǽ"), + (0x1FD, "V"), + (0x1FE, "M", "ǿ"), + (0x1FF, "V"), + (0x200, "M", "ȁ"), + (0x201, "V"), + (0x202, "M", "ȃ"), + (0x203, "V"), + (0x204, "M", "ȅ"), + (0x205, "V"), + (0x206, "M", "ȇ"), + (0x207, "V"), + (0x208, "M", "ȉ"), + (0x209, "V"), + (0x20A, "M", "ȋ"), + (0x20B, "V"), + (0x20C, "M", "ȍ"), + ] + + +def _seg_5() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x20D, "V"), + (0x20E, "M", "ȏ"), + (0x20F, "V"), + (0x210, "M", "ȑ"), + (0x211, "V"), + (0x212, "M", "ȓ"), + (0x213, "V"), + (0x214, "M", "ȕ"), + (0x215, "V"), + (0x216, "M", "ȗ"), + (0x217, "V"), + (0x218, "M", "ș"), + (0x219, "V"), + (0x21A, "M", "ț"), + (0x21B, "V"), + (0x21C, "M", "ȝ"), + (0x21D, "V"), + (0x21E, "M", "ȟ"), + (0x21F, "V"), + (0x220, "M", "ƞ"), + (0x221, "V"), + (0x222, "M", "ȣ"), + (0x223, "V"), + (0x224, "M", "ȥ"), + (0x225, "V"), + (0x226, "M", "ȧ"), + (0x227, "V"), + (0x228, "M", "ȩ"), + (0x229, "V"), + (0x22A, "M", "ȫ"), + (0x22B, "V"), + (0x22C, "M", "ȭ"), + (0x22D, "V"), + (0x22E, "M", "ȯ"), + (0x22F, "V"), + (0x230, "M", "ȱ"), + (0x231, "V"), + (0x232, "M", "ȳ"), + (0x233, "V"), + (0x23A, "M", "ⱥ"), + (0x23B, "M", "ȼ"), + (0x23C, "V"), + (0x23D, "M", "ƚ"), + (0x23E, "M", "ⱦ"), + (0x23F, "V"), + (0x241, "M", "ɂ"), + (0x242, "V"), + (0x243, "M", "ƀ"), + (0x244, "M", "ʉ"), + (0x245, "M", "ʌ"), + (0x246, "M", "ɇ"), + (0x247, "V"), + (0x248, "M", "ɉ"), + (0x249, "V"), + (0x24A, "M", "ɋ"), + (0x24B, "V"), + (0x24C, "M", "ɍ"), + (0x24D, "V"), + (0x24E, "M", "ɏ"), + (0x24F, "V"), + (0x2B0, "M", "h"), + (0x2B1, "M", "ɦ"), + (0x2B2, "M", "j"), + (0x2B3, "M", "r"), + (0x2B4, "M", "ɹ"), + (0x2B5, "M", "ɻ"), + (0x2B6, "M", "ʁ"), + (0x2B7, "M", "w"), + (0x2B8, "M", "y"), + (0x2B9, "V"), + (0x2D8, "M", " ̆"), + (0x2D9, "M", " ̇"), + (0x2DA, "M", " ̊"), + (0x2DB, "M", " ̨"), + (0x2DC, "M", " ̃"), + (0x2DD, "M", " ̋"), + (0x2DE, "V"), + (0x2E0, "M", "ɣ"), + (0x2E1, "M", "l"), + (0x2E2, "M", "s"), + (0x2E3, "M", "x"), + (0x2E4, "M", "ʕ"), + (0x2E5, "V"), + (0x340, "M", "̀"), + (0x341, "M", "́"), + (0x342, "V"), + (0x343, "M", "̓"), + (0x344, "M", "̈́"), + (0x345, "M", "ι"), + (0x346, "V"), + (0x34F, "I"), + (0x350, "V"), + (0x370, "M", "ͱ"), + (0x371, "V"), + (0x372, "M", "ͳ"), + (0x373, "V"), + (0x374, "M", "ʹ"), + (0x375, "V"), + (0x376, "M", "ͷ"), + (0x377, "V"), + ] + + +def _seg_6() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x378, "X"), + (0x37A, "M", " ι"), + (0x37B, "V"), + (0x37E, "M", ";"), + (0x37F, "M", "ϳ"), + (0x380, "X"), + (0x384, "M", " ́"), + (0x385, "M", " ̈́"), + (0x386, "M", "ά"), + (0x387, "M", "·"), + (0x388, "M", "έ"), + (0x389, "M", "ή"), + (0x38A, "M", "ί"), + (0x38B, "X"), + (0x38C, "M", "ό"), + (0x38D, "X"), + (0x38E, "M", "ύ"), + (0x38F, "M", "ώ"), + (0x390, "V"), + (0x391, "M", "α"), + (0x392, "M", "β"), + (0x393, "M", "γ"), + (0x394, "M", "δ"), + (0x395, "M", "ε"), + (0x396, "M", "ζ"), + (0x397, "M", "η"), + (0x398, "M", "θ"), + (0x399, "M", "ι"), + (0x39A, "M", "κ"), + (0x39B, "M", "λ"), + (0x39C, "M", "μ"), + (0x39D, "M", "ν"), + (0x39E, "M", "ξ"), + (0x39F, "M", "ο"), + (0x3A0, "M", "π"), + (0x3A1, "M", "ρ"), + (0x3A2, "X"), + (0x3A3, "M", "σ"), + (0x3A4, "M", "τ"), + (0x3A5, "M", "υ"), + (0x3A6, "M", "φ"), + (0x3A7, "M", "χ"), + (0x3A8, "M", "ψ"), + (0x3A9, "M", "ω"), + (0x3AA, "M", "ϊ"), + (0x3AB, "M", "ϋ"), + (0x3AC, "V"), + (0x3C2, "D", "σ"), + (0x3C3, "V"), + (0x3CF, "M", "ϗ"), + (0x3D0, "M", "β"), + (0x3D1, "M", "θ"), + (0x3D2, "M", "υ"), + (0x3D3, "M", "ύ"), + (0x3D4, "M", "ϋ"), + (0x3D5, "M", "φ"), + (0x3D6, "M", "π"), + (0x3D7, "V"), + (0x3D8, "M", "ϙ"), + (0x3D9, "V"), + (0x3DA, "M", "ϛ"), + (0x3DB, "V"), + (0x3DC, "M", "ϝ"), + (0x3DD, "V"), + (0x3DE, "M", "ϟ"), + (0x3DF, "V"), + (0x3E0, "M", "ϡ"), + (0x3E1, "V"), + (0x3E2, "M", "ϣ"), + (0x3E3, "V"), + (0x3E4, "M", "ϥ"), + (0x3E5, "V"), + (0x3E6, "M", "ϧ"), + (0x3E7, "V"), + (0x3E8, "M", "ϩ"), + (0x3E9, "V"), + (0x3EA, "M", "ϫ"), + (0x3EB, "V"), + (0x3EC, "M", "ϭ"), + (0x3ED, "V"), + (0x3EE, "M", "ϯ"), + (0x3EF, "V"), + (0x3F0, "M", "κ"), + (0x3F1, "M", "ρ"), + (0x3F2, "M", "σ"), + (0x3F3, "V"), + (0x3F4, "M", "θ"), + (0x3F5, "M", "ε"), + (0x3F6, "V"), + (0x3F7, "M", "ϸ"), + (0x3F8, "V"), + (0x3F9, "M", "σ"), + (0x3FA, "M", "ϻ"), + (0x3FB, "V"), + (0x3FD, "M", "ͻ"), + (0x3FE, "M", "ͼ"), + (0x3FF, "M", "ͽ"), + (0x400, "M", "ѐ"), + (0x401, "M", "ё"), + (0x402, "M", "ђ"), + ] + + +def _seg_7() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x403, "M", "ѓ"), + (0x404, "M", "є"), + (0x405, "M", "ѕ"), + (0x406, "M", "і"), + (0x407, "M", "ї"), + (0x408, "M", "ј"), + (0x409, "M", "љ"), + (0x40A, "M", "њ"), + (0x40B, "M", "ћ"), + (0x40C, "M", "ќ"), + (0x40D, "M", "ѝ"), + (0x40E, "M", "ў"), + (0x40F, "M", "џ"), + (0x410, "M", "а"), + (0x411, "M", "б"), + (0x412, "M", "в"), + (0x413, "M", "г"), + (0x414, "M", "д"), + (0x415, "M", "е"), + (0x416, "M", "ж"), + (0x417, "M", "з"), + (0x418, "M", "и"), + (0x419, "M", "й"), + (0x41A, "M", "к"), + (0x41B, "M", "л"), + (0x41C, "M", "м"), + (0x41D, "M", "н"), + (0x41E, "M", "о"), + (0x41F, "M", "п"), + (0x420, "M", "р"), + (0x421, "M", "с"), + (0x422, "M", "т"), + (0x423, "M", "у"), + (0x424, "M", "ф"), + (0x425, "M", "х"), + (0x426, "M", "ц"), + (0x427, "M", "ч"), + (0x428, "M", "ш"), + (0x429, "M", "щ"), + (0x42A, "M", "ъ"), + (0x42B, "M", "ы"), + (0x42C, "M", "ь"), + (0x42D, "M", "э"), + (0x42E, "M", "ю"), + (0x42F, "M", "я"), + (0x430, "V"), + (0x460, "M", "ѡ"), + (0x461, "V"), + (0x462, "M", "ѣ"), + (0x463, "V"), + (0x464, "M", "ѥ"), + (0x465, "V"), + (0x466, "M", "ѧ"), + (0x467, "V"), + (0x468, "M", "ѩ"), + (0x469, "V"), + (0x46A, "M", "ѫ"), + (0x46B, "V"), + (0x46C, "M", "ѭ"), + (0x46D, "V"), + (0x46E, "M", "ѯ"), + (0x46F, "V"), + (0x470, "M", "ѱ"), + (0x471, "V"), + (0x472, "M", "ѳ"), + (0x473, "V"), + (0x474, "M", "ѵ"), + (0x475, "V"), + (0x476, "M", "ѷ"), + (0x477, "V"), + (0x478, "M", "ѹ"), + (0x479, "V"), + (0x47A, "M", "ѻ"), + (0x47B, "V"), + (0x47C, "M", "ѽ"), + (0x47D, "V"), + (0x47E, "M", "ѿ"), + (0x47F, "V"), + (0x480, "M", "ҁ"), + (0x481, "V"), + (0x48A, "M", "ҋ"), + (0x48B, "V"), + (0x48C, "M", "ҍ"), + (0x48D, "V"), + (0x48E, "M", "ҏ"), + (0x48F, "V"), + (0x490, "M", "ґ"), + (0x491, "V"), + (0x492, "M", "ғ"), + (0x493, "V"), + (0x494, "M", "ҕ"), + (0x495, "V"), + (0x496, "M", "җ"), + (0x497, "V"), + (0x498, "M", "ҙ"), + (0x499, "V"), + (0x49A, "M", "қ"), + (0x49B, "V"), + (0x49C, "M", "ҝ"), + (0x49D, "V"), + ] + + +def _seg_8() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x49E, "M", "ҟ"), + (0x49F, "V"), + (0x4A0, "M", "ҡ"), + (0x4A1, "V"), + (0x4A2, "M", "ң"), + (0x4A3, "V"), + (0x4A4, "M", "ҥ"), + (0x4A5, "V"), + (0x4A6, "M", "ҧ"), + (0x4A7, "V"), + (0x4A8, "M", "ҩ"), + (0x4A9, "V"), + (0x4AA, "M", "ҫ"), + (0x4AB, "V"), + (0x4AC, "M", "ҭ"), + (0x4AD, "V"), + (0x4AE, "M", "ү"), + (0x4AF, "V"), + (0x4B0, "M", "ұ"), + (0x4B1, "V"), + (0x4B2, "M", "ҳ"), + (0x4B3, "V"), + (0x4B4, "M", "ҵ"), + (0x4B5, "V"), + (0x4B6, "M", "ҷ"), + (0x4B7, "V"), + (0x4B8, "M", "ҹ"), + (0x4B9, "V"), + (0x4BA, "M", "һ"), + (0x4BB, "V"), + (0x4BC, "M", "ҽ"), + (0x4BD, "V"), + (0x4BE, "M", "ҿ"), + (0x4BF, "V"), + (0x4C0, "M", "ӏ"), + (0x4C1, "M", "ӂ"), + (0x4C2, "V"), + (0x4C3, "M", "ӄ"), + (0x4C4, "V"), + (0x4C5, "M", "ӆ"), + (0x4C6, "V"), + (0x4C7, "M", "ӈ"), + (0x4C8, "V"), + (0x4C9, "M", "ӊ"), + (0x4CA, "V"), + (0x4CB, "M", "ӌ"), + (0x4CC, "V"), + (0x4CD, "M", "ӎ"), + (0x4CE, "V"), + (0x4D0, "M", "ӑ"), + (0x4D1, "V"), + (0x4D2, "M", "ӓ"), + (0x4D3, "V"), + (0x4D4, "M", "ӕ"), + (0x4D5, "V"), + (0x4D6, "M", "ӗ"), + (0x4D7, "V"), + (0x4D8, "M", "ә"), + (0x4D9, "V"), + (0x4DA, "M", "ӛ"), + (0x4DB, "V"), + (0x4DC, "M", "ӝ"), + (0x4DD, "V"), + (0x4DE, "M", "ӟ"), + (0x4DF, "V"), + (0x4E0, "M", "ӡ"), + (0x4E1, "V"), + (0x4E2, "M", "ӣ"), + (0x4E3, "V"), + (0x4E4, "M", "ӥ"), + (0x4E5, "V"), + (0x4E6, "M", "ӧ"), + (0x4E7, "V"), + (0x4E8, "M", "ө"), + (0x4E9, "V"), + (0x4EA, "M", "ӫ"), + (0x4EB, "V"), + (0x4EC, "M", "ӭ"), + (0x4ED, "V"), + (0x4EE, "M", "ӯ"), + (0x4EF, "V"), + (0x4F0, "M", "ӱ"), + (0x4F1, "V"), + (0x4F2, "M", "ӳ"), + (0x4F3, "V"), + (0x4F4, "M", "ӵ"), + (0x4F5, "V"), + (0x4F6, "M", "ӷ"), + (0x4F7, "V"), + (0x4F8, "M", "ӹ"), + (0x4F9, "V"), + (0x4FA, "M", "ӻ"), + (0x4FB, "V"), + (0x4FC, "M", "ӽ"), + (0x4FD, "V"), + (0x4FE, "M", "ӿ"), + (0x4FF, "V"), + (0x500, "M", "ԁ"), + (0x501, "V"), + (0x502, "M", "ԃ"), + ] + + +def _seg_9() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x503, "V"), + (0x504, "M", "ԅ"), + (0x505, "V"), + (0x506, "M", "ԇ"), + (0x507, "V"), + (0x508, "M", "ԉ"), + (0x509, "V"), + (0x50A, "M", "ԋ"), + (0x50B, "V"), + (0x50C, "M", "ԍ"), + (0x50D, "V"), + (0x50E, "M", "ԏ"), + (0x50F, "V"), + (0x510, "M", "ԑ"), + (0x511, "V"), + (0x512, "M", "ԓ"), + (0x513, "V"), + (0x514, "M", "ԕ"), + (0x515, "V"), + (0x516, "M", "ԗ"), + (0x517, "V"), + (0x518, "M", "ԙ"), + (0x519, "V"), + (0x51A, "M", "ԛ"), + (0x51B, "V"), + (0x51C, "M", "ԝ"), + (0x51D, "V"), + (0x51E, "M", "ԟ"), + (0x51F, "V"), + (0x520, "M", "ԡ"), + (0x521, "V"), + (0x522, "M", "ԣ"), + (0x523, "V"), + (0x524, "M", "ԥ"), + (0x525, "V"), + (0x526, "M", "ԧ"), + (0x527, "V"), + (0x528, "M", "ԩ"), + (0x529, "V"), + (0x52A, "M", "ԫ"), + (0x52B, "V"), + (0x52C, "M", "ԭ"), + (0x52D, "V"), + (0x52E, "M", "ԯ"), + (0x52F, "V"), + (0x530, "X"), + (0x531, "M", "ա"), + (0x532, "M", "բ"), + (0x533, "M", "գ"), + (0x534, "M", "դ"), + (0x535, "M", "ե"), + (0x536, "M", "զ"), + (0x537, "M", "է"), + (0x538, "M", "ը"), + (0x539, "M", "թ"), + (0x53A, "M", "ժ"), + (0x53B, "M", "ի"), + (0x53C, "M", "լ"), + (0x53D, "M", "խ"), + (0x53E, "M", "ծ"), + (0x53F, "M", "կ"), + (0x540, "M", "հ"), + (0x541, "M", "ձ"), + (0x542, "M", "ղ"), + (0x543, "M", "ճ"), + (0x544, "M", "մ"), + (0x545, "M", "յ"), + (0x546, "M", "ն"), + (0x547, "M", "շ"), + (0x548, "M", "ո"), + (0x549, "M", "չ"), + (0x54A, "M", "պ"), + (0x54B, "M", "ջ"), + (0x54C, "M", "ռ"), + (0x54D, "M", "ս"), + (0x54E, "M", "վ"), + (0x54F, "M", "տ"), + (0x550, "M", "ր"), + (0x551, "M", "ց"), + (0x552, "M", "ւ"), + (0x553, "M", "փ"), + (0x554, "M", "ք"), + (0x555, "M", "օ"), + (0x556, "M", "ֆ"), + (0x557, "X"), + (0x559, "V"), + (0x587, "M", "եւ"), + (0x588, "V"), + (0x58B, "X"), + (0x58D, "V"), + (0x590, "X"), + (0x591, "V"), + (0x5C8, "X"), + (0x5D0, "V"), + (0x5EB, "X"), + (0x5EF, "V"), + (0x5F5, "X"), + (0x606, "V"), + (0x61C, "X"), + (0x61D, "V"), + ] + + +def _seg_10() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x675, "M", "اٴ"), + (0x676, "M", "وٴ"), + (0x677, "M", "ۇٴ"), + (0x678, "M", "يٴ"), + (0x679, "V"), + (0x6DD, "X"), + (0x6DE, "V"), + (0x70E, "X"), + (0x710, "V"), + (0x74B, "X"), + (0x74D, "V"), + (0x7B2, "X"), + (0x7C0, "V"), + (0x7FB, "X"), + (0x7FD, "V"), + (0x82E, "X"), + (0x830, "V"), + (0x83F, "X"), + (0x840, "V"), + (0x85C, "X"), + (0x85E, "V"), + (0x85F, "X"), + (0x860, "V"), + (0x86B, "X"), + (0x870, "V"), + (0x88F, "X"), + (0x897, "V"), + (0x8E2, "X"), + (0x8E3, "V"), + (0x958, "M", "क़"), + (0x959, "M", "ख़"), + (0x95A, "M", "ग़"), + (0x95B, "M", "ज़"), + (0x95C, "M", "ड़"), + (0x95D, "M", "ढ़"), + (0x95E, "M", "फ़"), + (0x95F, "M", "य़"), + (0x960, "V"), + (0x984, "X"), + (0x985, "V"), + (0x98D, "X"), + (0x98F, "V"), + (0x991, "X"), + (0x993, "V"), + (0x9A9, "X"), + (0x9AA, "V"), + (0x9B1, "X"), + (0x9B2, "V"), + (0x9B3, "X"), + (0x9B6, "V"), + (0x9BA, "X"), + (0x9BC, "V"), + (0x9C5, "X"), + (0x9C7, "V"), + (0x9C9, "X"), + (0x9CB, "V"), + (0x9CF, "X"), + (0x9D7, "V"), + (0x9D8, "X"), + (0x9DC, "M", "ড়"), + (0x9DD, "M", "ঢ়"), + (0x9DE, "X"), + (0x9DF, "M", "য়"), + (0x9E0, "V"), + (0x9E4, "X"), + (0x9E6, "V"), + (0x9FF, "X"), + (0xA01, "V"), + (0xA04, "X"), + (0xA05, "V"), + (0xA0B, "X"), + (0xA0F, "V"), + (0xA11, "X"), + (0xA13, "V"), + (0xA29, "X"), + (0xA2A, "V"), + (0xA31, "X"), + (0xA32, "V"), + (0xA33, "M", "ਲ਼"), + (0xA34, "X"), + (0xA35, "V"), + (0xA36, "M", "ਸ਼"), + (0xA37, "X"), + (0xA38, "V"), + (0xA3A, "X"), + (0xA3C, "V"), + (0xA3D, "X"), + (0xA3E, "V"), + (0xA43, "X"), + (0xA47, "V"), + (0xA49, "X"), + (0xA4B, "V"), + (0xA4E, "X"), + (0xA51, "V"), + (0xA52, "X"), + (0xA59, "M", "ਖ਼"), + (0xA5A, "M", "ਗ਼"), + (0xA5B, "M", "ਜ਼"), + (0xA5C, "V"), + (0xA5D, "X"), + ] + + +def _seg_11() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA5E, "M", "ਫ਼"), + (0xA5F, "X"), + (0xA66, "V"), + (0xA77, "X"), + (0xA81, "V"), + (0xA84, "X"), + (0xA85, "V"), + (0xA8E, "X"), + (0xA8F, "V"), + (0xA92, "X"), + (0xA93, "V"), + (0xAA9, "X"), + (0xAAA, "V"), + (0xAB1, "X"), + (0xAB2, "V"), + (0xAB4, "X"), + (0xAB5, "V"), + (0xABA, "X"), + (0xABC, "V"), + (0xAC6, "X"), + (0xAC7, "V"), + (0xACA, "X"), + (0xACB, "V"), + (0xACE, "X"), + (0xAD0, "V"), + (0xAD1, "X"), + (0xAE0, "V"), + (0xAE4, "X"), + (0xAE6, "V"), + (0xAF2, "X"), + (0xAF9, "V"), + (0xB00, "X"), + (0xB01, "V"), + (0xB04, "X"), + (0xB05, "V"), + (0xB0D, "X"), + (0xB0F, "V"), + (0xB11, "X"), + (0xB13, "V"), + (0xB29, "X"), + (0xB2A, "V"), + (0xB31, "X"), + (0xB32, "V"), + (0xB34, "X"), + (0xB35, "V"), + (0xB3A, "X"), + (0xB3C, "V"), + (0xB45, "X"), + (0xB47, "V"), + (0xB49, "X"), + (0xB4B, "V"), + (0xB4E, "X"), + (0xB55, "V"), + (0xB58, "X"), + (0xB5C, "M", "ଡ଼"), + (0xB5D, "M", "ଢ଼"), + (0xB5E, "X"), + (0xB5F, "V"), + (0xB64, "X"), + (0xB66, "V"), + (0xB78, "X"), + (0xB82, "V"), + (0xB84, "X"), + (0xB85, "V"), + (0xB8B, "X"), + (0xB8E, "V"), + (0xB91, "X"), + (0xB92, "V"), + (0xB96, "X"), + (0xB99, "V"), + (0xB9B, "X"), + (0xB9C, "V"), + (0xB9D, "X"), + (0xB9E, "V"), + (0xBA0, "X"), + (0xBA3, "V"), + (0xBA5, "X"), + (0xBA8, "V"), + (0xBAB, "X"), + (0xBAE, "V"), + (0xBBA, "X"), + (0xBBE, "V"), + (0xBC3, "X"), + (0xBC6, "V"), + (0xBC9, "X"), + (0xBCA, "V"), + (0xBCE, "X"), + (0xBD0, "V"), + (0xBD1, "X"), + (0xBD7, "V"), + (0xBD8, "X"), + (0xBE6, "V"), + (0xBFB, "X"), + (0xC00, "V"), + (0xC0D, "X"), + (0xC0E, "V"), + (0xC11, "X"), + (0xC12, "V"), + (0xC29, "X"), + (0xC2A, "V"), + ] + + +def _seg_12() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC3A, "X"), + (0xC3C, "V"), + (0xC45, "X"), + (0xC46, "V"), + (0xC49, "X"), + (0xC4A, "V"), + (0xC4E, "X"), + (0xC55, "V"), + (0xC57, "X"), + (0xC58, "V"), + (0xC5B, "X"), + (0xC5D, "V"), + (0xC5E, "X"), + (0xC60, "V"), + (0xC64, "X"), + (0xC66, "V"), + (0xC70, "X"), + (0xC77, "V"), + (0xC8D, "X"), + (0xC8E, "V"), + (0xC91, "X"), + (0xC92, "V"), + (0xCA9, "X"), + (0xCAA, "V"), + (0xCB4, "X"), + (0xCB5, "V"), + (0xCBA, "X"), + (0xCBC, "V"), + (0xCC5, "X"), + (0xCC6, "V"), + (0xCC9, "X"), + (0xCCA, "V"), + (0xCCE, "X"), + (0xCD5, "V"), + (0xCD7, "X"), + (0xCDD, "V"), + (0xCDF, "X"), + (0xCE0, "V"), + (0xCE4, "X"), + (0xCE6, "V"), + (0xCF0, "X"), + (0xCF1, "V"), + (0xCF4, "X"), + (0xD00, "V"), + (0xD0D, "X"), + (0xD0E, "V"), + (0xD11, "X"), + (0xD12, "V"), + (0xD45, "X"), + (0xD46, "V"), + (0xD49, "X"), + (0xD4A, "V"), + (0xD50, "X"), + (0xD54, "V"), + (0xD64, "X"), + (0xD66, "V"), + (0xD80, "X"), + (0xD81, "V"), + (0xD84, "X"), + (0xD85, "V"), + (0xD97, "X"), + (0xD9A, "V"), + (0xDB2, "X"), + (0xDB3, "V"), + (0xDBC, "X"), + (0xDBD, "V"), + (0xDBE, "X"), + (0xDC0, "V"), + (0xDC7, "X"), + (0xDCA, "V"), + (0xDCB, "X"), + (0xDCF, "V"), + (0xDD5, "X"), + (0xDD6, "V"), + (0xDD7, "X"), + (0xDD8, "V"), + (0xDE0, "X"), + (0xDE6, "V"), + (0xDF0, "X"), + (0xDF2, "V"), + (0xDF5, "X"), + (0xE01, "V"), + (0xE33, "M", "ํา"), + (0xE34, "V"), + (0xE3B, "X"), + (0xE3F, "V"), + (0xE5C, "X"), + (0xE81, "V"), + (0xE83, "X"), + (0xE84, "V"), + (0xE85, "X"), + (0xE86, "V"), + (0xE8B, "X"), + (0xE8C, "V"), + (0xEA4, "X"), + (0xEA5, "V"), + (0xEA6, "X"), + (0xEA7, "V"), + (0xEB3, "M", "ໍາ"), + (0xEB4, "V"), + ] + + +def _seg_13() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xEBE, "X"), + (0xEC0, "V"), + (0xEC5, "X"), + (0xEC6, "V"), + (0xEC7, "X"), + (0xEC8, "V"), + (0xECF, "X"), + (0xED0, "V"), + (0xEDA, "X"), + (0xEDC, "M", "ຫນ"), + (0xEDD, "M", "ຫມ"), + (0xEDE, "V"), + (0xEE0, "X"), + (0xF00, "V"), + (0xF0C, "M", "་"), + (0xF0D, "V"), + (0xF43, "M", "གྷ"), + (0xF44, "V"), + (0xF48, "X"), + (0xF49, "V"), + (0xF4D, "M", "ཌྷ"), + (0xF4E, "V"), + (0xF52, "M", "དྷ"), + (0xF53, "V"), + (0xF57, "M", "བྷ"), + (0xF58, "V"), + (0xF5C, "M", "ཛྷ"), + (0xF5D, "V"), + (0xF69, "M", "ཀྵ"), + (0xF6A, "V"), + (0xF6D, "X"), + (0xF71, "V"), + (0xF73, "M", "ཱི"), + (0xF74, "V"), + (0xF75, "M", "ཱུ"), + (0xF76, "M", "ྲྀ"), + (0xF77, "M", "ྲཱྀ"), + (0xF78, "M", "ླྀ"), + (0xF79, "M", "ླཱྀ"), + (0xF7A, "V"), + (0xF81, "M", "ཱྀ"), + (0xF82, "V"), + (0xF93, "M", "ྒྷ"), + (0xF94, "V"), + (0xF98, "X"), + (0xF99, "V"), + (0xF9D, "M", "ྜྷ"), + (0xF9E, "V"), + (0xFA2, "M", "ྡྷ"), + (0xFA3, "V"), + (0xFA7, "M", "ྦྷ"), + (0xFA8, "V"), + (0xFAC, "M", "ྫྷ"), + (0xFAD, "V"), + (0xFB9, "M", "ྐྵ"), + (0xFBA, "V"), + (0xFBD, "X"), + (0xFBE, "V"), + (0xFCD, "X"), + (0xFCE, "V"), + (0xFDB, "X"), + (0x1000, "V"), + (0x10A0, "M", "ⴀ"), + (0x10A1, "M", "ⴁ"), + (0x10A2, "M", "ⴂ"), + (0x10A3, "M", "ⴃ"), + (0x10A4, "M", "ⴄ"), + (0x10A5, "M", "ⴅ"), + (0x10A6, "M", "ⴆ"), + (0x10A7, "M", "ⴇ"), + (0x10A8, "M", "ⴈ"), + (0x10A9, "M", "ⴉ"), + (0x10AA, "M", "ⴊ"), + (0x10AB, "M", "ⴋ"), + (0x10AC, "M", "ⴌ"), + (0x10AD, "M", "ⴍ"), + (0x10AE, "M", "ⴎ"), + (0x10AF, "M", "ⴏ"), + (0x10B0, "M", "ⴐ"), + (0x10B1, "M", "ⴑ"), + (0x10B2, "M", "ⴒ"), + (0x10B3, "M", "ⴓ"), + (0x10B4, "M", "ⴔ"), + (0x10B5, "M", "ⴕ"), + (0x10B6, "M", "ⴖ"), + (0x10B7, "M", "ⴗ"), + (0x10B8, "M", "ⴘ"), + (0x10B9, "M", "ⴙ"), + (0x10BA, "M", "ⴚ"), + (0x10BB, "M", "ⴛ"), + (0x10BC, "M", "ⴜ"), + (0x10BD, "M", "ⴝ"), + (0x10BE, "M", "ⴞ"), + (0x10BF, "M", "ⴟ"), + (0x10C0, "M", "ⴠ"), + (0x10C1, "M", "ⴡ"), + (0x10C2, "M", "ⴢ"), + (0x10C3, "M", "ⴣ"), + (0x10C4, "M", "ⴤ"), + (0x10C5, "M", "ⴥ"), + ] + + +def _seg_14() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x10C6, "X"), + (0x10C7, "M", "ⴧ"), + (0x10C8, "X"), + (0x10CD, "M", "ⴭ"), + (0x10CE, "X"), + (0x10D0, "V"), + (0x10FC, "M", "ნ"), + (0x10FD, "V"), + (0x115F, "I"), + (0x1161, "V"), + (0x1249, "X"), + (0x124A, "V"), + (0x124E, "X"), + (0x1250, "V"), + (0x1257, "X"), + (0x1258, "V"), + (0x1259, "X"), + (0x125A, "V"), + (0x125E, "X"), + (0x1260, "V"), + (0x1289, "X"), + (0x128A, "V"), + (0x128E, "X"), + (0x1290, "V"), + (0x12B1, "X"), + (0x12B2, "V"), + (0x12B6, "X"), + (0x12B8, "V"), + (0x12BF, "X"), + (0x12C0, "V"), + (0x12C1, "X"), + (0x12C2, "V"), + (0x12C6, "X"), + (0x12C8, "V"), + (0x12D7, "X"), + (0x12D8, "V"), + (0x1311, "X"), + (0x1312, "V"), + (0x1316, "X"), + (0x1318, "V"), + (0x135B, "X"), + (0x135D, "V"), + (0x137D, "X"), + (0x1380, "V"), + (0x139A, "X"), + (0x13A0, "V"), + (0x13F6, "X"), + (0x13F8, "M", "Ᏸ"), + (0x13F9, "M", "Ᏹ"), + (0x13FA, "M", "Ᏺ"), + (0x13FB, "M", "Ᏻ"), + (0x13FC, "M", "Ᏼ"), + (0x13FD, "M", "Ᏽ"), + (0x13FE, "X"), + (0x1400, "V"), + (0x1680, "X"), + (0x1681, "V"), + (0x169D, "X"), + (0x16A0, "V"), + (0x16F9, "X"), + (0x1700, "V"), + (0x1716, "X"), + (0x171F, "V"), + (0x1737, "X"), + (0x1740, "V"), + (0x1754, "X"), + (0x1760, "V"), + (0x176D, "X"), + (0x176E, "V"), + (0x1771, "X"), + (0x1772, "V"), + (0x1774, "X"), + (0x1780, "V"), + (0x17B4, "I"), + (0x17B6, "V"), + (0x17DE, "X"), + (0x17E0, "V"), + (0x17EA, "X"), + (0x17F0, "V"), + (0x17FA, "X"), + (0x1800, "V"), + (0x180B, "I"), + (0x1810, "V"), + (0x181A, "X"), + (0x1820, "V"), + (0x1879, "X"), + (0x1880, "V"), + (0x18AB, "X"), + (0x18B0, "V"), + (0x18F6, "X"), + (0x1900, "V"), + (0x191F, "X"), + (0x1920, "V"), + (0x192C, "X"), + (0x1930, "V"), + (0x193C, "X"), + (0x1940, "V"), + (0x1941, "X"), + (0x1944, "V"), + (0x196E, "X"), + ] + + +def _seg_15() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1970, "V"), + (0x1975, "X"), + (0x1980, "V"), + (0x19AC, "X"), + (0x19B0, "V"), + (0x19CA, "X"), + (0x19D0, "V"), + (0x19DB, "X"), + (0x19DE, "V"), + (0x1A1C, "X"), + (0x1A1E, "V"), + (0x1A5F, "X"), + (0x1A60, "V"), + (0x1A7D, "X"), + (0x1A7F, "V"), + (0x1A8A, "X"), + (0x1A90, "V"), + (0x1A9A, "X"), + (0x1AA0, "V"), + (0x1AAE, "X"), + (0x1AB0, "V"), + (0x1ACF, "X"), + (0x1B00, "V"), + (0x1B4D, "X"), + (0x1B4E, "V"), + (0x1BF4, "X"), + (0x1BFC, "V"), + (0x1C38, "X"), + (0x1C3B, "V"), + (0x1C4A, "X"), + (0x1C4D, "V"), + (0x1C80, "M", "в"), + (0x1C81, "M", "д"), + (0x1C82, "M", "о"), + (0x1C83, "M", "с"), + (0x1C84, "M", "т"), + (0x1C86, "M", "ъ"), + (0x1C87, "M", "ѣ"), + (0x1C88, "M", "ꙋ"), + (0x1C89, "M", "ᲊ"), + (0x1C8A, "V"), + (0x1C8B, "X"), + (0x1C90, "M", "ა"), + (0x1C91, "M", "ბ"), + (0x1C92, "M", "გ"), + (0x1C93, "M", "დ"), + (0x1C94, "M", "ე"), + (0x1C95, "M", "ვ"), + (0x1C96, "M", "ზ"), + (0x1C97, "M", "თ"), + (0x1C98, "M", "ი"), + (0x1C99, "M", "კ"), + (0x1C9A, "M", "ლ"), + (0x1C9B, "M", "მ"), + (0x1C9C, "M", "ნ"), + (0x1C9D, "M", "ო"), + (0x1C9E, "M", "პ"), + (0x1C9F, "M", "ჟ"), + (0x1CA0, "M", "რ"), + (0x1CA1, "M", "ს"), + (0x1CA2, "M", "ტ"), + (0x1CA3, "M", "უ"), + (0x1CA4, "M", "ფ"), + (0x1CA5, "M", "ქ"), + (0x1CA6, "M", "ღ"), + (0x1CA7, "M", "ყ"), + (0x1CA8, "M", "შ"), + (0x1CA9, "M", "ჩ"), + (0x1CAA, "M", "ც"), + (0x1CAB, "M", "ძ"), + (0x1CAC, "M", "წ"), + (0x1CAD, "M", "ჭ"), + (0x1CAE, "M", "ხ"), + (0x1CAF, "M", "ჯ"), + (0x1CB0, "M", "ჰ"), + (0x1CB1, "M", "ჱ"), + (0x1CB2, "M", "ჲ"), + (0x1CB3, "M", "ჳ"), + (0x1CB4, "M", "ჴ"), + (0x1CB5, "M", "ჵ"), + (0x1CB6, "M", "ჶ"), + (0x1CB7, "M", "ჷ"), + (0x1CB8, "M", "ჸ"), + (0x1CB9, "M", "ჹ"), + (0x1CBA, "M", "ჺ"), + (0x1CBB, "X"), + (0x1CBD, "M", "ჽ"), + (0x1CBE, "M", "ჾ"), + (0x1CBF, "M", "ჿ"), + (0x1CC0, "V"), + (0x1CC8, "X"), + (0x1CD0, "V"), + (0x1CFB, "X"), + (0x1D00, "V"), + (0x1D2C, "M", "a"), + (0x1D2D, "M", "æ"), + (0x1D2E, "M", "b"), + (0x1D2F, "V"), + (0x1D30, "M", "d"), + (0x1D31, "M", "e"), + ] + + +def _seg_16() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D32, "M", "ǝ"), + (0x1D33, "M", "g"), + (0x1D34, "M", "h"), + (0x1D35, "M", "i"), + (0x1D36, "M", "j"), + (0x1D37, "M", "k"), + (0x1D38, "M", "l"), + (0x1D39, "M", "m"), + (0x1D3A, "M", "n"), + (0x1D3B, "V"), + (0x1D3C, "M", "o"), + (0x1D3D, "M", "ȣ"), + (0x1D3E, "M", "p"), + (0x1D3F, "M", "r"), + (0x1D40, "M", "t"), + (0x1D41, "M", "u"), + (0x1D42, "M", "w"), + (0x1D43, "M", "a"), + (0x1D44, "M", "ɐ"), + (0x1D45, "M", "ɑ"), + (0x1D46, "M", "ᴂ"), + (0x1D47, "M", "b"), + (0x1D48, "M", "d"), + (0x1D49, "M", "e"), + (0x1D4A, "M", "ə"), + (0x1D4B, "M", "ɛ"), + (0x1D4C, "M", "ɜ"), + (0x1D4D, "M", "g"), + (0x1D4E, "V"), + (0x1D4F, "M", "k"), + (0x1D50, "M", "m"), + (0x1D51, "M", "ŋ"), + (0x1D52, "M", "o"), + (0x1D53, "M", "ɔ"), + (0x1D54, "M", "ᴖ"), + (0x1D55, "M", "ᴗ"), + (0x1D56, "M", "p"), + (0x1D57, "M", "t"), + (0x1D58, "M", "u"), + (0x1D59, "M", "ᴝ"), + (0x1D5A, "M", "ɯ"), + (0x1D5B, "M", "v"), + (0x1D5C, "M", "ᴥ"), + (0x1D5D, "M", "β"), + (0x1D5E, "M", "γ"), + (0x1D5F, "M", "δ"), + (0x1D60, "M", "φ"), + (0x1D61, "M", "χ"), + (0x1D62, "M", "i"), + (0x1D63, "M", "r"), + (0x1D64, "M", "u"), + (0x1D65, "M", "v"), + (0x1D66, "M", "β"), + (0x1D67, "M", "γ"), + (0x1D68, "M", "ρ"), + (0x1D69, "M", "φ"), + (0x1D6A, "M", "χ"), + (0x1D6B, "V"), + (0x1D78, "M", "н"), + (0x1D79, "V"), + (0x1D9B, "M", "ɒ"), + (0x1D9C, "M", "c"), + (0x1D9D, "M", "ɕ"), + (0x1D9E, "M", "ð"), + (0x1D9F, "M", "ɜ"), + (0x1DA0, "M", "f"), + (0x1DA1, "M", "ɟ"), + (0x1DA2, "M", "ɡ"), + (0x1DA3, "M", "ɥ"), + (0x1DA4, "M", "ɨ"), + (0x1DA5, "M", "ɩ"), + (0x1DA6, "M", "ɪ"), + (0x1DA7, "M", "ᵻ"), + (0x1DA8, "M", "ʝ"), + (0x1DA9, "M", "ɭ"), + (0x1DAA, "M", "ᶅ"), + (0x1DAB, "M", "ʟ"), + (0x1DAC, "M", "ɱ"), + (0x1DAD, "M", "ɰ"), + (0x1DAE, "M", "ɲ"), + (0x1DAF, "M", "ɳ"), + (0x1DB0, "M", "ɴ"), + (0x1DB1, "M", "ɵ"), + (0x1DB2, "M", "ɸ"), + (0x1DB3, "M", "ʂ"), + (0x1DB4, "M", "ʃ"), + (0x1DB5, "M", "ƫ"), + (0x1DB6, "M", "ʉ"), + (0x1DB7, "M", "ʊ"), + (0x1DB8, "M", "ᴜ"), + (0x1DB9, "M", "ʋ"), + (0x1DBA, "M", "ʌ"), + (0x1DBB, "M", "z"), + (0x1DBC, "M", "ʐ"), + (0x1DBD, "M", "ʑ"), + (0x1DBE, "M", "ʒ"), + (0x1DBF, "M", "θ"), + (0x1DC0, "V"), + (0x1E00, "M", "ḁ"), + (0x1E01, "V"), + ] + + +def _seg_17() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E02, "M", "ḃ"), + (0x1E03, "V"), + (0x1E04, "M", "ḅ"), + (0x1E05, "V"), + (0x1E06, "M", "ḇ"), + (0x1E07, "V"), + (0x1E08, "M", "ḉ"), + (0x1E09, "V"), + (0x1E0A, "M", "ḋ"), + (0x1E0B, "V"), + (0x1E0C, "M", "ḍ"), + (0x1E0D, "V"), + (0x1E0E, "M", "ḏ"), + (0x1E0F, "V"), + (0x1E10, "M", "ḑ"), + (0x1E11, "V"), + (0x1E12, "M", "ḓ"), + (0x1E13, "V"), + (0x1E14, "M", "ḕ"), + (0x1E15, "V"), + (0x1E16, "M", "ḗ"), + (0x1E17, "V"), + (0x1E18, "M", "ḙ"), + (0x1E19, "V"), + (0x1E1A, "M", "ḛ"), + (0x1E1B, "V"), + (0x1E1C, "M", "ḝ"), + (0x1E1D, "V"), + (0x1E1E, "M", "ḟ"), + (0x1E1F, "V"), + (0x1E20, "M", "ḡ"), + (0x1E21, "V"), + (0x1E22, "M", "ḣ"), + (0x1E23, "V"), + (0x1E24, "M", "ḥ"), + (0x1E25, "V"), + (0x1E26, "M", "ḧ"), + (0x1E27, "V"), + (0x1E28, "M", "ḩ"), + (0x1E29, "V"), + (0x1E2A, "M", "ḫ"), + (0x1E2B, "V"), + (0x1E2C, "M", "ḭ"), + (0x1E2D, "V"), + (0x1E2E, "M", "ḯ"), + (0x1E2F, "V"), + (0x1E30, "M", "ḱ"), + (0x1E31, "V"), + (0x1E32, "M", "ḳ"), + (0x1E33, "V"), + (0x1E34, "M", "ḵ"), + (0x1E35, "V"), + (0x1E36, "M", "ḷ"), + (0x1E37, "V"), + (0x1E38, "M", "ḹ"), + (0x1E39, "V"), + (0x1E3A, "M", "ḻ"), + (0x1E3B, "V"), + (0x1E3C, "M", "ḽ"), + (0x1E3D, "V"), + (0x1E3E, "M", "ḿ"), + (0x1E3F, "V"), + (0x1E40, "M", "ṁ"), + (0x1E41, "V"), + (0x1E42, "M", "ṃ"), + (0x1E43, "V"), + (0x1E44, "M", "ṅ"), + (0x1E45, "V"), + (0x1E46, "M", "ṇ"), + (0x1E47, "V"), + (0x1E48, "M", "ṉ"), + (0x1E49, "V"), + (0x1E4A, "M", "ṋ"), + (0x1E4B, "V"), + (0x1E4C, "M", "ṍ"), + (0x1E4D, "V"), + (0x1E4E, "M", "ṏ"), + (0x1E4F, "V"), + (0x1E50, "M", "ṑ"), + (0x1E51, "V"), + (0x1E52, "M", "ṓ"), + (0x1E53, "V"), + (0x1E54, "M", "ṕ"), + (0x1E55, "V"), + (0x1E56, "M", "ṗ"), + (0x1E57, "V"), + (0x1E58, "M", "ṙ"), + (0x1E59, "V"), + (0x1E5A, "M", "ṛ"), + (0x1E5B, "V"), + (0x1E5C, "M", "ṝ"), + (0x1E5D, "V"), + (0x1E5E, "M", "ṟ"), + (0x1E5F, "V"), + (0x1E60, "M", "ṡ"), + (0x1E61, "V"), + (0x1E62, "M", "ṣ"), + (0x1E63, "V"), + (0x1E64, "M", "ṥ"), + (0x1E65, "V"), + ] + + +def _seg_18() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E66, "M", "ṧ"), + (0x1E67, "V"), + (0x1E68, "M", "ṩ"), + (0x1E69, "V"), + (0x1E6A, "M", "ṫ"), + (0x1E6B, "V"), + (0x1E6C, "M", "ṭ"), + (0x1E6D, "V"), + (0x1E6E, "M", "ṯ"), + (0x1E6F, "V"), + (0x1E70, "M", "ṱ"), + (0x1E71, "V"), + (0x1E72, "M", "ṳ"), + (0x1E73, "V"), + (0x1E74, "M", "ṵ"), + (0x1E75, "V"), + (0x1E76, "M", "ṷ"), + (0x1E77, "V"), + (0x1E78, "M", "ṹ"), + (0x1E79, "V"), + (0x1E7A, "M", "ṻ"), + (0x1E7B, "V"), + (0x1E7C, "M", "ṽ"), + (0x1E7D, "V"), + (0x1E7E, "M", "ṿ"), + (0x1E7F, "V"), + (0x1E80, "M", "ẁ"), + (0x1E81, "V"), + (0x1E82, "M", "ẃ"), + (0x1E83, "V"), + (0x1E84, "M", "ẅ"), + (0x1E85, "V"), + (0x1E86, "M", "ẇ"), + (0x1E87, "V"), + (0x1E88, "M", "ẉ"), + (0x1E89, "V"), + (0x1E8A, "M", "ẋ"), + (0x1E8B, "V"), + (0x1E8C, "M", "ẍ"), + (0x1E8D, "V"), + (0x1E8E, "M", "ẏ"), + (0x1E8F, "V"), + (0x1E90, "M", "ẑ"), + (0x1E91, "V"), + (0x1E92, "M", "ẓ"), + (0x1E93, "V"), + (0x1E94, "M", "ẕ"), + (0x1E95, "V"), + (0x1E9A, "M", "aʾ"), + (0x1E9B, "M", "ṡ"), + (0x1E9C, "V"), + (0x1E9E, "M", "ß"), + (0x1E9F, "V"), + (0x1EA0, "M", "ạ"), + (0x1EA1, "V"), + (0x1EA2, "M", "ả"), + (0x1EA3, "V"), + (0x1EA4, "M", "ấ"), + (0x1EA5, "V"), + (0x1EA6, "M", "ầ"), + (0x1EA7, "V"), + (0x1EA8, "M", "ẩ"), + (0x1EA9, "V"), + (0x1EAA, "M", "ẫ"), + (0x1EAB, "V"), + (0x1EAC, "M", "ậ"), + (0x1EAD, "V"), + (0x1EAE, "M", "ắ"), + (0x1EAF, "V"), + (0x1EB0, "M", "ằ"), + (0x1EB1, "V"), + (0x1EB2, "M", "ẳ"), + (0x1EB3, "V"), + (0x1EB4, "M", "ẵ"), + (0x1EB5, "V"), + (0x1EB6, "M", "ặ"), + (0x1EB7, "V"), + (0x1EB8, "M", "ẹ"), + (0x1EB9, "V"), + (0x1EBA, "M", "ẻ"), + (0x1EBB, "V"), + (0x1EBC, "M", "ẽ"), + (0x1EBD, "V"), + (0x1EBE, "M", "ế"), + (0x1EBF, "V"), + (0x1EC0, "M", "ề"), + (0x1EC1, "V"), + (0x1EC2, "M", "ể"), + (0x1EC3, "V"), + (0x1EC4, "M", "ễ"), + (0x1EC5, "V"), + (0x1EC6, "M", "ệ"), + (0x1EC7, "V"), + (0x1EC8, "M", "ỉ"), + (0x1EC9, "V"), + (0x1ECA, "M", "ị"), + (0x1ECB, "V"), + (0x1ECC, "M", "ọ"), + (0x1ECD, "V"), + (0x1ECE, "M", "ỏ"), + ] + + +def _seg_19() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1ECF, "V"), + (0x1ED0, "M", "ố"), + (0x1ED1, "V"), + (0x1ED2, "M", "ồ"), + (0x1ED3, "V"), + (0x1ED4, "M", "ổ"), + (0x1ED5, "V"), + (0x1ED6, "M", "ỗ"), + (0x1ED7, "V"), + (0x1ED8, "M", "ộ"), + (0x1ED9, "V"), + (0x1EDA, "M", "ớ"), + (0x1EDB, "V"), + (0x1EDC, "M", "ờ"), + (0x1EDD, "V"), + (0x1EDE, "M", "ở"), + (0x1EDF, "V"), + (0x1EE0, "M", "ỡ"), + (0x1EE1, "V"), + (0x1EE2, "M", "ợ"), + (0x1EE3, "V"), + (0x1EE4, "M", "ụ"), + (0x1EE5, "V"), + (0x1EE6, "M", "ủ"), + (0x1EE7, "V"), + (0x1EE8, "M", "ứ"), + (0x1EE9, "V"), + (0x1EEA, "M", "ừ"), + (0x1EEB, "V"), + (0x1EEC, "M", "ử"), + (0x1EED, "V"), + (0x1EEE, "M", "ữ"), + (0x1EEF, "V"), + (0x1EF0, "M", "ự"), + (0x1EF1, "V"), + (0x1EF2, "M", "ỳ"), + (0x1EF3, "V"), + (0x1EF4, "M", "ỵ"), + (0x1EF5, "V"), + (0x1EF6, "M", "ỷ"), + (0x1EF7, "V"), + (0x1EF8, "M", "ỹ"), + (0x1EF9, "V"), + (0x1EFA, "M", "ỻ"), + (0x1EFB, "V"), + (0x1EFC, "M", "ỽ"), + (0x1EFD, "V"), + (0x1EFE, "M", "ỿ"), + (0x1EFF, "V"), + (0x1F08, "M", "ἀ"), + (0x1F09, "M", "ἁ"), + (0x1F0A, "M", "ἂ"), + (0x1F0B, "M", "ἃ"), + (0x1F0C, "M", "ἄ"), + (0x1F0D, "M", "ἅ"), + (0x1F0E, "M", "ἆ"), + (0x1F0F, "M", "ἇ"), + (0x1F10, "V"), + (0x1F16, "X"), + (0x1F18, "M", "ἐ"), + (0x1F19, "M", "ἑ"), + (0x1F1A, "M", "ἒ"), + (0x1F1B, "M", "ἓ"), + (0x1F1C, "M", "ἔ"), + (0x1F1D, "M", "ἕ"), + (0x1F1E, "X"), + (0x1F20, "V"), + (0x1F28, "M", "ἠ"), + (0x1F29, "M", "ἡ"), + (0x1F2A, "M", "ἢ"), + (0x1F2B, "M", "ἣ"), + (0x1F2C, "M", "ἤ"), + (0x1F2D, "M", "ἥ"), + (0x1F2E, "M", "ἦ"), + (0x1F2F, "M", "ἧ"), + (0x1F30, "V"), + (0x1F38, "M", "ἰ"), + (0x1F39, "M", "ἱ"), + (0x1F3A, "M", "ἲ"), + (0x1F3B, "M", "ἳ"), + (0x1F3C, "M", "ἴ"), + (0x1F3D, "M", "ἵ"), + (0x1F3E, "M", "ἶ"), + (0x1F3F, "M", "ἷ"), + (0x1F40, "V"), + (0x1F46, "X"), + (0x1F48, "M", "ὀ"), + (0x1F49, "M", "ὁ"), + (0x1F4A, "M", "ὂ"), + (0x1F4B, "M", "ὃ"), + (0x1F4C, "M", "ὄ"), + (0x1F4D, "M", "ὅ"), + (0x1F4E, "X"), + (0x1F50, "V"), + (0x1F58, "X"), + (0x1F59, "M", "ὑ"), + (0x1F5A, "X"), + (0x1F5B, "M", "ὓ"), + (0x1F5C, "X"), + (0x1F5D, "M", "ὕ"), + ] + + +def _seg_20() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F5E, "X"), + (0x1F5F, "M", "ὗ"), + (0x1F60, "V"), + (0x1F68, "M", "ὠ"), + (0x1F69, "M", "ὡ"), + (0x1F6A, "M", "ὢ"), + (0x1F6B, "M", "ὣ"), + (0x1F6C, "M", "ὤ"), + (0x1F6D, "M", "ὥ"), + (0x1F6E, "M", "ὦ"), + (0x1F6F, "M", "ὧ"), + (0x1F70, "V"), + (0x1F71, "M", "ά"), + (0x1F72, "V"), + (0x1F73, "M", "έ"), + (0x1F74, "V"), + (0x1F75, "M", "ή"), + (0x1F76, "V"), + (0x1F77, "M", "ί"), + (0x1F78, "V"), + (0x1F79, "M", "ό"), + (0x1F7A, "V"), + (0x1F7B, "M", "ύ"), + (0x1F7C, "V"), + (0x1F7D, "M", "ώ"), + (0x1F7E, "X"), + (0x1F80, "M", "ἀι"), + (0x1F81, "M", "ἁι"), + (0x1F82, "M", "ἂι"), + (0x1F83, "M", "ἃι"), + (0x1F84, "M", "ἄι"), + (0x1F85, "M", "ἅι"), + (0x1F86, "M", "ἆι"), + (0x1F87, "M", "ἇι"), + (0x1F88, "M", "ἀι"), + (0x1F89, "M", "ἁι"), + (0x1F8A, "M", "ἂι"), + (0x1F8B, "M", "ἃι"), + (0x1F8C, "M", "ἄι"), + (0x1F8D, "M", "ἅι"), + (0x1F8E, "M", "ἆι"), + (0x1F8F, "M", "ἇι"), + (0x1F90, "M", "ἠι"), + (0x1F91, "M", "ἡι"), + (0x1F92, "M", "ἢι"), + (0x1F93, "M", "ἣι"), + (0x1F94, "M", "ἤι"), + (0x1F95, "M", "ἥι"), + (0x1F96, "M", "ἦι"), + (0x1F97, "M", "ἧι"), + (0x1F98, "M", "ἠι"), + (0x1F99, "M", "ἡι"), + (0x1F9A, "M", "ἢι"), + (0x1F9B, "M", "ἣι"), + (0x1F9C, "M", "ἤι"), + (0x1F9D, "M", "ἥι"), + (0x1F9E, "M", "ἦι"), + (0x1F9F, "M", "ἧι"), + (0x1FA0, "M", "ὠι"), + (0x1FA1, "M", "ὡι"), + (0x1FA2, "M", "ὢι"), + (0x1FA3, "M", "ὣι"), + (0x1FA4, "M", "ὤι"), + (0x1FA5, "M", "ὥι"), + (0x1FA6, "M", "ὦι"), + (0x1FA7, "M", "ὧι"), + (0x1FA8, "M", "ὠι"), + (0x1FA9, "M", "ὡι"), + (0x1FAA, "M", "ὢι"), + (0x1FAB, "M", "ὣι"), + (0x1FAC, "M", "ὤι"), + (0x1FAD, "M", "ὥι"), + (0x1FAE, "M", "ὦι"), + (0x1FAF, "M", "ὧι"), + (0x1FB0, "V"), + (0x1FB2, "M", "ὰι"), + (0x1FB3, "M", "αι"), + (0x1FB4, "M", "άι"), + (0x1FB5, "X"), + (0x1FB6, "V"), + (0x1FB7, "M", "ᾶι"), + (0x1FB8, "M", "ᾰ"), + (0x1FB9, "M", "ᾱ"), + (0x1FBA, "M", "ὰ"), + (0x1FBB, "M", "ά"), + (0x1FBC, "M", "αι"), + (0x1FBD, "M", " ̓"), + (0x1FBE, "M", "ι"), + (0x1FBF, "M", " ̓"), + (0x1FC0, "M", " ͂"), + (0x1FC1, "M", " ̈͂"), + (0x1FC2, "M", "ὴι"), + (0x1FC3, "M", "ηι"), + (0x1FC4, "M", "ήι"), + (0x1FC5, "X"), + (0x1FC6, "V"), + (0x1FC7, "M", "ῆι"), + (0x1FC8, "M", "ὲ"), + (0x1FC9, "M", "έ"), + (0x1FCA, "M", "ὴ"), + ] + + +def _seg_21() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1FCB, "M", "ή"), + (0x1FCC, "M", "ηι"), + (0x1FCD, "M", " ̓̀"), + (0x1FCE, "M", " ̓́"), + (0x1FCF, "M", " ̓͂"), + (0x1FD0, "V"), + (0x1FD3, "M", "ΐ"), + (0x1FD4, "X"), + (0x1FD6, "V"), + (0x1FD8, "M", "ῐ"), + (0x1FD9, "M", "ῑ"), + (0x1FDA, "M", "ὶ"), + (0x1FDB, "M", "ί"), + (0x1FDC, "X"), + (0x1FDD, "M", " ̔̀"), + (0x1FDE, "M", " ̔́"), + (0x1FDF, "M", " ̔͂"), + (0x1FE0, "V"), + (0x1FE3, "M", "ΰ"), + (0x1FE4, "V"), + (0x1FE8, "M", "ῠ"), + (0x1FE9, "M", "ῡ"), + (0x1FEA, "M", "ὺ"), + (0x1FEB, "M", "ύ"), + (0x1FEC, "M", "ῥ"), + (0x1FED, "M", " ̈̀"), + (0x1FEE, "M", " ̈́"), + (0x1FEF, "M", "`"), + (0x1FF0, "X"), + (0x1FF2, "M", "ὼι"), + (0x1FF3, "M", "ωι"), + (0x1FF4, "M", "ώι"), + (0x1FF5, "X"), + (0x1FF6, "V"), + (0x1FF7, "M", "ῶι"), + (0x1FF8, "M", "ὸ"), + (0x1FF9, "M", "ό"), + (0x1FFA, "M", "ὼ"), + (0x1FFB, "M", "ώ"), + (0x1FFC, "M", "ωι"), + (0x1FFD, "M", " ́"), + (0x1FFE, "M", " ̔"), + (0x1FFF, "X"), + (0x2000, "M", " "), + (0x200B, "I"), + (0x200C, "D", ""), + (0x200E, "X"), + (0x2010, "V"), + (0x2011, "M", "‐"), + (0x2012, "V"), + (0x2017, "M", " ̳"), + (0x2018, "V"), + (0x2024, "X"), + (0x2027, "V"), + (0x2028, "X"), + (0x202F, "M", " "), + (0x2030, "V"), + (0x2033, "M", "′′"), + (0x2034, "M", "′′′"), + (0x2035, "V"), + (0x2036, "M", "‵‵"), + (0x2037, "M", "‵‵‵"), + (0x2038, "V"), + (0x203C, "M", "!!"), + (0x203D, "V"), + (0x203E, "M", " ̅"), + (0x203F, "V"), + (0x2047, "M", "??"), + (0x2048, "M", "?!"), + (0x2049, "M", "!?"), + (0x204A, "V"), + (0x2057, "M", "′′′′"), + (0x2058, "V"), + (0x205F, "M", " "), + (0x2060, "I"), + (0x2065, "X"), + (0x206A, "I"), + (0x2070, "M", "0"), + (0x2071, "M", "i"), + (0x2072, "X"), + (0x2074, "M", "4"), + (0x2075, "M", "5"), + (0x2076, "M", "6"), + (0x2077, "M", "7"), + (0x2078, "M", "8"), + (0x2079, "M", "9"), + (0x207A, "M", "+"), + (0x207B, "M", "−"), + (0x207C, "M", "="), + (0x207D, "M", "("), + (0x207E, "M", ")"), + (0x207F, "M", "n"), + (0x2080, "M", "0"), + (0x2081, "M", "1"), + (0x2082, "M", "2"), + (0x2083, "M", "3"), + (0x2084, "M", "4"), + (0x2085, "M", "5"), + (0x2086, "M", "6"), + (0x2087, "M", "7"), + ] + + +def _seg_22() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2088, "M", "8"), + (0x2089, "M", "9"), + (0x208A, "M", "+"), + (0x208B, "M", "−"), + (0x208C, "M", "="), + (0x208D, "M", "("), + (0x208E, "M", ")"), + (0x208F, "X"), + (0x2090, "M", "a"), + (0x2091, "M", "e"), + (0x2092, "M", "o"), + (0x2093, "M", "x"), + (0x2094, "M", "ə"), + (0x2095, "M", "h"), + (0x2096, "M", "k"), + (0x2097, "M", "l"), + (0x2098, "M", "m"), + (0x2099, "M", "n"), + (0x209A, "M", "p"), + (0x209B, "M", "s"), + (0x209C, "M", "t"), + (0x209D, "X"), + (0x20A0, "V"), + (0x20A8, "M", "rs"), + (0x20A9, "V"), + (0x20C1, "X"), + (0x20D0, "V"), + (0x20F1, "X"), + (0x2100, "M", "a/c"), + (0x2101, "M", "a/s"), + (0x2102, "M", "c"), + (0x2103, "M", "°c"), + (0x2104, "V"), + (0x2105, "M", "c/o"), + (0x2106, "M", "c/u"), + (0x2107, "M", "ɛ"), + (0x2108, "V"), + (0x2109, "M", "°f"), + (0x210A, "M", "g"), + (0x210B, "M", "h"), + (0x210F, "M", "ħ"), + (0x2110, "M", "i"), + (0x2112, "M", "l"), + (0x2114, "V"), + (0x2115, "M", "n"), + (0x2116, "M", "no"), + (0x2117, "V"), + (0x2119, "M", "p"), + (0x211A, "M", "q"), + (0x211B, "M", "r"), + (0x211E, "V"), + (0x2120, "M", "sm"), + (0x2121, "M", "tel"), + (0x2122, "M", "tm"), + (0x2123, "V"), + (0x2124, "M", "z"), + (0x2125, "V"), + (0x2126, "M", "ω"), + (0x2127, "V"), + (0x2128, "M", "z"), + (0x2129, "V"), + (0x212A, "M", "k"), + (0x212B, "M", "å"), + (0x212C, "M", "b"), + (0x212D, "M", "c"), + (0x212E, "V"), + (0x212F, "M", "e"), + (0x2131, "M", "f"), + (0x2132, "M", "ⅎ"), + (0x2133, "M", "m"), + (0x2134, "M", "o"), + (0x2135, "M", "א"), + (0x2136, "M", "ב"), + (0x2137, "M", "ג"), + (0x2138, "M", "ד"), + (0x2139, "M", "i"), + (0x213A, "V"), + (0x213B, "M", "fax"), + (0x213C, "M", "π"), + (0x213D, "M", "γ"), + (0x213F, "M", "π"), + (0x2140, "M", "∑"), + (0x2141, "V"), + (0x2145, "M", "d"), + (0x2147, "M", "e"), + (0x2148, "M", "i"), + (0x2149, "M", "j"), + (0x214A, "V"), + (0x2150, "M", "1⁄7"), + (0x2151, "M", "1⁄9"), + (0x2152, "M", "1⁄10"), + (0x2153, "M", "1⁄3"), + (0x2154, "M", "2⁄3"), + (0x2155, "M", "1⁄5"), + (0x2156, "M", "2⁄5"), + (0x2157, "M", "3⁄5"), + (0x2158, "M", "4⁄5"), + (0x2159, "M", "1⁄6"), + (0x215A, "M", "5⁄6"), + (0x215B, "M", "1⁄8"), + ] + + +def _seg_23() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x215C, "M", "3⁄8"), + (0x215D, "M", "5⁄8"), + (0x215E, "M", "7⁄8"), + (0x215F, "M", "1⁄"), + (0x2160, "M", "i"), + (0x2161, "M", "ii"), + (0x2162, "M", "iii"), + (0x2163, "M", "iv"), + (0x2164, "M", "v"), + (0x2165, "M", "vi"), + (0x2166, "M", "vii"), + (0x2167, "M", "viii"), + (0x2168, "M", "ix"), + (0x2169, "M", "x"), + (0x216A, "M", "xi"), + (0x216B, "M", "xii"), + (0x216C, "M", "l"), + (0x216D, "M", "c"), + (0x216E, "M", "d"), + (0x216F, "M", "m"), + (0x2170, "M", "i"), + (0x2171, "M", "ii"), + (0x2172, "M", "iii"), + (0x2173, "M", "iv"), + (0x2174, "M", "v"), + (0x2175, "M", "vi"), + (0x2176, "M", "vii"), + (0x2177, "M", "viii"), + (0x2178, "M", "ix"), + (0x2179, "M", "x"), + (0x217A, "M", "xi"), + (0x217B, "M", "xii"), + (0x217C, "M", "l"), + (0x217D, "M", "c"), + (0x217E, "M", "d"), + (0x217F, "M", "m"), + (0x2180, "V"), + (0x2183, "M", "ↄ"), + (0x2184, "V"), + (0x2189, "M", "0⁄3"), + (0x218A, "V"), + (0x218C, "X"), + (0x2190, "V"), + (0x222C, "M", "∫∫"), + (0x222D, "M", "∫∫∫"), + (0x222E, "V"), + (0x222F, "M", "∮∮"), + (0x2230, "M", "∮∮∮"), + (0x2231, "V"), + (0x2329, "M", "〈"), + (0x232A, "M", "〉"), + (0x232B, "V"), + (0x242A, "X"), + (0x2440, "V"), + (0x244B, "X"), + (0x2460, "M", "1"), + (0x2461, "M", "2"), + (0x2462, "M", "3"), + (0x2463, "M", "4"), + (0x2464, "M", "5"), + (0x2465, "M", "6"), + (0x2466, "M", "7"), + (0x2467, "M", "8"), + (0x2468, "M", "9"), + (0x2469, "M", "10"), + (0x246A, "M", "11"), + (0x246B, "M", "12"), + (0x246C, "M", "13"), + (0x246D, "M", "14"), + (0x246E, "M", "15"), + (0x246F, "M", "16"), + (0x2470, "M", "17"), + (0x2471, "M", "18"), + (0x2472, "M", "19"), + (0x2473, "M", "20"), + (0x2474, "M", "(1)"), + (0x2475, "M", "(2)"), + (0x2476, "M", "(3)"), + (0x2477, "M", "(4)"), + (0x2478, "M", "(5)"), + (0x2479, "M", "(6)"), + (0x247A, "M", "(7)"), + (0x247B, "M", "(8)"), + (0x247C, "M", "(9)"), + (0x247D, "M", "(10)"), + (0x247E, "M", "(11)"), + (0x247F, "M", "(12)"), + (0x2480, "M", "(13)"), + (0x2481, "M", "(14)"), + (0x2482, "M", "(15)"), + (0x2483, "M", "(16)"), + (0x2484, "M", "(17)"), + (0x2485, "M", "(18)"), + (0x2486, "M", "(19)"), + (0x2487, "M", "(20)"), + (0x2488, "X"), + (0x249C, "M", "(a)"), + (0x249D, "M", "(b)"), + (0x249E, "M", "(c)"), + (0x249F, "M", "(d)"), + ] + + +def _seg_24() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x24A0, "M", "(e)"), + (0x24A1, "M", "(f)"), + (0x24A2, "M", "(g)"), + (0x24A3, "M", "(h)"), + (0x24A4, "M", "(i)"), + (0x24A5, "M", "(j)"), + (0x24A6, "M", "(k)"), + (0x24A7, "M", "(l)"), + (0x24A8, "M", "(m)"), + (0x24A9, "M", "(n)"), + (0x24AA, "M", "(o)"), + (0x24AB, "M", "(p)"), + (0x24AC, "M", "(q)"), + (0x24AD, "M", "(r)"), + (0x24AE, "M", "(s)"), + (0x24AF, "M", "(t)"), + (0x24B0, "M", "(u)"), + (0x24B1, "M", "(v)"), + (0x24B2, "M", "(w)"), + (0x24B3, "M", "(x)"), + (0x24B4, "M", "(y)"), + (0x24B5, "M", "(z)"), + (0x24B6, "M", "a"), + (0x24B7, "M", "b"), + (0x24B8, "M", "c"), + (0x24B9, "M", "d"), + (0x24BA, "M", "e"), + (0x24BB, "M", "f"), + (0x24BC, "M", "g"), + (0x24BD, "M", "h"), + (0x24BE, "M", "i"), + (0x24BF, "M", "j"), + (0x24C0, "M", "k"), + (0x24C1, "M", "l"), + (0x24C2, "M", "m"), + (0x24C3, "M", "n"), + (0x24C4, "M", "o"), + (0x24C5, "M", "p"), + (0x24C6, "M", "q"), + (0x24C7, "M", "r"), + (0x24C8, "M", "s"), + (0x24C9, "M", "t"), + (0x24CA, "M", "u"), + (0x24CB, "M", "v"), + (0x24CC, "M", "w"), + (0x24CD, "M", "x"), + (0x24CE, "M", "y"), + (0x24CF, "M", "z"), + (0x24D0, "M", "a"), + (0x24D1, "M", "b"), + (0x24D2, "M", "c"), + (0x24D3, "M", "d"), + (0x24D4, "M", "e"), + (0x24D5, "M", "f"), + (0x24D6, "M", "g"), + (0x24D7, "M", "h"), + (0x24D8, "M", "i"), + (0x24D9, "M", "j"), + (0x24DA, "M", "k"), + (0x24DB, "M", "l"), + (0x24DC, "M", "m"), + (0x24DD, "M", "n"), + (0x24DE, "M", "o"), + (0x24DF, "M", "p"), + (0x24E0, "M", "q"), + (0x24E1, "M", "r"), + (0x24E2, "M", "s"), + (0x24E3, "M", "t"), + (0x24E4, "M", "u"), + (0x24E5, "M", "v"), + (0x24E6, "M", "w"), + (0x24E7, "M", "x"), + (0x24E8, "M", "y"), + (0x24E9, "M", "z"), + (0x24EA, "M", "0"), + (0x24EB, "V"), + (0x2A0C, "M", "∫∫∫∫"), + (0x2A0D, "V"), + (0x2A74, "M", "::="), + (0x2A75, "M", "=="), + (0x2A76, "M", "==="), + (0x2A77, "V"), + (0x2ADC, "M", "⫝̸"), + (0x2ADD, "V"), + (0x2B74, "X"), + (0x2B76, "V"), + (0x2B96, "X"), + (0x2B97, "V"), + (0x2C00, "M", "ⰰ"), + (0x2C01, "M", "ⰱ"), + (0x2C02, "M", "ⰲ"), + (0x2C03, "M", "ⰳ"), + (0x2C04, "M", "ⰴ"), + (0x2C05, "M", "ⰵ"), + (0x2C06, "M", "ⰶ"), + (0x2C07, "M", "ⰷ"), + (0x2C08, "M", "ⰸ"), + (0x2C09, "M", "ⰹ"), + (0x2C0A, "M", "ⰺ"), + (0x2C0B, "M", "ⰻ"), + ] + + +def _seg_25() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2C0C, "M", "ⰼ"), + (0x2C0D, "M", "ⰽ"), + (0x2C0E, "M", "ⰾ"), + (0x2C0F, "M", "ⰿ"), + (0x2C10, "M", "ⱀ"), + (0x2C11, "M", "ⱁ"), + (0x2C12, "M", "ⱂ"), + (0x2C13, "M", "ⱃ"), + (0x2C14, "M", "ⱄ"), + (0x2C15, "M", "ⱅ"), + (0x2C16, "M", "ⱆ"), + (0x2C17, "M", "ⱇ"), + (0x2C18, "M", "ⱈ"), + (0x2C19, "M", "ⱉ"), + (0x2C1A, "M", "ⱊ"), + (0x2C1B, "M", "ⱋ"), + (0x2C1C, "M", "ⱌ"), + (0x2C1D, "M", "ⱍ"), + (0x2C1E, "M", "ⱎ"), + (0x2C1F, "M", "ⱏ"), + (0x2C20, "M", "ⱐ"), + (0x2C21, "M", "ⱑ"), + (0x2C22, "M", "ⱒ"), + (0x2C23, "M", "ⱓ"), + (0x2C24, "M", "ⱔ"), + (0x2C25, "M", "ⱕ"), + (0x2C26, "M", "ⱖ"), + (0x2C27, "M", "ⱗ"), + (0x2C28, "M", "ⱘ"), + (0x2C29, "M", "ⱙ"), + (0x2C2A, "M", "ⱚ"), + (0x2C2B, "M", "ⱛ"), + (0x2C2C, "M", "ⱜ"), + (0x2C2D, "M", "ⱝ"), + (0x2C2E, "M", "ⱞ"), + (0x2C2F, "M", "ⱟ"), + (0x2C30, "V"), + (0x2C60, "M", "ⱡ"), + (0x2C61, "V"), + (0x2C62, "M", "ɫ"), + (0x2C63, "M", "ᵽ"), + (0x2C64, "M", "ɽ"), + (0x2C65, "V"), + (0x2C67, "M", "ⱨ"), + (0x2C68, "V"), + (0x2C69, "M", "ⱪ"), + (0x2C6A, "V"), + (0x2C6B, "M", "ⱬ"), + (0x2C6C, "V"), + (0x2C6D, "M", "ɑ"), + (0x2C6E, "M", "ɱ"), + (0x2C6F, "M", "ɐ"), + (0x2C70, "M", "ɒ"), + (0x2C71, "V"), + (0x2C72, "M", "ⱳ"), + (0x2C73, "V"), + (0x2C75, "M", "ⱶ"), + (0x2C76, "V"), + (0x2C7C, "M", "j"), + (0x2C7D, "M", "v"), + (0x2C7E, "M", "ȿ"), + (0x2C7F, "M", "ɀ"), + (0x2C80, "M", "ⲁ"), + (0x2C81, "V"), + (0x2C82, "M", "ⲃ"), + (0x2C83, "V"), + (0x2C84, "M", "ⲅ"), + (0x2C85, "V"), + (0x2C86, "M", "ⲇ"), + (0x2C87, "V"), + (0x2C88, "M", "ⲉ"), + (0x2C89, "V"), + (0x2C8A, "M", "ⲋ"), + (0x2C8B, "V"), + (0x2C8C, "M", "ⲍ"), + (0x2C8D, "V"), + (0x2C8E, "M", "ⲏ"), + (0x2C8F, "V"), + (0x2C90, "M", "ⲑ"), + (0x2C91, "V"), + (0x2C92, "M", "ⲓ"), + (0x2C93, "V"), + (0x2C94, "M", "ⲕ"), + (0x2C95, "V"), + (0x2C96, "M", "ⲗ"), + (0x2C97, "V"), + (0x2C98, "M", "ⲙ"), + (0x2C99, "V"), + (0x2C9A, "M", "ⲛ"), + (0x2C9B, "V"), + (0x2C9C, "M", "ⲝ"), + (0x2C9D, "V"), + (0x2C9E, "M", "ⲟ"), + (0x2C9F, "V"), + (0x2CA0, "M", "ⲡ"), + (0x2CA1, "V"), + (0x2CA2, "M", "ⲣ"), + (0x2CA3, "V"), + (0x2CA4, "M", "ⲥ"), + (0x2CA5, "V"), + ] + + +def _seg_26() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2CA6, "M", "ⲧ"), + (0x2CA7, "V"), + (0x2CA8, "M", "ⲩ"), + (0x2CA9, "V"), + (0x2CAA, "M", "ⲫ"), + (0x2CAB, "V"), + (0x2CAC, "M", "ⲭ"), + (0x2CAD, "V"), + (0x2CAE, "M", "ⲯ"), + (0x2CAF, "V"), + (0x2CB0, "M", "ⲱ"), + (0x2CB1, "V"), + (0x2CB2, "M", "ⲳ"), + (0x2CB3, "V"), + (0x2CB4, "M", "ⲵ"), + (0x2CB5, "V"), + (0x2CB6, "M", "ⲷ"), + (0x2CB7, "V"), + (0x2CB8, "M", "ⲹ"), + (0x2CB9, "V"), + (0x2CBA, "M", "ⲻ"), + (0x2CBB, "V"), + (0x2CBC, "M", "ⲽ"), + (0x2CBD, "V"), + (0x2CBE, "M", "ⲿ"), + (0x2CBF, "V"), + (0x2CC0, "M", "ⳁ"), + (0x2CC1, "V"), + (0x2CC2, "M", "ⳃ"), + (0x2CC3, "V"), + (0x2CC4, "M", "ⳅ"), + (0x2CC5, "V"), + (0x2CC6, "M", "ⳇ"), + (0x2CC7, "V"), + (0x2CC8, "M", "ⳉ"), + (0x2CC9, "V"), + (0x2CCA, "M", "ⳋ"), + (0x2CCB, "V"), + (0x2CCC, "M", "ⳍ"), + (0x2CCD, "V"), + (0x2CCE, "M", "ⳏ"), + (0x2CCF, "V"), + (0x2CD0, "M", "ⳑ"), + (0x2CD1, "V"), + (0x2CD2, "M", "ⳓ"), + (0x2CD3, "V"), + (0x2CD4, "M", "ⳕ"), + (0x2CD5, "V"), + (0x2CD6, "M", "ⳗ"), + (0x2CD7, "V"), + (0x2CD8, "M", "ⳙ"), + (0x2CD9, "V"), + (0x2CDA, "M", "ⳛ"), + (0x2CDB, "V"), + (0x2CDC, "M", "ⳝ"), + (0x2CDD, "V"), + (0x2CDE, "M", "ⳟ"), + (0x2CDF, "V"), + (0x2CE0, "M", "ⳡ"), + (0x2CE1, "V"), + (0x2CE2, "M", "ⳣ"), + (0x2CE3, "V"), + (0x2CEB, "M", "ⳬ"), + (0x2CEC, "V"), + (0x2CED, "M", "ⳮ"), + (0x2CEE, "V"), + (0x2CF2, "M", "ⳳ"), + (0x2CF3, "V"), + (0x2CF4, "X"), + (0x2CF9, "V"), + (0x2D26, "X"), + (0x2D27, "V"), + (0x2D28, "X"), + (0x2D2D, "V"), + (0x2D2E, "X"), + (0x2D30, "V"), + (0x2D68, "X"), + (0x2D6F, "M", "ⵡ"), + (0x2D70, "V"), + (0x2D71, "X"), + (0x2D7F, "V"), + (0x2D97, "X"), + (0x2DA0, "V"), + (0x2DA7, "X"), + (0x2DA8, "V"), + (0x2DAF, "X"), + (0x2DB0, "V"), + (0x2DB7, "X"), + (0x2DB8, "V"), + (0x2DBF, "X"), + (0x2DC0, "V"), + (0x2DC7, "X"), + (0x2DC8, "V"), + (0x2DCF, "X"), + (0x2DD0, "V"), + (0x2DD7, "X"), + (0x2DD8, "V"), + (0x2DDF, "X"), + (0x2DE0, "V"), + (0x2E5E, "X"), + ] + + +def _seg_27() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2E80, "V"), + (0x2E9A, "X"), + (0x2E9B, "V"), + (0x2E9F, "M", "母"), + (0x2EA0, "V"), + (0x2EF3, "M", "龟"), + (0x2EF4, "X"), + (0x2F00, "M", "一"), + (0x2F01, "M", "丨"), + (0x2F02, "M", "丶"), + (0x2F03, "M", "丿"), + (0x2F04, "M", "乙"), + (0x2F05, "M", "亅"), + (0x2F06, "M", "二"), + (0x2F07, "M", "亠"), + (0x2F08, "M", "人"), + (0x2F09, "M", "儿"), + (0x2F0A, "M", "入"), + (0x2F0B, "M", "八"), + (0x2F0C, "M", "冂"), + (0x2F0D, "M", "冖"), + (0x2F0E, "M", "冫"), + (0x2F0F, "M", "几"), + (0x2F10, "M", "凵"), + (0x2F11, "M", "刀"), + (0x2F12, "M", "力"), + (0x2F13, "M", "勹"), + (0x2F14, "M", "匕"), + (0x2F15, "M", "匚"), + (0x2F16, "M", "匸"), + (0x2F17, "M", "十"), + (0x2F18, "M", "卜"), + (0x2F19, "M", "卩"), + (0x2F1A, "M", "厂"), + (0x2F1B, "M", "厶"), + (0x2F1C, "M", "又"), + (0x2F1D, "M", "口"), + (0x2F1E, "M", "囗"), + (0x2F1F, "M", "土"), + (0x2F20, "M", "士"), + (0x2F21, "M", "夂"), + (0x2F22, "M", "夊"), + (0x2F23, "M", "夕"), + (0x2F24, "M", "大"), + (0x2F25, "M", "女"), + (0x2F26, "M", "子"), + (0x2F27, "M", "宀"), + (0x2F28, "M", "寸"), + (0x2F29, "M", "小"), + (0x2F2A, "M", "尢"), + (0x2F2B, "M", "尸"), + (0x2F2C, "M", "屮"), + (0x2F2D, "M", "山"), + (0x2F2E, "M", "巛"), + (0x2F2F, "M", "工"), + (0x2F30, "M", "己"), + (0x2F31, "M", "巾"), + (0x2F32, "M", "干"), + (0x2F33, "M", "幺"), + (0x2F34, "M", "广"), + (0x2F35, "M", "廴"), + (0x2F36, "M", "廾"), + (0x2F37, "M", "弋"), + (0x2F38, "M", "弓"), + (0x2F39, "M", "彐"), + (0x2F3A, "M", "彡"), + (0x2F3B, "M", "彳"), + (0x2F3C, "M", "心"), + (0x2F3D, "M", "戈"), + (0x2F3E, "M", "戶"), + (0x2F3F, "M", "手"), + (0x2F40, "M", "支"), + (0x2F41, "M", "攴"), + (0x2F42, "M", "文"), + (0x2F43, "M", "斗"), + (0x2F44, "M", "斤"), + (0x2F45, "M", "方"), + (0x2F46, "M", "无"), + (0x2F47, "M", "日"), + (0x2F48, "M", "曰"), + (0x2F49, "M", "月"), + (0x2F4A, "M", "木"), + (0x2F4B, "M", "欠"), + (0x2F4C, "M", "止"), + (0x2F4D, "M", "歹"), + (0x2F4E, "M", "殳"), + (0x2F4F, "M", "毋"), + (0x2F50, "M", "比"), + (0x2F51, "M", "毛"), + (0x2F52, "M", "氏"), + (0x2F53, "M", "气"), + (0x2F54, "M", "水"), + (0x2F55, "M", "火"), + (0x2F56, "M", "爪"), + (0x2F57, "M", "父"), + (0x2F58, "M", "爻"), + (0x2F59, "M", "爿"), + (0x2F5A, "M", "片"), + (0x2F5B, "M", "牙"), + (0x2F5C, "M", "牛"), + ] + + +def _seg_28() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F5D, "M", "犬"), + (0x2F5E, "M", "玄"), + (0x2F5F, "M", "玉"), + (0x2F60, "M", "瓜"), + (0x2F61, "M", "瓦"), + (0x2F62, "M", "甘"), + (0x2F63, "M", "生"), + (0x2F64, "M", "用"), + (0x2F65, "M", "田"), + (0x2F66, "M", "疋"), + (0x2F67, "M", "疒"), + (0x2F68, "M", "癶"), + (0x2F69, "M", "白"), + (0x2F6A, "M", "皮"), + (0x2F6B, "M", "皿"), + (0x2F6C, "M", "目"), + (0x2F6D, "M", "矛"), + (0x2F6E, "M", "矢"), + (0x2F6F, "M", "石"), + (0x2F70, "M", "示"), + (0x2F71, "M", "禸"), + (0x2F72, "M", "禾"), + (0x2F73, "M", "穴"), + (0x2F74, "M", "立"), + (0x2F75, "M", "竹"), + (0x2F76, "M", "米"), + (0x2F77, "M", "糸"), + (0x2F78, "M", "缶"), + (0x2F79, "M", "网"), + (0x2F7A, "M", "羊"), + (0x2F7B, "M", "羽"), + (0x2F7C, "M", "老"), + (0x2F7D, "M", "而"), + (0x2F7E, "M", "耒"), + (0x2F7F, "M", "耳"), + (0x2F80, "M", "聿"), + (0x2F81, "M", "肉"), + (0x2F82, "M", "臣"), + (0x2F83, "M", "自"), + (0x2F84, "M", "至"), + (0x2F85, "M", "臼"), + (0x2F86, "M", "舌"), + (0x2F87, "M", "舛"), + (0x2F88, "M", "舟"), + (0x2F89, "M", "艮"), + (0x2F8A, "M", "色"), + (0x2F8B, "M", "艸"), + (0x2F8C, "M", "虍"), + (0x2F8D, "M", "虫"), + (0x2F8E, "M", "血"), + (0x2F8F, "M", "行"), + (0x2F90, "M", "衣"), + (0x2F91, "M", "襾"), + (0x2F92, "M", "見"), + (0x2F93, "M", "角"), + (0x2F94, "M", "言"), + (0x2F95, "M", "谷"), + (0x2F96, "M", "豆"), + (0x2F97, "M", "豕"), + (0x2F98, "M", "豸"), + (0x2F99, "M", "貝"), + (0x2F9A, "M", "赤"), + (0x2F9B, "M", "走"), + (0x2F9C, "M", "足"), + (0x2F9D, "M", "身"), + (0x2F9E, "M", "車"), + (0x2F9F, "M", "辛"), + (0x2FA0, "M", "辰"), + (0x2FA1, "M", "辵"), + (0x2FA2, "M", "邑"), + (0x2FA3, "M", "酉"), + (0x2FA4, "M", "釆"), + (0x2FA5, "M", "里"), + (0x2FA6, "M", "金"), + (0x2FA7, "M", "長"), + (0x2FA8, "M", "門"), + (0x2FA9, "M", "阜"), + (0x2FAA, "M", "隶"), + (0x2FAB, "M", "隹"), + (0x2FAC, "M", "雨"), + (0x2FAD, "M", "靑"), + (0x2FAE, "M", "非"), + (0x2FAF, "M", "面"), + (0x2FB0, "M", "革"), + (0x2FB1, "M", "韋"), + (0x2FB2, "M", "韭"), + (0x2FB3, "M", "音"), + (0x2FB4, "M", "頁"), + (0x2FB5, "M", "風"), + (0x2FB6, "M", "飛"), + (0x2FB7, "M", "食"), + (0x2FB8, "M", "首"), + (0x2FB9, "M", "香"), + (0x2FBA, "M", "馬"), + (0x2FBB, "M", "骨"), + (0x2FBC, "M", "高"), + (0x2FBD, "M", "髟"), + (0x2FBE, "M", "鬥"), + (0x2FBF, "M", "鬯"), + (0x2FC0, "M", "鬲"), + ] + + +def _seg_29() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2FC1, "M", "鬼"), + (0x2FC2, "M", "魚"), + (0x2FC3, "M", "鳥"), + (0x2FC4, "M", "鹵"), + (0x2FC5, "M", "鹿"), + (0x2FC6, "M", "麥"), + (0x2FC7, "M", "麻"), + (0x2FC8, "M", "黃"), + (0x2FC9, "M", "黍"), + (0x2FCA, "M", "黑"), + (0x2FCB, "M", "黹"), + (0x2FCC, "M", "黽"), + (0x2FCD, "M", "鼎"), + (0x2FCE, "M", "鼓"), + (0x2FCF, "M", "鼠"), + (0x2FD0, "M", "鼻"), + (0x2FD1, "M", "齊"), + (0x2FD2, "M", "齒"), + (0x2FD3, "M", "龍"), + (0x2FD4, "M", "龜"), + (0x2FD5, "M", "龠"), + (0x2FD6, "X"), + (0x3000, "M", " "), + (0x3001, "V"), + (0x3002, "M", "."), + (0x3003, "V"), + (0x3036, "M", "〒"), + (0x3037, "V"), + (0x3038, "M", "十"), + (0x3039, "M", "卄"), + (0x303A, "M", "卅"), + (0x303B, "V"), + (0x3040, "X"), + (0x3041, "V"), + (0x3097, "X"), + (0x3099, "V"), + (0x309B, "M", " ゙"), + (0x309C, "M", " ゚"), + (0x309D, "V"), + (0x309F, "M", "より"), + (0x30A0, "V"), + (0x30FF, "M", "コト"), + (0x3100, "X"), + (0x3105, "V"), + (0x3130, "X"), + (0x3131, "M", "ᄀ"), + (0x3132, "M", "ᄁ"), + (0x3133, "M", "ᆪ"), + (0x3134, "M", "ᄂ"), + (0x3135, "M", "ᆬ"), + (0x3136, "M", "ᆭ"), + (0x3137, "M", "ᄃ"), + (0x3138, "M", "ᄄ"), + (0x3139, "M", "ᄅ"), + (0x313A, "M", "ᆰ"), + (0x313B, "M", "ᆱ"), + (0x313C, "M", "ᆲ"), + (0x313D, "M", "ᆳ"), + (0x313E, "M", "ᆴ"), + (0x313F, "M", "ᆵ"), + (0x3140, "M", "ᄚ"), + (0x3141, "M", "ᄆ"), + (0x3142, "M", "ᄇ"), + (0x3143, "M", "ᄈ"), + (0x3144, "M", "ᄡ"), + (0x3145, "M", "ᄉ"), + (0x3146, "M", "ᄊ"), + (0x3147, "M", "ᄋ"), + (0x3148, "M", "ᄌ"), + (0x3149, "M", "ᄍ"), + (0x314A, "M", "ᄎ"), + (0x314B, "M", "ᄏ"), + (0x314C, "M", "ᄐ"), + (0x314D, "M", "ᄑ"), + (0x314E, "M", "ᄒ"), + (0x314F, "M", "ᅡ"), + (0x3150, "M", "ᅢ"), + (0x3151, "M", "ᅣ"), + (0x3152, "M", "ᅤ"), + (0x3153, "M", "ᅥ"), + (0x3154, "M", "ᅦ"), + (0x3155, "M", "ᅧ"), + (0x3156, "M", "ᅨ"), + (0x3157, "M", "ᅩ"), + (0x3158, "M", "ᅪ"), + (0x3159, "M", "ᅫ"), + (0x315A, "M", "ᅬ"), + (0x315B, "M", "ᅭ"), + (0x315C, "M", "ᅮ"), + (0x315D, "M", "ᅯ"), + (0x315E, "M", "ᅰ"), + (0x315F, "M", "ᅱ"), + (0x3160, "M", "ᅲ"), + (0x3161, "M", "ᅳ"), + (0x3162, "M", "ᅴ"), + (0x3163, "M", "ᅵ"), + (0x3164, "I"), + (0x3165, "M", "ᄔ"), + (0x3166, "M", "ᄕ"), + (0x3167, "M", "ᇇ"), + ] + + +def _seg_30() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3168, "M", "ᇈ"), + (0x3169, "M", "ᇌ"), + (0x316A, "M", "ᇎ"), + (0x316B, "M", "ᇓ"), + (0x316C, "M", "ᇗ"), + (0x316D, "M", "ᇙ"), + (0x316E, "M", "ᄜ"), + (0x316F, "M", "ᇝ"), + (0x3170, "M", "ᇟ"), + (0x3171, "M", "ᄝ"), + (0x3172, "M", "ᄞ"), + (0x3173, "M", "ᄠ"), + (0x3174, "M", "ᄢ"), + (0x3175, "M", "ᄣ"), + (0x3176, "M", "ᄧ"), + (0x3177, "M", "ᄩ"), + (0x3178, "M", "ᄫ"), + (0x3179, "M", "ᄬ"), + (0x317A, "M", "ᄭ"), + (0x317B, "M", "ᄮ"), + (0x317C, "M", "ᄯ"), + (0x317D, "M", "ᄲ"), + (0x317E, "M", "ᄶ"), + (0x317F, "M", "ᅀ"), + (0x3180, "M", "ᅇ"), + (0x3181, "M", "ᅌ"), + (0x3182, "M", "ᇱ"), + (0x3183, "M", "ᇲ"), + (0x3184, "M", "ᅗ"), + (0x3185, "M", "ᅘ"), + (0x3186, "M", "ᅙ"), + (0x3187, "M", "ᆄ"), + (0x3188, "M", "ᆅ"), + (0x3189, "M", "ᆈ"), + (0x318A, "M", "ᆑ"), + (0x318B, "M", "ᆒ"), + (0x318C, "M", "ᆔ"), + (0x318D, "M", "ᆞ"), + (0x318E, "M", "ᆡ"), + (0x318F, "X"), + (0x3190, "V"), + (0x3192, "M", "一"), + (0x3193, "M", "二"), + (0x3194, "M", "三"), + (0x3195, "M", "四"), + (0x3196, "M", "上"), + (0x3197, "M", "中"), + (0x3198, "M", "下"), + (0x3199, "M", "甲"), + (0x319A, "M", "乙"), + (0x319B, "M", "丙"), + (0x319C, "M", "丁"), + (0x319D, "M", "天"), + (0x319E, "M", "地"), + (0x319F, "M", "人"), + (0x31A0, "V"), + (0x31E6, "X"), + (0x31F0, "V"), + (0x3200, "M", "(ᄀ)"), + (0x3201, "M", "(ᄂ)"), + (0x3202, "M", "(ᄃ)"), + (0x3203, "M", "(ᄅ)"), + (0x3204, "M", "(ᄆ)"), + (0x3205, "M", "(ᄇ)"), + (0x3206, "M", "(ᄉ)"), + (0x3207, "M", "(ᄋ)"), + (0x3208, "M", "(ᄌ)"), + (0x3209, "M", "(ᄎ)"), + (0x320A, "M", "(ᄏ)"), + (0x320B, "M", "(ᄐ)"), + (0x320C, "M", "(ᄑ)"), + (0x320D, "M", "(ᄒ)"), + (0x320E, "M", "(가)"), + (0x320F, "M", "(나)"), + (0x3210, "M", "(다)"), + (0x3211, "M", "(라)"), + (0x3212, "M", "(마)"), + (0x3213, "M", "(바)"), + (0x3214, "M", "(사)"), + (0x3215, "M", "(아)"), + (0x3216, "M", "(자)"), + (0x3217, "M", "(차)"), + (0x3218, "M", "(카)"), + (0x3219, "M", "(타)"), + (0x321A, "M", "(파)"), + (0x321B, "M", "(하)"), + (0x321C, "M", "(주)"), + (0x321D, "M", "(오전)"), + (0x321E, "M", "(오후)"), + (0x321F, "X"), + (0x3220, "M", "(一)"), + (0x3221, "M", "(二)"), + (0x3222, "M", "(三)"), + (0x3223, "M", "(四)"), + (0x3224, "M", "(五)"), + (0x3225, "M", "(六)"), + (0x3226, "M", "(七)"), + (0x3227, "M", "(八)"), + (0x3228, "M", "(九)"), + (0x3229, "M", "(十)"), + ] + + +def _seg_31() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x322A, "M", "(月)"), + (0x322B, "M", "(火)"), + (0x322C, "M", "(水)"), + (0x322D, "M", "(木)"), + (0x322E, "M", "(金)"), + (0x322F, "M", "(土)"), + (0x3230, "M", "(日)"), + (0x3231, "M", "(株)"), + (0x3232, "M", "(有)"), + (0x3233, "M", "(社)"), + (0x3234, "M", "(名)"), + (0x3235, "M", "(特)"), + (0x3236, "M", "(財)"), + (0x3237, "M", "(祝)"), + (0x3238, "M", "(労)"), + (0x3239, "M", "(代)"), + (0x323A, "M", "(呼)"), + (0x323B, "M", "(学)"), + (0x323C, "M", "(監)"), + (0x323D, "M", "(企)"), + (0x323E, "M", "(資)"), + (0x323F, "M", "(協)"), + (0x3240, "M", "(祭)"), + (0x3241, "M", "(休)"), + (0x3242, "M", "(自)"), + (0x3243, "M", "(至)"), + (0x3244, "M", "問"), + (0x3245, "M", "幼"), + (0x3246, "M", "文"), + (0x3247, "M", "箏"), + (0x3248, "V"), + (0x3250, "M", "pte"), + (0x3251, "M", "21"), + (0x3252, "M", "22"), + (0x3253, "M", "23"), + (0x3254, "M", "24"), + (0x3255, "M", "25"), + (0x3256, "M", "26"), + (0x3257, "M", "27"), + (0x3258, "M", "28"), + (0x3259, "M", "29"), + (0x325A, "M", "30"), + (0x325B, "M", "31"), + (0x325C, "M", "32"), + (0x325D, "M", "33"), + (0x325E, "M", "34"), + (0x325F, "M", "35"), + (0x3260, "M", "ᄀ"), + (0x3261, "M", "ᄂ"), + (0x3262, "M", "ᄃ"), + (0x3263, "M", "ᄅ"), + (0x3264, "M", "ᄆ"), + (0x3265, "M", "ᄇ"), + (0x3266, "M", "ᄉ"), + (0x3267, "M", "ᄋ"), + (0x3268, "M", "ᄌ"), + (0x3269, "M", "ᄎ"), + (0x326A, "M", "ᄏ"), + (0x326B, "M", "ᄐ"), + (0x326C, "M", "ᄑ"), + (0x326D, "M", "ᄒ"), + (0x326E, "M", "가"), + (0x326F, "M", "나"), + (0x3270, "M", "다"), + (0x3271, "M", "라"), + (0x3272, "M", "마"), + (0x3273, "M", "바"), + (0x3274, "M", "사"), + (0x3275, "M", "아"), + (0x3276, "M", "자"), + (0x3277, "M", "차"), + (0x3278, "M", "카"), + (0x3279, "M", "타"), + (0x327A, "M", "파"), + (0x327B, "M", "하"), + (0x327C, "M", "참고"), + (0x327D, "M", "주의"), + (0x327E, "M", "우"), + (0x327F, "V"), + (0x3280, "M", "一"), + (0x3281, "M", "二"), + (0x3282, "M", "三"), + (0x3283, "M", "四"), + (0x3284, "M", "五"), + (0x3285, "M", "六"), + (0x3286, "M", "七"), + (0x3287, "M", "八"), + (0x3288, "M", "九"), + (0x3289, "M", "十"), + (0x328A, "M", "月"), + (0x328B, "M", "火"), + (0x328C, "M", "水"), + (0x328D, "M", "木"), + (0x328E, "M", "金"), + (0x328F, "M", "土"), + (0x3290, "M", "日"), + (0x3291, "M", "株"), + (0x3292, "M", "有"), + (0x3293, "M", "社"), + (0x3294, "M", "名"), + ] + + +def _seg_32() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3295, "M", "特"), + (0x3296, "M", "財"), + (0x3297, "M", "祝"), + (0x3298, "M", "労"), + (0x3299, "M", "秘"), + (0x329A, "M", "男"), + (0x329B, "M", "女"), + (0x329C, "M", "適"), + (0x329D, "M", "優"), + (0x329E, "M", "印"), + (0x329F, "M", "注"), + (0x32A0, "M", "項"), + (0x32A1, "M", "休"), + (0x32A2, "M", "写"), + (0x32A3, "M", "正"), + (0x32A4, "M", "上"), + (0x32A5, "M", "中"), + (0x32A6, "M", "下"), + (0x32A7, "M", "左"), + (0x32A8, "M", "右"), + (0x32A9, "M", "医"), + (0x32AA, "M", "宗"), + (0x32AB, "M", "学"), + (0x32AC, "M", "監"), + (0x32AD, "M", "企"), + (0x32AE, "M", "資"), + (0x32AF, "M", "協"), + (0x32B0, "M", "夜"), + (0x32B1, "M", "36"), + (0x32B2, "M", "37"), + (0x32B3, "M", "38"), + (0x32B4, "M", "39"), + (0x32B5, "M", "40"), + (0x32B6, "M", "41"), + (0x32B7, "M", "42"), + (0x32B8, "M", "43"), + (0x32B9, "M", "44"), + (0x32BA, "M", "45"), + (0x32BB, "M", "46"), + (0x32BC, "M", "47"), + (0x32BD, "M", "48"), + (0x32BE, "M", "49"), + (0x32BF, "M", "50"), + (0x32C0, "M", "1月"), + (0x32C1, "M", "2月"), + (0x32C2, "M", "3月"), + (0x32C3, "M", "4月"), + (0x32C4, "M", "5月"), + (0x32C5, "M", "6月"), + (0x32C6, "M", "7月"), + (0x32C7, "M", "8月"), + (0x32C8, "M", "9月"), + (0x32C9, "M", "10月"), + (0x32CA, "M", "11月"), + (0x32CB, "M", "12月"), + (0x32CC, "M", "hg"), + (0x32CD, "M", "erg"), + (0x32CE, "M", "ev"), + (0x32CF, "M", "ltd"), + (0x32D0, "M", "ア"), + (0x32D1, "M", "イ"), + (0x32D2, "M", "ウ"), + (0x32D3, "M", "エ"), + (0x32D4, "M", "オ"), + (0x32D5, "M", "カ"), + (0x32D6, "M", "キ"), + (0x32D7, "M", "ク"), + (0x32D8, "M", "ケ"), + (0x32D9, "M", "コ"), + (0x32DA, "M", "サ"), + (0x32DB, "M", "シ"), + (0x32DC, "M", "ス"), + (0x32DD, "M", "セ"), + (0x32DE, "M", "ソ"), + (0x32DF, "M", "タ"), + (0x32E0, "M", "チ"), + (0x32E1, "M", "ツ"), + (0x32E2, "M", "テ"), + (0x32E3, "M", "ト"), + (0x32E4, "M", "ナ"), + (0x32E5, "M", "ニ"), + (0x32E6, "M", "ヌ"), + (0x32E7, "M", "ネ"), + (0x32E8, "M", "ノ"), + (0x32E9, "M", "ハ"), + (0x32EA, "M", "ヒ"), + (0x32EB, "M", "フ"), + (0x32EC, "M", "ヘ"), + (0x32ED, "M", "ホ"), + (0x32EE, "M", "マ"), + (0x32EF, "M", "ミ"), + (0x32F0, "M", "ム"), + (0x32F1, "M", "メ"), + (0x32F2, "M", "モ"), + (0x32F3, "M", "ヤ"), + (0x32F4, "M", "ユ"), + (0x32F5, "M", "ヨ"), + (0x32F6, "M", "ラ"), + (0x32F7, "M", "リ"), + (0x32F8, "M", "ル"), + ] + + +def _seg_33() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x32F9, "M", "レ"), + (0x32FA, "M", "ロ"), + (0x32FB, "M", "ワ"), + (0x32FC, "M", "ヰ"), + (0x32FD, "M", "ヱ"), + (0x32FE, "M", "ヲ"), + (0x32FF, "M", "令和"), + (0x3300, "M", "アパート"), + (0x3301, "M", "アルファ"), + (0x3302, "M", "アンペア"), + (0x3303, "M", "アール"), + (0x3304, "M", "イニング"), + (0x3305, "M", "インチ"), + (0x3306, "M", "ウォン"), + (0x3307, "M", "エスクード"), + (0x3308, "M", "エーカー"), + (0x3309, "M", "オンス"), + (0x330A, "M", "オーム"), + (0x330B, "M", "カイリ"), + (0x330C, "M", "カラット"), + (0x330D, "M", "カロリー"), + (0x330E, "M", "ガロン"), + (0x330F, "M", "ガンマ"), + (0x3310, "M", "ギガ"), + (0x3311, "M", "ギニー"), + (0x3312, "M", "キュリー"), + (0x3313, "M", "ギルダー"), + (0x3314, "M", "キロ"), + (0x3315, "M", "キログラム"), + (0x3316, "M", "キロメートル"), + (0x3317, "M", "キロワット"), + (0x3318, "M", "グラム"), + (0x3319, "M", "グラムトン"), + (0x331A, "M", "クルゼイロ"), + (0x331B, "M", "クローネ"), + (0x331C, "M", "ケース"), + (0x331D, "M", "コルナ"), + (0x331E, "M", "コーポ"), + (0x331F, "M", "サイクル"), + (0x3320, "M", "サンチーム"), + (0x3321, "M", "シリング"), + (0x3322, "M", "センチ"), + (0x3323, "M", "セント"), + (0x3324, "M", "ダース"), + (0x3325, "M", "デシ"), + (0x3326, "M", "ドル"), + (0x3327, "M", "トン"), + (0x3328, "M", "ナノ"), + (0x3329, "M", "ノット"), + (0x332A, "M", "ハイツ"), + (0x332B, "M", "パーセント"), + (0x332C, "M", "パーツ"), + (0x332D, "M", "バーレル"), + (0x332E, "M", "ピアストル"), + (0x332F, "M", "ピクル"), + (0x3330, "M", "ピコ"), + (0x3331, "M", "ビル"), + (0x3332, "M", "ファラッド"), + (0x3333, "M", "フィート"), + (0x3334, "M", "ブッシェル"), + (0x3335, "M", "フラン"), + (0x3336, "M", "ヘクタール"), + (0x3337, "M", "ペソ"), + (0x3338, "M", "ペニヒ"), + (0x3339, "M", "ヘルツ"), + (0x333A, "M", "ペンス"), + (0x333B, "M", "ページ"), + (0x333C, "M", "ベータ"), + (0x333D, "M", "ポイント"), + (0x333E, "M", "ボルト"), + (0x333F, "M", "ホン"), + (0x3340, "M", "ポンド"), + (0x3341, "M", "ホール"), + (0x3342, "M", "ホーン"), + (0x3343, "M", "マイクロ"), + (0x3344, "M", "マイル"), + (0x3345, "M", "マッハ"), + (0x3346, "M", "マルク"), + (0x3347, "M", "マンション"), + (0x3348, "M", "ミクロン"), + (0x3349, "M", "ミリ"), + (0x334A, "M", "ミリバール"), + (0x334B, "M", "メガ"), + (0x334C, "M", "メガトン"), + (0x334D, "M", "メートル"), + (0x334E, "M", "ヤード"), + (0x334F, "M", "ヤール"), + (0x3350, "M", "ユアン"), + (0x3351, "M", "リットル"), + (0x3352, "M", "リラ"), + (0x3353, "M", "ルピー"), + (0x3354, "M", "ルーブル"), + (0x3355, "M", "レム"), + (0x3356, "M", "レントゲン"), + (0x3357, "M", "ワット"), + (0x3358, "M", "0点"), + (0x3359, "M", "1点"), + (0x335A, "M", "2点"), + (0x335B, "M", "3点"), + (0x335C, "M", "4点"), + ] + + +def _seg_34() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x335D, "M", "5点"), + (0x335E, "M", "6点"), + (0x335F, "M", "7点"), + (0x3360, "M", "8点"), + (0x3361, "M", "9点"), + (0x3362, "M", "10点"), + (0x3363, "M", "11点"), + (0x3364, "M", "12点"), + (0x3365, "M", "13点"), + (0x3366, "M", "14点"), + (0x3367, "M", "15点"), + (0x3368, "M", "16点"), + (0x3369, "M", "17点"), + (0x336A, "M", "18点"), + (0x336B, "M", "19点"), + (0x336C, "M", "20点"), + (0x336D, "M", "21点"), + (0x336E, "M", "22点"), + (0x336F, "M", "23点"), + (0x3370, "M", "24点"), + (0x3371, "M", "hpa"), + (0x3372, "M", "da"), + (0x3373, "M", "au"), + (0x3374, "M", "bar"), + (0x3375, "M", "ov"), + (0x3376, "M", "pc"), + (0x3377, "M", "dm"), + (0x3378, "M", "dm2"), + (0x3379, "M", "dm3"), + (0x337A, "M", "iu"), + (0x337B, "M", "平成"), + (0x337C, "M", "昭和"), + (0x337D, "M", "大正"), + (0x337E, "M", "明治"), + (0x337F, "M", "株式会社"), + (0x3380, "M", "pa"), + (0x3381, "M", "na"), + (0x3382, "M", "μa"), + (0x3383, "M", "ma"), + (0x3384, "M", "ka"), + (0x3385, "M", "kb"), + (0x3386, "M", "mb"), + (0x3387, "M", "gb"), + (0x3388, "M", "cal"), + (0x3389, "M", "kcal"), + (0x338A, "M", "pf"), + (0x338B, "M", "nf"), + (0x338C, "M", "μf"), + (0x338D, "M", "μg"), + (0x338E, "M", "mg"), + (0x338F, "M", "kg"), + (0x3390, "M", "hz"), + (0x3391, "M", "khz"), + (0x3392, "M", "mhz"), + (0x3393, "M", "ghz"), + (0x3394, "M", "thz"), + (0x3395, "M", "μl"), + (0x3396, "M", "ml"), + (0x3397, "M", "dl"), + (0x3398, "M", "kl"), + (0x3399, "M", "fm"), + (0x339A, "M", "nm"), + (0x339B, "M", "μm"), + (0x339C, "M", "mm"), + (0x339D, "M", "cm"), + (0x339E, "M", "km"), + (0x339F, "M", "mm2"), + (0x33A0, "M", "cm2"), + (0x33A1, "M", "m2"), + (0x33A2, "M", "km2"), + (0x33A3, "M", "mm3"), + (0x33A4, "M", "cm3"), + (0x33A5, "M", "m3"), + (0x33A6, "M", "km3"), + (0x33A7, "M", "m∕s"), + (0x33A8, "M", "m∕s2"), + (0x33A9, "M", "pa"), + (0x33AA, "M", "kpa"), + (0x33AB, "M", "mpa"), + (0x33AC, "M", "gpa"), + (0x33AD, "M", "rad"), + (0x33AE, "M", "rad∕s"), + (0x33AF, "M", "rad∕s2"), + (0x33B0, "M", "ps"), + (0x33B1, "M", "ns"), + (0x33B2, "M", "μs"), + (0x33B3, "M", "ms"), + (0x33B4, "M", "pv"), + (0x33B5, "M", "nv"), + (0x33B6, "M", "μv"), + (0x33B7, "M", "mv"), + (0x33B8, "M", "kv"), + (0x33B9, "M", "mv"), + (0x33BA, "M", "pw"), + (0x33BB, "M", "nw"), + (0x33BC, "M", "μw"), + (0x33BD, "M", "mw"), + (0x33BE, "M", "kw"), + (0x33BF, "M", "mw"), + (0x33C0, "M", "kω"), + ] + + +def _seg_35() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x33C1, "M", "mω"), + (0x33C2, "X"), + (0x33C3, "M", "bq"), + (0x33C4, "M", "cc"), + (0x33C5, "M", "cd"), + (0x33C6, "M", "c∕kg"), + (0x33C7, "X"), + (0x33C8, "M", "db"), + (0x33C9, "M", "gy"), + (0x33CA, "M", "ha"), + (0x33CB, "M", "hp"), + (0x33CC, "M", "in"), + (0x33CD, "M", "kk"), + (0x33CE, "M", "km"), + (0x33CF, "M", "kt"), + (0x33D0, "M", "lm"), + (0x33D1, "M", "ln"), + (0x33D2, "M", "log"), + (0x33D3, "M", "lx"), + (0x33D4, "M", "mb"), + (0x33D5, "M", "mil"), + (0x33D6, "M", "mol"), + (0x33D7, "M", "ph"), + (0x33D8, "X"), + (0x33D9, "M", "ppm"), + (0x33DA, "M", "pr"), + (0x33DB, "M", "sr"), + (0x33DC, "M", "sv"), + (0x33DD, "M", "wb"), + (0x33DE, "M", "v∕m"), + (0x33DF, "M", "a∕m"), + (0x33E0, "M", "1日"), + (0x33E1, "M", "2日"), + (0x33E2, "M", "3日"), + (0x33E3, "M", "4日"), + (0x33E4, "M", "5日"), + (0x33E5, "M", "6日"), + (0x33E6, "M", "7日"), + (0x33E7, "M", "8日"), + (0x33E8, "M", "9日"), + (0x33E9, "M", "10日"), + (0x33EA, "M", "11日"), + (0x33EB, "M", "12日"), + (0x33EC, "M", "13日"), + (0x33ED, "M", "14日"), + (0x33EE, "M", "15日"), + (0x33EF, "M", "16日"), + (0x33F0, "M", "17日"), + (0x33F1, "M", "18日"), + (0x33F2, "M", "19日"), + (0x33F3, "M", "20日"), + (0x33F4, "M", "21日"), + (0x33F5, "M", "22日"), + (0x33F6, "M", "23日"), + (0x33F7, "M", "24日"), + (0x33F8, "M", "25日"), + (0x33F9, "M", "26日"), + (0x33FA, "M", "27日"), + (0x33FB, "M", "28日"), + (0x33FC, "M", "29日"), + (0x33FD, "M", "30日"), + (0x33FE, "M", "31日"), + (0x33FF, "M", "gal"), + (0x3400, "V"), + (0xA48D, "X"), + (0xA490, "V"), + (0xA4C7, "X"), + (0xA4D0, "V"), + (0xA62C, "X"), + (0xA640, "M", "ꙁ"), + (0xA641, "V"), + (0xA642, "M", "ꙃ"), + (0xA643, "V"), + (0xA644, "M", "ꙅ"), + (0xA645, "V"), + (0xA646, "M", "ꙇ"), + (0xA647, "V"), + (0xA648, "M", "ꙉ"), + (0xA649, "V"), + (0xA64A, "M", "ꙋ"), + (0xA64B, "V"), + (0xA64C, "M", "ꙍ"), + (0xA64D, "V"), + (0xA64E, "M", "ꙏ"), + (0xA64F, "V"), + (0xA650, "M", "ꙑ"), + (0xA651, "V"), + (0xA652, "M", "ꙓ"), + (0xA653, "V"), + (0xA654, "M", "ꙕ"), + (0xA655, "V"), + (0xA656, "M", "ꙗ"), + (0xA657, "V"), + (0xA658, "M", "ꙙ"), + (0xA659, "V"), + (0xA65A, "M", "ꙛ"), + (0xA65B, "V"), + (0xA65C, "M", "ꙝ"), + (0xA65D, "V"), + (0xA65E, "M", "ꙟ"), + ] + + +def _seg_36() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA65F, "V"), + (0xA660, "M", "ꙡ"), + (0xA661, "V"), + (0xA662, "M", "ꙣ"), + (0xA663, "V"), + (0xA664, "M", "ꙥ"), + (0xA665, "V"), + (0xA666, "M", "ꙧ"), + (0xA667, "V"), + (0xA668, "M", "ꙩ"), + (0xA669, "V"), + (0xA66A, "M", "ꙫ"), + (0xA66B, "V"), + (0xA66C, "M", "ꙭ"), + (0xA66D, "V"), + (0xA680, "M", "ꚁ"), + (0xA681, "V"), + (0xA682, "M", "ꚃ"), + (0xA683, "V"), + (0xA684, "M", "ꚅ"), + (0xA685, "V"), + (0xA686, "M", "ꚇ"), + (0xA687, "V"), + (0xA688, "M", "ꚉ"), + (0xA689, "V"), + (0xA68A, "M", "ꚋ"), + (0xA68B, "V"), + (0xA68C, "M", "ꚍ"), + (0xA68D, "V"), + (0xA68E, "M", "ꚏ"), + (0xA68F, "V"), + (0xA690, "M", "ꚑ"), + (0xA691, "V"), + (0xA692, "M", "ꚓ"), + (0xA693, "V"), + (0xA694, "M", "ꚕ"), + (0xA695, "V"), + (0xA696, "M", "ꚗ"), + (0xA697, "V"), + (0xA698, "M", "ꚙ"), + (0xA699, "V"), + (0xA69A, "M", "ꚛ"), + (0xA69B, "V"), + (0xA69C, "M", "ъ"), + (0xA69D, "M", "ь"), + (0xA69E, "V"), + (0xA6F8, "X"), + (0xA700, "V"), + (0xA722, "M", "ꜣ"), + (0xA723, "V"), + (0xA724, "M", "ꜥ"), + (0xA725, "V"), + (0xA726, "M", "ꜧ"), + (0xA727, "V"), + (0xA728, "M", "ꜩ"), + (0xA729, "V"), + (0xA72A, "M", "ꜫ"), + (0xA72B, "V"), + (0xA72C, "M", "ꜭ"), + (0xA72D, "V"), + (0xA72E, "M", "ꜯ"), + (0xA72F, "V"), + (0xA732, "M", "ꜳ"), + (0xA733, "V"), + (0xA734, "M", "ꜵ"), + (0xA735, "V"), + (0xA736, "M", "ꜷ"), + (0xA737, "V"), + (0xA738, "M", "ꜹ"), + (0xA739, "V"), + (0xA73A, "M", "ꜻ"), + (0xA73B, "V"), + (0xA73C, "M", "ꜽ"), + (0xA73D, "V"), + (0xA73E, "M", "ꜿ"), + (0xA73F, "V"), + (0xA740, "M", "ꝁ"), + (0xA741, "V"), + (0xA742, "M", "ꝃ"), + (0xA743, "V"), + (0xA744, "M", "ꝅ"), + (0xA745, "V"), + (0xA746, "M", "ꝇ"), + (0xA747, "V"), + (0xA748, "M", "ꝉ"), + (0xA749, "V"), + (0xA74A, "M", "ꝋ"), + (0xA74B, "V"), + (0xA74C, "M", "ꝍ"), + (0xA74D, "V"), + (0xA74E, "M", "ꝏ"), + (0xA74F, "V"), + (0xA750, "M", "ꝑ"), + (0xA751, "V"), + (0xA752, "M", "ꝓ"), + (0xA753, "V"), + (0xA754, "M", "ꝕ"), + (0xA755, "V"), + (0xA756, "M", "ꝗ"), + (0xA757, "V"), + ] + + +def _seg_37() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA758, "M", "ꝙ"), + (0xA759, "V"), + (0xA75A, "M", "ꝛ"), + (0xA75B, "V"), + (0xA75C, "M", "ꝝ"), + (0xA75D, "V"), + (0xA75E, "M", "ꝟ"), + (0xA75F, "V"), + (0xA760, "M", "ꝡ"), + (0xA761, "V"), + (0xA762, "M", "ꝣ"), + (0xA763, "V"), + (0xA764, "M", "ꝥ"), + (0xA765, "V"), + (0xA766, "M", "ꝧ"), + (0xA767, "V"), + (0xA768, "M", "ꝩ"), + (0xA769, "V"), + (0xA76A, "M", "ꝫ"), + (0xA76B, "V"), + (0xA76C, "M", "ꝭ"), + (0xA76D, "V"), + (0xA76E, "M", "ꝯ"), + (0xA76F, "V"), + (0xA770, "M", "ꝯ"), + (0xA771, "V"), + (0xA779, "M", "ꝺ"), + (0xA77A, "V"), + (0xA77B, "M", "ꝼ"), + (0xA77C, "V"), + (0xA77D, "M", "ᵹ"), + (0xA77E, "M", "ꝿ"), + (0xA77F, "V"), + (0xA780, "M", "ꞁ"), + (0xA781, "V"), + (0xA782, "M", "ꞃ"), + (0xA783, "V"), + (0xA784, "M", "ꞅ"), + (0xA785, "V"), + (0xA786, "M", "ꞇ"), + (0xA787, "V"), + (0xA78B, "M", "ꞌ"), + (0xA78C, "V"), + (0xA78D, "M", "ɥ"), + (0xA78E, "V"), + (0xA790, "M", "ꞑ"), + (0xA791, "V"), + (0xA792, "M", "ꞓ"), + (0xA793, "V"), + (0xA796, "M", "ꞗ"), + (0xA797, "V"), + (0xA798, "M", "ꞙ"), + (0xA799, "V"), + (0xA79A, "M", "ꞛ"), + (0xA79B, "V"), + (0xA79C, "M", "ꞝ"), + (0xA79D, "V"), + (0xA79E, "M", "ꞟ"), + (0xA79F, "V"), + (0xA7A0, "M", "ꞡ"), + (0xA7A1, "V"), + (0xA7A2, "M", "ꞣ"), + (0xA7A3, "V"), + (0xA7A4, "M", "ꞥ"), + (0xA7A5, "V"), + (0xA7A6, "M", "ꞧ"), + (0xA7A7, "V"), + (0xA7A8, "M", "ꞩ"), + (0xA7A9, "V"), + (0xA7AA, "M", "ɦ"), + (0xA7AB, "M", "ɜ"), + (0xA7AC, "M", "ɡ"), + (0xA7AD, "M", "ɬ"), + (0xA7AE, "M", "ɪ"), + (0xA7AF, "V"), + (0xA7B0, "M", "ʞ"), + (0xA7B1, "M", "ʇ"), + (0xA7B2, "M", "ʝ"), + (0xA7B3, "M", "ꭓ"), + (0xA7B4, "M", "ꞵ"), + (0xA7B5, "V"), + (0xA7B6, "M", "ꞷ"), + (0xA7B7, "V"), + (0xA7B8, "M", "ꞹ"), + (0xA7B9, "V"), + (0xA7BA, "M", "ꞻ"), + (0xA7BB, "V"), + (0xA7BC, "M", "ꞽ"), + (0xA7BD, "V"), + (0xA7BE, "M", "ꞿ"), + (0xA7BF, "V"), + (0xA7C0, "M", "ꟁ"), + (0xA7C1, "V"), + (0xA7C2, "M", "ꟃ"), + (0xA7C3, "V"), + (0xA7C4, "M", "ꞔ"), + (0xA7C5, "M", "ʂ"), + (0xA7C6, "M", "ᶎ"), + (0xA7C7, "M", "ꟈ"), + (0xA7C8, "V"), + ] + + +def _seg_38() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA7C9, "M", "ꟊ"), + (0xA7CA, "V"), + (0xA7CB, "M", "ɤ"), + (0xA7CC, "M", "ꟍ"), + (0xA7CD, "V"), + (0xA7CE, "X"), + (0xA7D0, "M", "ꟑ"), + (0xA7D1, "V"), + (0xA7D2, "X"), + (0xA7D3, "V"), + (0xA7D4, "X"), + (0xA7D5, "V"), + (0xA7D6, "M", "ꟗ"), + (0xA7D7, "V"), + (0xA7D8, "M", "ꟙ"), + (0xA7D9, "V"), + (0xA7DA, "M", "ꟛ"), + (0xA7DB, "V"), + (0xA7DC, "M", "ƛ"), + (0xA7DD, "X"), + (0xA7F2, "M", "c"), + (0xA7F3, "M", "f"), + (0xA7F4, "M", "q"), + (0xA7F5, "M", "ꟶ"), + (0xA7F6, "V"), + (0xA7F8, "M", "ħ"), + (0xA7F9, "M", "œ"), + (0xA7FA, "V"), + (0xA82D, "X"), + (0xA830, "V"), + (0xA83A, "X"), + (0xA840, "V"), + (0xA878, "X"), + (0xA880, "V"), + (0xA8C6, "X"), + (0xA8CE, "V"), + (0xA8DA, "X"), + (0xA8E0, "V"), + (0xA954, "X"), + (0xA95F, "V"), + (0xA97D, "X"), + (0xA980, "V"), + (0xA9CE, "X"), + (0xA9CF, "V"), + (0xA9DA, "X"), + (0xA9DE, "V"), + (0xA9FF, "X"), + (0xAA00, "V"), + (0xAA37, "X"), + (0xAA40, "V"), + (0xAA4E, "X"), + (0xAA50, "V"), + (0xAA5A, "X"), + (0xAA5C, "V"), + (0xAAC3, "X"), + (0xAADB, "V"), + (0xAAF7, "X"), + (0xAB01, "V"), + (0xAB07, "X"), + (0xAB09, "V"), + (0xAB0F, "X"), + (0xAB11, "V"), + (0xAB17, "X"), + (0xAB20, "V"), + (0xAB27, "X"), + (0xAB28, "V"), + (0xAB2F, "X"), + (0xAB30, "V"), + (0xAB5C, "M", "ꜧ"), + (0xAB5D, "M", "ꬷ"), + (0xAB5E, "M", "ɫ"), + (0xAB5F, "M", "ꭒ"), + (0xAB60, "V"), + (0xAB69, "M", "ʍ"), + (0xAB6A, "V"), + (0xAB6C, "X"), + (0xAB70, "M", "Ꭰ"), + (0xAB71, "M", "Ꭱ"), + (0xAB72, "M", "Ꭲ"), + (0xAB73, "M", "Ꭳ"), + (0xAB74, "M", "Ꭴ"), + (0xAB75, "M", "Ꭵ"), + (0xAB76, "M", "Ꭶ"), + (0xAB77, "M", "Ꭷ"), + (0xAB78, "M", "Ꭸ"), + (0xAB79, "M", "Ꭹ"), + (0xAB7A, "M", "Ꭺ"), + (0xAB7B, "M", "Ꭻ"), + (0xAB7C, "M", "Ꭼ"), + (0xAB7D, "M", "Ꭽ"), + (0xAB7E, "M", "Ꭾ"), + (0xAB7F, "M", "Ꭿ"), + (0xAB80, "M", "Ꮀ"), + (0xAB81, "M", "Ꮁ"), + (0xAB82, "M", "Ꮂ"), + (0xAB83, "M", "Ꮃ"), + (0xAB84, "M", "Ꮄ"), + (0xAB85, "M", "Ꮅ"), + (0xAB86, "M", "Ꮆ"), + (0xAB87, "M", "Ꮇ"), + ] + + +def _seg_39() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xAB88, "M", "Ꮈ"), + (0xAB89, "M", "Ꮉ"), + (0xAB8A, "M", "Ꮊ"), + (0xAB8B, "M", "Ꮋ"), + (0xAB8C, "M", "Ꮌ"), + (0xAB8D, "M", "Ꮍ"), + (0xAB8E, "M", "Ꮎ"), + (0xAB8F, "M", "Ꮏ"), + (0xAB90, "M", "Ꮐ"), + (0xAB91, "M", "Ꮑ"), + (0xAB92, "M", "Ꮒ"), + (0xAB93, "M", "Ꮓ"), + (0xAB94, "M", "Ꮔ"), + (0xAB95, "M", "Ꮕ"), + (0xAB96, "M", "Ꮖ"), + (0xAB97, "M", "Ꮗ"), + (0xAB98, "M", "Ꮘ"), + (0xAB99, "M", "Ꮙ"), + (0xAB9A, "M", "Ꮚ"), + (0xAB9B, "M", "Ꮛ"), + (0xAB9C, "M", "Ꮜ"), + (0xAB9D, "M", "Ꮝ"), + (0xAB9E, "M", "Ꮞ"), + (0xAB9F, "M", "Ꮟ"), + (0xABA0, "M", "Ꮠ"), + (0xABA1, "M", "Ꮡ"), + (0xABA2, "M", "Ꮢ"), + (0xABA3, "M", "Ꮣ"), + (0xABA4, "M", "Ꮤ"), + (0xABA5, "M", "Ꮥ"), + (0xABA6, "M", "Ꮦ"), + (0xABA7, "M", "Ꮧ"), + (0xABA8, "M", "Ꮨ"), + (0xABA9, "M", "Ꮩ"), + (0xABAA, "M", "Ꮪ"), + (0xABAB, "M", "Ꮫ"), + (0xABAC, "M", "Ꮬ"), + (0xABAD, "M", "Ꮭ"), + (0xABAE, "M", "Ꮮ"), + (0xABAF, "M", "Ꮯ"), + (0xABB0, "M", "Ꮰ"), + (0xABB1, "M", "Ꮱ"), + (0xABB2, "M", "Ꮲ"), + (0xABB3, "M", "Ꮳ"), + (0xABB4, "M", "Ꮴ"), + (0xABB5, "M", "Ꮵ"), + (0xABB6, "M", "Ꮶ"), + (0xABB7, "M", "Ꮷ"), + (0xABB8, "M", "Ꮸ"), + (0xABB9, "M", "Ꮹ"), + (0xABBA, "M", "Ꮺ"), + (0xABBB, "M", "Ꮻ"), + (0xABBC, "M", "Ꮼ"), + (0xABBD, "M", "Ꮽ"), + (0xABBE, "M", "Ꮾ"), + (0xABBF, "M", "Ꮿ"), + (0xABC0, "V"), + (0xABEE, "X"), + (0xABF0, "V"), + (0xABFA, "X"), + (0xAC00, "V"), + (0xD7A4, "X"), + (0xD7B0, "V"), + (0xD7C7, "X"), + (0xD7CB, "V"), + (0xD7FC, "X"), + (0xF900, "M", "豈"), + (0xF901, "M", "更"), + (0xF902, "M", "車"), + (0xF903, "M", "賈"), + (0xF904, "M", "滑"), + (0xF905, "M", "串"), + (0xF906, "M", "句"), + (0xF907, "M", "龜"), + (0xF909, "M", "契"), + (0xF90A, "M", "金"), + (0xF90B, "M", "喇"), + (0xF90C, "M", "奈"), + (0xF90D, "M", "懶"), + (0xF90E, "M", "癩"), + (0xF90F, "M", "羅"), + (0xF910, "M", "蘿"), + (0xF911, "M", "螺"), + (0xF912, "M", "裸"), + (0xF913, "M", "邏"), + (0xF914, "M", "樂"), + (0xF915, "M", "洛"), + (0xF916, "M", "烙"), + (0xF917, "M", "珞"), + (0xF918, "M", "落"), + (0xF919, "M", "酪"), + (0xF91A, "M", "駱"), + (0xF91B, "M", "亂"), + (0xF91C, "M", "卵"), + (0xF91D, "M", "欄"), + (0xF91E, "M", "爛"), + (0xF91F, "M", "蘭"), + (0xF920, "M", "鸞"), + (0xF921, "M", "嵐"), + (0xF922, "M", "濫"), + ] + + +def _seg_40() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF923, "M", "藍"), + (0xF924, "M", "襤"), + (0xF925, "M", "拉"), + (0xF926, "M", "臘"), + (0xF927, "M", "蠟"), + (0xF928, "M", "廊"), + (0xF929, "M", "朗"), + (0xF92A, "M", "浪"), + (0xF92B, "M", "狼"), + (0xF92C, "M", "郎"), + (0xF92D, "M", "來"), + (0xF92E, "M", "冷"), + (0xF92F, "M", "勞"), + (0xF930, "M", "擄"), + (0xF931, "M", "櫓"), + (0xF932, "M", "爐"), + (0xF933, "M", "盧"), + (0xF934, "M", "老"), + (0xF935, "M", "蘆"), + (0xF936, "M", "虜"), + (0xF937, "M", "路"), + (0xF938, "M", "露"), + (0xF939, "M", "魯"), + (0xF93A, "M", "鷺"), + (0xF93B, "M", "碌"), + (0xF93C, "M", "祿"), + (0xF93D, "M", "綠"), + (0xF93E, "M", "菉"), + (0xF93F, "M", "錄"), + (0xF940, "M", "鹿"), + (0xF941, "M", "論"), + (0xF942, "M", "壟"), + (0xF943, "M", "弄"), + (0xF944, "M", "籠"), + (0xF945, "M", "聾"), + (0xF946, "M", "牢"), + (0xF947, "M", "磊"), + (0xF948, "M", "賂"), + (0xF949, "M", "雷"), + (0xF94A, "M", "壘"), + (0xF94B, "M", "屢"), + (0xF94C, "M", "樓"), + (0xF94D, "M", "淚"), + (0xF94E, "M", "漏"), + (0xF94F, "M", "累"), + (0xF950, "M", "縷"), + (0xF951, "M", "陋"), + (0xF952, "M", "勒"), + (0xF953, "M", "肋"), + (0xF954, "M", "凜"), + (0xF955, "M", "凌"), + (0xF956, "M", "稜"), + (0xF957, "M", "綾"), + (0xF958, "M", "菱"), + (0xF959, "M", "陵"), + (0xF95A, "M", "讀"), + (0xF95B, "M", "拏"), + (0xF95C, "M", "樂"), + (0xF95D, "M", "諾"), + (0xF95E, "M", "丹"), + (0xF95F, "M", "寧"), + (0xF960, "M", "怒"), + (0xF961, "M", "率"), + (0xF962, "M", "異"), + (0xF963, "M", "北"), + (0xF964, "M", "磻"), + (0xF965, "M", "便"), + (0xF966, "M", "復"), + (0xF967, "M", "不"), + (0xF968, "M", "泌"), + (0xF969, "M", "數"), + (0xF96A, "M", "索"), + (0xF96B, "M", "參"), + (0xF96C, "M", "塞"), + (0xF96D, "M", "省"), + (0xF96E, "M", "葉"), + (0xF96F, "M", "說"), + (0xF970, "M", "殺"), + (0xF971, "M", "辰"), + (0xF972, "M", "沈"), + (0xF973, "M", "拾"), + (0xF974, "M", "若"), + (0xF975, "M", "掠"), + (0xF976, "M", "略"), + (0xF977, "M", "亮"), + (0xF978, "M", "兩"), + (0xF979, "M", "凉"), + (0xF97A, "M", "梁"), + (0xF97B, "M", "糧"), + (0xF97C, "M", "良"), + (0xF97D, "M", "諒"), + (0xF97E, "M", "量"), + (0xF97F, "M", "勵"), + (0xF980, "M", "呂"), + (0xF981, "M", "女"), + (0xF982, "M", "廬"), + (0xF983, "M", "旅"), + (0xF984, "M", "濾"), + (0xF985, "M", "礪"), + (0xF986, "M", "閭"), + ] + + +def _seg_41() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF987, "M", "驪"), + (0xF988, "M", "麗"), + (0xF989, "M", "黎"), + (0xF98A, "M", "力"), + (0xF98B, "M", "曆"), + (0xF98C, "M", "歷"), + (0xF98D, "M", "轢"), + (0xF98E, "M", "年"), + (0xF98F, "M", "憐"), + (0xF990, "M", "戀"), + (0xF991, "M", "撚"), + (0xF992, "M", "漣"), + (0xF993, "M", "煉"), + (0xF994, "M", "璉"), + (0xF995, "M", "秊"), + (0xF996, "M", "練"), + (0xF997, "M", "聯"), + (0xF998, "M", "輦"), + (0xF999, "M", "蓮"), + (0xF99A, "M", "連"), + (0xF99B, "M", "鍊"), + (0xF99C, "M", "列"), + (0xF99D, "M", "劣"), + (0xF99E, "M", "咽"), + (0xF99F, "M", "烈"), + (0xF9A0, "M", "裂"), + (0xF9A1, "M", "說"), + (0xF9A2, "M", "廉"), + (0xF9A3, "M", "念"), + (0xF9A4, "M", "捻"), + (0xF9A5, "M", "殮"), + (0xF9A6, "M", "簾"), + (0xF9A7, "M", "獵"), + (0xF9A8, "M", "令"), + (0xF9A9, "M", "囹"), + (0xF9AA, "M", "寧"), + (0xF9AB, "M", "嶺"), + (0xF9AC, "M", "怜"), + (0xF9AD, "M", "玲"), + (0xF9AE, "M", "瑩"), + (0xF9AF, "M", "羚"), + (0xF9B0, "M", "聆"), + (0xF9B1, "M", "鈴"), + (0xF9B2, "M", "零"), + (0xF9B3, "M", "靈"), + (0xF9B4, "M", "領"), + (0xF9B5, "M", "例"), + (0xF9B6, "M", "禮"), + (0xF9B7, "M", "醴"), + (0xF9B8, "M", "隸"), + (0xF9B9, "M", "惡"), + (0xF9BA, "M", "了"), + (0xF9BB, "M", "僚"), + (0xF9BC, "M", "寮"), + (0xF9BD, "M", "尿"), + (0xF9BE, "M", "料"), + (0xF9BF, "M", "樂"), + (0xF9C0, "M", "燎"), + (0xF9C1, "M", "療"), + (0xF9C2, "M", "蓼"), + (0xF9C3, "M", "遼"), + (0xF9C4, "M", "龍"), + (0xF9C5, "M", "暈"), + (0xF9C6, "M", "阮"), + (0xF9C7, "M", "劉"), + (0xF9C8, "M", "杻"), + (0xF9C9, "M", "柳"), + (0xF9CA, "M", "流"), + (0xF9CB, "M", "溜"), + (0xF9CC, "M", "琉"), + (0xF9CD, "M", "留"), + (0xF9CE, "M", "硫"), + (0xF9CF, "M", "紐"), + (0xF9D0, "M", "類"), + (0xF9D1, "M", "六"), + (0xF9D2, "M", "戮"), + (0xF9D3, "M", "陸"), + (0xF9D4, "M", "倫"), + (0xF9D5, "M", "崙"), + (0xF9D6, "M", "淪"), + (0xF9D7, "M", "輪"), + (0xF9D8, "M", "律"), + (0xF9D9, "M", "慄"), + (0xF9DA, "M", "栗"), + (0xF9DB, "M", "率"), + (0xF9DC, "M", "隆"), + (0xF9DD, "M", "利"), + (0xF9DE, "M", "吏"), + (0xF9DF, "M", "履"), + (0xF9E0, "M", "易"), + (0xF9E1, "M", "李"), + (0xF9E2, "M", "梨"), + (0xF9E3, "M", "泥"), + (0xF9E4, "M", "理"), + (0xF9E5, "M", "痢"), + (0xF9E6, "M", "罹"), + (0xF9E7, "M", "裏"), + (0xF9E8, "M", "裡"), + (0xF9E9, "M", "里"), + (0xF9EA, "M", "離"), + ] + + +def _seg_42() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF9EB, "M", "匿"), + (0xF9EC, "M", "溺"), + (0xF9ED, "M", "吝"), + (0xF9EE, "M", "燐"), + (0xF9EF, "M", "璘"), + (0xF9F0, "M", "藺"), + (0xF9F1, "M", "隣"), + (0xF9F2, "M", "鱗"), + (0xF9F3, "M", "麟"), + (0xF9F4, "M", "林"), + (0xF9F5, "M", "淋"), + (0xF9F6, "M", "臨"), + (0xF9F7, "M", "立"), + (0xF9F8, "M", "笠"), + (0xF9F9, "M", "粒"), + (0xF9FA, "M", "狀"), + (0xF9FB, "M", "炙"), + (0xF9FC, "M", "識"), + (0xF9FD, "M", "什"), + (0xF9FE, "M", "茶"), + (0xF9FF, "M", "刺"), + (0xFA00, "M", "切"), + (0xFA01, "M", "度"), + (0xFA02, "M", "拓"), + (0xFA03, "M", "糖"), + (0xFA04, "M", "宅"), + (0xFA05, "M", "洞"), + (0xFA06, "M", "暴"), + (0xFA07, "M", "輻"), + (0xFA08, "M", "行"), + (0xFA09, "M", "降"), + (0xFA0A, "M", "見"), + (0xFA0B, "M", "廓"), + (0xFA0C, "M", "兀"), + (0xFA0D, "M", "嗀"), + (0xFA0E, "V"), + (0xFA10, "M", "塚"), + (0xFA11, "V"), + (0xFA12, "M", "晴"), + (0xFA13, "V"), + (0xFA15, "M", "凞"), + (0xFA16, "M", "猪"), + (0xFA17, "M", "益"), + (0xFA18, "M", "礼"), + (0xFA19, "M", "神"), + (0xFA1A, "M", "祥"), + (0xFA1B, "M", "福"), + (0xFA1C, "M", "靖"), + (0xFA1D, "M", "精"), + (0xFA1E, "M", "羽"), + (0xFA1F, "V"), + (0xFA20, "M", "蘒"), + (0xFA21, "V"), + (0xFA22, "M", "諸"), + (0xFA23, "V"), + (0xFA25, "M", "逸"), + (0xFA26, "M", "都"), + (0xFA27, "V"), + (0xFA2A, "M", "飯"), + (0xFA2B, "M", "飼"), + (0xFA2C, "M", "館"), + (0xFA2D, "M", "鶴"), + (0xFA2E, "M", "郞"), + (0xFA2F, "M", "隷"), + (0xFA30, "M", "侮"), + (0xFA31, "M", "僧"), + (0xFA32, "M", "免"), + (0xFA33, "M", "勉"), + (0xFA34, "M", "勤"), + (0xFA35, "M", "卑"), + (0xFA36, "M", "喝"), + (0xFA37, "M", "嘆"), + (0xFA38, "M", "器"), + (0xFA39, "M", "塀"), + (0xFA3A, "M", "墨"), + (0xFA3B, "M", "層"), + (0xFA3C, "M", "屮"), + (0xFA3D, "M", "悔"), + (0xFA3E, "M", "慨"), + (0xFA3F, "M", "憎"), + (0xFA40, "M", "懲"), + (0xFA41, "M", "敏"), + (0xFA42, "M", "既"), + (0xFA43, "M", "暑"), + (0xFA44, "M", "梅"), + (0xFA45, "M", "海"), + (0xFA46, "M", "渚"), + (0xFA47, "M", "漢"), + (0xFA48, "M", "煮"), + (0xFA49, "M", "爫"), + (0xFA4A, "M", "琢"), + (0xFA4B, "M", "碑"), + (0xFA4C, "M", "社"), + (0xFA4D, "M", "祉"), + (0xFA4E, "M", "祈"), + (0xFA4F, "M", "祐"), + (0xFA50, "M", "祖"), + (0xFA51, "M", "祝"), + (0xFA52, "M", "禍"), + (0xFA53, "M", "禎"), + ] + + +def _seg_43() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFA54, "M", "穀"), + (0xFA55, "M", "突"), + (0xFA56, "M", "節"), + (0xFA57, "M", "練"), + (0xFA58, "M", "縉"), + (0xFA59, "M", "繁"), + (0xFA5A, "M", "署"), + (0xFA5B, "M", "者"), + (0xFA5C, "M", "臭"), + (0xFA5D, "M", "艹"), + (0xFA5F, "M", "著"), + (0xFA60, "M", "褐"), + (0xFA61, "M", "視"), + (0xFA62, "M", "謁"), + (0xFA63, "M", "謹"), + (0xFA64, "M", "賓"), + (0xFA65, "M", "贈"), + (0xFA66, "M", "辶"), + (0xFA67, "M", "逸"), + (0xFA68, "M", "難"), + (0xFA69, "M", "響"), + (0xFA6A, "M", "頻"), + (0xFA6B, "M", "恵"), + (0xFA6C, "M", "𤋮"), + (0xFA6D, "M", "舘"), + (0xFA6E, "X"), + (0xFA70, "M", "並"), + (0xFA71, "M", "况"), + (0xFA72, "M", "全"), + (0xFA73, "M", "侀"), + (0xFA74, "M", "充"), + (0xFA75, "M", "冀"), + (0xFA76, "M", "勇"), + (0xFA77, "M", "勺"), + (0xFA78, "M", "喝"), + (0xFA79, "M", "啕"), + (0xFA7A, "M", "喙"), + (0xFA7B, "M", "嗢"), + (0xFA7C, "M", "塚"), + (0xFA7D, "M", "墳"), + (0xFA7E, "M", "奄"), + (0xFA7F, "M", "奔"), + (0xFA80, "M", "婢"), + (0xFA81, "M", "嬨"), + (0xFA82, "M", "廒"), + (0xFA83, "M", "廙"), + (0xFA84, "M", "彩"), + (0xFA85, "M", "徭"), + (0xFA86, "M", "惘"), + (0xFA87, "M", "慎"), + (0xFA88, "M", "愈"), + (0xFA89, "M", "憎"), + (0xFA8A, "M", "慠"), + (0xFA8B, "M", "懲"), + (0xFA8C, "M", "戴"), + (0xFA8D, "M", "揄"), + (0xFA8E, "M", "搜"), + (0xFA8F, "M", "摒"), + (0xFA90, "M", "敖"), + (0xFA91, "M", "晴"), + (0xFA92, "M", "朗"), + (0xFA93, "M", "望"), + (0xFA94, "M", "杖"), + (0xFA95, "M", "歹"), + (0xFA96, "M", "殺"), + (0xFA97, "M", "流"), + (0xFA98, "M", "滛"), + (0xFA99, "M", "滋"), + (0xFA9A, "M", "漢"), + (0xFA9B, "M", "瀞"), + (0xFA9C, "M", "煮"), + (0xFA9D, "M", "瞧"), + (0xFA9E, "M", "爵"), + (0xFA9F, "M", "犯"), + (0xFAA0, "M", "猪"), + (0xFAA1, "M", "瑱"), + (0xFAA2, "M", "甆"), + (0xFAA3, "M", "画"), + (0xFAA4, "M", "瘝"), + (0xFAA5, "M", "瘟"), + (0xFAA6, "M", "益"), + (0xFAA7, "M", "盛"), + (0xFAA8, "M", "直"), + (0xFAA9, "M", "睊"), + (0xFAAA, "M", "着"), + (0xFAAB, "M", "磌"), + (0xFAAC, "M", "窱"), + (0xFAAD, "M", "節"), + (0xFAAE, "M", "类"), + (0xFAAF, "M", "絛"), + (0xFAB0, "M", "練"), + (0xFAB1, "M", "缾"), + (0xFAB2, "M", "者"), + (0xFAB3, "M", "荒"), + (0xFAB4, "M", "華"), + (0xFAB5, "M", "蝹"), + (0xFAB6, "M", "襁"), + (0xFAB7, "M", "覆"), + (0xFAB8, "M", "視"), + (0xFAB9, "M", "調"), + ] + + +def _seg_44() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFABA, "M", "諸"), + (0xFABB, "M", "請"), + (0xFABC, "M", "謁"), + (0xFABD, "M", "諾"), + (0xFABE, "M", "諭"), + (0xFABF, "M", "謹"), + (0xFAC0, "M", "變"), + (0xFAC1, "M", "贈"), + (0xFAC2, "M", "輸"), + (0xFAC3, "M", "遲"), + (0xFAC4, "M", "醙"), + (0xFAC5, "M", "鉶"), + (0xFAC6, "M", "陼"), + (0xFAC7, "M", "難"), + (0xFAC8, "M", "靖"), + (0xFAC9, "M", "韛"), + (0xFACA, "M", "響"), + (0xFACB, "M", "頋"), + (0xFACC, "M", "頻"), + (0xFACD, "M", "鬒"), + (0xFACE, "M", "龜"), + (0xFACF, "M", "𢡊"), + (0xFAD0, "M", "𢡄"), + (0xFAD1, "M", "𣏕"), + (0xFAD2, "M", "㮝"), + (0xFAD3, "M", "䀘"), + (0xFAD4, "M", "䀹"), + (0xFAD5, "M", "𥉉"), + (0xFAD6, "M", "𥳐"), + (0xFAD7, "M", "𧻓"), + (0xFAD8, "M", "齃"), + (0xFAD9, "M", "龎"), + (0xFADA, "X"), + (0xFB00, "M", "ff"), + (0xFB01, "M", "fi"), + (0xFB02, "M", "fl"), + (0xFB03, "M", "ffi"), + (0xFB04, "M", "ffl"), + (0xFB05, "M", "st"), + (0xFB07, "X"), + (0xFB13, "M", "մն"), + (0xFB14, "M", "մե"), + (0xFB15, "M", "մի"), + (0xFB16, "M", "վն"), + (0xFB17, "M", "մխ"), + (0xFB18, "X"), + (0xFB1D, "M", "יִ"), + (0xFB1E, "V"), + (0xFB1F, "M", "ײַ"), + (0xFB20, "M", "ע"), + (0xFB21, "M", "א"), + (0xFB22, "M", "ד"), + (0xFB23, "M", "ה"), + (0xFB24, "M", "כ"), + (0xFB25, "M", "ל"), + (0xFB26, "M", "ם"), + (0xFB27, "M", "ר"), + (0xFB28, "M", "ת"), + (0xFB29, "M", "+"), + (0xFB2A, "M", "שׁ"), + (0xFB2B, "M", "שׂ"), + (0xFB2C, "M", "שּׁ"), + (0xFB2D, "M", "שּׂ"), + (0xFB2E, "M", "אַ"), + (0xFB2F, "M", "אָ"), + (0xFB30, "M", "אּ"), + (0xFB31, "M", "בּ"), + (0xFB32, "M", "גּ"), + (0xFB33, "M", "דּ"), + (0xFB34, "M", "הּ"), + (0xFB35, "M", "וּ"), + (0xFB36, "M", "זּ"), + (0xFB37, "X"), + (0xFB38, "M", "טּ"), + (0xFB39, "M", "יּ"), + (0xFB3A, "M", "ךּ"), + (0xFB3B, "M", "כּ"), + (0xFB3C, "M", "לּ"), + (0xFB3D, "X"), + (0xFB3E, "M", "מּ"), + (0xFB3F, "X"), + (0xFB40, "M", "נּ"), + (0xFB41, "M", "סּ"), + (0xFB42, "X"), + (0xFB43, "M", "ףּ"), + (0xFB44, "M", "פּ"), + (0xFB45, "X"), + (0xFB46, "M", "צּ"), + (0xFB47, "M", "קּ"), + (0xFB48, "M", "רּ"), + (0xFB49, "M", "שּ"), + (0xFB4A, "M", "תּ"), + (0xFB4B, "M", "וֹ"), + (0xFB4C, "M", "בֿ"), + (0xFB4D, "M", "כֿ"), + (0xFB4E, "M", "פֿ"), + (0xFB4F, "M", "אל"), + (0xFB50, "M", "ٱ"), + (0xFB52, "M", "ٻ"), + (0xFB56, "M", "پ"), + ] + + +def _seg_45() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFB5A, "M", "ڀ"), + (0xFB5E, "M", "ٺ"), + (0xFB62, "M", "ٿ"), + (0xFB66, "M", "ٹ"), + (0xFB6A, "M", "ڤ"), + (0xFB6E, "M", "ڦ"), + (0xFB72, "M", "ڄ"), + (0xFB76, "M", "ڃ"), + (0xFB7A, "M", "چ"), + (0xFB7E, "M", "ڇ"), + (0xFB82, "M", "ڍ"), + (0xFB84, "M", "ڌ"), + (0xFB86, "M", "ڎ"), + (0xFB88, "M", "ڈ"), + (0xFB8A, "M", "ژ"), + (0xFB8C, "M", "ڑ"), + (0xFB8E, "M", "ک"), + (0xFB92, "M", "گ"), + (0xFB96, "M", "ڳ"), + (0xFB9A, "M", "ڱ"), + (0xFB9E, "M", "ں"), + (0xFBA0, "M", "ڻ"), + (0xFBA4, "M", "ۀ"), + (0xFBA6, "M", "ہ"), + (0xFBAA, "M", "ھ"), + (0xFBAE, "M", "ے"), + (0xFBB0, "M", "ۓ"), + (0xFBB2, "V"), + (0xFBC3, "X"), + (0xFBD3, "M", "ڭ"), + (0xFBD7, "M", "ۇ"), + (0xFBD9, "M", "ۆ"), + (0xFBDB, "M", "ۈ"), + (0xFBDD, "M", "ۇٴ"), + (0xFBDE, "M", "ۋ"), + (0xFBE0, "M", "ۅ"), + (0xFBE2, "M", "ۉ"), + (0xFBE4, "M", "ې"), + (0xFBE8, "M", "ى"), + (0xFBEA, "M", "ئا"), + (0xFBEC, "M", "ئە"), + (0xFBEE, "M", "ئو"), + (0xFBF0, "M", "ئۇ"), + (0xFBF2, "M", "ئۆ"), + (0xFBF4, "M", "ئۈ"), + (0xFBF6, "M", "ئې"), + (0xFBF9, "M", "ئى"), + (0xFBFC, "M", "ی"), + (0xFC00, "M", "ئج"), + (0xFC01, "M", "ئح"), + (0xFC02, "M", "ئم"), + (0xFC03, "M", "ئى"), + (0xFC04, "M", "ئي"), + (0xFC05, "M", "بج"), + (0xFC06, "M", "بح"), + (0xFC07, "M", "بخ"), + (0xFC08, "M", "بم"), + (0xFC09, "M", "بى"), + (0xFC0A, "M", "بي"), + (0xFC0B, "M", "تج"), + (0xFC0C, "M", "تح"), + (0xFC0D, "M", "تخ"), + (0xFC0E, "M", "تم"), + (0xFC0F, "M", "تى"), + (0xFC10, "M", "تي"), + (0xFC11, "M", "ثج"), + (0xFC12, "M", "ثم"), + (0xFC13, "M", "ثى"), + (0xFC14, "M", "ثي"), + (0xFC15, "M", "جح"), + (0xFC16, "M", "جم"), + (0xFC17, "M", "حج"), + (0xFC18, "M", "حم"), + (0xFC19, "M", "خج"), + (0xFC1A, "M", "خح"), + (0xFC1B, "M", "خم"), + (0xFC1C, "M", "سج"), + (0xFC1D, "M", "سح"), + (0xFC1E, "M", "سخ"), + (0xFC1F, "M", "سم"), + (0xFC20, "M", "صح"), + (0xFC21, "M", "صم"), + (0xFC22, "M", "ضج"), + (0xFC23, "M", "ضح"), + (0xFC24, "M", "ضخ"), + (0xFC25, "M", "ضم"), + (0xFC26, "M", "طح"), + (0xFC27, "M", "طم"), + (0xFC28, "M", "ظم"), + (0xFC29, "M", "عج"), + (0xFC2A, "M", "عم"), + (0xFC2B, "M", "غج"), + (0xFC2C, "M", "غم"), + (0xFC2D, "M", "فج"), + (0xFC2E, "M", "فح"), + (0xFC2F, "M", "فخ"), + (0xFC30, "M", "فم"), + (0xFC31, "M", "فى"), + (0xFC32, "M", "في"), + (0xFC33, "M", "قح"), + ] + + +def _seg_46() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFC34, "M", "قم"), + (0xFC35, "M", "قى"), + (0xFC36, "M", "قي"), + (0xFC37, "M", "كا"), + (0xFC38, "M", "كج"), + (0xFC39, "M", "كح"), + (0xFC3A, "M", "كخ"), + (0xFC3B, "M", "كل"), + (0xFC3C, "M", "كم"), + (0xFC3D, "M", "كى"), + (0xFC3E, "M", "كي"), + (0xFC3F, "M", "لج"), + (0xFC40, "M", "لح"), + (0xFC41, "M", "لخ"), + (0xFC42, "M", "لم"), + (0xFC43, "M", "لى"), + (0xFC44, "M", "لي"), + (0xFC45, "M", "مج"), + (0xFC46, "M", "مح"), + (0xFC47, "M", "مخ"), + (0xFC48, "M", "مم"), + (0xFC49, "M", "مى"), + (0xFC4A, "M", "مي"), + (0xFC4B, "M", "نج"), + (0xFC4C, "M", "نح"), + (0xFC4D, "M", "نخ"), + (0xFC4E, "M", "نم"), + (0xFC4F, "M", "نى"), + (0xFC50, "M", "ني"), + (0xFC51, "M", "هج"), + (0xFC52, "M", "هم"), + (0xFC53, "M", "هى"), + (0xFC54, "M", "هي"), + (0xFC55, "M", "يج"), + (0xFC56, "M", "يح"), + (0xFC57, "M", "يخ"), + (0xFC58, "M", "يم"), + (0xFC59, "M", "يى"), + (0xFC5A, "M", "يي"), + (0xFC5B, "M", "ذٰ"), + (0xFC5C, "M", "رٰ"), + (0xFC5D, "M", "ىٰ"), + (0xFC5E, "M", " ٌّ"), + (0xFC5F, "M", " ٍّ"), + (0xFC60, "M", " َّ"), + (0xFC61, "M", " ُّ"), + (0xFC62, "M", " ِّ"), + (0xFC63, "M", " ّٰ"), + (0xFC64, "M", "ئر"), + (0xFC65, "M", "ئز"), + (0xFC66, "M", "ئم"), + (0xFC67, "M", "ئن"), + (0xFC68, "M", "ئى"), + (0xFC69, "M", "ئي"), + (0xFC6A, "M", "بر"), + (0xFC6B, "M", "بز"), + (0xFC6C, "M", "بم"), + (0xFC6D, "M", "بن"), + (0xFC6E, "M", "بى"), + (0xFC6F, "M", "بي"), + (0xFC70, "M", "تر"), + (0xFC71, "M", "تز"), + (0xFC72, "M", "تم"), + (0xFC73, "M", "تن"), + (0xFC74, "M", "تى"), + (0xFC75, "M", "تي"), + (0xFC76, "M", "ثر"), + (0xFC77, "M", "ثز"), + (0xFC78, "M", "ثم"), + (0xFC79, "M", "ثن"), + (0xFC7A, "M", "ثى"), + (0xFC7B, "M", "ثي"), + (0xFC7C, "M", "فى"), + (0xFC7D, "M", "في"), + (0xFC7E, "M", "قى"), + (0xFC7F, "M", "قي"), + (0xFC80, "M", "كا"), + (0xFC81, "M", "كل"), + (0xFC82, "M", "كم"), + (0xFC83, "M", "كى"), + (0xFC84, "M", "كي"), + (0xFC85, "M", "لم"), + (0xFC86, "M", "لى"), + (0xFC87, "M", "لي"), + (0xFC88, "M", "ما"), + (0xFC89, "M", "مم"), + (0xFC8A, "M", "نر"), + (0xFC8B, "M", "نز"), + (0xFC8C, "M", "نم"), + (0xFC8D, "M", "نن"), + (0xFC8E, "M", "نى"), + (0xFC8F, "M", "ني"), + (0xFC90, "M", "ىٰ"), + (0xFC91, "M", "ير"), + (0xFC92, "M", "يز"), + (0xFC93, "M", "يم"), + (0xFC94, "M", "ين"), + (0xFC95, "M", "يى"), + (0xFC96, "M", "يي"), + (0xFC97, "M", "ئج"), + ] + + +def _seg_47() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFC98, "M", "ئح"), + (0xFC99, "M", "ئخ"), + (0xFC9A, "M", "ئم"), + (0xFC9B, "M", "ئه"), + (0xFC9C, "M", "بج"), + (0xFC9D, "M", "بح"), + (0xFC9E, "M", "بخ"), + (0xFC9F, "M", "بم"), + (0xFCA0, "M", "به"), + (0xFCA1, "M", "تج"), + (0xFCA2, "M", "تح"), + (0xFCA3, "M", "تخ"), + (0xFCA4, "M", "تم"), + (0xFCA5, "M", "ته"), + (0xFCA6, "M", "ثم"), + (0xFCA7, "M", "جح"), + (0xFCA8, "M", "جم"), + (0xFCA9, "M", "حج"), + (0xFCAA, "M", "حم"), + (0xFCAB, "M", "خج"), + (0xFCAC, "M", "خم"), + (0xFCAD, "M", "سج"), + (0xFCAE, "M", "سح"), + (0xFCAF, "M", "سخ"), + (0xFCB0, "M", "سم"), + (0xFCB1, "M", "صح"), + (0xFCB2, "M", "صخ"), + (0xFCB3, "M", "صم"), + (0xFCB4, "M", "ضج"), + (0xFCB5, "M", "ضح"), + (0xFCB6, "M", "ضخ"), + (0xFCB7, "M", "ضم"), + (0xFCB8, "M", "طح"), + (0xFCB9, "M", "ظم"), + (0xFCBA, "M", "عج"), + (0xFCBB, "M", "عم"), + (0xFCBC, "M", "غج"), + (0xFCBD, "M", "غم"), + (0xFCBE, "M", "فج"), + (0xFCBF, "M", "فح"), + (0xFCC0, "M", "فخ"), + (0xFCC1, "M", "فم"), + (0xFCC2, "M", "قح"), + (0xFCC3, "M", "قم"), + (0xFCC4, "M", "كج"), + (0xFCC5, "M", "كح"), + (0xFCC6, "M", "كخ"), + (0xFCC7, "M", "كل"), + (0xFCC8, "M", "كم"), + (0xFCC9, "M", "لج"), + (0xFCCA, "M", "لح"), + (0xFCCB, "M", "لخ"), + (0xFCCC, "M", "لم"), + (0xFCCD, "M", "له"), + (0xFCCE, "M", "مج"), + (0xFCCF, "M", "مح"), + (0xFCD0, "M", "مخ"), + (0xFCD1, "M", "مم"), + (0xFCD2, "M", "نج"), + (0xFCD3, "M", "نح"), + (0xFCD4, "M", "نخ"), + (0xFCD5, "M", "نم"), + (0xFCD6, "M", "نه"), + (0xFCD7, "M", "هج"), + (0xFCD8, "M", "هم"), + (0xFCD9, "M", "هٰ"), + (0xFCDA, "M", "يج"), + (0xFCDB, "M", "يح"), + (0xFCDC, "M", "يخ"), + (0xFCDD, "M", "يم"), + (0xFCDE, "M", "يه"), + (0xFCDF, "M", "ئم"), + (0xFCE0, "M", "ئه"), + (0xFCE1, "M", "بم"), + (0xFCE2, "M", "به"), + (0xFCE3, "M", "تم"), + (0xFCE4, "M", "ته"), + (0xFCE5, "M", "ثم"), + (0xFCE6, "M", "ثه"), + (0xFCE7, "M", "سم"), + (0xFCE8, "M", "سه"), + (0xFCE9, "M", "شم"), + (0xFCEA, "M", "شه"), + (0xFCEB, "M", "كل"), + (0xFCEC, "M", "كم"), + (0xFCED, "M", "لم"), + (0xFCEE, "M", "نم"), + (0xFCEF, "M", "نه"), + (0xFCF0, "M", "يم"), + (0xFCF1, "M", "يه"), + (0xFCF2, "M", "ـَّ"), + (0xFCF3, "M", "ـُّ"), + (0xFCF4, "M", "ـِّ"), + (0xFCF5, "M", "طى"), + (0xFCF6, "M", "طي"), + (0xFCF7, "M", "عى"), + (0xFCF8, "M", "عي"), + (0xFCF9, "M", "غى"), + (0xFCFA, "M", "غي"), + (0xFCFB, "M", "سى"), + ] + + +def _seg_48() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFCFC, "M", "سي"), + (0xFCFD, "M", "شى"), + (0xFCFE, "M", "شي"), + (0xFCFF, "M", "حى"), + (0xFD00, "M", "حي"), + (0xFD01, "M", "جى"), + (0xFD02, "M", "جي"), + (0xFD03, "M", "خى"), + (0xFD04, "M", "خي"), + (0xFD05, "M", "صى"), + (0xFD06, "M", "صي"), + (0xFD07, "M", "ضى"), + (0xFD08, "M", "ضي"), + (0xFD09, "M", "شج"), + (0xFD0A, "M", "شح"), + (0xFD0B, "M", "شخ"), + (0xFD0C, "M", "شم"), + (0xFD0D, "M", "شر"), + (0xFD0E, "M", "سر"), + (0xFD0F, "M", "صر"), + (0xFD10, "M", "ضر"), + (0xFD11, "M", "طى"), + (0xFD12, "M", "طي"), + (0xFD13, "M", "عى"), + (0xFD14, "M", "عي"), + (0xFD15, "M", "غى"), + (0xFD16, "M", "غي"), + (0xFD17, "M", "سى"), + (0xFD18, "M", "سي"), + (0xFD19, "M", "شى"), + (0xFD1A, "M", "شي"), + (0xFD1B, "M", "حى"), + (0xFD1C, "M", "حي"), + (0xFD1D, "M", "جى"), + (0xFD1E, "M", "جي"), + (0xFD1F, "M", "خى"), + (0xFD20, "M", "خي"), + (0xFD21, "M", "صى"), + (0xFD22, "M", "صي"), + (0xFD23, "M", "ضى"), + (0xFD24, "M", "ضي"), + (0xFD25, "M", "شج"), + (0xFD26, "M", "شح"), + (0xFD27, "M", "شخ"), + (0xFD28, "M", "شم"), + (0xFD29, "M", "شر"), + (0xFD2A, "M", "سر"), + (0xFD2B, "M", "صر"), + (0xFD2C, "M", "ضر"), + (0xFD2D, "M", "شج"), + (0xFD2E, "M", "شح"), + (0xFD2F, "M", "شخ"), + (0xFD30, "M", "شم"), + (0xFD31, "M", "سه"), + (0xFD32, "M", "شه"), + (0xFD33, "M", "طم"), + (0xFD34, "M", "سج"), + (0xFD35, "M", "سح"), + (0xFD36, "M", "سخ"), + (0xFD37, "M", "شج"), + (0xFD38, "M", "شح"), + (0xFD39, "M", "شخ"), + (0xFD3A, "M", "طم"), + (0xFD3B, "M", "ظم"), + (0xFD3C, "M", "اً"), + (0xFD3E, "V"), + (0xFD50, "M", "تجم"), + (0xFD51, "M", "تحج"), + (0xFD53, "M", "تحم"), + (0xFD54, "M", "تخم"), + (0xFD55, "M", "تمج"), + (0xFD56, "M", "تمح"), + (0xFD57, "M", "تمخ"), + (0xFD58, "M", "جمح"), + (0xFD5A, "M", "حمي"), + (0xFD5B, "M", "حمى"), + (0xFD5C, "M", "سحج"), + (0xFD5D, "M", "سجح"), + (0xFD5E, "M", "سجى"), + (0xFD5F, "M", "سمح"), + (0xFD61, "M", "سمج"), + (0xFD62, "M", "سمم"), + (0xFD64, "M", "صحح"), + (0xFD66, "M", "صمم"), + (0xFD67, "M", "شحم"), + (0xFD69, "M", "شجي"), + (0xFD6A, "M", "شمخ"), + (0xFD6C, "M", "شمم"), + (0xFD6E, "M", "ضحى"), + (0xFD6F, "M", "ضخم"), + (0xFD71, "M", "طمح"), + (0xFD73, "M", "طمم"), + (0xFD74, "M", "طمي"), + (0xFD75, "M", "عجم"), + (0xFD76, "M", "عمم"), + (0xFD78, "M", "عمى"), + (0xFD79, "M", "غمم"), + (0xFD7A, "M", "غمي"), + (0xFD7B, "M", "غمى"), + (0xFD7C, "M", "فخم"), + ] + + +def _seg_49() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFD7E, "M", "قمح"), + (0xFD7F, "M", "قمم"), + (0xFD80, "M", "لحم"), + (0xFD81, "M", "لحي"), + (0xFD82, "M", "لحى"), + (0xFD83, "M", "لجج"), + (0xFD85, "M", "لخم"), + (0xFD87, "M", "لمح"), + (0xFD89, "M", "محج"), + (0xFD8A, "M", "محم"), + (0xFD8B, "M", "محي"), + (0xFD8C, "M", "مجح"), + (0xFD8D, "M", "مجم"), + (0xFD8E, "M", "مخج"), + (0xFD8F, "M", "مخم"), + (0xFD90, "X"), + (0xFD92, "M", "مجخ"), + (0xFD93, "M", "همج"), + (0xFD94, "M", "همم"), + (0xFD95, "M", "نحم"), + (0xFD96, "M", "نحى"), + (0xFD97, "M", "نجم"), + (0xFD99, "M", "نجى"), + (0xFD9A, "M", "نمي"), + (0xFD9B, "M", "نمى"), + (0xFD9C, "M", "يمم"), + (0xFD9E, "M", "بخي"), + (0xFD9F, "M", "تجي"), + (0xFDA0, "M", "تجى"), + (0xFDA1, "M", "تخي"), + (0xFDA2, "M", "تخى"), + (0xFDA3, "M", "تمي"), + (0xFDA4, "M", "تمى"), + (0xFDA5, "M", "جمي"), + (0xFDA6, "M", "جحى"), + (0xFDA7, "M", "جمى"), + (0xFDA8, "M", "سخى"), + (0xFDA9, "M", "صحي"), + (0xFDAA, "M", "شحي"), + (0xFDAB, "M", "ضحي"), + (0xFDAC, "M", "لجي"), + (0xFDAD, "M", "لمي"), + (0xFDAE, "M", "يحي"), + (0xFDAF, "M", "يجي"), + (0xFDB0, "M", "يمي"), + (0xFDB1, "M", "ممي"), + (0xFDB2, "M", "قمي"), + (0xFDB3, "M", "نحي"), + (0xFDB4, "M", "قمح"), + (0xFDB5, "M", "لحم"), + (0xFDB6, "M", "عمي"), + (0xFDB7, "M", "كمي"), + (0xFDB8, "M", "نجح"), + (0xFDB9, "M", "مخي"), + (0xFDBA, "M", "لجم"), + (0xFDBB, "M", "كمم"), + (0xFDBC, "M", "لجم"), + (0xFDBD, "M", "نجح"), + (0xFDBE, "M", "جحي"), + (0xFDBF, "M", "حجي"), + (0xFDC0, "M", "مجي"), + (0xFDC1, "M", "فمي"), + (0xFDC2, "M", "بحي"), + (0xFDC3, "M", "كمم"), + (0xFDC4, "M", "عجم"), + (0xFDC5, "M", "صمم"), + (0xFDC6, "M", "سخي"), + (0xFDC7, "M", "نجي"), + (0xFDC8, "X"), + (0xFDCF, "V"), + (0xFDD0, "X"), + (0xFDF0, "M", "صلے"), + (0xFDF1, "M", "قلے"), + (0xFDF2, "M", "الله"), + (0xFDF3, "M", "اكبر"), + (0xFDF4, "M", "محمد"), + (0xFDF5, "M", "صلعم"), + (0xFDF6, "M", "رسول"), + (0xFDF7, "M", "عليه"), + (0xFDF8, "M", "وسلم"), + (0xFDF9, "M", "صلى"), + (0xFDFA, "M", "صلى الله عليه وسلم"), + (0xFDFB, "M", "جل جلاله"), + (0xFDFC, "M", "ریال"), + (0xFDFD, "V"), + (0xFE00, "I"), + (0xFE10, "M", ","), + (0xFE11, "M", "、"), + (0xFE12, "X"), + (0xFE13, "M", ":"), + (0xFE14, "M", ";"), + (0xFE15, "M", "!"), + (0xFE16, "M", "?"), + (0xFE17, "M", "〖"), + (0xFE18, "M", "〗"), + (0xFE19, "X"), + (0xFE20, "V"), + (0xFE30, "X"), + (0xFE31, "M", "—"), + (0xFE32, "M", "–"), + ] + + +def _seg_50() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFE33, "M", "_"), + (0xFE35, "M", "("), + (0xFE36, "M", ")"), + (0xFE37, "M", "{"), + (0xFE38, "M", "}"), + (0xFE39, "M", "〔"), + (0xFE3A, "M", "〕"), + (0xFE3B, "M", "【"), + (0xFE3C, "M", "】"), + (0xFE3D, "M", "《"), + (0xFE3E, "M", "》"), + (0xFE3F, "M", "〈"), + (0xFE40, "M", "〉"), + (0xFE41, "M", "「"), + (0xFE42, "M", "」"), + (0xFE43, "M", "『"), + (0xFE44, "M", "』"), + (0xFE45, "V"), + (0xFE47, "M", "["), + (0xFE48, "M", "]"), + (0xFE49, "M", " ̅"), + (0xFE4D, "M", "_"), + (0xFE50, "M", ","), + (0xFE51, "M", "、"), + (0xFE52, "X"), + (0xFE54, "M", ";"), + (0xFE55, "M", ":"), + (0xFE56, "M", "?"), + (0xFE57, "M", "!"), + (0xFE58, "M", "—"), + (0xFE59, "M", "("), + (0xFE5A, "M", ")"), + (0xFE5B, "M", "{"), + (0xFE5C, "M", "}"), + (0xFE5D, "M", "〔"), + (0xFE5E, "M", "〕"), + (0xFE5F, "M", "#"), + (0xFE60, "M", "&"), + (0xFE61, "M", "*"), + (0xFE62, "M", "+"), + (0xFE63, "M", "-"), + (0xFE64, "M", "<"), + (0xFE65, "M", ">"), + (0xFE66, "M", "="), + (0xFE67, "X"), + (0xFE68, "M", "\\"), + (0xFE69, "M", "$"), + (0xFE6A, "M", "%"), + (0xFE6B, "M", "@"), + (0xFE6C, "X"), + (0xFE70, "M", " ً"), + (0xFE71, "M", "ـً"), + (0xFE72, "M", " ٌ"), + (0xFE73, "V"), + (0xFE74, "M", " ٍ"), + (0xFE75, "X"), + (0xFE76, "M", " َ"), + (0xFE77, "M", "ـَ"), + (0xFE78, "M", " ُ"), + (0xFE79, "M", "ـُ"), + (0xFE7A, "M", " ِ"), + (0xFE7B, "M", "ـِ"), + (0xFE7C, "M", " ّ"), + (0xFE7D, "M", "ـّ"), + (0xFE7E, "M", " ْ"), + (0xFE7F, "M", "ـْ"), + (0xFE80, "M", "ء"), + (0xFE81, "M", "آ"), + (0xFE83, "M", "أ"), + (0xFE85, "M", "ؤ"), + (0xFE87, "M", "إ"), + (0xFE89, "M", "ئ"), + (0xFE8D, "M", "ا"), + (0xFE8F, "M", "ب"), + (0xFE93, "M", "ة"), + (0xFE95, "M", "ت"), + (0xFE99, "M", "ث"), + (0xFE9D, "M", "ج"), + (0xFEA1, "M", "ح"), + (0xFEA5, "M", "خ"), + (0xFEA9, "M", "د"), + (0xFEAB, "M", "ذ"), + (0xFEAD, "M", "ر"), + (0xFEAF, "M", "ز"), + (0xFEB1, "M", "س"), + (0xFEB5, "M", "ش"), + (0xFEB9, "M", "ص"), + (0xFEBD, "M", "ض"), + (0xFEC1, "M", "ط"), + (0xFEC5, "M", "ظ"), + (0xFEC9, "M", "ع"), + (0xFECD, "M", "غ"), + (0xFED1, "M", "ف"), + (0xFED5, "M", "ق"), + (0xFED9, "M", "ك"), + (0xFEDD, "M", "ل"), + (0xFEE1, "M", "م"), + (0xFEE5, "M", "ن"), + (0xFEE9, "M", "ه"), + (0xFEED, "M", "و"), + ] + + +def _seg_51() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFEEF, "M", "ى"), + (0xFEF1, "M", "ي"), + (0xFEF5, "M", "لآ"), + (0xFEF7, "M", "لأ"), + (0xFEF9, "M", "لإ"), + (0xFEFB, "M", "لا"), + (0xFEFD, "X"), + (0xFEFF, "I"), + (0xFF00, "X"), + (0xFF01, "M", "!"), + (0xFF02, "M", '"'), + (0xFF03, "M", "#"), + (0xFF04, "M", "$"), + (0xFF05, "M", "%"), + (0xFF06, "M", "&"), + (0xFF07, "M", "'"), + (0xFF08, "M", "("), + (0xFF09, "M", ")"), + (0xFF0A, "M", "*"), + (0xFF0B, "M", "+"), + (0xFF0C, "M", ","), + (0xFF0D, "M", "-"), + (0xFF0E, "M", "."), + (0xFF0F, "M", "/"), + (0xFF10, "M", "0"), + (0xFF11, "M", "1"), + (0xFF12, "M", "2"), + (0xFF13, "M", "3"), + (0xFF14, "M", "4"), + (0xFF15, "M", "5"), + (0xFF16, "M", "6"), + (0xFF17, "M", "7"), + (0xFF18, "M", "8"), + (0xFF19, "M", "9"), + (0xFF1A, "M", ":"), + (0xFF1B, "M", ";"), + (0xFF1C, "M", "<"), + (0xFF1D, "M", "="), + (0xFF1E, "M", ">"), + (0xFF1F, "M", "?"), + (0xFF20, "M", "@"), + (0xFF21, "M", "a"), + (0xFF22, "M", "b"), + (0xFF23, "M", "c"), + (0xFF24, "M", "d"), + (0xFF25, "M", "e"), + (0xFF26, "M", "f"), + (0xFF27, "M", "g"), + (0xFF28, "M", "h"), + (0xFF29, "M", "i"), + (0xFF2A, "M", "j"), + (0xFF2B, "M", "k"), + (0xFF2C, "M", "l"), + (0xFF2D, "M", "m"), + (0xFF2E, "M", "n"), + (0xFF2F, "M", "o"), + (0xFF30, "M", "p"), + (0xFF31, "M", "q"), + (0xFF32, "M", "r"), + (0xFF33, "M", "s"), + (0xFF34, "M", "t"), + (0xFF35, "M", "u"), + (0xFF36, "M", "v"), + (0xFF37, "M", "w"), + (0xFF38, "M", "x"), + (0xFF39, "M", "y"), + (0xFF3A, "M", "z"), + (0xFF3B, "M", "["), + (0xFF3C, "M", "\\"), + (0xFF3D, "M", "]"), + (0xFF3E, "M", "^"), + (0xFF3F, "M", "_"), + (0xFF40, "M", "`"), + (0xFF41, "M", "a"), + (0xFF42, "M", "b"), + (0xFF43, "M", "c"), + (0xFF44, "M", "d"), + (0xFF45, "M", "e"), + (0xFF46, "M", "f"), + (0xFF47, "M", "g"), + (0xFF48, "M", "h"), + (0xFF49, "M", "i"), + (0xFF4A, "M", "j"), + (0xFF4B, "M", "k"), + (0xFF4C, "M", "l"), + (0xFF4D, "M", "m"), + (0xFF4E, "M", "n"), + (0xFF4F, "M", "o"), + (0xFF50, "M", "p"), + (0xFF51, "M", "q"), + (0xFF52, "M", "r"), + (0xFF53, "M", "s"), + (0xFF54, "M", "t"), + (0xFF55, "M", "u"), + (0xFF56, "M", "v"), + (0xFF57, "M", "w"), + (0xFF58, "M", "x"), + (0xFF59, "M", "y"), + (0xFF5A, "M", "z"), + (0xFF5B, "M", "{"), + ] + + +def _seg_52() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFF5C, "M", "|"), + (0xFF5D, "M", "}"), + (0xFF5E, "M", "~"), + (0xFF5F, "M", "⦅"), + (0xFF60, "M", "⦆"), + (0xFF61, "M", "."), + (0xFF62, "M", "「"), + (0xFF63, "M", "」"), + (0xFF64, "M", "、"), + (0xFF65, "M", "・"), + (0xFF66, "M", "ヲ"), + (0xFF67, "M", "ァ"), + (0xFF68, "M", "ィ"), + (0xFF69, "M", "ゥ"), + (0xFF6A, "M", "ェ"), + (0xFF6B, "M", "ォ"), + (0xFF6C, "M", "ャ"), + (0xFF6D, "M", "ュ"), + (0xFF6E, "M", "ョ"), + (0xFF6F, "M", "ッ"), + (0xFF70, "M", "ー"), + (0xFF71, "M", "ア"), + (0xFF72, "M", "イ"), + (0xFF73, "M", "ウ"), + (0xFF74, "M", "エ"), + (0xFF75, "M", "オ"), + (0xFF76, "M", "カ"), + (0xFF77, "M", "キ"), + (0xFF78, "M", "ク"), + (0xFF79, "M", "ケ"), + (0xFF7A, "M", "コ"), + (0xFF7B, "M", "サ"), + (0xFF7C, "M", "シ"), + (0xFF7D, "M", "ス"), + (0xFF7E, "M", "セ"), + (0xFF7F, "M", "ソ"), + (0xFF80, "M", "タ"), + (0xFF81, "M", "チ"), + (0xFF82, "M", "ツ"), + (0xFF83, "M", "テ"), + (0xFF84, "M", "ト"), + (0xFF85, "M", "ナ"), + (0xFF86, "M", "ニ"), + (0xFF87, "M", "ヌ"), + (0xFF88, "M", "ネ"), + (0xFF89, "M", "ノ"), + (0xFF8A, "M", "ハ"), + (0xFF8B, "M", "ヒ"), + (0xFF8C, "M", "フ"), + (0xFF8D, "M", "ヘ"), + (0xFF8E, "M", "ホ"), + (0xFF8F, "M", "マ"), + (0xFF90, "M", "ミ"), + (0xFF91, "M", "ム"), + (0xFF92, "M", "メ"), + (0xFF93, "M", "モ"), + (0xFF94, "M", "ヤ"), + (0xFF95, "M", "ユ"), + (0xFF96, "M", "ヨ"), + (0xFF97, "M", "ラ"), + (0xFF98, "M", "リ"), + (0xFF99, "M", "ル"), + (0xFF9A, "M", "レ"), + (0xFF9B, "M", "ロ"), + (0xFF9C, "M", "ワ"), + (0xFF9D, "M", "ン"), + (0xFF9E, "M", "゙"), + (0xFF9F, "M", "゚"), + (0xFFA0, "I"), + (0xFFA1, "M", "ᄀ"), + (0xFFA2, "M", "ᄁ"), + (0xFFA3, "M", "ᆪ"), + (0xFFA4, "M", "ᄂ"), + (0xFFA5, "M", "ᆬ"), + (0xFFA6, "M", "ᆭ"), + (0xFFA7, "M", "ᄃ"), + (0xFFA8, "M", "ᄄ"), + (0xFFA9, "M", "ᄅ"), + (0xFFAA, "M", "ᆰ"), + (0xFFAB, "M", "ᆱ"), + (0xFFAC, "M", "ᆲ"), + (0xFFAD, "M", "ᆳ"), + (0xFFAE, "M", "ᆴ"), + (0xFFAF, "M", "ᆵ"), + (0xFFB0, "M", "ᄚ"), + (0xFFB1, "M", "ᄆ"), + (0xFFB2, "M", "ᄇ"), + (0xFFB3, "M", "ᄈ"), + (0xFFB4, "M", "ᄡ"), + (0xFFB5, "M", "ᄉ"), + (0xFFB6, "M", "ᄊ"), + (0xFFB7, "M", "ᄋ"), + (0xFFB8, "M", "ᄌ"), + (0xFFB9, "M", "ᄍ"), + (0xFFBA, "M", "ᄎ"), + (0xFFBB, "M", "ᄏ"), + (0xFFBC, "M", "ᄐ"), + (0xFFBD, "M", "ᄑ"), + (0xFFBE, "M", "ᄒ"), + (0xFFBF, "X"), + ] + + +def _seg_53() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFFC2, "M", "ᅡ"), + (0xFFC3, "M", "ᅢ"), + (0xFFC4, "M", "ᅣ"), + (0xFFC5, "M", "ᅤ"), + (0xFFC6, "M", "ᅥ"), + (0xFFC7, "M", "ᅦ"), + (0xFFC8, "X"), + (0xFFCA, "M", "ᅧ"), + (0xFFCB, "M", "ᅨ"), + (0xFFCC, "M", "ᅩ"), + (0xFFCD, "M", "ᅪ"), + (0xFFCE, "M", "ᅫ"), + (0xFFCF, "M", "ᅬ"), + (0xFFD0, "X"), + (0xFFD2, "M", "ᅭ"), + (0xFFD3, "M", "ᅮ"), + (0xFFD4, "M", "ᅯ"), + (0xFFD5, "M", "ᅰ"), + (0xFFD6, "M", "ᅱ"), + (0xFFD7, "M", "ᅲ"), + (0xFFD8, "X"), + (0xFFDA, "M", "ᅳ"), + (0xFFDB, "M", "ᅴ"), + (0xFFDC, "M", "ᅵ"), + (0xFFDD, "X"), + (0xFFE0, "M", "¢"), + (0xFFE1, "M", "£"), + (0xFFE2, "M", "¬"), + (0xFFE3, "M", " ̄"), + (0xFFE4, "M", "¦"), + (0xFFE5, "M", "¥"), + (0xFFE6, "M", "₩"), + (0xFFE7, "X"), + (0xFFE8, "M", "│"), + (0xFFE9, "M", "←"), + (0xFFEA, "M", "↑"), + (0xFFEB, "M", "→"), + (0xFFEC, "M", "↓"), + (0xFFED, "M", "■"), + (0xFFEE, "M", "○"), + (0xFFEF, "X"), + (0x10000, "V"), + (0x1000C, "X"), + (0x1000D, "V"), + (0x10027, "X"), + (0x10028, "V"), + (0x1003B, "X"), + (0x1003C, "V"), + (0x1003E, "X"), + (0x1003F, "V"), + (0x1004E, "X"), + (0x10050, "V"), + (0x1005E, "X"), + (0x10080, "V"), + (0x100FB, "X"), + (0x10100, "V"), + (0x10103, "X"), + (0x10107, "V"), + (0x10134, "X"), + (0x10137, "V"), + (0x1018F, "X"), + (0x10190, "V"), + (0x1019D, "X"), + (0x101A0, "V"), + (0x101A1, "X"), + (0x101D0, "V"), + (0x101FE, "X"), + (0x10280, "V"), + (0x1029D, "X"), + (0x102A0, "V"), + (0x102D1, "X"), + (0x102E0, "V"), + (0x102FC, "X"), + (0x10300, "V"), + (0x10324, "X"), + (0x1032D, "V"), + (0x1034B, "X"), + (0x10350, "V"), + (0x1037B, "X"), + (0x10380, "V"), + (0x1039E, "X"), + (0x1039F, "V"), + (0x103C4, "X"), + (0x103C8, "V"), + (0x103D6, "X"), + (0x10400, "M", "𐐨"), + (0x10401, "M", "𐐩"), + (0x10402, "M", "𐐪"), + (0x10403, "M", "𐐫"), + (0x10404, "M", "𐐬"), + (0x10405, "M", "𐐭"), + (0x10406, "M", "𐐮"), + (0x10407, "M", "𐐯"), + (0x10408, "M", "𐐰"), + (0x10409, "M", "𐐱"), + (0x1040A, "M", "𐐲"), + (0x1040B, "M", "𐐳"), + (0x1040C, "M", "𐐴"), + (0x1040D, "M", "𐐵"), + (0x1040E, "M", "𐐶"), + ] + + +def _seg_54() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1040F, "M", "𐐷"), + (0x10410, "M", "𐐸"), + (0x10411, "M", "𐐹"), + (0x10412, "M", "𐐺"), + (0x10413, "M", "𐐻"), + (0x10414, "M", "𐐼"), + (0x10415, "M", "𐐽"), + (0x10416, "M", "𐐾"), + (0x10417, "M", "𐐿"), + (0x10418, "M", "𐑀"), + (0x10419, "M", "𐑁"), + (0x1041A, "M", "𐑂"), + (0x1041B, "M", "𐑃"), + (0x1041C, "M", "𐑄"), + (0x1041D, "M", "𐑅"), + (0x1041E, "M", "𐑆"), + (0x1041F, "M", "𐑇"), + (0x10420, "M", "𐑈"), + (0x10421, "M", "𐑉"), + (0x10422, "M", "𐑊"), + (0x10423, "M", "𐑋"), + (0x10424, "M", "𐑌"), + (0x10425, "M", "𐑍"), + (0x10426, "M", "𐑎"), + (0x10427, "M", "𐑏"), + (0x10428, "V"), + (0x1049E, "X"), + (0x104A0, "V"), + (0x104AA, "X"), + (0x104B0, "M", "𐓘"), + (0x104B1, "M", "𐓙"), + (0x104B2, "M", "𐓚"), + (0x104B3, "M", "𐓛"), + (0x104B4, "M", "𐓜"), + (0x104B5, "M", "𐓝"), + (0x104B6, "M", "𐓞"), + (0x104B7, "M", "𐓟"), + (0x104B8, "M", "𐓠"), + (0x104B9, "M", "𐓡"), + (0x104BA, "M", "𐓢"), + (0x104BB, "M", "𐓣"), + (0x104BC, "M", "𐓤"), + (0x104BD, "M", "𐓥"), + (0x104BE, "M", "𐓦"), + (0x104BF, "M", "𐓧"), + (0x104C0, "M", "𐓨"), + (0x104C1, "M", "𐓩"), + (0x104C2, "M", "𐓪"), + (0x104C3, "M", "𐓫"), + (0x104C4, "M", "𐓬"), + (0x104C5, "M", "𐓭"), + (0x104C6, "M", "𐓮"), + (0x104C7, "M", "𐓯"), + (0x104C8, "M", "𐓰"), + (0x104C9, "M", "𐓱"), + (0x104CA, "M", "𐓲"), + (0x104CB, "M", "𐓳"), + (0x104CC, "M", "𐓴"), + (0x104CD, "M", "𐓵"), + (0x104CE, "M", "𐓶"), + (0x104CF, "M", "𐓷"), + (0x104D0, "M", "𐓸"), + (0x104D1, "M", "𐓹"), + (0x104D2, "M", "𐓺"), + (0x104D3, "M", "𐓻"), + (0x104D4, "X"), + (0x104D8, "V"), + (0x104FC, "X"), + (0x10500, "V"), + (0x10528, "X"), + (0x10530, "V"), + (0x10564, "X"), + (0x1056F, "V"), + (0x10570, "M", "𐖗"), + (0x10571, "M", "𐖘"), + (0x10572, "M", "𐖙"), + (0x10573, "M", "𐖚"), + (0x10574, "M", "𐖛"), + (0x10575, "M", "𐖜"), + (0x10576, "M", "𐖝"), + (0x10577, "M", "𐖞"), + (0x10578, "M", "𐖟"), + (0x10579, "M", "𐖠"), + (0x1057A, "M", "𐖡"), + (0x1057B, "X"), + (0x1057C, "M", "𐖣"), + (0x1057D, "M", "𐖤"), + (0x1057E, "M", "𐖥"), + (0x1057F, "M", "𐖦"), + (0x10580, "M", "𐖧"), + (0x10581, "M", "𐖨"), + (0x10582, "M", "𐖩"), + (0x10583, "M", "𐖪"), + (0x10584, "M", "𐖫"), + (0x10585, "M", "𐖬"), + (0x10586, "M", "𐖭"), + (0x10587, "M", "𐖮"), + (0x10588, "M", "𐖯"), + (0x10589, "M", "𐖰"), + (0x1058A, "M", "𐖱"), + ] + + +def _seg_55() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1058B, "X"), + (0x1058C, "M", "𐖳"), + (0x1058D, "M", "𐖴"), + (0x1058E, "M", "𐖵"), + (0x1058F, "M", "𐖶"), + (0x10590, "M", "𐖷"), + (0x10591, "M", "𐖸"), + (0x10592, "M", "𐖹"), + (0x10593, "X"), + (0x10594, "M", "𐖻"), + (0x10595, "M", "𐖼"), + (0x10596, "X"), + (0x10597, "V"), + (0x105A2, "X"), + (0x105A3, "V"), + (0x105B2, "X"), + (0x105B3, "V"), + (0x105BA, "X"), + (0x105BB, "V"), + (0x105BD, "X"), + (0x105C0, "V"), + (0x105F4, "X"), + (0x10600, "V"), + (0x10737, "X"), + (0x10740, "V"), + (0x10756, "X"), + (0x10760, "V"), + (0x10768, "X"), + (0x10780, "V"), + (0x10781, "M", "ː"), + (0x10782, "M", "ˑ"), + (0x10783, "M", "æ"), + (0x10784, "M", "ʙ"), + (0x10785, "M", "ɓ"), + (0x10786, "X"), + (0x10787, "M", "ʣ"), + (0x10788, "M", "ꭦ"), + (0x10789, "M", "ʥ"), + (0x1078A, "M", "ʤ"), + (0x1078B, "M", "ɖ"), + (0x1078C, "M", "ɗ"), + (0x1078D, "M", "ᶑ"), + (0x1078E, "M", "ɘ"), + (0x1078F, "M", "ɞ"), + (0x10790, "M", "ʩ"), + (0x10791, "M", "ɤ"), + (0x10792, "M", "ɢ"), + (0x10793, "M", "ɠ"), + (0x10794, "M", "ʛ"), + (0x10795, "M", "ħ"), + (0x10796, "M", "ʜ"), + (0x10797, "M", "ɧ"), + (0x10798, "M", "ʄ"), + (0x10799, "M", "ʪ"), + (0x1079A, "M", "ʫ"), + (0x1079B, "M", "ɬ"), + (0x1079C, "M", "𝼄"), + (0x1079D, "M", "ꞎ"), + (0x1079E, "M", "ɮ"), + (0x1079F, "M", "𝼅"), + (0x107A0, "M", "ʎ"), + (0x107A1, "M", "𝼆"), + (0x107A2, "M", "ø"), + (0x107A3, "M", "ɶ"), + (0x107A4, "M", "ɷ"), + (0x107A5, "M", "q"), + (0x107A6, "M", "ɺ"), + (0x107A7, "M", "𝼈"), + (0x107A8, "M", "ɽ"), + (0x107A9, "M", "ɾ"), + (0x107AA, "M", "ʀ"), + (0x107AB, "M", "ʨ"), + (0x107AC, "M", "ʦ"), + (0x107AD, "M", "ꭧ"), + (0x107AE, "M", "ʧ"), + (0x107AF, "M", "ʈ"), + (0x107B0, "M", "ⱱ"), + (0x107B1, "X"), + (0x107B2, "M", "ʏ"), + (0x107B3, "M", "ʡ"), + (0x107B4, "M", "ʢ"), + (0x107B5, "M", "ʘ"), + (0x107B6, "M", "ǀ"), + (0x107B7, "M", "ǁ"), + (0x107B8, "M", "ǂ"), + (0x107B9, "M", "𝼊"), + (0x107BA, "M", "𝼞"), + (0x107BB, "X"), + (0x10800, "V"), + (0x10806, "X"), + (0x10808, "V"), + (0x10809, "X"), + (0x1080A, "V"), + (0x10836, "X"), + (0x10837, "V"), + (0x10839, "X"), + (0x1083C, "V"), + (0x1083D, "X"), + (0x1083F, "V"), + (0x10856, "X"), + ] + + +def _seg_56() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x10857, "V"), + (0x1089F, "X"), + (0x108A7, "V"), + (0x108B0, "X"), + (0x108E0, "V"), + (0x108F3, "X"), + (0x108F4, "V"), + (0x108F6, "X"), + (0x108FB, "V"), + (0x1091C, "X"), + (0x1091F, "V"), + (0x1093A, "X"), + (0x1093F, "V"), + (0x10940, "X"), + (0x10980, "V"), + (0x109B8, "X"), + (0x109BC, "V"), + (0x109D0, "X"), + (0x109D2, "V"), + (0x10A04, "X"), + (0x10A05, "V"), + (0x10A07, "X"), + (0x10A0C, "V"), + (0x10A14, "X"), + (0x10A15, "V"), + (0x10A18, "X"), + (0x10A19, "V"), + (0x10A36, "X"), + (0x10A38, "V"), + (0x10A3B, "X"), + (0x10A3F, "V"), + (0x10A49, "X"), + (0x10A50, "V"), + (0x10A59, "X"), + (0x10A60, "V"), + (0x10AA0, "X"), + (0x10AC0, "V"), + (0x10AE7, "X"), + (0x10AEB, "V"), + (0x10AF7, "X"), + (0x10B00, "V"), + (0x10B36, "X"), + (0x10B39, "V"), + (0x10B56, "X"), + (0x10B58, "V"), + (0x10B73, "X"), + (0x10B78, "V"), + (0x10B92, "X"), + (0x10B99, "V"), + (0x10B9D, "X"), + (0x10BA9, "V"), + (0x10BB0, "X"), + (0x10C00, "V"), + (0x10C49, "X"), + (0x10C80, "M", "𐳀"), + (0x10C81, "M", "𐳁"), + (0x10C82, "M", "𐳂"), + (0x10C83, "M", "𐳃"), + (0x10C84, "M", "𐳄"), + (0x10C85, "M", "𐳅"), + (0x10C86, "M", "𐳆"), + (0x10C87, "M", "𐳇"), + (0x10C88, "M", "𐳈"), + (0x10C89, "M", "𐳉"), + (0x10C8A, "M", "𐳊"), + (0x10C8B, "M", "𐳋"), + (0x10C8C, "M", "𐳌"), + (0x10C8D, "M", "𐳍"), + (0x10C8E, "M", "𐳎"), + (0x10C8F, "M", "𐳏"), + (0x10C90, "M", "𐳐"), + (0x10C91, "M", "𐳑"), + (0x10C92, "M", "𐳒"), + (0x10C93, "M", "𐳓"), + (0x10C94, "M", "𐳔"), + (0x10C95, "M", "𐳕"), + (0x10C96, "M", "𐳖"), + (0x10C97, "M", "𐳗"), + (0x10C98, "M", "𐳘"), + (0x10C99, "M", "𐳙"), + (0x10C9A, "M", "𐳚"), + (0x10C9B, "M", "𐳛"), + (0x10C9C, "M", "𐳜"), + (0x10C9D, "M", "𐳝"), + (0x10C9E, "M", "𐳞"), + (0x10C9F, "M", "𐳟"), + (0x10CA0, "M", "𐳠"), + (0x10CA1, "M", "𐳡"), + (0x10CA2, "M", "𐳢"), + (0x10CA3, "M", "𐳣"), + (0x10CA4, "M", "𐳤"), + (0x10CA5, "M", "𐳥"), + (0x10CA6, "M", "𐳦"), + (0x10CA7, "M", "𐳧"), + (0x10CA8, "M", "𐳨"), + (0x10CA9, "M", "𐳩"), + (0x10CAA, "M", "𐳪"), + (0x10CAB, "M", "𐳫"), + (0x10CAC, "M", "𐳬"), + (0x10CAD, "M", "𐳭"), + ] + + +def _seg_57() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x10CAE, "M", "𐳮"), + (0x10CAF, "M", "𐳯"), + (0x10CB0, "M", "𐳰"), + (0x10CB1, "M", "𐳱"), + (0x10CB2, "M", "𐳲"), + (0x10CB3, "X"), + (0x10CC0, "V"), + (0x10CF3, "X"), + (0x10CFA, "V"), + (0x10D28, "X"), + (0x10D30, "V"), + (0x10D3A, "X"), + (0x10D40, "V"), + (0x10D50, "M", "𐵰"), + (0x10D51, "M", "𐵱"), + (0x10D52, "M", "𐵲"), + (0x10D53, "M", "𐵳"), + (0x10D54, "M", "𐵴"), + (0x10D55, "M", "𐵵"), + (0x10D56, "M", "𐵶"), + (0x10D57, "M", "𐵷"), + (0x10D58, "M", "𐵸"), + (0x10D59, "M", "𐵹"), + (0x10D5A, "M", "𐵺"), + (0x10D5B, "M", "𐵻"), + (0x10D5C, "M", "𐵼"), + (0x10D5D, "M", "𐵽"), + (0x10D5E, "M", "𐵾"), + (0x10D5F, "M", "𐵿"), + (0x10D60, "M", "𐶀"), + (0x10D61, "M", "𐶁"), + (0x10D62, "M", "𐶂"), + (0x10D63, "M", "𐶃"), + (0x10D64, "M", "𐶄"), + (0x10D65, "M", "𐶅"), + (0x10D66, "X"), + (0x10D69, "V"), + (0x10D86, "X"), + (0x10D8E, "V"), + (0x10D90, "X"), + (0x10E60, "V"), + (0x10E7F, "X"), + (0x10E80, "V"), + (0x10EAA, "X"), + (0x10EAB, "V"), + (0x10EAE, "X"), + (0x10EB0, "V"), + (0x10EB2, "X"), + (0x10EC2, "V"), + (0x10EC5, "X"), + (0x10EFC, "V"), + (0x10F28, "X"), + (0x10F30, "V"), + (0x10F5A, "X"), + (0x10F70, "V"), + (0x10F8A, "X"), + (0x10FB0, "V"), + (0x10FCC, "X"), + (0x10FE0, "V"), + (0x10FF7, "X"), + (0x11000, "V"), + (0x1104E, "X"), + (0x11052, "V"), + (0x11076, "X"), + (0x1107F, "V"), + (0x110BD, "X"), + (0x110BE, "V"), + (0x110C3, "X"), + (0x110D0, "V"), + (0x110E9, "X"), + (0x110F0, "V"), + (0x110FA, "X"), + (0x11100, "V"), + (0x11135, "X"), + (0x11136, "V"), + (0x11148, "X"), + (0x11150, "V"), + (0x11177, "X"), + (0x11180, "V"), + (0x111E0, "X"), + (0x111E1, "V"), + (0x111F5, "X"), + (0x11200, "V"), + (0x11212, "X"), + (0x11213, "V"), + (0x11242, "X"), + (0x11280, "V"), + (0x11287, "X"), + (0x11288, "V"), + (0x11289, "X"), + (0x1128A, "V"), + (0x1128E, "X"), + (0x1128F, "V"), + (0x1129E, "X"), + (0x1129F, "V"), + (0x112AA, "X"), + (0x112B0, "V"), + (0x112EB, "X"), + (0x112F0, "V"), + (0x112FA, "X"), + ] + + +def _seg_58() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x11300, "V"), + (0x11304, "X"), + (0x11305, "V"), + (0x1130D, "X"), + (0x1130F, "V"), + (0x11311, "X"), + (0x11313, "V"), + (0x11329, "X"), + (0x1132A, "V"), + (0x11331, "X"), + (0x11332, "V"), + (0x11334, "X"), + (0x11335, "V"), + (0x1133A, "X"), + (0x1133B, "V"), + (0x11345, "X"), + (0x11347, "V"), + (0x11349, "X"), + (0x1134B, "V"), + (0x1134E, "X"), + (0x11350, "V"), + (0x11351, "X"), + (0x11357, "V"), + (0x11358, "X"), + (0x1135D, "V"), + (0x11364, "X"), + (0x11366, "V"), + (0x1136D, "X"), + (0x11370, "V"), + (0x11375, "X"), + (0x11380, "V"), + (0x1138A, "X"), + (0x1138B, "V"), + (0x1138C, "X"), + (0x1138E, "V"), + (0x1138F, "X"), + (0x11390, "V"), + (0x113B6, "X"), + (0x113B7, "V"), + (0x113C1, "X"), + (0x113C2, "V"), + (0x113C3, "X"), + (0x113C5, "V"), + (0x113C6, "X"), + (0x113C7, "V"), + (0x113CB, "X"), + (0x113CC, "V"), + (0x113D6, "X"), + (0x113D7, "V"), + (0x113D9, "X"), + (0x113E1, "V"), + (0x113E3, "X"), + (0x11400, "V"), + (0x1145C, "X"), + (0x1145D, "V"), + (0x11462, "X"), + (0x11480, "V"), + (0x114C8, "X"), + (0x114D0, "V"), + (0x114DA, "X"), + (0x11580, "V"), + (0x115B6, "X"), + (0x115B8, "V"), + (0x115DE, "X"), + (0x11600, "V"), + (0x11645, "X"), + (0x11650, "V"), + (0x1165A, "X"), + (0x11660, "V"), + (0x1166D, "X"), + (0x11680, "V"), + (0x116BA, "X"), + (0x116C0, "V"), + (0x116CA, "X"), + (0x116D0, "V"), + (0x116E4, "X"), + (0x11700, "V"), + (0x1171B, "X"), + (0x1171D, "V"), + (0x1172C, "X"), + (0x11730, "V"), + (0x11747, "X"), + (0x11800, "V"), + (0x1183C, "X"), + (0x118A0, "M", "𑣀"), + (0x118A1, "M", "𑣁"), + (0x118A2, "M", "𑣂"), + (0x118A3, "M", "𑣃"), + (0x118A4, "M", "𑣄"), + (0x118A5, "M", "𑣅"), + (0x118A6, "M", "𑣆"), + (0x118A7, "M", "𑣇"), + (0x118A8, "M", "𑣈"), + (0x118A9, "M", "𑣉"), + (0x118AA, "M", "𑣊"), + (0x118AB, "M", "𑣋"), + (0x118AC, "M", "𑣌"), + (0x118AD, "M", "𑣍"), + (0x118AE, "M", "𑣎"), + (0x118AF, "M", "𑣏"), + ] + + +def _seg_59() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x118B0, "M", "𑣐"), + (0x118B1, "M", "𑣑"), + (0x118B2, "M", "𑣒"), + (0x118B3, "M", "𑣓"), + (0x118B4, "M", "𑣔"), + (0x118B5, "M", "𑣕"), + (0x118B6, "M", "𑣖"), + (0x118B7, "M", "𑣗"), + (0x118B8, "M", "𑣘"), + (0x118B9, "M", "𑣙"), + (0x118BA, "M", "𑣚"), + (0x118BB, "M", "𑣛"), + (0x118BC, "M", "𑣜"), + (0x118BD, "M", "𑣝"), + (0x118BE, "M", "𑣞"), + (0x118BF, "M", "𑣟"), + (0x118C0, "V"), + (0x118F3, "X"), + (0x118FF, "V"), + (0x11907, "X"), + (0x11909, "V"), + (0x1190A, "X"), + (0x1190C, "V"), + (0x11914, "X"), + (0x11915, "V"), + (0x11917, "X"), + (0x11918, "V"), + (0x11936, "X"), + (0x11937, "V"), + (0x11939, "X"), + (0x1193B, "V"), + (0x11947, "X"), + (0x11950, "V"), + (0x1195A, "X"), + (0x119A0, "V"), + (0x119A8, "X"), + (0x119AA, "V"), + (0x119D8, "X"), + (0x119DA, "V"), + (0x119E5, "X"), + (0x11A00, "V"), + (0x11A48, "X"), + (0x11A50, "V"), + (0x11AA3, "X"), + (0x11AB0, "V"), + (0x11AF9, "X"), + (0x11B00, "V"), + (0x11B0A, "X"), + (0x11BC0, "V"), + (0x11BE2, "X"), + (0x11BF0, "V"), + (0x11BFA, "X"), + (0x11C00, "V"), + (0x11C09, "X"), + (0x11C0A, "V"), + (0x11C37, "X"), + (0x11C38, "V"), + (0x11C46, "X"), + (0x11C50, "V"), + (0x11C6D, "X"), + (0x11C70, "V"), + (0x11C90, "X"), + (0x11C92, "V"), + (0x11CA8, "X"), + (0x11CA9, "V"), + (0x11CB7, "X"), + (0x11D00, "V"), + (0x11D07, "X"), + (0x11D08, "V"), + (0x11D0A, "X"), + (0x11D0B, "V"), + (0x11D37, "X"), + (0x11D3A, "V"), + (0x11D3B, "X"), + (0x11D3C, "V"), + (0x11D3E, "X"), + (0x11D3F, "V"), + (0x11D48, "X"), + (0x11D50, "V"), + (0x11D5A, "X"), + (0x11D60, "V"), + (0x11D66, "X"), + (0x11D67, "V"), + (0x11D69, "X"), + (0x11D6A, "V"), + (0x11D8F, "X"), + (0x11D90, "V"), + (0x11D92, "X"), + (0x11D93, "V"), + (0x11D99, "X"), + (0x11DA0, "V"), + (0x11DAA, "X"), + (0x11EE0, "V"), + (0x11EF9, "X"), + (0x11F00, "V"), + (0x11F11, "X"), + (0x11F12, "V"), + (0x11F3B, "X"), + (0x11F3E, "V"), + (0x11F5B, "X"), + ] + + +def _seg_60() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x11FB0, "V"), + (0x11FB1, "X"), + (0x11FC0, "V"), + (0x11FF2, "X"), + (0x11FFF, "V"), + (0x1239A, "X"), + (0x12400, "V"), + (0x1246F, "X"), + (0x12470, "V"), + (0x12475, "X"), + (0x12480, "V"), + (0x12544, "X"), + (0x12F90, "V"), + (0x12FF3, "X"), + (0x13000, "V"), + (0x13430, "X"), + (0x13440, "V"), + (0x13456, "X"), + (0x13460, "V"), + (0x143FB, "X"), + (0x14400, "V"), + (0x14647, "X"), + (0x16100, "V"), + (0x1613A, "X"), + (0x16800, "V"), + (0x16A39, "X"), + (0x16A40, "V"), + (0x16A5F, "X"), + (0x16A60, "V"), + (0x16A6A, "X"), + (0x16A6E, "V"), + (0x16ABF, "X"), + (0x16AC0, "V"), + (0x16ACA, "X"), + (0x16AD0, "V"), + (0x16AEE, "X"), + (0x16AF0, "V"), + (0x16AF6, "X"), + (0x16B00, "V"), + (0x16B46, "X"), + (0x16B50, "V"), + (0x16B5A, "X"), + (0x16B5B, "V"), + (0x16B62, "X"), + (0x16B63, "V"), + (0x16B78, "X"), + (0x16B7D, "V"), + (0x16B90, "X"), + (0x16D40, "V"), + (0x16D7A, "X"), + (0x16E40, "M", "𖹠"), + (0x16E41, "M", "𖹡"), + (0x16E42, "M", "𖹢"), + (0x16E43, "M", "𖹣"), + (0x16E44, "M", "𖹤"), + (0x16E45, "M", "𖹥"), + (0x16E46, "M", "𖹦"), + (0x16E47, "M", "𖹧"), + (0x16E48, "M", "𖹨"), + (0x16E49, "M", "𖹩"), + (0x16E4A, "M", "𖹪"), + (0x16E4B, "M", "𖹫"), + (0x16E4C, "M", "𖹬"), + (0x16E4D, "M", "𖹭"), + (0x16E4E, "M", "𖹮"), + (0x16E4F, "M", "𖹯"), + (0x16E50, "M", "𖹰"), + (0x16E51, "M", "𖹱"), + (0x16E52, "M", "𖹲"), + (0x16E53, "M", "𖹳"), + (0x16E54, "M", "𖹴"), + (0x16E55, "M", "𖹵"), + (0x16E56, "M", "𖹶"), + (0x16E57, "M", "𖹷"), + (0x16E58, "M", "𖹸"), + (0x16E59, "M", "𖹹"), + (0x16E5A, "M", "𖹺"), + (0x16E5B, "M", "𖹻"), + (0x16E5C, "M", "𖹼"), + (0x16E5D, "M", "𖹽"), + (0x16E5E, "M", "𖹾"), + (0x16E5F, "M", "𖹿"), + (0x16E60, "V"), + (0x16E9B, "X"), + (0x16F00, "V"), + (0x16F4B, "X"), + (0x16F4F, "V"), + (0x16F88, "X"), + (0x16F8F, "V"), + (0x16FA0, "X"), + (0x16FE0, "V"), + (0x16FE5, "X"), + (0x16FF0, "V"), + (0x16FF2, "X"), + (0x17000, "V"), + (0x187F8, "X"), + (0x18800, "V"), + (0x18CD6, "X"), + (0x18CFF, "V"), + (0x18D09, "X"), + ] + + +def _seg_61() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1AFF0, "V"), + (0x1AFF4, "X"), + (0x1AFF5, "V"), + (0x1AFFC, "X"), + (0x1AFFD, "V"), + (0x1AFFF, "X"), + (0x1B000, "V"), + (0x1B123, "X"), + (0x1B132, "V"), + (0x1B133, "X"), + (0x1B150, "V"), + (0x1B153, "X"), + (0x1B155, "V"), + (0x1B156, "X"), + (0x1B164, "V"), + (0x1B168, "X"), + (0x1B170, "V"), + (0x1B2FC, "X"), + (0x1BC00, "V"), + (0x1BC6B, "X"), + (0x1BC70, "V"), + (0x1BC7D, "X"), + (0x1BC80, "V"), + (0x1BC89, "X"), + (0x1BC90, "V"), + (0x1BC9A, "X"), + (0x1BC9C, "V"), + (0x1BCA0, "I"), + (0x1BCA4, "X"), + (0x1CC00, "V"), + (0x1CCD6, "M", "a"), + (0x1CCD7, "M", "b"), + (0x1CCD8, "M", "c"), + (0x1CCD9, "M", "d"), + (0x1CCDA, "M", "e"), + (0x1CCDB, "M", "f"), + (0x1CCDC, "M", "g"), + (0x1CCDD, "M", "h"), + (0x1CCDE, "M", "i"), + (0x1CCDF, "M", "j"), + (0x1CCE0, "M", "k"), + (0x1CCE1, "M", "l"), + (0x1CCE2, "M", "m"), + (0x1CCE3, "M", "n"), + (0x1CCE4, "M", "o"), + (0x1CCE5, "M", "p"), + (0x1CCE6, "M", "q"), + (0x1CCE7, "M", "r"), + (0x1CCE8, "M", "s"), + (0x1CCE9, "M", "t"), + (0x1CCEA, "M", "u"), + (0x1CCEB, "M", "v"), + (0x1CCEC, "M", "w"), + (0x1CCED, "M", "x"), + (0x1CCEE, "M", "y"), + (0x1CCEF, "M", "z"), + (0x1CCF0, "M", "0"), + (0x1CCF1, "M", "1"), + (0x1CCF2, "M", "2"), + (0x1CCF3, "M", "3"), + (0x1CCF4, "M", "4"), + (0x1CCF5, "M", "5"), + (0x1CCF6, "M", "6"), + (0x1CCF7, "M", "7"), + (0x1CCF8, "M", "8"), + (0x1CCF9, "M", "9"), + (0x1CCFA, "X"), + (0x1CD00, "V"), + (0x1CEB4, "X"), + (0x1CF00, "V"), + (0x1CF2E, "X"), + (0x1CF30, "V"), + (0x1CF47, "X"), + (0x1CF50, "V"), + (0x1CFC4, "X"), + (0x1D000, "V"), + (0x1D0F6, "X"), + (0x1D100, "V"), + (0x1D127, "X"), + (0x1D129, "V"), + (0x1D15E, "M", "𝅗𝅥"), + (0x1D15F, "M", "𝅘𝅥"), + (0x1D160, "M", "𝅘𝅥𝅮"), + (0x1D161, "M", "𝅘𝅥𝅯"), + (0x1D162, "M", "𝅘𝅥𝅰"), + (0x1D163, "M", "𝅘𝅥𝅱"), + (0x1D164, "M", "𝅘𝅥𝅲"), + (0x1D165, "V"), + (0x1D173, "I"), + (0x1D17B, "V"), + (0x1D1BB, "M", "𝆹𝅥"), + (0x1D1BC, "M", "𝆺𝅥"), + (0x1D1BD, "M", "𝆹𝅥𝅮"), + (0x1D1BE, "M", "𝆺𝅥𝅮"), + (0x1D1BF, "M", "𝆹𝅥𝅯"), + (0x1D1C0, "M", "𝆺𝅥𝅯"), + (0x1D1C1, "V"), + (0x1D1EB, "X"), + (0x1D200, "V"), + (0x1D246, "X"), + ] + + +def _seg_62() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D2C0, "V"), + (0x1D2D4, "X"), + (0x1D2E0, "V"), + (0x1D2F4, "X"), + (0x1D300, "V"), + (0x1D357, "X"), + (0x1D360, "V"), + (0x1D379, "X"), + (0x1D400, "M", "a"), + (0x1D401, "M", "b"), + (0x1D402, "M", "c"), + (0x1D403, "M", "d"), + (0x1D404, "M", "e"), + (0x1D405, "M", "f"), + (0x1D406, "M", "g"), + (0x1D407, "M", "h"), + (0x1D408, "M", "i"), + (0x1D409, "M", "j"), + (0x1D40A, "M", "k"), + (0x1D40B, "M", "l"), + (0x1D40C, "M", "m"), + (0x1D40D, "M", "n"), + (0x1D40E, "M", "o"), + (0x1D40F, "M", "p"), + (0x1D410, "M", "q"), + (0x1D411, "M", "r"), + (0x1D412, "M", "s"), + (0x1D413, "M", "t"), + (0x1D414, "M", "u"), + (0x1D415, "M", "v"), + (0x1D416, "M", "w"), + (0x1D417, "M", "x"), + (0x1D418, "M", "y"), + (0x1D419, "M", "z"), + (0x1D41A, "M", "a"), + (0x1D41B, "M", "b"), + (0x1D41C, "M", "c"), + (0x1D41D, "M", "d"), + (0x1D41E, "M", "e"), + (0x1D41F, "M", "f"), + (0x1D420, "M", "g"), + (0x1D421, "M", "h"), + (0x1D422, "M", "i"), + (0x1D423, "M", "j"), + (0x1D424, "M", "k"), + (0x1D425, "M", "l"), + (0x1D426, "M", "m"), + (0x1D427, "M", "n"), + (0x1D428, "M", "o"), + (0x1D429, "M", "p"), + (0x1D42A, "M", "q"), + (0x1D42B, "M", "r"), + (0x1D42C, "M", "s"), + (0x1D42D, "M", "t"), + (0x1D42E, "M", "u"), + (0x1D42F, "M", "v"), + (0x1D430, "M", "w"), + (0x1D431, "M", "x"), + (0x1D432, "M", "y"), + (0x1D433, "M", "z"), + (0x1D434, "M", "a"), + (0x1D435, "M", "b"), + (0x1D436, "M", "c"), + (0x1D437, "M", "d"), + (0x1D438, "M", "e"), + (0x1D439, "M", "f"), + (0x1D43A, "M", "g"), + (0x1D43B, "M", "h"), + (0x1D43C, "M", "i"), + (0x1D43D, "M", "j"), + (0x1D43E, "M", "k"), + (0x1D43F, "M", "l"), + (0x1D440, "M", "m"), + (0x1D441, "M", "n"), + (0x1D442, "M", "o"), + (0x1D443, "M", "p"), + (0x1D444, "M", "q"), + (0x1D445, "M", "r"), + (0x1D446, "M", "s"), + (0x1D447, "M", "t"), + (0x1D448, "M", "u"), + (0x1D449, "M", "v"), + (0x1D44A, "M", "w"), + (0x1D44B, "M", "x"), + (0x1D44C, "M", "y"), + (0x1D44D, "M", "z"), + (0x1D44E, "M", "a"), + (0x1D44F, "M", "b"), + (0x1D450, "M", "c"), + (0x1D451, "M", "d"), + (0x1D452, "M", "e"), + (0x1D453, "M", "f"), + (0x1D454, "M", "g"), + (0x1D455, "X"), + (0x1D456, "M", "i"), + (0x1D457, "M", "j"), + (0x1D458, "M", "k"), + (0x1D459, "M", "l"), + (0x1D45A, "M", "m"), + (0x1D45B, "M", "n"), + ] + + +def _seg_63() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D45C, "M", "o"), + (0x1D45D, "M", "p"), + (0x1D45E, "M", "q"), + (0x1D45F, "M", "r"), + (0x1D460, "M", "s"), + (0x1D461, "M", "t"), + (0x1D462, "M", "u"), + (0x1D463, "M", "v"), + (0x1D464, "M", "w"), + (0x1D465, "M", "x"), + (0x1D466, "M", "y"), + (0x1D467, "M", "z"), + (0x1D468, "M", "a"), + (0x1D469, "M", "b"), + (0x1D46A, "M", "c"), + (0x1D46B, "M", "d"), + (0x1D46C, "M", "e"), + (0x1D46D, "M", "f"), + (0x1D46E, "M", "g"), + (0x1D46F, "M", "h"), + (0x1D470, "M", "i"), + (0x1D471, "M", "j"), + (0x1D472, "M", "k"), + (0x1D473, "M", "l"), + (0x1D474, "M", "m"), + (0x1D475, "M", "n"), + (0x1D476, "M", "o"), + (0x1D477, "M", "p"), + (0x1D478, "M", "q"), + (0x1D479, "M", "r"), + (0x1D47A, "M", "s"), + (0x1D47B, "M", "t"), + (0x1D47C, "M", "u"), + (0x1D47D, "M", "v"), + (0x1D47E, "M", "w"), + (0x1D47F, "M", "x"), + (0x1D480, "M", "y"), + (0x1D481, "M", "z"), + (0x1D482, "M", "a"), + (0x1D483, "M", "b"), + (0x1D484, "M", "c"), + (0x1D485, "M", "d"), + (0x1D486, "M", "e"), + (0x1D487, "M", "f"), + (0x1D488, "M", "g"), + (0x1D489, "M", "h"), + (0x1D48A, "M", "i"), + (0x1D48B, "M", "j"), + (0x1D48C, "M", "k"), + (0x1D48D, "M", "l"), + (0x1D48E, "M", "m"), + (0x1D48F, "M", "n"), + (0x1D490, "M", "o"), + (0x1D491, "M", "p"), + (0x1D492, "M", "q"), + (0x1D493, "M", "r"), + (0x1D494, "M", "s"), + (0x1D495, "M", "t"), + (0x1D496, "M", "u"), + (0x1D497, "M", "v"), + (0x1D498, "M", "w"), + (0x1D499, "M", "x"), + (0x1D49A, "M", "y"), + (0x1D49B, "M", "z"), + (0x1D49C, "M", "a"), + (0x1D49D, "X"), + (0x1D49E, "M", "c"), + (0x1D49F, "M", "d"), + (0x1D4A0, "X"), + (0x1D4A2, "M", "g"), + (0x1D4A3, "X"), + (0x1D4A5, "M", "j"), + (0x1D4A6, "M", "k"), + (0x1D4A7, "X"), + (0x1D4A9, "M", "n"), + (0x1D4AA, "M", "o"), + (0x1D4AB, "M", "p"), + (0x1D4AC, "M", "q"), + (0x1D4AD, "X"), + (0x1D4AE, "M", "s"), + (0x1D4AF, "M", "t"), + (0x1D4B0, "M", "u"), + (0x1D4B1, "M", "v"), + (0x1D4B2, "M", "w"), + (0x1D4B3, "M", "x"), + (0x1D4B4, "M", "y"), + (0x1D4B5, "M", "z"), + (0x1D4B6, "M", "a"), + (0x1D4B7, "M", "b"), + (0x1D4B8, "M", "c"), + (0x1D4B9, "M", "d"), + (0x1D4BA, "X"), + (0x1D4BB, "M", "f"), + (0x1D4BC, "X"), + (0x1D4BD, "M", "h"), + (0x1D4BE, "M", "i"), + (0x1D4BF, "M", "j"), + (0x1D4C0, "M", "k"), + (0x1D4C1, "M", "l"), + (0x1D4C2, "M", "m"), + ] + + +def _seg_64() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D4C3, "M", "n"), + (0x1D4C4, "X"), + (0x1D4C5, "M", "p"), + (0x1D4C6, "M", "q"), + (0x1D4C7, "M", "r"), + (0x1D4C8, "M", "s"), + (0x1D4C9, "M", "t"), + (0x1D4CA, "M", "u"), + (0x1D4CB, "M", "v"), + (0x1D4CC, "M", "w"), + (0x1D4CD, "M", "x"), + (0x1D4CE, "M", "y"), + (0x1D4CF, "M", "z"), + (0x1D4D0, "M", "a"), + (0x1D4D1, "M", "b"), + (0x1D4D2, "M", "c"), + (0x1D4D3, "M", "d"), + (0x1D4D4, "M", "e"), + (0x1D4D5, "M", "f"), + (0x1D4D6, "M", "g"), + (0x1D4D7, "M", "h"), + (0x1D4D8, "M", "i"), + (0x1D4D9, "M", "j"), + (0x1D4DA, "M", "k"), + (0x1D4DB, "M", "l"), + (0x1D4DC, "M", "m"), + (0x1D4DD, "M", "n"), + (0x1D4DE, "M", "o"), + (0x1D4DF, "M", "p"), + (0x1D4E0, "M", "q"), + (0x1D4E1, "M", "r"), + (0x1D4E2, "M", "s"), + (0x1D4E3, "M", "t"), + (0x1D4E4, "M", "u"), + (0x1D4E5, "M", "v"), + (0x1D4E6, "M", "w"), + (0x1D4E7, "M", "x"), + (0x1D4E8, "M", "y"), + (0x1D4E9, "M", "z"), + (0x1D4EA, "M", "a"), + (0x1D4EB, "M", "b"), + (0x1D4EC, "M", "c"), + (0x1D4ED, "M", "d"), + (0x1D4EE, "M", "e"), + (0x1D4EF, "M", "f"), + (0x1D4F0, "M", "g"), + (0x1D4F1, "M", "h"), + (0x1D4F2, "M", "i"), + (0x1D4F3, "M", "j"), + (0x1D4F4, "M", "k"), + (0x1D4F5, "M", "l"), + (0x1D4F6, "M", "m"), + (0x1D4F7, "M", "n"), + (0x1D4F8, "M", "o"), + (0x1D4F9, "M", "p"), + (0x1D4FA, "M", "q"), + (0x1D4FB, "M", "r"), + (0x1D4FC, "M", "s"), + (0x1D4FD, "M", "t"), + (0x1D4FE, "M", "u"), + (0x1D4FF, "M", "v"), + (0x1D500, "M", "w"), + (0x1D501, "M", "x"), + (0x1D502, "M", "y"), + (0x1D503, "M", "z"), + (0x1D504, "M", "a"), + (0x1D505, "M", "b"), + (0x1D506, "X"), + (0x1D507, "M", "d"), + (0x1D508, "M", "e"), + (0x1D509, "M", "f"), + (0x1D50A, "M", "g"), + (0x1D50B, "X"), + (0x1D50D, "M", "j"), + (0x1D50E, "M", "k"), + (0x1D50F, "M", "l"), + (0x1D510, "M", "m"), + (0x1D511, "M", "n"), + (0x1D512, "M", "o"), + (0x1D513, "M", "p"), + (0x1D514, "M", "q"), + (0x1D515, "X"), + (0x1D516, "M", "s"), + (0x1D517, "M", "t"), + (0x1D518, "M", "u"), + (0x1D519, "M", "v"), + (0x1D51A, "M", "w"), + (0x1D51B, "M", "x"), + (0x1D51C, "M", "y"), + (0x1D51D, "X"), + (0x1D51E, "M", "a"), + (0x1D51F, "M", "b"), + (0x1D520, "M", "c"), + (0x1D521, "M", "d"), + (0x1D522, "M", "e"), + (0x1D523, "M", "f"), + (0x1D524, "M", "g"), + (0x1D525, "M", "h"), + (0x1D526, "M", "i"), + (0x1D527, "M", "j"), + ] + + +def _seg_65() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D528, "M", "k"), + (0x1D529, "M", "l"), + (0x1D52A, "M", "m"), + (0x1D52B, "M", "n"), + (0x1D52C, "M", "o"), + (0x1D52D, "M", "p"), + (0x1D52E, "M", "q"), + (0x1D52F, "M", "r"), + (0x1D530, "M", "s"), + (0x1D531, "M", "t"), + (0x1D532, "M", "u"), + (0x1D533, "M", "v"), + (0x1D534, "M", "w"), + (0x1D535, "M", "x"), + (0x1D536, "M", "y"), + (0x1D537, "M", "z"), + (0x1D538, "M", "a"), + (0x1D539, "M", "b"), + (0x1D53A, "X"), + (0x1D53B, "M", "d"), + (0x1D53C, "M", "e"), + (0x1D53D, "M", "f"), + (0x1D53E, "M", "g"), + (0x1D53F, "X"), + (0x1D540, "M", "i"), + (0x1D541, "M", "j"), + (0x1D542, "M", "k"), + (0x1D543, "M", "l"), + (0x1D544, "M", "m"), + (0x1D545, "X"), + (0x1D546, "M", "o"), + (0x1D547, "X"), + (0x1D54A, "M", "s"), + (0x1D54B, "M", "t"), + (0x1D54C, "M", "u"), + (0x1D54D, "M", "v"), + (0x1D54E, "M", "w"), + (0x1D54F, "M", "x"), + (0x1D550, "M", "y"), + (0x1D551, "X"), + (0x1D552, "M", "a"), + (0x1D553, "M", "b"), + (0x1D554, "M", "c"), + (0x1D555, "M", "d"), + (0x1D556, "M", "e"), + (0x1D557, "M", "f"), + (0x1D558, "M", "g"), + (0x1D559, "M", "h"), + (0x1D55A, "M", "i"), + (0x1D55B, "M", "j"), + (0x1D55C, "M", "k"), + (0x1D55D, "M", "l"), + (0x1D55E, "M", "m"), + (0x1D55F, "M", "n"), + (0x1D560, "M", "o"), + (0x1D561, "M", "p"), + (0x1D562, "M", "q"), + (0x1D563, "M", "r"), + (0x1D564, "M", "s"), + (0x1D565, "M", "t"), + (0x1D566, "M", "u"), + (0x1D567, "M", "v"), + (0x1D568, "M", "w"), + (0x1D569, "M", "x"), + (0x1D56A, "M", "y"), + (0x1D56B, "M", "z"), + (0x1D56C, "M", "a"), + (0x1D56D, "M", "b"), + (0x1D56E, "M", "c"), + (0x1D56F, "M", "d"), + (0x1D570, "M", "e"), + (0x1D571, "M", "f"), + (0x1D572, "M", "g"), + (0x1D573, "M", "h"), + (0x1D574, "M", "i"), + (0x1D575, "M", "j"), + (0x1D576, "M", "k"), + (0x1D577, "M", "l"), + (0x1D578, "M", "m"), + (0x1D579, "M", "n"), + (0x1D57A, "M", "o"), + (0x1D57B, "M", "p"), + (0x1D57C, "M", "q"), + (0x1D57D, "M", "r"), + (0x1D57E, "M", "s"), + (0x1D57F, "M", "t"), + (0x1D580, "M", "u"), + (0x1D581, "M", "v"), + (0x1D582, "M", "w"), + (0x1D583, "M", "x"), + (0x1D584, "M", "y"), + (0x1D585, "M", "z"), + (0x1D586, "M", "a"), + (0x1D587, "M", "b"), + (0x1D588, "M", "c"), + (0x1D589, "M", "d"), + (0x1D58A, "M", "e"), + (0x1D58B, "M", "f"), + (0x1D58C, "M", "g"), + (0x1D58D, "M", "h"), + ] + + +def _seg_66() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D58E, "M", "i"), + (0x1D58F, "M", "j"), + (0x1D590, "M", "k"), + (0x1D591, "M", "l"), + (0x1D592, "M", "m"), + (0x1D593, "M", "n"), + (0x1D594, "M", "o"), + (0x1D595, "M", "p"), + (0x1D596, "M", "q"), + (0x1D597, "M", "r"), + (0x1D598, "M", "s"), + (0x1D599, "M", "t"), + (0x1D59A, "M", "u"), + (0x1D59B, "M", "v"), + (0x1D59C, "M", "w"), + (0x1D59D, "M", "x"), + (0x1D59E, "M", "y"), + (0x1D59F, "M", "z"), + (0x1D5A0, "M", "a"), + (0x1D5A1, "M", "b"), + (0x1D5A2, "M", "c"), + (0x1D5A3, "M", "d"), + (0x1D5A4, "M", "e"), + (0x1D5A5, "M", "f"), + (0x1D5A6, "M", "g"), + (0x1D5A7, "M", "h"), + (0x1D5A8, "M", "i"), + (0x1D5A9, "M", "j"), + (0x1D5AA, "M", "k"), + (0x1D5AB, "M", "l"), + (0x1D5AC, "M", "m"), + (0x1D5AD, "M", "n"), + (0x1D5AE, "M", "o"), + (0x1D5AF, "M", "p"), + (0x1D5B0, "M", "q"), + (0x1D5B1, "M", "r"), + (0x1D5B2, "M", "s"), + (0x1D5B3, "M", "t"), + (0x1D5B4, "M", "u"), + (0x1D5B5, "M", "v"), + (0x1D5B6, "M", "w"), + (0x1D5B7, "M", "x"), + (0x1D5B8, "M", "y"), + (0x1D5B9, "M", "z"), + (0x1D5BA, "M", "a"), + (0x1D5BB, "M", "b"), + (0x1D5BC, "M", "c"), + (0x1D5BD, "M", "d"), + (0x1D5BE, "M", "e"), + (0x1D5BF, "M", "f"), + (0x1D5C0, "M", "g"), + (0x1D5C1, "M", "h"), + (0x1D5C2, "M", "i"), + (0x1D5C3, "M", "j"), + (0x1D5C4, "M", "k"), + (0x1D5C5, "M", "l"), + (0x1D5C6, "M", "m"), + (0x1D5C7, "M", "n"), + (0x1D5C8, "M", "o"), + (0x1D5C9, "M", "p"), + (0x1D5CA, "M", "q"), + (0x1D5CB, "M", "r"), + (0x1D5CC, "M", "s"), + (0x1D5CD, "M", "t"), + (0x1D5CE, "M", "u"), + (0x1D5CF, "M", "v"), + (0x1D5D0, "M", "w"), + (0x1D5D1, "M", "x"), + (0x1D5D2, "M", "y"), + (0x1D5D3, "M", "z"), + (0x1D5D4, "M", "a"), + (0x1D5D5, "M", "b"), + (0x1D5D6, "M", "c"), + (0x1D5D7, "M", "d"), + (0x1D5D8, "M", "e"), + (0x1D5D9, "M", "f"), + (0x1D5DA, "M", "g"), + (0x1D5DB, "M", "h"), + (0x1D5DC, "M", "i"), + (0x1D5DD, "M", "j"), + (0x1D5DE, "M", "k"), + (0x1D5DF, "M", "l"), + (0x1D5E0, "M", "m"), + (0x1D5E1, "M", "n"), + (0x1D5E2, "M", "o"), + (0x1D5E3, "M", "p"), + (0x1D5E4, "M", "q"), + (0x1D5E5, "M", "r"), + (0x1D5E6, "M", "s"), + (0x1D5E7, "M", "t"), + (0x1D5E8, "M", "u"), + (0x1D5E9, "M", "v"), + (0x1D5EA, "M", "w"), + (0x1D5EB, "M", "x"), + (0x1D5EC, "M", "y"), + (0x1D5ED, "M", "z"), + (0x1D5EE, "M", "a"), + (0x1D5EF, "M", "b"), + (0x1D5F0, "M", "c"), + (0x1D5F1, "M", "d"), + ] + + +def _seg_67() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D5F2, "M", "e"), + (0x1D5F3, "M", "f"), + (0x1D5F4, "M", "g"), + (0x1D5F5, "M", "h"), + (0x1D5F6, "M", "i"), + (0x1D5F7, "M", "j"), + (0x1D5F8, "M", "k"), + (0x1D5F9, "M", "l"), + (0x1D5FA, "M", "m"), + (0x1D5FB, "M", "n"), + (0x1D5FC, "M", "o"), + (0x1D5FD, "M", "p"), + (0x1D5FE, "M", "q"), + (0x1D5FF, "M", "r"), + (0x1D600, "M", "s"), + (0x1D601, "M", "t"), + (0x1D602, "M", "u"), + (0x1D603, "M", "v"), + (0x1D604, "M", "w"), + (0x1D605, "M", "x"), + (0x1D606, "M", "y"), + (0x1D607, "M", "z"), + (0x1D608, "M", "a"), + (0x1D609, "M", "b"), + (0x1D60A, "M", "c"), + (0x1D60B, "M", "d"), + (0x1D60C, "M", "e"), + (0x1D60D, "M", "f"), + (0x1D60E, "M", "g"), + (0x1D60F, "M", "h"), + (0x1D610, "M", "i"), + (0x1D611, "M", "j"), + (0x1D612, "M", "k"), + (0x1D613, "M", "l"), + (0x1D614, "M", "m"), + (0x1D615, "M", "n"), + (0x1D616, "M", "o"), + (0x1D617, "M", "p"), + (0x1D618, "M", "q"), + (0x1D619, "M", "r"), + (0x1D61A, "M", "s"), + (0x1D61B, "M", "t"), + (0x1D61C, "M", "u"), + (0x1D61D, "M", "v"), + (0x1D61E, "M", "w"), + (0x1D61F, "M", "x"), + (0x1D620, "M", "y"), + (0x1D621, "M", "z"), + (0x1D622, "M", "a"), + (0x1D623, "M", "b"), + (0x1D624, "M", "c"), + (0x1D625, "M", "d"), + (0x1D626, "M", "e"), + (0x1D627, "M", "f"), + (0x1D628, "M", "g"), + (0x1D629, "M", "h"), + (0x1D62A, "M", "i"), + (0x1D62B, "M", "j"), + (0x1D62C, "M", "k"), + (0x1D62D, "M", "l"), + (0x1D62E, "M", "m"), + (0x1D62F, "M", "n"), + (0x1D630, "M", "o"), + (0x1D631, "M", "p"), + (0x1D632, "M", "q"), + (0x1D633, "M", "r"), + (0x1D634, "M", "s"), + (0x1D635, "M", "t"), + (0x1D636, "M", "u"), + (0x1D637, "M", "v"), + (0x1D638, "M", "w"), + (0x1D639, "M", "x"), + (0x1D63A, "M", "y"), + (0x1D63B, "M", "z"), + (0x1D63C, "M", "a"), + (0x1D63D, "M", "b"), + (0x1D63E, "M", "c"), + (0x1D63F, "M", "d"), + (0x1D640, "M", "e"), + (0x1D641, "M", "f"), + (0x1D642, "M", "g"), + (0x1D643, "M", "h"), + (0x1D644, "M", "i"), + (0x1D645, "M", "j"), + (0x1D646, "M", "k"), + (0x1D647, "M", "l"), + (0x1D648, "M", "m"), + (0x1D649, "M", "n"), + (0x1D64A, "M", "o"), + (0x1D64B, "M", "p"), + (0x1D64C, "M", "q"), + (0x1D64D, "M", "r"), + (0x1D64E, "M", "s"), + (0x1D64F, "M", "t"), + (0x1D650, "M", "u"), + (0x1D651, "M", "v"), + (0x1D652, "M", "w"), + (0x1D653, "M", "x"), + (0x1D654, "M", "y"), + (0x1D655, "M", "z"), + ] + + +def _seg_68() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D656, "M", "a"), + (0x1D657, "M", "b"), + (0x1D658, "M", "c"), + (0x1D659, "M", "d"), + (0x1D65A, "M", "e"), + (0x1D65B, "M", "f"), + (0x1D65C, "M", "g"), + (0x1D65D, "M", "h"), + (0x1D65E, "M", "i"), + (0x1D65F, "M", "j"), + (0x1D660, "M", "k"), + (0x1D661, "M", "l"), + (0x1D662, "M", "m"), + (0x1D663, "M", "n"), + (0x1D664, "M", "o"), + (0x1D665, "M", "p"), + (0x1D666, "M", "q"), + (0x1D667, "M", "r"), + (0x1D668, "M", "s"), + (0x1D669, "M", "t"), + (0x1D66A, "M", "u"), + (0x1D66B, "M", "v"), + (0x1D66C, "M", "w"), + (0x1D66D, "M", "x"), + (0x1D66E, "M", "y"), + (0x1D66F, "M", "z"), + (0x1D670, "M", "a"), + (0x1D671, "M", "b"), + (0x1D672, "M", "c"), + (0x1D673, "M", "d"), + (0x1D674, "M", "e"), + (0x1D675, "M", "f"), + (0x1D676, "M", "g"), + (0x1D677, "M", "h"), + (0x1D678, "M", "i"), + (0x1D679, "M", "j"), + (0x1D67A, "M", "k"), + (0x1D67B, "M", "l"), + (0x1D67C, "M", "m"), + (0x1D67D, "M", "n"), + (0x1D67E, "M", "o"), + (0x1D67F, "M", "p"), + (0x1D680, "M", "q"), + (0x1D681, "M", "r"), + (0x1D682, "M", "s"), + (0x1D683, "M", "t"), + (0x1D684, "M", "u"), + (0x1D685, "M", "v"), + (0x1D686, "M", "w"), + (0x1D687, "M", "x"), + (0x1D688, "M", "y"), + (0x1D689, "M", "z"), + (0x1D68A, "M", "a"), + (0x1D68B, "M", "b"), + (0x1D68C, "M", "c"), + (0x1D68D, "M", "d"), + (0x1D68E, "M", "e"), + (0x1D68F, "M", "f"), + (0x1D690, "M", "g"), + (0x1D691, "M", "h"), + (0x1D692, "M", "i"), + (0x1D693, "M", "j"), + (0x1D694, "M", "k"), + (0x1D695, "M", "l"), + (0x1D696, "M", "m"), + (0x1D697, "M", "n"), + (0x1D698, "M", "o"), + (0x1D699, "M", "p"), + (0x1D69A, "M", "q"), + (0x1D69B, "M", "r"), + (0x1D69C, "M", "s"), + (0x1D69D, "M", "t"), + (0x1D69E, "M", "u"), + (0x1D69F, "M", "v"), + (0x1D6A0, "M", "w"), + (0x1D6A1, "M", "x"), + (0x1D6A2, "M", "y"), + (0x1D6A3, "M", "z"), + (0x1D6A4, "M", "ı"), + (0x1D6A5, "M", "ȷ"), + (0x1D6A6, "X"), + (0x1D6A8, "M", "α"), + (0x1D6A9, "M", "β"), + (0x1D6AA, "M", "γ"), + (0x1D6AB, "M", "δ"), + (0x1D6AC, "M", "ε"), + (0x1D6AD, "M", "ζ"), + (0x1D6AE, "M", "η"), + (0x1D6AF, "M", "θ"), + (0x1D6B0, "M", "ι"), + (0x1D6B1, "M", "κ"), + (0x1D6B2, "M", "λ"), + (0x1D6B3, "M", "μ"), + (0x1D6B4, "M", "ν"), + (0x1D6B5, "M", "ξ"), + (0x1D6B6, "M", "ο"), + (0x1D6B7, "M", "π"), + (0x1D6B8, "M", "ρ"), + (0x1D6B9, "M", "θ"), + (0x1D6BA, "M", "σ"), + ] + + +def _seg_69() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D6BB, "M", "τ"), + (0x1D6BC, "M", "υ"), + (0x1D6BD, "M", "φ"), + (0x1D6BE, "M", "χ"), + (0x1D6BF, "M", "ψ"), + (0x1D6C0, "M", "ω"), + (0x1D6C1, "M", "∇"), + (0x1D6C2, "M", "α"), + (0x1D6C3, "M", "β"), + (0x1D6C4, "M", "γ"), + (0x1D6C5, "M", "δ"), + (0x1D6C6, "M", "ε"), + (0x1D6C7, "M", "ζ"), + (0x1D6C8, "M", "η"), + (0x1D6C9, "M", "θ"), + (0x1D6CA, "M", "ι"), + (0x1D6CB, "M", "κ"), + (0x1D6CC, "M", "λ"), + (0x1D6CD, "M", "μ"), + (0x1D6CE, "M", "ν"), + (0x1D6CF, "M", "ξ"), + (0x1D6D0, "M", "ο"), + (0x1D6D1, "M", "π"), + (0x1D6D2, "M", "ρ"), + (0x1D6D3, "M", "σ"), + (0x1D6D5, "M", "τ"), + (0x1D6D6, "M", "υ"), + (0x1D6D7, "M", "φ"), + (0x1D6D8, "M", "χ"), + (0x1D6D9, "M", "ψ"), + (0x1D6DA, "M", "ω"), + (0x1D6DB, "M", "∂"), + (0x1D6DC, "M", "ε"), + (0x1D6DD, "M", "θ"), + (0x1D6DE, "M", "κ"), + (0x1D6DF, "M", "φ"), + (0x1D6E0, "M", "ρ"), + (0x1D6E1, "M", "π"), + (0x1D6E2, "M", "α"), + (0x1D6E3, "M", "β"), + (0x1D6E4, "M", "γ"), + (0x1D6E5, "M", "δ"), + (0x1D6E6, "M", "ε"), + (0x1D6E7, "M", "ζ"), + (0x1D6E8, "M", "η"), + (0x1D6E9, "M", "θ"), + (0x1D6EA, "M", "ι"), + (0x1D6EB, "M", "κ"), + (0x1D6EC, "M", "λ"), + (0x1D6ED, "M", "μ"), + (0x1D6EE, "M", "ν"), + (0x1D6EF, "M", "ξ"), + (0x1D6F0, "M", "ο"), + (0x1D6F1, "M", "π"), + (0x1D6F2, "M", "ρ"), + (0x1D6F3, "M", "θ"), + (0x1D6F4, "M", "σ"), + (0x1D6F5, "M", "τ"), + (0x1D6F6, "M", "υ"), + (0x1D6F7, "M", "φ"), + (0x1D6F8, "M", "χ"), + (0x1D6F9, "M", "ψ"), + (0x1D6FA, "M", "ω"), + (0x1D6FB, "M", "∇"), + (0x1D6FC, "M", "α"), + (0x1D6FD, "M", "β"), + (0x1D6FE, "M", "γ"), + (0x1D6FF, "M", "δ"), + (0x1D700, "M", "ε"), + (0x1D701, "M", "ζ"), + (0x1D702, "M", "η"), + (0x1D703, "M", "θ"), + (0x1D704, "M", "ι"), + (0x1D705, "M", "κ"), + (0x1D706, "M", "λ"), + (0x1D707, "M", "μ"), + (0x1D708, "M", "ν"), + (0x1D709, "M", "ξ"), + (0x1D70A, "M", "ο"), + (0x1D70B, "M", "π"), + (0x1D70C, "M", "ρ"), + (0x1D70D, "M", "σ"), + (0x1D70F, "M", "τ"), + (0x1D710, "M", "υ"), + (0x1D711, "M", "φ"), + (0x1D712, "M", "χ"), + (0x1D713, "M", "ψ"), + (0x1D714, "M", "ω"), + (0x1D715, "M", "∂"), + (0x1D716, "M", "ε"), + (0x1D717, "M", "θ"), + (0x1D718, "M", "κ"), + (0x1D719, "M", "φ"), + (0x1D71A, "M", "ρ"), + (0x1D71B, "M", "π"), + (0x1D71C, "M", "α"), + (0x1D71D, "M", "β"), + (0x1D71E, "M", "γ"), + (0x1D71F, "M", "δ"), + (0x1D720, "M", "ε"), + ] + + +def _seg_70() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D721, "M", "ζ"), + (0x1D722, "M", "η"), + (0x1D723, "M", "θ"), + (0x1D724, "M", "ι"), + (0x1D725, "M", "κ"), + (0x1D726, "M", "λ"), + (0x1D727, "M", "μ"), + (0x1D728, "M", "ν"), + (0x1D729, "M", "ξ"), + (0x1D72A, "M", "ο"), + (0x1D72B, "M", "π"), + (0x1D72C, "M", "ρ"), + (0x1D72D, "M", "θ"), + (0x1D72E, "M", "σ"), + (0x1D72F, "M", "τ"), + (0x1D730, "M", "υ"), + (0x1D731, "M", "φ"), + (0x1D732, "M", "χ"), + (0x1D733, "M", "ψ"), + (0x1D734, "M", "ω"), + (0x1D735, "M", "∇"), + (0x1D736, "M", "α"), + (0x1D737, "M", "β"), + (0x1D738, "M", "γ"), + (0x1D739, "M", "δ"), + (0x1D73A, "M", "ε"), + (0x1D73B, "M", "ζ"), + (0x1D73C, "M", "η"), + (0x1D73D, "M", "θ"), + (0x1D73E, "M", "ι"), + (0x1D73F, "M", "κ"), + (0x1D740, "M", "λ"), + (0x1D741, "M", "μ"), + (0x1D742, "M", "ν"), + (0x1D743, "M", "ξ"), + (0x1D744, "M", "ο"), + (0x1D745, "M", "π"), + (0x1D746, "M", "ρ"), + (0x1D747, "M", "σ"), + (0x1D749, "M", "τ"), + (0x1D74A, "M", "υ"), + (0x1D74B, "M", "φ"), + (0x1D74C, "M", "χ"), + (0x1D74D, "M", "ψ"), + (0x1D74E, "M", "ω"), + (0x1D74F, "M", "∂"), + (0x1D750, "M", "ε"), + (0x1D751, "M", "θ"), + (0x1D752, "M", "κ"), + (0x1D753, "M", "φ"), + (0x1D754, "M", "ρ"), + (0x1D755, "M", "π"), + (0x1D756, "M", "α"), + (0x1D757, "M", "β"), + (0x1D758, "M", "γ"), + (0x1D759, "M", "δ"), + (0x1D75A, "M", "ε"), + (0x1D75B, "M", "ζ"), + (0x1D75C, "M", "η"), + (0x1D75D, "M", "θ"), + (0x1D75E, "M", "ι"), + (0x1D75F, "M", "κ"), + (0x1D760, "M", "λ"), + (0x1D761, "M", "μ"), + (0x1D762, "M", "ν"), + (0x1D763, "M", "ξ"), + (0x1D764, "M", "ο"), + (0x1D765, "M", "π"), + (0x1D766, "M", "ρ"), + (0x1D767, "M", "θ"), + (0x1D768, "M", "σ"), + (0x1D769, "M", "τ"), + (0x1D76A, "M", "υ"), + (0x1D76B, "M", "φ"), + (0x1D76C, "M", "χ"), + (0x1D76D, "M", "ψ"), + (0x1D76E, "M", "ω"), + (0x1D76F, "M", "∇"), + (0x1D770, "M", "α"), + (0x1D771, "M", "β"), + (0x1D772, "M", "γ"), + (0x1D773, "M", "δ"), + (0x1D774, "M", "ε"), + (0x1D775, "M", "ζ"), + (0x1D776, "M", "η"), + (0x1D777, "M", "θ"), + (0x1D778, "M", "ι"), + (0x1D779, "M", "κ"), + (0x1D77A, "M", "λ"), + (0x1D77B, "M", "μ"), + (0x1D77C, "M", "ν"), + (0x1D77D, "M", "ξ"), + (0x1D77E, "M", "ο"), + (0x1D77F, "M", "π"), + (0x1D780, "M", "ρ"), + (0x1D781, "M", "σ"), + (0x1D783, "M", "τ"), + (0x1D784, "M", "υ"), + (0x1D785, "M", "φ"), + (0x1D786, "M", "χ"), + ] + + +def _seg_71() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D787, "M", "ψ"), + (0x1D788, "M", "ω"), + (0x1D789, "M", "∂"), + (0x1D78A, "M", "ε"), + (0x1D78B, "M", "θ"), + (0x1D78C, "M", "κ"), + (0x1D78D, "M", "φ"), + (0x1D78E, "M", "ρ"), + (0x1D78F, "M", "π"), + (0x1D790, "M", "α"), + (0x1D791, "M", "β"), + (0x1D792, "M", "γ"), + (0x1D793, "M", "δ"), + (0x1D794, "M", "ε"), + (0x1D795, "M", "ζ"), + (0x1D796, "M", "η"), + (0x1D797, "M", "θ"), + (0x1D798, "M", "ι"), + (0x1D799, "M", "κ"), + (0x1D79A, "M", "λ"), + (0x1D79B, "M", "μ"), + (0x1D79C, "M", "ν"), + (0x1D79D, "M", "ξ"), + (0x1D79E, "M", "ο"), + (0x1D79F, "M", "π"), + (0x1D7A0, "M", "ρ"), + (0x1D7A1, "M", "θ"), + (0x1D7A2, "M", "σ"), + (0x1D7A3, "M", "τ"), + (0x1D7A4, "M", "υ"), + (0x1D7A5, "M", "φ"), + (0x1D7A6, "M", "χ"), + (0x1D7A7, "M", "ψ"), + (0x1D7A8, "M", "ω"), + (0x1D7A9, "M", "∇"), + (0x1D7AA, "M", "α"), + (0x1D7AB, "M", "β"), + (0x1D7AC, "M", "γ"), + (0x1D7AD, "M", "δ"), + (0x1D7AE, "M", "ε"), + (0x1D7AF, "M", "ζ"), + (0x1D7B0, "M", "η"), + (0x1D7B1, "M", "θ"), + (0x1D7B2, "M", "ι"), + (0x1D7B3, "M", "κ"), + (0x1D7B4, "M", "λ"), + (0x1D7B5, "M", "μ"), + (0x1D7B6, "M", "ν"), + (0x1D7B7, "M", "ξ"), + (0x1D7B8, "M", "ο"), + (0x1D7B9, "M", "π"), + (0x1D7BA, "M", "ρ"), + (0x1D7BB, "M", "σ"), + (0x1D7BD, "M", "τ"), + (0x1D7BE, "M", "υ"), + (0x1D7BF, "M", "φ"), + (0x1D7C0, "M", "χ"), + (0x1D7C1, "M", "ψ"), + (0x1D7C2, "M", "ω"), + (0x1D7C3, "M", "∂"), + (0x1D7C4, "M", "ε"), + (0x1D7C5, "M", "θ"), + (0x1D7C6, "M", "κ"), + (0x1D7C7, "M", "φ"), + (0x1D7C8, "M", "ρ"), + (0x1D7C9, "M", "π"), + (0x1D7CA, "M", "ϝ"), + (0x1D7CC, "X"), + (0x1D7CE, "M", "0"), + (0x1D7CF, "M", "1"), + (0x1D7D0, "M", "2"), + (0x1D7D1, "M", "3"), + (0x1D7D2, "M", "4"), + (0x1D7D3, "M", "5"), + (0x1D7D4, "M", "6"), + (0x1D7D5, "M", "7"), + (0x1D7D6, "M", "8"), + (0x1D7D7, "M", "9"), + (0x1D7D8, "M", "0"), + (0x1D7D9, "M", "1"), + (0x1D7DA, "M", "2"), + (0x1D7DB, "M", "3"), + (0x1D7DC, "M", "4"), + (0x1D7DD, "M", "5"), + (0x1D7DE, "M", "6"), + (0x1D7DF, "M", "7"), + (0x1D7E0, "M", "8"), + (0x1D7E1, "M", "9"), + (0x1D7E2, "M", "0"), + (0x1D7E3, "M", "1"), + (0x1D7E4, "M", "2"), + (0x1D7E5, "M", "3"), + (0x1D7E6, "M", "4"), + (0x1D7E7, "M", "5"), + (0x1D7E8, "M", "6"), + (0x1D7E9, "M", "7"), + (0x1D7EA, "M", "8"), + (0x1D7EB, "M", "9"), + (0x1D7EC, "M", "0"), + (0x1D7ED, "M", "1"), + ] + + +def _seg_72() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D7EE, "M", "2"), + (0x1D7EF, "M", "3"), + (0x1D7F0, "M", "4"), + (0x1D7F1, "M", "5"), + (0x1D7F2, "M", "6"), + (0x1D7F3, "M", "7"), + (0x1D7F4, "M", "8"), + (0x1D7F5, "M", "9"), + (0x1D7F6, "M", "0"), + (0x1D7F7, "M", "1"), + (0x1D7F8, "M", "2"), + (0x1D7F9, "M", "3"), + (0x1D7FA, "M", "4"), + (0x1D7FB, "M", "5"), + (0x1D7FC, "M", "6"), + (0x1D7FD, "M", "7"), + (0x1D7FE, "M", "8"), + (0x1D7FF, "M", "9"), + (0x1D800, "V"), + (0x1DA8C, "X"), + (0x1DA9B, "V"), + (0x1DAA0, "X"), + (0x1DAA1, "V"), + (0x1DAB0, "X"), + (0x1DF00, "V"), + (0x1DF1F, "X"), + (0x1DF25, "V"), + (0x1DF2B, "X"), + (0x1E000, "V"), + (0x1E007, "X"), + (0x1E008, "V"), + (0x1E019, "X"), + (0x1E01B, "V"), + (0x1E022, "X"), + (0x1E023, "V"), + (0x1E025, "X"), + (0x1E026, "V"), + (0x1E02B, "X"), + (0x1E030, "M", "а"), + (0x1E031, "M", "б"), + (0x1E032, "M", "в"), + (0x1E033, "M", "г"), + (0x1E034, "M", "д"), + (0x1E035, "M", "е"), + (0x1E036, "M", "ж"), + (0x1E037, "M", "з"), + (0x1E038, "M", "и"), + (0x1E039, "M", "к"), + (0x1E03A, "M", "л"), + (0x1E03B, "M", "м"), + (0x1E03C, "M", "о"), + (0x1E03D, "M", "п"), + (0x1E03E, "M", "р"), + (0x1E03F, "M", "с"), + (0x1E040, "M", "т"), + (0x1E041, "M", "у"), + (0x1E042, "M", "ф"), + (0x1E043, "M", "х"), + (0x1E044, "M", "ц"), + (0x1E045, "M", "ч"), + (0x1E046, "M", "ш"), + (0x1E047, "M", "ы"), + (0x1E048, "M", "э"), + (0x1E049, "M", "ю"), + (0x1E04A, "M", "ꚉ"), + (0x1E04B, "M", "ә"), + (0x1E04C, "M", "і"), + (0x1E04D, "M", "ј"), + (0x1E04E, "M", "ө"), + (0x1E04F, "M", "ү"), + (0x1E050, "M", "ӏ"), + (0x1E051, "M", "а"), + (0x1E052, "M", "б"), + (0x1E053, "M", "в"), + (0x1E054, "M", "г"), + (0x1E055, "M", "д"), + (0x1E056, "M", "е"), + (0x1E057, "M", "ж"), + (0x1E058, "M", "з"), + (0x1E059, "M", "и"), + (0x1E05A, "M", "к"), + (0x1E05B, "M", "л"), + (0x1E05C, "M", "о"), + (0x1E05D, "M", "п"), + (0x1E05E, "M", "с"), + (0x1E05F, "M", "у"), + (0x1E060, "M", "ф"), + (0x1E061, "M", "х"), + (0x1E062, "M", "ц"), + (0x1E063, "M", "ч"), + (0x1E064, "M", "ш"), + (0x1E065, "M", "ъ"), + (0x1E066, "M", "ы"), + (0x1E067, "M", "ґ"), + (0x1E068, "M", "і"), + (0x1E069, "M", "ѕ"), + (0x1E06A, "M", "џ"), + (0x1E06B, "M", "ҫ"), + (0x1E06C, "M", "ꙑ"), + (0x1E06D, "M", "ұ"), + ] + + +def _seg_73() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E06E, "X"), + (0x1E08F, "V"), + (0x1E090, "X"), + (0x1E100, "V"), + (0x1E12D, "X"), + (0x1E130, "V"), + (0x1E13E, "X"), + (0x1E140, "V"), + (0x1E14A, "X"), + (0x1E14E, "V"), + (0x1E150, "X"), + (0x1E290, "V"), + (0x1E2AF, "X"), + (0x1E2C0, "V"), + (0x1E2FA, "X"), + (0x1E2FF, "V"), + (0x1E300, "X"), + (0x1E4D0, "V"), + (0x1E4FA, "X"), + (0x1E5D0, "V"), + (0x1E5FB, "X"), + (0x1E5FF, "V"), + (0x1E600, "X"), + (0x1E7E0, "V"), + (0x1E7E7, "X"), + (0x1E7E8, "V"), + (0x1E7EC, "X"), + (0x1E7ED, "V"), + (0x1E7EF, "X"), + (0x1E7F0, "V"), + (0x1E7FF, "X"), + (0x1E800, "V"), + (0x1E8C5, "X"), + (0x1E8C7, "V"), + (0x1E8D7, "X"), + (0x1E900, "M", "𞤢"), + (0x1E901, "M", "𞤣"), + (0x1E902, "M", "𞤤"), + (0x1E903, "M", "𞤥"), + (0x1E904, "M", "𞤦"), + (0x1E905, "M", "𞤧"), + (0x1E906, "M", "𞤨"), + (0x1E907, "M", "𞤩"), + (0x1E908, "M", "𞤪"), + (0x1E909, "M", "𞤫"), + (0x1E90A, "M", "𞤬"), + (0x1E90B, "M", "𞤭"), + (0x1E90C, "M", "𞤮"), + (0x1E90D, "M", "𞤯"), + (0x1E90E, "M", "𞤰"), + (0x1E90F, "M", "𞤱"), + (0x1E910, "M", "𞤲"), + (0x1E911, "M", "𞤳"), + (0x1E912, "M", "𞤴"), + (0x1E913, "M", "𞤵"), + (0x1E914, "M", "𞤶"), + (0x1E915, "M", "𞤷"), + (0x1E916, "M", "𞤸"), + (0x1E917, "M", "𞤹"), + (0x1E918, "M", "𞤺"), + (0x1E919, "M", "𞤻"), + (0x1E91A, "M", "𞤼"), + (0x1E91B, "M", "𞤽"), + (0x1E91C, "M", "𞤾"), + (0x1E91D, "M", "𞤿"), + (0x1E91E, "M", "𞥀"), + (0x1E91F, "M", "𞥁"), + (0x1E920, "M", "𞥂"), + (0x1E921, "M", "𞥃"), + (0x1E922, "V"), + (0x1E94C, "X"), + (0x1E950, "V"), + (0x1E95A, "X"), + (0x1E95E, "V"), + (0x1E960, "X"), + (0x1EC71, "V"), + (0x1ECB5, "X"), + (0x1ED01, "V"), + (0x1ED3E, "X"), + (0x1EE00, "M", "ا"), + (0x1EE01, "M", "ب"), + (0x1EE02, "M", "ج"), + (0x1EE03, "M", "د"), + (0x1EE04, "X"), + (0x1EE05, "M", "و"), + (0x1EE06, "M", "ز"), + (0x1EE07, "M", "ح"), + (0x1EE08, "M", "ط"), + (0x1EE09, "M", "ي"), + (0x1EE0A, "M", "ك"), + (0x1EE0B, "M", "ل"), + (0x1EE0C, "M", "م"), + (0x1EE0D, "M", "ن"), + (0x1EE0E, "M", "س"), + (0x1EE0F, "M", "ع"), + (0x1EE10, "M", "ف"), + (0x1EE11, "M", "ص"), + (0x1EE12, "M", "ق"), + (0x1EE13, "M", "ر"), + (0x1EE14, "M", "ش"), + ] + + +def _seg_74() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EE15, "M", "ت"), + (0x1EE16, "M", "ث"), + (0x1EE17, "M", "خ"), + (0x1EE18, "M", "ذ"), + (0x1EE19, "M", "ض"), + (0x1EE1A, "M", "ظ"), + (0x1EE1B, "M", "غ"), + (0x1EE1C, "M", "ٮ"), + (0x1EE1D, "M", "ں"), + (0x1EE1E, "M", "ڡ"), + (0x1EE1F, "M", "ٯ"), + (0x1EE20, "X"), + (0x1EE21, "M", "ب"), + (0x1EE22, "M", "ج"), + (0x1EE23, "X"), + (0x1EE24, "M", "ه"), + (0x1EE25, "X"), + (0x1EE27, "M", "ح"), + (0x1EE28, "X"), + (0x1EE29, "M", "ي"), + (0x1EE2A, "M", "ك"), + (0x1EE2B, "M", "ل"), + (0x1EE2C, "M", "م"), + (0x1EE2D, "M", "ن"), + (0x1EE2E, "M", "س"), + (0x1EE2F, "M", "ع"), + (0x1EE30, "M", "ف"), + (0x1EE31, "M", "ص"), + (0x1EE32, "M", "ق"), + (0x1EE33, "X"), + (0x1EE34, "M", "ش"), + (0x1EE35, "M", "ت"), + (0x1EE36, "M", "ث"), + (0x1EE37, "M", "خ"), + (0x1EE38, "X"), + (0x1EE39, "M", "ض"), + (0x1EE3A, "X"), + (0x1EE3B, "M", "غ"), + (0x1EE3C, "X"), + (0x1EE42, "M", "ج"), + (0x1EE43, "X"), + (0x1EE47, "M", "ح"), + (0x1EE48, "X"), + (0x1EE49, "M", "ي"), + (0x1EE4A, "X"), + (0x1EE4B, "M", "ل"), + (0x1EE4C, "X"), + (0x1EE4D, "M", "ن"), + (0x1EE4E, "M", "س"), + (0x1EE4F, "M", "ع"), + (0x1EE50, "X"), + (0x1EE51, "M", "ص"), + (0x1EE52, "M", "ق"), + (0x1EE53, "X"), + (0x1EE54, "M", "ش"), + (0x1EE55, "X"), + (0x1EE57, "M", "خ"), + (0x1EE58, "X"), + (0x1EE59, "M", "ض"), + (0x1EE5A, "X"), + (0x1EE5B, "M", "غ"), + (0x1EE5C, "X"), + (0x1EE5D, "M", "ں"), + (0x1EE5E, "X"), + (0x1EE5F, "M", "ٯ"), + (0x1EE60, "X"), + (0x1EE61, "M", "ب"), + (0x1EE62, "M", "ج"), + (0x1EE63, "X"), + (0x1EE64, "M", "ه"), + (0x1EE65, "X"), + (0x1EE67, "M", "ح"), + (0x1EE68, "M", "ط"), + (0x1EE69, "M", "ي"), + (0x1EE6A, "M", "ك"), + (0x1EE6B, "X"), + (0x1EE6C, "M", "م"), + (0x1EE6D, "M", "ن"), + (0x1EE6E, "M", "س"), + (0x1EE6F, "M", "ع"), + (0x1EE70, "M", "ف"), + (0x1EE71, "M", "ص"), + (0x1EE72, "M", "ق"), + (0x1EE73, "X"), + (0x1EE74, "M", "ش"), + (0x1EE75, "M", "ت"), + (0x1EE76, "M", "ث"), + (0x1EE77, "M", "خ"), + (0x1EE78, "X"), + (0x1EE79, "M", "ض"), + (0x1EE7A, "M", "ظ"), + (0x1EE7B, "M", "غ"), + (0x1EE7C, "M", "ٮ"), + (0x1EE7D, "X"), + (0x1EE7E, "M", "ڡ"), + (0x1EE7F, "X"), + (0x1EE80, "M", "ا"), + (0x1EE81, "M", "ب"), + (0x1EE82, "M", "ج"), + (0x1EE83, "M", "د"), + ] + + +def _seg_75() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EE84, "M", "ه"), + (0x1EE85, "M", "و"), + (0x1EE86, "M", "ز"), + (0x1EE87, "M", "ح"), + (0x1EE88, "M", "ط"), + (0x1EE89, "M", "ي"), + (0x1EE8A, "X"), + (0x1EE8B, "M", "ل"), + (0x1EE8C, "M", "م"), + (0x1EE8D, "M", "ن"), + (0x1EE8E, "M", "س"), + (0x1EE8F, "M", "ع"), + (0x1EE90, "M", "ف"), + (0x1EE91, "M", "ص"), + (0x1EE92, "M", "ق"), + (0x1EE93, "M", "ر"), + (0x1EE94, "M", "ش"), + (0x1EE95, "M", "ت"), + (0x1EE96, "M", "ث"), + (0x1EE97, "M", "خ"), + (0x1EE98, "M", "ذ"), + (0x1EE99, "M", "ض"), + (0x1EE9A, "M", "ظ"), + (0x1EE9B, "M", "غ"), + (0x1EE9C, "X"), + (0x1EEA1, "M", "ب"), + (0x1EEA2, "M", "ج"), + (0x1EEA3, "M", "د"), + (0x1EEA4, "X"), + (0x1EEA5, "M", "و"), + (0x1EEA6, "M", "ز"), + (0x1EEA7, "M", "ح"), + (0x1EEA8, "M", "ط"), + (0x1EEA9, "M", "ي"), + (0x1EEAA, "X"), + (0x1EEAB, "M", "ل"), + (0x1EEAC, "M", "م"), + (0x1EEAD, "M", "ن"), + (0x1EEAE, "M", "س"), + (0x1EEAF, "M", "ع"), + (0x1EEB0, "M", "ف"), + (0x1EEB1, "M", "ص"), + (0x1EEB2, "M", "ق"), + (0x1EEB3, "M", "ر"), + (0x1EEB4, "M", "ش"), + (0x1EEB5, "M", "ت"), + (0x1EEB6, "M", "ث"), + (0x1EEB7, "M", "خ"), + (0x1EEB8, "M", "ذ"), + (0x1EEB9, "M", "ض"), + (0x1EEBA, "M", "ظ"), + (0x1EEBB, "M", "غ"), + (0x1EEBC, "X"), + (0x1EEF0, "V"), + (0x1EEF2, "X"), + (0x1F000, "V"), + (0x1F02C, "X"), + (0x1F030, "V"), + (0x1F094, "X"), + (0x1F0A0, "V"), + (0x1F0AF, "X"), + (0x1F0B1, "V"), + (0x1F0C0, "X"), + (0x1F0C1, "V"), + (0x1F0D0, "X"), + (0x1F0D1, "V"), + (0x1F0F6, "X"), + (0x1F101, "M", "0,"), + (0x1F102, "M", "1,"), + (0x1F103, "M", "2,"), + (0x1F104, "M", "3,"), + (0x1F105, "M", "4,"), + (0x1F106, "M", "5,"), + (0x1F107, "M", "6,"), + (0x1F108, "M", "7,"), + (0x1F109, "M", "8,"), + (0x1F10A, "M", "9,"), + (0x1F10B, "V"), + (0x1F110, "M", "(a)"), + (0x1F111, "M", "(b)"), + (0x1F112, "M", "(c)"), + (0x1F113, "M", "(d)"), + (0x1F114, "M", "(e)"), + (0x1F115, "M", "(f)"), + (0x1F116, "M", "(g)"), + (0x1F117, "M", "(h)"), + (0x1F118, "M", "(i)"), + (0x1F119, "M", "(j)"), + (0x1F11A, "M", "(k)"), + (0x1F11B, "M", "(l)"), + (0x1F11C, "M", "(m)"), + (0x1F11D, "M", "(n)"), + (0x1F11E, "M", "(o)"), + (0x1F11F, "M", "(p)"), + (0x1F120, "M", "(q)"), + (0x1F121, "M", "(r)"), + (0x1F122, "M", "(s)"), + (0x1F123, "M", "(t)"), + (0x1F124, "M", "(u)"), + (0x1F125, "M", "(v)"), + ] + + +def _seg_76() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F126, "M", "(w)"), + (0x1F127, "M", "(x)"), + (0x1F128, "M", "(y)"), + (0x1F129, "M", "(z)"), + (0x1F12A, "M", "〔s〕"), + (0x1F12B, "M", "c"), + (0x1F12C, "M", "r"), + (0x1F12D, "M", "cd"), + (0x1F12E, "M", "wz"), + (0x1F12F, "V"), + (0x1F130, "M", "a"), + (0x1F131, "M", "b"), + (0x1F132, "M", "c"), + (0x1F133, "M", "d"), + (0x1F134, "M", "e"), + (0x1F135, "M", "f"), + (0x1F136, "M", "g"), + (0x1F137, "M", "h"), + (0x1F138, "M", "i"), + (0x1F139, "M", "j"), + (0x1F13A, "M", "k"), + (0x1F13B, "M", "l"), + (0x1F13C, "M", "m"), + (0x1F13D, "M", "n"), + (0x1F13E, "M", "o"), + (0x1F13F, "M", "p"), + (0x1F140, "M", "q"), + (0x1F141, "M", "r"), + (0x1F142, "M", "s"), + (0x1F143, "M", "t"), + (0x1F144, "M", "u"), + (0x1F145, "M", "v"), + (0x1F146, "M", "w"), + (0x1F147, "M", "x"), + (0x1F148, "M", "y"), + (0x1F149, "M", "z"), + (0x1F14A, "M", "hv"), + (0x1F14B, "M", "mv"), + (0x1F14C, "M", "sd"), + (0x1F14D, "M", "ss"), + (0x1F14E, "M", "ppv"), + (0x1F14F, "M", "wc"), + (0x1F150, "V"), + (0x1F16A, "M", "mc"), + (0x1F16B, "M", "md"), + (0x1F16C, "M", "mr"), + (0x1F16D, "V"), + (0x1F190, "M", "dj"), + (0x1F191, "V"), + (0x1F1AE, "X"), + (0x1F1E6, "V"), + (0x1F200, "M", "ほか"), + (0x1F201, "M", "ココ"), + (0x1F202, "M", "サ"), + (0x1F203, "X"), + (0x1F210, "M", "手"), + (0x1F211, "M", "字"), + (0x1F212, "M", "双"), + (0x1F213, "M", "デ"), + (0x1F214, "M", "二"), + (0x1F215, "M", "多"), + (0x1F216, "M", "解"), + (0x1F217, "M", "天"), + (0x1F218, "M", "交"), + (0x1F219, "M", "映"), + (0x1F21A, "M", "無"), + (0x1F21B, "M", "料"), + (0x1F21C, "M", "前"), + (0x1F21D, "M", "後"), + (0x1F21E, "M", "再"), + (0x1F21F, "M", "新"), + (0x1F220, "M", "初"), + (0x1F221, "M", "終"), + (0x1F222, "M", "生"), + (0x1F223, "M", "販"), + (0x1F224, "M", "声"), + (0x1F225, "M", "吹"), + (0x1F226, "M", "演"), + (0x1F227, "M", "投"), + (0x1F228, "M", "捕"), + (0x1F229, "M", "一"), + (0x1F22A, "M", "三"), + (0x1F22B, "M", "遊"), + (0x1F22C, "M", "左"), + (0x1F22D, "M", "中"), + (0x1F22E, "M", "右"), + (0x1F22F, "M", "指"), + (0x1F230, "M", "走"), + (0x1F231, "M", "打"), + (0x1F232, "M", "禁"), + (0x1F233, "M", "空"), + (0x1F234, "M", "合"), + (0x1F235, "M", "満"), + (0x1F236, "M", "有"), + (0x1F237, "M", "月"), + (0x1F238, "M", "申"), + (0x1F239, "M", "割"), + (0x1F23A, "M", "営"), + (0x1F23B, "M", "配"), + (0x1F23C, "X"), + ] + + +def _seg_77() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F240, "M", "〔本〕"), + (0x1F241, "M", "〔三〕"), + (0x1F242, "M", "〔二〕"), + (0x1F243, "M", "〔安〕"), + (0x1F244, "M", "〔点〕"), + (0x1F245, "M", "〔打〕"), + (0x1F246, "M", "〔盗〕"), + (0x1F247, "M", "〔勝〕"), + (0x1F248, "M", "〔敗〕"), + (0x1F249, "X"), + (0x1F250, "M", "得"), + (0x1F251, "M", "可"), + (0x1F252, "X"), + (0x1F260, "V"), + (0x1F266, "X"), + (0x1F300, "V"), + (0x1F6D8, "X"), + (0x1F6DC, "V"), + (0x1F6ED, "X"), + (0x1F6F0, "V"), + (0x1F6FD, "X"), + (0x1F700, "V"), + (0x1F777, "X"), + (0x1F77B, "V"), + (0x1F7DA, "X"), + (0x1F7E0, "V"), + (0x1F7EC, "X"), + (0x1F7F0, "V"), + (0x1F7F1, "X"), + (0x1F800, "V"), + (0x1F80C, "X"), + (0x1F810, "V"), + (0x1F848, "X"), + (0x1F850, "V"), + (0x1F85A, "X"), + (0x1F860, "V"), + (0x1F888, "X"), + (0x1F890, "V"), + (0x1F8AE, "X"), + (0x1F8B0, "V"), + (0x1F8BC, "X"), + (0x1F8C0, "V"), + (0x1F8C2, "X"), + (0x1F900, "V"), + (0x1FA54, "X"), + (0x1FA60, "V"), + (0x1FA6E, "X"), + (0x1FA70, "V"), + (0x1FA7D, "X"), + (0x1FA80, "V"), + (0x1FA8A, "X"), + (0x1FA8F, "V"), + (0x1FAC7, "X"), + (0x1FACE, "V"), + (0x1FADD, "X"), + (0x1FADF, "V"), + (0x1FAEA, "X"), + (0x1FAF0, "V"), + (0x1FAF9, "X"), + (0x1FB00, "V"), + (0x1FB93, "X"), + (0x1FB94, "V"), + (0x1FBF0, "M", "0"), + (0x1FBF1, "M", "1"), + (0x1FBF2, "M", "2"), + (0x1FBF3, "M", "3"), + (0x1FBF4, "M", "4"), + (0x1FBF5, "M", "5"), + (0x1FBF6, "M", "6"), + (0x1FBF7, "M", "7"), + (0x1FBF8, "M", "8"), + (0x1FBF9, "M", "9"), + (0x1FBFA, "X"), + (0x20000, "V"), + (0x2A6E0, "X"), + (0x2A700, "V"), + (0x2B73A, "X"), + (0x2B740, "V"), + (0x2B81E, "X"), + (0x2B820, "V"), + (0x2CEA2, "X"), + (0x2CEB0, "V"), + (0x2EBE1, "X"), + (0x2EBF0, "V"), + (0x2EE5E, "X"), + (0x2F800, "M", "丽"), + (0x2F801, "M", "丸"), + (0x2F802, "M", "乁"), + (0x2F803, "M", "𠄢"), + (0x2F804, "M", "你"), + (0x2F805, "M", "侮"), + (0x2F806, "M", "侻"), + (0x2F807, "M", "倂"), + (0x2F808, "M", "偺"), + (0x2F809, "M", "備"), + (0x2F80A, "M", "僧"), + (0x2F80B, "M", "像"), + (0x2F80C, "M", "㒞"), + (0x2F80D, "M", "𠘺"), + (0x2F80E, "M", "免"), + ] + + +def _seg_78() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F80F, "M", "兔"), + (0x2F810, "M", "兤"), + (0x2F811, "M", "具"), + (0x2F812, "M", "𠔜"), + (0x2F813, "M", "㒹"), + (0x2F814, "M", "內"), + (0x2F815, "M", "再"), + (0x2F816, "M", "𠕋"), + (0x2F817, "M", "冗"), + (0x2F818, "M", "冤"), + (0x2F819, "M", "仌"), + (0x2F81A, "M", "冬"), + (0x2F81B, "M", "况"), + (0x2F81C, "M", "𩇟"), + (0x2F81D, "M", "凵"), + (0x2F81E, "M", "刃"), + (0x2F81F, "M", "㓟"), + (0x2F820, "M", "刻"), + (0x2F821, "M", "剆"), + (0x2F822, "M", "割"), + (0x2F823, "M", "剷"), + (0x2F824, "M", "㔕"), + (0x2F825, "M", "勇"), + (0x2F826, "M", "勉"), + (0x2F827, "M", "勤"), + (0x2F828, "M", "勺"), + (0x2F829, "M", "包"), + (0x2F82A, "M", "匆"), + (0x2F82B, "M", "北"), + (0x2F82C, "M", "卉"), + (0x2F82D, "M", "卑"), + (0x2F82E, "M", "博"), + (0x2F82F, "M", "即"), + (0x2F830, "M", "卽"), + (0x2F831, "M", "卿"), + (0x2F834, "M", "𠨬"), + (0x2F835, "M", "灰"), + (0x2F836, "M", "及"), + (0x2F837, "M", "叟"), + (0x2F838, "M", "𠭣"), + (0x2F839, "M", "叫"), + (0x2F83A, "M", "叱"), + (0x2F83B, "M", "吆"), + (0x2F83C, "M", "咞"), + (0x2F83D, "M", "吸"), + (0x2F83E, "M", "呈"), + (0x2F83F, "M", "周"), + (0x2F840, "M", "咢"), + (0x2F841, "M", "哶"), + (0x2F842, "M", "唐"), + (0x2F843, "M", "啓"), + (0x2F844, "M", "啣"), + (0x2F845, "M", "善"), + (0x2F847, "M", "喙"), + (0x2F848, "M", "喫"), + (0x2F849, "M", "喳"), + (0x2F84A, "M", "嗂"), + (0x2F84B, "M", "圖"), + (0x2F84C, "M", "嘆"), + (0x2F84D, "M", "圗"), + (0x2F84E, "M", "噑"), + (0x2F84F, "M", "噴"), + (0x2F850, "M", "切"), + (0x2F851, "M", "壮"), + (0x2F852, "M", "城"), + (0x2F853, "M", "埴"), + (0x2F854, "M", "堍"), + (0x2F855, "M", "型"), + (0x2F856, "M", "堲"), + (0x2F857, "M", "報"), + (0x2F858, "M", "墬"), + (0x2F859, "M", "𡓤"), + (0x2F85A, "M", "売"), + (0x2F85B, "M", "壷"), + (0x2F85C, "M", "夆"), + (0x2F85D, "M", "多"), + (0x2F85E, "M", "夢"), + (0x2F85F, "M", "奢"), + (0x2F860, "M", "𡚨"), + (0x2F861, "M", "𡛪"), + (0x2F862, "M", "姬"), + (0x2F863, "M", "娛"), + (0x2F864, "M", "娧"), + (0x2F865, "M", "姘"), + (0x2F866, "M", "婦"), + (0x2F867, "M", "㛮"), + (0x2F868, "M", "㛼"), + (0x2F869, "M", "嬈"), + (0x2F86A, "M", "嬾"), + (0x2F86C, "M", "𡧈"), + (0x2F86D, "M", "寃"), + (0x2F86E, "M", "寘"), + (0x2F86F, "M", "寧"), + (0x2F870, "M", "寳"), + (0x2F871, "M", "𡬘"), + (0x2F872, "M", "寿"), + (0x2F873, "M", "将"), + (0x2F874, "M", "当"), + (0x2F875, "M", "尢"), + (0x2F876, "M", "㞁"), + ] + + +def _seg_79() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F877, "M", "屠"), + (0x2F878, "M", "屮"), + (0x2F879, "M", "峀"), + (0x2F87A, "M", "岍"), + (0x2F87B, "M", "𡷤"), + (0x2F87C, "M", "嵃"), + (0x2F87D, "M", "𡷦"), + (0x2F87E, "M", "嵮"), + (0x2F87F, "M", "嵫"), + (0x2F880, "M", "嵼"), + (0x2F881, "M", "巡"), + (0x2F882, "M", "巢"), + (0x2F883, "M", "㠯"), + (0x2F884, "M", "巽"), + (0x2F885, "M", "帨"), + (0x2F886, "M", "帽"), + (0x2F887, "M", "幩"), + (0x2F888, "M", "㡢"), + (0x2F889, "M", "𢆃"), + (0x2F88A, "M", "㡼"), + (0x2F88B, "M", "庰"), + (0x2F88C, "M", "庳"), + (0x2F88D, "M", "庶"), + (0x2F88E, "M", "廊"), + (0x2F88F, "M", "𪎒"), + (0x2F890, "M", "廾"), + (0x2F891, "M", "𢌱"), + (0x2F893, "M", "舁"), + (0x2F894, "M", "弢"), + (0x2F896, "M", "㣇"), + (0x2F897, "M", "𣊸"), + (0x2F898, "M", "𦇚"), + (0x2F899, "M", "形"), + (0x2F89A, "M", "彫"), + (0x2F89B, "M", "㣣"), + (0x2F89C, "M", "徚"), + (0x2F89D, "M", "忍"), + (0x2F89E, "M", "志"), + (0x2F89F, "M", "忹"), + (0x2F8A0, "M", "悁"), + (0x2F8A1, "M", "㤺"), + (0x2F8A2, "M", "㤜"), + (0x2F8A3, "M", "悔"), + (0x2F8A4, "M", "𢛔"), + (0x2F8A5, "M", "惇"), + (0x2F8A6, "M", "慈"), + (0x2F8A7, "M", "慌"), + (0x2F8A8, "M", "慎"), + (0x2F8A9, "M", "慌"), + (0x2F8AA, "M", "慺"), + (0x2F8AB, "M", "憎"), + (0x2F8AC, "M", "憲"), + (0x2F8AD, "M", "憤"), + (0x2F8AE, "M", "憯"), + (0x2F8AF, "M", "懞"), + (0x2F8B0, "M", "懲"), + (0x2F8B1, "M", "懶"), + (0x2F8B2, "M", "成"), + (0x2F8B3, "M", "戛"), + (0x2F8B4, "M", "扝"), + (0x2F8B5, "M", "抱"), + (0x2F8B6, "M", "拔"), + (0x2F8B7, "M", "捐"), + (0x2F8B8, "M", "𢬌"), + (0x2F8B9, "M", "挽"), + (0x2F8BA, "M", "拼"), + (0x2F8BB, "M", "捨"), + (0x2F8BC, "M", "掃"), + (0x2F8BD, "M", "揤"), + (0x2F8BE, "M", "𢯱"), + (0x2F8BF, "M", "搢"), + (0x2F8C0, "M", "揅"), + (0x2F8C1, "M", "掩"), + (0x2F8C2, "M", "㨮"), + (0x2F8C3, "M", "摩"), + (0x2F8C4, "M", "摾"), + (0x2F8C5, "M", "撝"), + (0x2F8C6, "M", "摷"), + (0x2F8C7, "M", "㩬"), + (0x2F8C8, "M", "敏"), + (0x2F8C9, "M", "敬"), + (0x2F8CA, "M", "𣀊"), + (0x2F8CB, "M", "旣"), + (0x2F8CC, "M", "書"), + (0x2F8CD, "M", "晉"), + (0x2F8CE, "M", "㬙"), + (0x2F8CF, "M", "暑"), + (0x2F8D0, "M", "㬈"), + (0x2F8D1, "M", "㫤"), + (0x2F8D2, "M", "冒"), + (0x2F8D3, "M", "冕"), + (0x2F8D4, "M", "最"), + (0x2F8D5, "M", "暜"), + (0x2F8D6, "M", "肭"), + (0x2F8D7, "M", "䏙"), + (0x2F8D8, "M", "朗"), + (0x2F8D9, "M", "望"), + (0x2F8DA, "M", "朡"), + (0x2F8DB, "M", "杞"), + (0x2F8DC, "M", "杓"), + ] + + +def _seg_80() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F8DD, "M", "𣏃"), + (0x2F8DE, "M", "㭉"), + (0x2F8DF, "M", "柺"), + (0x2F8E0, "M", "枅"), + (0x2F8E1, "M", "桒"), + (0x2F8E2, "M", "梅"), + (0x2F8E3, "M", "𣑭"), + (0x2F8E4, "M", "梎"), + (0x2F8E5, "M", "栟"), + (0x2F8E6, "M", "椔"), + (0x2F8E7, "M", "㮝"), + (0x2F8E8, "M", "楂"), + (0x2F8E9, "M", "榣"), + (0x2F8EA, "M", "槪"), + (0x2F8EB, "M", "檨"), + (0x2F8EC, "M", "𣚣"), + (0x2F8ED, "M", "櫛"), + (0x2F8EE, "M", "㰘"), + (0x2F8EF, "M", "次"), + (0x2F8F0, "M", "𣢧"), + (0x2F8F1, "M", "歔"), + (0x2F8F2, "M", "㱎"), + (0x2F8F3, "M", "歲"), + (0x2F8F4, "M", "殟"), + (0x2F8F5, "M", "殺"), + (0x2F8F6, "M", "殻"), + (0x2F8F7, "M", "𣪍"), + (0x2F8F8, "M", "𡴋"), + (0x2F8F9, "M", "𣫺"), + (0x2F8FA, "M", "汎"), + (0x2F8FB, "M", "𣲼"), + (0x2F8FC, "M", "沿"), + (0x2F8FD, "M", "泍"), + (0x2F8FE, "M", "汧"), + (0x2F8FF, "M", "洖"), + (0x2F900, "M", "派"), + (0x2F901, "M", "海"), + (0x2F902, "M", "流"), + (0x2F903, "M", "浩"), + (0x2F904, "M", "浸"), + (0x2F905, "M", "涅"), + (0x2F906, "M", "𣴞"), + (0x2F907, "M", "洴"), + (0x2F908, "M", "港"), + (0x2F909, "M", "湮"), + (0x2F90A, "M", "㴳"), + (0x2F90B, "M", "滋"), + (0x2F90C, "M", "滇"), + (0x2F90D, "M", "𣻑"), + (0x2F90E, "M", "淹"), + (0x2F90F, "M", "潮"), + (0x2F910, "M", "𣽞"), + (0x2F911, "M", "𣾎"), + (0x2F912, "M", "濆"), + (0x2F913, "M", "瀹"), + (0x2F914, "M", "瀞"), + (0x2F915, "M", "瀛"), + (0x2F916, "M", "㶖"), + (0x2F917, "M", "灊"), + (0x2F918, "M", "災"), + (0x2F919, "M", "灷"), + (0x2F91A, "M", "炭"), + (0x2F91B, "M", "𠔥"), + (0x2F91C, "M", "煅"), + (0x2F91D, "M", "𤉣"), + (0x2F91E, "M", "熜"), + (0x2F91F, "M", "𤎫"), + (0x2F920, "M", "爨"), + (0x2F921, "M", "爵"), + (0x2F922, "M", "牐"), + (0x2F923, "M", "𤘈"), + (0x2F924, "M", "犀"), + (0x2F925, "M", "犕"), + (0x2F926, "M", "𤜵"), + (0x2F927, "M", "𤠔"), + (0x2F928, "M", "獺"), + (0x2F929, "M", "王"), + (0x2F92A, "M", "㺬"), + (0x2F92B, "M", "玥"), + (0x2F92C, "M", "㺸"), + (0x2F92E, "M", "瑇"), + (0x2F92F, "M", "瑜"), + (0x2F930, "M", "瑱"), + (0x2F931, "M", "璅"), + (0x2F932, "M", "瓊"), + (0x2F933, "M", "㼛"), + (0x2F934, "M", "甤"), + (0x2F935, "M", "𤰶"), + (0x2F936, "M", "甾"), + (0x2F937, "M", "𤲒"), + (0x2F938, "M", "異"), + (0x2F939, "M", "𢆟"), + (0x2F93A, "M", "瘐"), + (0x2F93B, "M", "𤾡"), + (0x2F93C, "M", "𤾸"), + (0x2F93D, "M", "𥁄"), + (0x2F93E, "M", "㿼"), + (0x2F93F, "M", "䀈"), + (0x2F940, "M", "直"), + (0x2F941, "M", "𥃳"), + ] + + +def _seg_81() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F942, "M", "𥃲"), + (0x2F943, "M", "𥄙"), + (0x2F944, "M", "𥄳"), + (0x2F945, "M", "眞"), + (0x2F946, "M", "真"), + (0x2F948, "M", "睊"), + (0x2F949, "M", "䀹"), + (0x2F94A, "M", "瞋"), + (0x2F94B, "M", "䁆"), + (0x2F94C, "M", "䂖"), + (0x2F94D, "M", "𥐝"), + (0x2F94E, "M", "硎"), + (0x2F94F, "M", "碌"), + (0x2F950, "M", "磌"), + (0x2F951, "M", "䃣"), + (0x2F952, "M", "𥘦"), + (0x2F953, "M", "祖"), + (0x2F954, "M", "𥚚"), + (0x2F955, "M", "𥛅"), + (0x2F956, "M", "福"), + (0x2F957, "M", "秫"), + (0x2F958, "M", "䄯"), + (0x2F959, "M", "穀"), + (0x2F95A, "M", "穊"), + (0x2F95B, "M", "穏"), + (0x2F95C, "M", "𥥼"), + (0x2F95D, "M", "𥪧"), + (0x2F95F, "M", "竮"), + (0x2F960, "M", "䈂"), + (0x2F961, "M", "𥮫"), + (0x2F962, "M", "篆"), + (0x2F963, "M", "築"), + (0x2F964, "M", "䈧"), + (0x2F965, "M", "𥲀"), + (0x2F966, "M", "糒"), + (0x2F967, "M", "䊠"), + (0x2F968, "M", "糨"), + (0x2F969, "M", "糣"), + (0x2F96A, "M", "紀"), + (0x2F96B, "M", "𥾆"), + (0x2F96C, "M", "絣"), + (0x2F96D, "M", "䌁"), + (0x2F96E, "M", "緇"), + (0x2F96F, "M", "縂"), + (0x2F970, "M", "繅"), + (0x2F971, "M", "䌴"), + (0x2F972, "M", "𦈨"), + (0x2F973, "M", "𦉇"), + (0x2F974, "M", "䍙"), + (0x2F975, "M", "𦋙"), + (0x2F976, "M", "罺"), + (0x2F977, "M", "𦌾"), + (0x2F978, "M", "羕"), + (0x2F979, "M", "翺"), + (0x2F97A, "M", "者"), + (0x2F97B, "M", "𦓚"), + (0x2F97C, "M", "𦔣"), + (0x2F97D, "M", "聠"), + (0x2F97E, "M", "𦖨"), + (0x2F97F, "M", "聰"), + (0x2F980, "M", "𣍟"), + (0x2F981, "M", "䏕"), + (0x2F982, "M", "育"), + (0x2F983, "M", "脃"), + (0x2F984, "M", "䐋"), + (0x2F985, "M", "脾"), + (0x2F986, "M", "媵"), + (0x2F987, "M", "𦞧"), + (0x2F988, "M", "𦞵"), + (0x2F989, "M", "𣎓"), + (0x2F98A, "M", "𣎜"), + (0x2F98B, "M", "舁"), + (0x2F98C, "M", "舄"), + (0x2F98D, "M", "辞"), + (0x2F98E, "M", "䑫"), + (0x2F98F, "M", "芑"), + (0x2F990, "M", "芋"), + (0x2F991, "M", "芝"), + (0x2F992, "M", "劳"), + (0x2F993, "M", "花"), + (0x2F994, "M", "芳"), + (0x2F995, "M", "芽"), + (0x2F996, "M", "苦"), + (0x2F997, "M", "𦬼"), + (0x2F998, "M", "若"), + (0x2F999, "M", "茝"), + (0x2F99A, "M", "荣"), + (0x2F99B, "M", "莭"), + (0x2F99C, "M", "茣"), + (0x2F99D, "M", "莽"), + (0x2F99E, "M", "菧"), + (0x2F99F, "M", "著"), + (0x2F9A0, "M", "荓"), + (0x2F9A1, "M", "菊"), + (0x2F9A2, "M", "菌"), + (0x2F9A3, "M", "菜"), + (0x2F9A4, "M", "𦰶"), + (0x2F9A5, "M", "𦵫"), + (0x2F9A6, "M", "𦳕"), + (0x2F9A7, "M", "䔫"), + ] + + +def _seg_82() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F9A8, "M", "蓱"), + (0x2F9A9, "M", "蓳"), + (0x2F9AA, "M", "蔖"), + (0x2F9AB, "M", "𧏊"), + (0x2F9AC, "M", "蕤"), + (0x2F9AD, "M", "𦼬"), + (0x2F9AE, "M", "䕝"), + (0x2F9AF, "M", "䕡"), + (0x2F9B0, "M", "𦾱"), + (0x2F9B1, "M", "𧃒"), + (0x2F9B2, "M", "䕫"), + (0x2F9B3, "M", "虐"), + (0x2F9B4, "M", "虜"), + (0x2F9B5, "M", "虧"), + (0x2F9B6, "M", "虩"), + (0x2F9B7, "M", "蚩"), + (0x2F9B8, "M", "蚈"), + (0x2F9B9, "M", "蜎"), + (0x2F9BA, "M", "蛢"), + (0x2F9BB, "M", "蝹"), + (0x2F9BC, "M", "蜨"), + (0x2F9BD, "M", "蝫"), + (0x2F9BE, "M", "螆"), + (0x2F9BF, "M", "䗗"), + (0x2F9C0, "M", "蟡"), + (0x2F9C1, "M", "蠁"), + (0x2F9C2, "M", "䗹"), + (0x2F9C3, "M", "衠"), + (0x2F9C4, "M", "衣"), + (0x2F9C5, "M", "𧙧"), + (0x2F9C6, "M", "裗"), + (0x2F9C7, "M", "裞"), + (0x2F9C8, "M", "䘵"), + (0x2F9C9, "M", "裺"), + (0x2F9CA, "M", "㒻"), + (0x2F9CB, "M", "𧢮"), + (0x2F9CC, "M", "𧥦"), + (0x2F9CD, "M", "䚾"), + (0x2F9CE, "M", "䛇"), + (0x2F9CF, "M", "誠"), + (0x2F9D0, "M", "諭"), + (0x2F9D1, "M", "變"), + (0x2F9D2, "M", "豕"), + (0x2F9D3, "M", "𧲨"), + (0x2F9D4, "M", "貫"), + (0x2F9D5, "M", "賁"), + (0x2F9D6, "M", "贛"), + (0x2F9D7, "M", "起"), + (0x2F9D8, "M", "𧼯"), + (0x2F9D9, "M", "𠠄"), + (0x2F9DA, "M", "跋"), + (0x2F9DB, "M", "趼"), + (0x2F9DC, "M", "跰"), + (0x2F9DD, "M", "𠣞"), + (0x2F9DE, "M", "軔"), + (0x2F9DF, "M", "輸"), + (0x2F9E0, "M", "𨗒"), + (0x2F9E1, "M", "𨗭"), + (0x2F9E2, "M", "邔"), + (0x2F9E3, "M", "郱"), + (0x2F9E4, "M", "鄑"), + (0x2F9E5, "M", "𨜮"), + (0x2F9E6, "M", "鄛"), + (0x2F9E7, "M", "鈸"), + (0x2F9E8, "M", "鋗"), + (0x2F9E9, "M", "鋘"), + (0x2F9EA, "M", "鉼"), + (0x2F9EB, "M", "鏹"), + (0x2F9EC, "M", "鐕"), + (0x2F9ED, "M", "𨯺"), + (0x2F9EE, "M", "開"), + (0x2F9EF, "M", "䦕"), + (0x2F9F0, "M", "閷"), + (0x2F9F1, "M", "𨵷"), + (0x2F9F2, "M", "䧦"), + (0x2F9F3, "M", "雃"), + (0x2F9F4, "M", "嶲"), + (0x2F9F5, "M", "霣"), + (0x2F9F6, "M", "𩅅"), + (0x2F9F7, "M", "𩈚"), + (0x2F9F8, "M", "䩮"), + (0x2F9F9, "M", "䩶"), + (0x2F9FA, "M", "韠"), + (0x2F9FB, "M", "𩐊"), + (0x2F9FC, "M", "䪲"), + (0x2F9FD, "M", "𩒖"), + (0x2F9FE, "M", "頋"), + (0x2FA00, "M", "頩"), + (0x2FA01, "M", "𩖶"), + (0x2FA02, "M", "飢"), + (0x2FA03, "M", "䬳"), + (0x2FA04, "M", "餩"), + (0x2FA05, "M", "馧"), + (0x2FA06, "M", "駂"), + (0x2FA07, "M", "駾"), + (0x2FA08, "M", "䯎"), + (0x2FA09, "M", "𩬰"), + (0x2FA0A, "M", "鬒"), + (0x2FA0B, "M", "鱀"), + (0x2FA0C, "M", "鳽"), + ] + + +def _seg_83() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2FA0D, "M", "䳎"), + (0x2FA0E, "M", "䳭"), + (0x2FA0F, "M", "鵧"), + (0x2FA10, "M", "𪃎"), + (0x2FA11, "M", "䳸"), + (0x2FA12, "M", "𪄅"), + (0x2FA13, "M", "𪈎"), + (0x2FA14, "M", "𪊑"), + (0x2FA15, "M", "麻"), + (0x2FA16, "M", "䵖"), + (0x2FA17, "M", "黹"), + (0x2FA18, "M", "黾"), + (0x2FA19, "M", "鼅"), + (0x2FA1A, "M", "鼏"), + (0x2FA1B, "M", "鼖"), + (0x2FA1C, "M", "鼻"), + (0x2FA1D, "M", "𪘀"), + (0x2FA1E, "X"), + (0x30000, "V"), + (0x3134B, "X"), + (0x31350, "V"), + (0x323B0, "X"), + (0xE0100, "I"), + (0xE01F0, "X"), + ] + + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() + + _seg_73() + + _seg_74() + + _seg_75() + + _seg_76() + + _seg_77() + + _seg_78() + + _seg_79() + + _seg_80() + + _seg_81() + + _seg_82() + + _seg_83() +) # type: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...] diff --git a/backend/venv/Lib/site-packages/multipart/__init__.py b/backend/venv/Lib/site-packages/multipart/__init__.py new file mode 100644 index 0000000..67f0e5b --- /dev/null +++ b/backend/venv/Lib/site-packages/multipart/__init__.py @@ -0,0 +1,24 @@ +# This only works if using a file system, other loaders not implemented. + +import importlib.util +import sys +import warnings +from pathlib import Path + +for p in sys.path: + file_path = Path(p, "multipart.py") + try: + if file_path.is_file(): + spec = importlib.util.spec_from_file_location("multipart", file_path) + assert spec is not None, f"{file_path} found but not loadable!" + module = importlib.util.module_from_spec(spec) + sys.modules["multipart"] = module + assert spec.loader is not None, f"{file_path} must be loadable!" + spec.loader.exec_module(module) + break + except PermissionError: + pass +else: + warnings.warn("Please use `import python_multipart` instead.", PendingDeprecationWarning, stacklevel=2) + from python_multipart import * + from python_multipart import __all__, __author__, __copyright__, __license__, __version__ diff --git a/backend/venv/Lib/site-packages/multipart/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/multipart/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d4d79a9709f27197ab770707cf214ef9d4416dd GIT binary patch literal 1426 zcmZ`&O>7%Q6rQnn^OFsD7d(#N}B`;a!Ff7Dh?IYX-N?h%F5|>?VTj+?0Q$T z>!c2sfP@HAq>@uAA*3P>1f@kBIU@DQWi1EdOhF)V>IGTkf^uTUj-5bZqo6gu_9=*4y8_qkZKC;CBu>OFT9X|9}8&0~M%H2NG;)kK}1-ujFOgqYH*8i4b5< z33bv>^fZ|N0szV90a(O7)w}Cy?@9gu!2VMFB(h`e9vkE%3`>0-?};uYPwbAR3fSLe zMi{LJZ!q@HfGU3O>F|9B|A%j|!*ZfA+GTz7B}H(AbvE2ar===fWe}rM`n0!gckB23 zqyB%!mNL)h<4C7I1Q1l==9dCsH|QoI7@5DsOXMn zDa0AKsx;6=YpL{tSt+aOLd8j!O((6JimDWJe0D9CHY&E0F5pwXu~{7}HcnUAcULnk zlQ?Os>MWUMxl4IBt(9#DE9&?&{-3ZT1Z_ttF6(#&>kPq*BO>+5vZCv1O zYag9P|9!K>&srb>F8He_AujlP{TduH36AEnm-7}e7l~pRj5EJ#nnlwvFezeLE3e?P zW0GpVz=pw!<{4he&uE3btvPtiVqRqt+xhMwUy)go#wNjk8UNLGA5-K!tHd9ceZ)l5 z3n4u00kHom2tEb9zkt+l0dzmLnOeVg5bgW)_Jc@0dSU&orY9(d8==1a&`>Qjv=yP!B}$$h_UrIKfd|FO*eMU&E{RL^rNu+v+&Zd!u(Id p{9nxwK!bk*D25OGi1jRnkL(z0|IzF5?5O9-sF?m%-2$L!VtQ(E4BU8q pnDKfAmA5!-a`RJ4b5iY!IDj@W0&y{j@qw9nb}<5RF^KVjnURt4E`w$f8;}D4k90+< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/multipart/__pycache__/multipart.cpython-312.pyc b/backend/venv/Lib/site-packages/multipart/__pycache__/multipart.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..431ae70a3480e100ee3a6bdd8d26f38946beea50 GIT binary patch literal 235 zcmX@j%ge<81pe!SGBttpV-N=hn4pZ$d_cx@h7^Vr#vF#VOpFYbOq$FuL6Vw`w-~kj zfTUDGWl2VUUVLt8PDy4#Vo`}6oVAkSGf3&LC}*pff};HNqQu +License: MIT +Project-URL: Homepage, https://pip.pypa.io/ +Project-URL: Documentation, https://pip.pypa.io +Project-URL: Source, https://github.com/pypa/pip +Project-URL: Changelog, https://pip.pypa.io/en/stable/news/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Build Tools +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt +License-File: AUTHORS.txt + +pip - The Python Package Installer +================================== + +.. |pypi-version| image:: https://img.shields.io/pypi/v/pip.svg + :target: https://pypi.org/project/pip/ + :alt: PyPI + +.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pip + :target: https://pypi.org/project/pip + :alt: PyPI - Python Version + +.. |docs-badge| image:: https://readthedocs.org/projects/pip/badge/?version=latest + :target: https://pip.pypa.io/en/latest + :alt: Documentation + +|pypi-version| |python-versions| |docs-badge| + +pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes. + +Please take a look at our documentation for how to install and use pip: + +* `Installation`_ +* `Usage`_ + +We release updates regularly, with a new version every 3 months. Find more details in our documentation: + +* `Release notes`_ +* `Release process`_ + +If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms: + +* `Issue tracking`_ +* `Discourse channel`_ +* `User IRC`_ + +If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms: + +* `GitHub page`_ +* `Development documentation`_ +* `Development IRC`_ + +Code of Conduct +--------------- + +Everyone interacting in the pip project's codebases, issue trackers, chat +rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_. + +.. _package installer: https://packaging.python.org/guides/tool-recommendations/ +.. _Python Package Index: https://pypi.org +.. _Installation: https://pip.pypa.io/en/stable/installation/ +.. _Usage: https://pip.pypa.io/en/stable/ +.. _Release notes: https://pip.pypa.io/en/stable/news.html +.. _Release process: https://pip.pypa.io/en/latest/development/release-process/ +.. _GitHub page: https://github.com/pypa/pip +.. _Development documentation: https://pip.pypa.io/en/latest/development +.. _Issue tracking: https://github.com/pypa/pip/issues +.. _Discourse channel: https://discuss.python.org/c/packaging +.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa +.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev +.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md diff --git a/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/RECORD b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/RECORD new file mode 100644 index 0000000..169ff7b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/RECORD @@ -0,0 +1,854 @@ +../../Scripts/pip.exe,sha256=SWK0A8ZZKwSRX7gvdUP4FqPFIEhCeOpxuOQyr9MzNjw,108425 +../../Scripts/pip3.12.exe,sha256=SWK0A8ZZKwSRX7gvdUP4FqPFIEhCeOpxuOQyr9MzNjw,108425 +../../Scripts/pip3.exe,sha256=SWK0A8ZZKwSRX7gvdUP4FqPFIEhCeOpxuOQyr9MzNjw,108425 +pip-25.0.1.dist-info/AUTHORS.txt,sha256=HqzpBVLfT1lBthqQfiDlVeFkg65hJ7ZQvvWhoq-BAsA,11018 +pip-25.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip-25.0.1.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093 +pip-25.0.1.dist-info/METADATA,sha256=T6cxjPMPl523zsRcEsu8K0-IoV8S7vv1mmKR0KA6-SY,3677 +pip-25.0.1.dist-info/RECORD,, +pip-25.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip-25.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91 +pip-25.0.1.dist-info/entry_points.txt,sha256=eeIjuzfnfR2PrhbjnbzFU6MnSS70kZLxwaHHq6M-bD0,87 +pip-25.0.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip/__init__.py,sha256=aKiv_sTe7UbE7qmtCinJutFjqN0MndZQZ1fKLNwFFLE,357 +pip/__main__.py,sha256=WzbhHXTbSE6gBY19mNN9m4s5o_365LOvTYSgqgbdBhE,854 +pip/__pip-runner__.py,sha256=cPPWuJ6NK_k-GzfvlejLFgwzmYUROmpAR6QC3Q-vkXQ,1450 +pip/__pycache__/__init__.cpython-312.pyc,, +pip/__pycache__/__main__.cpython-312.pyc,, +pip/__pycache__/__pip-runner__.cpython-312.pyc,, +pip/_internal/__init__.py,sha256=MfcoOluDZ8QMCFYal04IqOJ9q6m2V7a0aOsnI-WOxUo,513 +pip/_internal/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/__pycache__/build_env.cpython-312.pyc,, +pip/_internal/__pycache__/cache.cpython-312.pyc,, +pip/_internal/__pycache__/configuration.cpython-312.pyc,, +pip/_internal/__pycache__/exceptions.cpython-312.pyc,, +pip/_internal/__pycache__/main.cpython-312.pyc,, +pip/_internal/__pycache__/pyproject.cpython-312.pyc,, +pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc,, +pip/_internal/__pycache__/wheel_builder.cpython-312.pyc,, +pip/_internal/build_env.py,sha256=Dv4UCClSg4uNaal_hL-trg5-zl3Is9CuIDxkChCkXF4,10700 +pip/_internal/cache.py,sha256=Jb698p5PNigRtpW5o26wQNkkUv4MnQ94mc471wL63A0,10369 +pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132 +pip/_internal/cli/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc,, +pip/_internal/cli/__pycache__/base_command.cpython-312.pyc,, +pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc,, +pip/_internal/cli/__pycache__/command_context.cpython-312.pyc,, +pip/_internal/cli/__pycache__/index_command.cpython-312.pyc,, +pip/_internal/cli/__pycache__/main.cpython-312.pyc,, +pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc,, +pip/_internal/cli/__pycache__/parser.cpython-312.pyc,, +pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc,, +pip/_internal/cli/__pycache__/req_command.cpython-312.pyc,, +pip/_internal/cli/__pycache__/spinners.cpython-312.pyc,, +pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc,, +pip/_internal/cli/autocompletion.py,sha256=Lli3Mr6aDNu7ZkJJFFvwD2-hFxNI6Avz8OwMyS5TVrs,6865 +pip/_internal/cli/base_command.py,sha256=NZin6KMzW9NSYzKk4Tc8isb_TQYKR4CKd5j9mSm46PI,8625 +pip/_internal/cli/cmdoptions.py,sha256=V3BB22F4_v_RkHaZ5onWnszhbBtjYZvNhbn9M0NO0HI,30116 +pip/_internal/cli/command_context.py,sha256=RHgIPwtObh5KhMrd3YZTkl8zbVG-6Okml7YbFX4Ehg0,774 +pip/_internal/cli/index_command.py,sha256=i_sgNlPmXC5iHUaY-dmmrHKKTgc5O4hWzisr5Al1rr0,5677 +pip/_internal/cli/main.py,sha256=BDZef-bWe9g9Jpr4OVs4dDf-845HJsKw835T7AqEnAc,2817 +pip/_internal/cli/main_parser.py,sha256=laDpsuBDl6kyfywp9eMMA9s84jfH2TJJn-vmL0GG90w,4338 +pip/_internal/cli/parser.py,sha256=VCMtduzECUV87KaHNu-xJ-wLNL82yT3x16V4XBxOAqI,10825 +pip/_internal/cli/progress_bars.py,sha256=9GcgusWtwfqou2zhAQp1XNbQHIDslqyyz9UwLzw7Jgc,2717 +pip/_internal/cli/req_command.py,sha256=DqeFhmUMs6o6Ev8qawAcOoYNdAZsfyKS0MZI5jsJYwQ,12250 +pip/_internal/cli/spinners.py,sha256=hIJ83GerdFgFCdobIA23Jggetegl_uC4Sp586nzFbPE,5118 +pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116 +pip/_internal/commands/__init__.py,sha256=5oRO9O3dM2vGuh0bFw4HOVletryrz5HHMmmPWwJrH9U,3882 +pip/_internal/commands/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/commands/__pycache__/cache.cpython-312.pyc,, +pip/_internal/commands/__pycache__/check.cpython-312.pyc,, +pip/_internal/commands/__pycache__/completion.cpython-312.pyc,, +pip/_internal/commands/__pycache__/configuration.cpython-312.pyc,, +pip/_internal/commands/__pycache__/debug.cpython-312.pyc,, +pip/_internal/commands/__pycache__/download.cpython-312.pyc,, +pip/_internal/commands/__pycache__/freeze.cpython-312.pyc,, +pip/_internal/commands/__pycache__/hash.cpython-312.pyc,, +pip/_internal/commands/__pycache__/help.cpython-312.pyc,, +pip/_internal/commands/__pycache__/index.cpython-312.pyc,, +pip/_internal/commands/__pycache__/inspect.cpython-312.pyc,, +pip/_internal/commands/__pycache__/install.cpython-312.pyc,, +pip/_internal/commands/__pycache__/list.cpython-312.pyc,, +pip/_internal/commands/__pycache__/search.cpython-312.pyc,, +pip/_internal/commands/__pycache__/show.cpython-312.pyc,, +pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc,, +pip/_internal/commands/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/commands/cache.py,sha256=IOezTicHjGE5sWdBx2nwPVgbjuJHM3s-BZEkpZLemuY,8107 +pip/_internal/commands/check.py,sha256=Hr_4eiMd9cgVDgEvjtIdw915NmL7ROIWW8enkr8slPQ,2268 +pip/_internal/commands/completion.py,sha256=HT4lD0bgsflHq2IDgYfiEdp7IGGtE7s6MgI3xn0VQEw,4287 +pip/_internal/commands/configuration.py,sha256=n98enwp6y0b5G6fiRQjaZo43FlJKYve_daMhN-4BRNc,9766 +pip/_internal/commands/debug.py,sha256=DNDRgE9YsKrbYzU0s3VKi8rHtKF4X13CJ_br_8PUXO0,6797 +pip/_internal/commands/download.py,sha256=0qB0nys6ZEPsog451lDsjL5Bx7Z97t-B80oFZKhpzKM,5273 +pip/_internal/commands/freeze.py,sha256=2Vt72BYTSm9rzue6d8dNzt8idxWK4Db6Hd-anq7GQ80,3203 +pip/_internal/commands/hash.py,sha256=EVVOuvGtoPEdFi8SNnmdqlCQrhCxV-kJsdwtdcCnXGQ,1703 +pip/_internal/commands/help.py,sha256=gcc6QDkcgHMOuAn5UxaZwAStsRBrnGSn_yxjS57JIoM,1132 +pip/_internal/commands/index.py,sha256=RAXxmJwFhVb5S1BYzb5ifX3sn9Na8v2CCVYwSMP8pao,4731 +pip/_internal/commands/inspect.py,sha256=PGrY9TRTRCM3y5Ml8Bdk8DEOXquWRfscr4DRo1LOTPc,3189 +pip/_internal/commands/install.py,sha256=r3yHQUxvxt7gD5j9n6zRDslAvtx9CT_whLuQJcktp6M,29390 +pip/_internal/commands/list.py,sha256=oiIzSjLP6__d7dIS3q0Xb5ywsaOThBWRqMyjjKzkPdM,12769 +pip/_internal/commands/search.py,sha256=fWkUQVx_gm8ebbFAlCgqtxKXT9rNahpJ-BI__3HNZpg,5626 +pip/_internal/commands/show.py,sha256=0YBhCga3PAd81vT3l7UWflktSpB5-aYqQcJxBVPazVM,7857 +pip/_internal/commands/uninstall.py,sha256=7pOR7enK76gimyxQbzxcG1OsyLXL3DvX939xmM8Fvtg,3892 +pip/_internal/commands/wheel.py,sha256=eJRhr_qoNNxWAkkdJCNiQM7CXd4E1_YyQhsqJnBPGGg,6414 +pip/_internal/configuration.py,sha256=-KOok6jh3hFzXMPQFPJ1_EFjBpAsge-RSreQuLHLmzo,14005 +pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858 +pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/distributions/__pycache__/base.cpython-312.pyc,, +pip/_internal/distributions/__pycache__/installed.cpython-312.pyc,, +pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc,, +pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/distributions/base.py,sha256=QeB9qvKXDIjLdPBDE5fMgpfGqMMCr-govnuoQnGuiF8,1783 +pip/_internal/distributions/installed.py,sha256=QinHFbWAQ8oE0pbD8MFZWkwlnfU1QYTccA1vnhrlYOU,842 +pip/_internal/distributions/sdist.py,sha256=PlcP4a6-R6c98XnOM-b6Lkb3rsvh9iG4ok8shaanrzs,6751 +pip/_internal/distributions/wheel.py,sha256=THBYfnv7VVt8mYhMYUtH13S1E7FDwtDyDfmUcl8ai0E,1317 +pip/_internal/exceptions.py,sha256=2_byISIv3kSnI_9T-Esfxrt0LnTRgcUHyxu0twsHjQY,26481 +pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30 +pip/_internal/index/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/index/__pycache__/collector.cpython-312.pyc,, +pip/_internal/index/__pycache__/package_finder.cpython-312.pyc,, +pip/_internal/index/__pycache__/sources.cpython-312.pyc,, +pip/_internal/index/collector.py,sha256=RdPO0JLAlmyBWPAWYHPyRoGjz3GNAeTngCNkbGey_mE,16265 +pip/_internal/index/package_finder.py,sha256=mJHAljlHeHuclyuxtjvBZO6DtovKjsZjF_tCh_wux5E,38076 +pip/_internal/index/sources.py,sha256=lPBLK5Xiy8Q6IQMio26Wl7ocfZOKkgGklIBNyUJ23fI,8632 +pip/_internal/locations/__init__.py,sha256=UaAxeZ_f93FyouuFf4p7SXYF-4WstXuEvd3LbmPCAno,14925 +pip/_internal/locations/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc,, +pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc,, +pip/_internal/locations/__pycache__/base.cpython-312.pyc,, +pip/_internal/locations/_distutils.py,sha256=x6nyVLj7X11Y4khIdf-mFlxMl2FWadtVEgeb8upc_WI,6013 +pip/_internal/locations/_sysconfig.py,sha256=IGzds60qsFneRogC-oeBaY7bEh3lPt_v47kMJChQXsU,7724 +pip/_internal/locations/base.py,sha256=RQiPi1d4FVM2Bxk04dQhXZ2PqkeljEL2fZZ9SYqIQ78,2556 +pip/_internal/main.py,sha256=r-UnUe8HLo5XFJz8inTcOOTiu_sxNhgHb6VwlGUllOI,340 +pip/_internal/metadata/__init__.py,sha256=CU8jK1TZso7jOLdr0sX9xDjrcs5iy8d7IRK-hvaIO5Y,4337 +pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/metadata/__pycache__/_json.cpython-312.pyc,, +pip/_internal/metadata/__pycache__/base.cpython-312.pyc,, +pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc,, +pip/_internal/metadata/_json.py,sha256=ezrIYazHCINM2QUk1eA9wEAMj3aeGWeDVgGalgUzKpc,2707 +pip/_internal/metadata/base.py,sha256=ft0K5XNgI4ETqZnRv2-CtvgYiMOMAeGMAzxT-f6VLJA,25298 +pip/_internal/metadata/importlib/__init__.py,sha256=jUUidoxnHcfITHHaAWG1G2i5fdBYklv_uJcjo2x7VYE,135 +pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc,, +pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc,, +pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc,, +pip/_internal/metadata/importlib/_compat.py,sha256=c6av8sP8BBjAZuFSJow1iWfygUXNM3xRTCn5nqw6B9M,2796 +pip/_internal/metadata/importlib/_dists.py,sha256=ftmYiyfUGUIjnVwt6W-Ijsimy5c28KgmXly5Q5IQ2P4,8279 +pip/_internal/metadata/importlib/_envs.py,sha256=UUB980XSrDWrMpQ1_G45i0r8Hqlg_tg3IPQ63mEqbNc,7431 +pip/_internal/metadata/pkg_resources.py,sha256=U07ETAINSGeSRBfWUG93E4tZZbaW_f7PGzEqZN0hulc,10542 +pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63 +pip/_internal/models/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/models/__pycache__/candidate.cpython-312.pyc,, +pip/_internal/models/__pycache__/direct_url.cpython-312.pyc,, +pip/_internal/models/__pycache__/format_control.cpython-312.pyc,, +pip/_internal/models/__pycache__/index.cpython-312.pyc,, +pip/_internal/models/__pycache__/installation_report.cpython-312.pyc,, +pip/_internal/models/__pycache__/link.cpython-312.pyc,, +pip/_internal/models/__pycache__/scheme.cpython-312.pyc,, +pip/_internal/models/__pycache__/search_scope.cpython-312.pyc,, +pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc,, +pip/_internal/models/__pycache__/target_python.cpython-312.pyc,, +pip/_internal/models/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/models/candidate.py,sha256=zzgFRuw_kWPjKpGw7LC0ZUMD2CQ2EberUIYs8izjdCA,753 +pip/_internal/models/direct_url.py,sha256=uBtY2HHd3TO9cKQJWh0ThvE5FRr-MWRYChRU4IG9HZE,6578 +pip/_internal/models/format_control.py,sha256=wtsQqSK9HaUiNxQEuB-C62eVimw6G4_VQFxV9-_KDBE,2486 +pip/_internal/models/index.py,sha256=tYnL8oxGi4aSNWur0mG8DAP7rC6yuha_MwJO8xw0crI,1030 +pip/_internal/models/installation_report.py,sha256=zRVZoaz-2vsrezj_H3hLOhMZCK9c7TbzWgC-jOalD00,2818 +pip/_internal/models/link.py,sha256=GQ8hq7x-FDFPv25Nbn2veIM-MlBrGZDGLd7aZeF4Xrg,21448 +pip/_internal/models/scheme.py,sha256=PakmHJM3e8OOWSZFtfz1Az7f1meONJnkGuQxFlt3wBE,575 +pip/_internal/models/search_scope.py,sha256=67NEnsYY84784S-MM7ekQuo9KXLH-7MzFntXjapvAo0,4531 +pip/_internal/models/selection_prefs.py,sha256=qaFfDs3ciqoXPg6xx45N1jPLqccLJw4N0s4P0PyHTQ8,2015 +pip/_internal/models/target_python.py,sha256=2XaH2rZ5ZF-K5wcJbEMGEl7SqrTToDDNkrtQ2v_v_-Q,4271 +pip/_internal/models/wheel.py,sha256=G7dND_s4ebPkEL7RJ1qCY0QhUUWIIK6AnjWgRATF5no,4539 +pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50 +pip/_internal/network/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/network/__pycache__/auth.cpython-312.pyc,, +pip/_internal/network/__pycache__/cache.cpython-312.pyc,, +pip/_internal/network/__pycache__/download.cpython-312.pyc,, +pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc,, +pip/_internal/network/__pycache__/session.cpython-312.pyc,, +pip/_internal/network/__pycache__/utils.cpython-312.pyc,, +pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc,, +pip/_internal/network/auth.py,sha256=D4gASjUrqoDFlSt6gQ767KAAjv6PUyJU0puDlhXNVRE,20809 +pip/_internal/network/cache.py,sha256=0yGMA3Eet59xBSLtbPAenvI53dl29oUOeqZ2c0QL2Ss,4614 +pip/_internal/network/download.py,sha256=FLOP29dPYECBiAi7eEjvAbNkyzaKNqbyjOT2m8HPW8U,6048 +pip/_internal/network/lazy_wheel.py,sha256=PBdoMoNQQIA84Fhgne38jWF52W4x_KtsHjxgv4dkRKA,7622 +pip/_internal/network/session.py,sha256=msM4es16LmmNEYNkrYyg8fTc7gAHbKFltawfKP27LOI,18771 +pip/_internal/network/utils.py,sha256=Inaxel-NxBu4PQWkjyErdnfewsFCcgHph7dzR1-FboY,4088 +pip/_internal/network/xmlrpc.py,sha256=sAxzOacJ-N1NXGPvap9jC3zuYWSnnv3GXtgR2-E2APA,1838 +pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/operations/__pycache__/check.cpython-312.pyc,, +pip/_internal/operations/__pycache__/freeze.cpython-312.pyc,, +pip/_internal/operations/__pycache__/prepare.cpython-312.pyc,, +pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc,, +pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc,, +pip/_internal/operations/build/build_tracker.py,sha256=-ARW_TcjHCOX7D2NUOGntB4Fgc6b4aolsXkAK6BWL7w,4774 +pip/_internal/operations/build/metadata.py,sha256=9S0CUD8U3QqZeXp-Zyt8HxwU90lE4QrnYDgrqZDzBnc,1422 +pip/_internal/operations/build/metadata_editable.py,sha256=xlAwcP9q_8_fmv_3I39w9EZ7SQV9hnJZr9VuTsq2Y68,1510 +pip/_internal/operations/build/metadata_legacy.py,sha256=8i6i1QZX9m_lKPStEFsHKM0MT4a-CD408JOw99daLmo,2190 +pip/_internal/operations/build/wheel.py,sha256=sT12FBLAxDC6wyrDorh8kvcZ1jG5qInCRWzzP-UkJiQ,1075 +pip/_internal/operations/build/wheel_editable.py,sha256=yOtoH6zpAkoKYEUtr8FhzrYnkNHQaQBjWQ2HYae1MQg,1417 +pip/_internal/operations/build/wheel_legacy.py,sha256=K-6kNhmj-1xDF45ny1yheMerF0ui4EoQCLzEoHh6-tc,3045 +pip/_internal/operations/check.py,sha256=L24vRL8VWbyywdoeAhM89WCd8zLTnjIbULlKelUgIec,5912 +pip/_internal/operations/freeze.py,sha256=1_M79jAQKnCxWr-KCCmHuVXOVFGaUJHmoWLfFzgh7K4,9843 +pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51 +pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc,, +pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/operations/install/editable_legacy.py,sha256=PoEsNEPGbIZ2yQphPsmYTKLOCMs4gv5OcCdzW124NcA,1283 +pip/_internal/operations/install/wheel.py,sha256=X5Iz9yUg5LlK5VNQ9g2ikc6dcRu8EPi_SUi5iuEDRgo,27615 +pip/_internal/operations/prepare.py,sha256=joWJwPkuqGscQgVNImLK71e9hRapwKvRCM8HclysmvU,28118 +pip/_internal/pyproject.py,sha256=GLJ6rWRS5_2noKdajohoLyDty57Z7QXhcUAYghmTnWc,7286 +pip/_internal/req/__init__.py,sha256=HxBFtZy_BbCclLgr26waMtpzYdO5T3vxePvpGAXSt5s,2653 +pip/_internal/req/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/req/__pycache__/constructors.cpython-312.pyc,, +pip/_internal/req/__pycache__/req_file.cpython-312.pyc,, +pip/_internal/req/__pycache__/req_install.cpython-312.pyc,, +pip/_internal/req/__pycache__/req_set.cpython-312.pyc,, +pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc,, +pip/_internal/req/constructors.py,sha256=v1qzCN1mIldwx-nCrPc8JO4lxkm3Fv8M5RWvt8LISjc,18430 +pip/_internal/req/req_file.py,sha256=eys82McgaICOGic2UZRHjD720piKJPwmeSYdXlWwl6w,20234 +pip/_internal/req/req_install.py,sha256=BMptxHYg2uG_b-7HFEULPb3nuw0FMAbuea8zTq2rE7w,35786 +pip/_internal/req/req_set.py,sha256=j3esG0s6SzoVReX9rWn4rpYNtyET_fwxbwJPRimvRxo,2858 +pip/_internal/req/req_uninstall.py,sha256=qzDIxJo-OETWqGais7tSMCDcWbATYABT-Tid3ityF0s,23853 +pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/resolution/__pycache__/base.cpython-312.pyc,, +pip/_internal/resolution/base.py,sha256=qlmh325SBVfvG6Me9gc5Nsh5sdwHBwzHBq6aEXtKsLA,583 +pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc,, +pip/_internal/resolution/legacy/resolver.py,sha256=3HZiJBRd1FTN6jQpI4qRO8-TbLYeIbUTS6PFvXnXs2w,24068 +pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc,, +pip/_internal/resolution/resolvelib/base.py,sha256=DCf669FsqyQY5uqXeePDHQY1e4QO-pBzWH8O0s9-K94,5023 +pip/_internal/resolution/resolvelib/candidates.py,sha256=5UZ1upNnmqsP-nmEZaDYxaBgCoejw_e2WVGmmAvBxXc,20001 +pip/_internal/resolution/resolvelib/factory.py,sha256=MJOLSZJY8_28PPdcutoQ6gjJ_1eBDt6Z1edtfTJyR4E,32659 +pip/_internal/resolution/resolvelib/found_candidates.py,sha256=9hrTyQqFvl9I7Tji79F1AxHv39Qh1rkJ_7deSHSMfQc,6383 +pip/_internal/resolution/resolvelib/provider.py,sha256=bcsFnYvlmtB80cwVdW1fIwgol8ZNr1f1VHyRTkz47SM,9935 +pip/_internal/resolution/resolvelib/reporter.py,sha256=00JtoXEkTlw0-rl_sl54d71avwOsJHt9GGHcrj5Sza0,3168 +pip/_internal/resolution/resolvelib/requirements.py,sha256=7JG4Z72e5Yk4vU0S5ulGvbqTy4FMQGYhY5zQhX9zTtY,8065 +pip/_internal/resolution/resolvelib/resolver.py,sha256=nLJOsVMEVi2gQUVJoUFKMZAeu2f7GRMjGMvNSWyz0Bc,12592 +pip/_internal/self_outdated_check.py,sha256=1PFtttvLAeyCVR3tPoBq2sOlPD0IJ-KSqU6bc1HUk9c,8318 +pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/utils/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc,, +pip/_internal/utils/__pycache__/_log.cpython-312.pyc,, +pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc,, +pip/_internal/utils/__pycache__/compat.cpython-312.pyc,, +pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc,, +pip/_internal/utils/__pycache__/datetime.cpython-312.pyc,, +pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc,, +pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc,, +pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc,, +pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc,, +pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc,, +pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc,, +pip/_internal/utils/__pycache__/glibc.cpython-312.pyc,, +pip/_internal/utils/__pycache__/hashes.cpython-312.pyc,, +pip/_internal/utils/__pycache__/logging.cpython-312.pyc,, +pip/_internal/utils/__pycache__/misc.cpython-312.pyc,, +pip/_internal/utils/__pycache__/packaging.cpython-312.pyc,, +pip/_internal/utils/__pycache__/retry.cpython-312.pyc,, +pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc,, +pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc,, +pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc,, +pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc,, +pip/_internal/utils/__pycache__/urls.cpython-312.pyc,, +pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc,, +pip/_internal/utils/__pycache__/wheel.cpython-312.pyc,, +pip/_internal/utils/_jaraco_text.py,sha256=M15uUPIh5NpP1tdUGBxRau6q1ZAEtI8-XyLEETscFfE,3350 +pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015 +pip/_internal/utils/appdirs.py,sha256=swgcTKOm3daLeXTW6v5BUS2Ti2RvEnGRQYH_yDXklAo,1665 +pip/_internal/utils/compat.py,sha256=ckkFveBiYQjRWjkNsajt_oWPS57tJvE8XxoC4OIYgCY,2399 +pip/_internal/utils/compatibility_tags.py,sha256=OWq5axHpW-MEEPztGdvgADrgJPAcV9a88Rxm4Z8VBs8,6272 +pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242 +pip/_internal/utils/deprecation.py,sha256=k7Qg_UBAaaTdyq82YVARA6D7RmcGTXGv7fnfcgigj4Q,3707 +pip/_internal/utils/direct_url_helpers.py,sha256=r2MRtkVDACv9AGqYODBUC9CjwgtsUU1s68hmgfCJMtA,3196 +pip/_internal/utils/egg_link.py,sha256=0FePZoUYKv4RGQ2t6x7w5Z427wbA_Uo3WZnAkrgsuqo,2463 +pip/_internal/utils/entrypoints.py,sha256=YlhLTRl2oHBAuqhc-zmL7USS67TPWVHImjeAQHreZTQ,3064 +pip/_internal/utils/filesystem.py,sha256=ajvA-q4ocliW9kPp8Yquh-4vssXbu-UKbo5FV9V4X64,4950 +pip/_internal/utils/filetypes.py,sha256=i8XAQ0eFCog26Fw9yV0Yb1ygAqKYB1w9Cz9n0fj8gZU,716 +pip/_internal/utils/glibc.py,sha256=vUkWq_1pJuzcYNcGKLlQmABoUiisK8noYY1yc8Wq4w4,3734 +pip/_internal/utils/hashes.py,sha256=XGGLL0AG8-RhWnyz87xF6MFZ--BKadHU35D47eApCKI,4972 +pip/_internal/utils/logging.py,sha256=ONfbrhaD248akkosK79if97n20EABxwjOxp5dE5RCRY,11845 +pip/_internal/utils/misc.py,sha256=DWnYxBUItjRp7hhxEg4ih6P6YpKrykM86dbi_EcU8SQ,23450 +pip/_internal/utils/packaging.py,sha256=cm-X_0HVHV_jRwUVZh6AuEWqSitzf8EpaJ7Uv2UGu6A,2142 +pip/_internal/utils/retry.py,sha256=mhFbykXjhTnZfgzeuy-vl9c8nECnYn_CMtwNJX2tYzQ,1392 +pip/_internal/utils/setuptools_build.py,sha256=ouXpud-jeS8xPyTPsXJ-m34NPvK5os45otAzdSV_IJE,4435 +pip/_internal/utils/subprocess.py,sha256=EsvqSRiSMHF98T8Txmu6NLU3U--MpTTQjtNgKP0P--M,8988 +pip/_internal/utils/temp_dir.py,sha256=5qOXe8M4JeY6vaFQM867d5zkp1bSwMZ-KT5jymmP0Zg,9310 +pip/_internal/utils/unpacking.py,sha256=_gVdyzTRDMYktpnYljn4OoxrZTtMCf4xknSm4rK0WaA,11967 +pip/_internal/utils/urls.py,sha256=qceSOZb5lbNDrHNsv7_S4L4Ytszja5NwPKUMnZHbYnM,1599 +pip/_internal/utils/virtualenv.py,sha256=S6f7csYorRpiD6cvn3jISZYc3I8PJC43H5iMFpRAEDU,3456 +pip/_internal/utils/wheel.py,sha256=b442jkydFHjXzDy6cMR7MpzWBJ1Q82hR5F33cmcHV3g,4494 +pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596 +pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc,, +pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc,, +pip/_internal/vcs/__pycache__/git.cpython-312.pyc,, +pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc,, +pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc,, +pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc,, +pip/_internal/vcs/bazaar.py,sha256=EKStcQaKpNu0NK4p5Q10Oc4xb3DUxFw024XrJy40bFQ,3528 +pip/_internal/vcs/git.py,sha256=3tpc9LQA_J4IVW5r5NvWaaSeDzcmJOrSFZN0J8vIKfU,18177 +pip/_internal/vcs/mercurial.py,sha256=oULOhzJ2Uie-06d1omkL-_Gc6meGaUkyogvqG9ZCyPs,5249 +pip/_internal/vcs/subversion.py,sha256=ddTugHBqHzV3ebKlU5QXHPN4gUqlyXbOx8q8NgXKvs8,11735 +pip/_internal/vcs/versioncontrol.py,sha256=cvf_-hnTAjQLXJ3d17FMNhQfcO1AcKWUF10tfrYyP-c,22440 +pip/_internal/wheel_builder.py,sha256=DL3A8LKeRj_ACp11WS5wSgASgPFqeyAeXJKdXfmaWXU,11799 +pip/_vendor/__init__.py,sha256=JYuAXvClhInxIrA2FTp5p-uuWVL7WV6-vEpTs46-Qh4,4873 +pip/_vendor/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc,, +pip/_vendor/cachecontrol/__init__.py,sha256=LMC5CBe94ZRL5xhlzwyPDmHXvBD0p7lT4R3Z73D6a_I,677 +pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc,, +pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc,, +pip/_vendor/cachecontrol/_cmd.py,sha256=iist2EpzJvDVIhMAxXq8iFnTBsiZAd6iplxfmNboNyk,1737 +pip/_vendor/cachecontrol/adapter.py,sha256=febjY4LV87iiCIK3jcl8iH58iaSA7b9WkovsByIDK0Y,6348 +pip/_vendor/cachecontrol/cache.py,sha256=OXwv7Fn2AwnKNiahJHnjtvaKLndvVLv_-zO-ltlV9qI,1953 +pip/_vendor/cachecontrol/caches/__init__.py,sha256=dtrrroK5BnADR1GWjCZ19aZ0tFsMfvFBtLQQU1sp_ag,303 +pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc,, +pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc,, +pip/_vendor/cachecontrol/caches/file_cache.py,sha256=b7oMgsRSqPmEsonVJw6uFEYUlFgD6GF8TyacOGG1x3M,5399 +pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=9rmqwtYu_ljVkW6_oLqbC7EaX_a8YT_yLuna-eS0dgo,1386 +pip/_vendor/cachecontrol/controller.py,sha256=glbPj2iZlGqdBg8z09D2DtQOzoOGXnWvy7K2LEyBsEQ,18576 +pip/_vendor/cachecontrol/filewrapper.py,sha256=2ktXNPE0KqnyzF24aOsKCA58HQq1xeC6l2g6_zwjghc,4291 +pip/_vendor/cachecontrol/heuristics.py,sha256=gqMXU8w0gQuEQiSdu3Yg-0vd9kW7nrWKbLca75rheGE,4881 +pip/_vendor/cachecontrol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/cachecontrol/serialize.py,sha256=HQd2IllQ05HzPkVLMXTF2uX5mjEQjDBkxCqUJUODpZk,5163 +pip/_vendor/cachecontrol/wrapper.py,sha256=hsGc7g8QGQTT-4f8tgz3AM5qwScg6FO0BSdLSRdEvpU,1417 +pip/_vendor/certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94 +pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255 +pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc,, +pip/_vendor/certifi/__pycache__/core.cpython-312.pyc,, +pip/_vendor/certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427 +pip/_vendor/certifi/core.py,sha256=2SRT5rIcQChFDbe37BQa-kULxAgJ8qN6l1jfqTp4HIs,4486 +pip/_vendor/certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/distlib/__init__.py,sha256=dcwgYGYGQqAEawBXPDtIx80DO_3cOmFv8HTc8JMzknQ,625 +pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/database.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/index.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/util.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/version.cpython-312.pyc,, +pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc,, +pip/_vendor/distlib/compat.py,sha256=2jRSjRI4o-vlXeTK2BCGIUhkc6e9ZGhSsacRM5oseTw,41467 +pip/_vendor/distlib/database.py,sha256=mHy_LxiXIsIVRb-T0-idBrVLw3Ffij5teHCpbjmJ9YU,51160 +pip/_vendor/distlib/index.py,sha256=lTbw268rRhj8dw1sib3VZ_0EhSGgoJO3FKJzSFMOaeA,20797 +pip/_vendor/distlib/locators.py,sha256=oBeAZpFuPQSY09MgNnLfQGGAXXvVO96BFpZyKMuK4tM,51026 +pip/_vendor/distlib/manifest.py,sha256=3qfmAmVwxRqU1o23AlfXrQGZzh6g_GGzTAP_Hb9C5zQ,14168 +pip/_vendor/distlib/markers.py,sha256=X6sDvkFGcYS8gUW8hfsWuKEKAqhQZAJ7iXOMLxRYjYk,5164 +pip/_vendor/distlib/metadata.py,sha256=zil3sg2EUfLXVigljY2d_03IJt-JSs7nX-73fECMX2s,38724 +pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820 +pip/_vendor/distlib/scripts.py,sha256=BJliaDAZaVB7WAkwokgC3HXwLD2iWiHaVI50H7C6eG8,18608 +pip/_vendor/distlib/t32.exe,sha256=a0GV5kCoWsMutvliiCKmIgV98eRZ33wXoS-XrqvJQVs,97792 +pip/_vendor/distlib/t64-arm.exe,sha256=68TAa32V504xVBnufojh0PcenpR3U4wAqTqf-MZqbPw,182784 +pip/_vendor/distlib/t64.exe,sha256=gaYY8hy4fbkHYTTnA4i26ct8IQZzkBG2pRdy0iyuBrc,108032 +pip/_vendor/distlib/util.py,sha256=vMPGvsS4j9hF6Y9k3Tyom1aaHLb0rFmZAEyzeAdel9w,66682 +pip/_vendor/distlib/version.py,sha256=s5VIs8wBn0fxzGxWM_aA2ZZyx525HcZbMvcTlTyZ3Rg,23727 +pip/_vendor/distlib/w32.exe,sha256=R4csx3-OGM9kL4aPIzQKRo5TfmRSHZo6QWyLhDhNBks,91648 +pip/_vendor/distlib/w64-arm.exe,sha256=xdyYhKj0WDcVUOCb05blQYvzdYIKMbmJn2SZvzkcey4,168448 +pip/_vendor/distlib/w64.exe,sha256=ejGf-rojoBfXseGLpya6bFTFPWRG21X5KvU8J5iU-K0,101888 +pip/_vendor/distlib/wheel.py,sha256=DFIVguEQHCdxnSdAO0dfFsgMcvVZitg7bCOuLwZ7A_s,43979 +pip/_vendor/distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981 +pip/_vendor/distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64 +pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc,, +pip/_vendor/distro/__pycache__/distro.cpython-312.pyc,, +pip/_vendor/distro/distro.py,sha256=XqbefacAhDT4zr_trnbA15eY8vdK4GTghgmvUGrEM_4,49430 +pip/_vendor/distro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 +pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/codec.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/compat.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/core.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc,, +pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc,, +pip/_vendor/idna/codec.py,sha256=PEew3ItwzjW4hymbasnty2N2OXvNcgHB-JjrBuxHPYY,3422 +pip/_vendor/idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 +pip/_vendor/idna/core.py,sha256=YJYyAMnwiQEPjVC4-Fqu_p4CJ6yKKuDGmppBNQNQpFs,13239 +pip/_vendor/idna/idnadata.py,sha256=W30GcIGvtOWYwAjZj4ZjuouUutC6ffgNuyjJy7fZ-lo,78306 +pip/_vendor/idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 +pip/_vendor/idna/package_data.py,sha256=q59S3OXsc5VI8j6vSD0sGBMyk6zZ4vWFREE88yCJYKs,21 +pip/_vendor/idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/idna/uts46data.py,sha256=rt90K9J40gUSwppDPCrhjgi5AA6pWM65dEGRSf6rIhM,239289 +pip/_vendor/msgpack/__init__.py,sha256=reRaiOtEzSjPnr7TpxjgIvbfln5pV66FhricAs2eC-g,1109 +pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc,, +pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc,, +pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc,, +pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081 +pip/_vendor/msgpack/ext.py,sha256=kteJv03n9tYzd5oo3xYopVTo4vRaAxonBQQJhXohZZo,5726 +pip/_vendor/msgpack/fallback.py,sha256=0g1Pzp0vtmBEmJ5w9F3s_-JMVURP8RS4G1cc5TRaAsI,32390 +pip/_vendor/packaging/__init__.py,sha256=dk4Ta_vmdVJxYHDcfyhvQNw8V3PgSBomKNXqg-D2JDY,494 +pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc,, +pip/_vendor/packaging/__pycache__/version.cpython-312.pyc,, +pip/_vendor/packaging/_elffile.py,sha256=cflAQAkE25tzhYmq_aCi72QfbT_tn891tPzfpbeHOwE,3306 +pip/_vendor/packaging/_manylinux.py,sha256=vl5OCoz4kx80H5rwXKeXWjl9WNISGmr4ZgTpTP9lU9c,9612 +pip/_vendor/packaging/_musllinux.py,sha256=p9ZqNYiOItGee8KcZFeHF_YcdhVwGHdK6r-8lgixvGQ,2694 +pip/_vendor/packaging/_parser.py,sha256=s_TvTvDNK0NrM2QB3VKThdWFM4Nc0P6JnkObkl3MjpM,10236 +pip/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 +pip/_vendor/packaging/_tokenizer.py,sha256=J6v5H7Jzvb-g81xp_2QACKwO7LxHQA6ikryMU7zXwN8,5273 +pip/_vendor/packaging/licenses/__init__.py,sha256=A116-FU49_Dz4162M4y1uAiZN4Rgdc83FxNd8EjlfqI,5727 +pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/packaging/licenses/__pycache__/_spdx.cpython-312.pyc,, +pip/_vendor/packaging/licenses/_spdx.py,sha256=oAm1ztPFwlsmCKe7lAAsv_OIOfS1cWDu9bNBkeu-2ns,48398 +pip/_vendor/packaging/markers.py,sha256=c89TNzB7ZdGYhkovm6PYmqGyHxXlYVaLW591PHUNKD8,10561 +pip/_vendor/packaging/metadata.py,sha256=YJibM7GYe4re8-0a3OlXmGS-XDgTEoO4tlBt2q25Bng,34762 +pip/_vendor/packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/packaging/requirements.py,sha256=gYyRSAdbrIyKDY66ugIDUQjRMvxkH2ALioTmX3tnL6o,2947 +pip/_vendor/packaging/specifiers.py,sha256=hGU6kuCd77bL-msIL6yLCp6MNT75RSMUKZDuju26c8U,40098 +pip/_vendor/packaging/tags.py,sha256=CFqrJzAzc2XNGexerH__T-Y5Iwq7WbsYXsiLERLWxY0,21014 +pip/_vendor/packaging/utils.py,sha256=0F3Hh9OFuRgrhTgGZUl5K22Fv1YP2tZl1z_2gO6kJiA,5050 +pip/_vendor/packaging/version.py,sha256=oiHqzTUv_p12hpjgsLDVcaF5hT7pDaSOViUNMD4GTW0,16688 +pip/_vendor/pkg_resources/__init__.py,sha256=jrhDRbOubP74QuPXxd7U7Po42PH2l-LZ2XfcO7llpZ4,124463 +pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/platformdirs/__init__.py,sha256=JueR2cRLkxY7iwik-qNWJCwKOrAlBgVgcZ_IHQzqGLE,22344 +pip/_vendor/platformdirs/__main__.py,sha256=jBJ8zb7Mpx5ebcqF83xrpO94MaeCpNGHVf9cvDN2JLg,1505 +pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc,, +pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc,, +pip/_vendor/platformdirs/android.py,sha256=kV5oL3V3DZ6WZKu9yFiQupv18yp_jlSV2ChH1TmPcds,9007 +pip/_vendor/platformdirs/api.py,sha256=2dfUDNbEXeDhDKarqtR5NY7oUikUZ4RZhs3ozstmhBQ,9246 +pip/_vendor/platformdirs/macos.py,sha256=UlbyFZ8Rzu3xndCqQEHrfsYTeHwYdFap1Ioz-yxveT4,6154 +pip/_vendor/platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/platformdirs/unix.py,sha256=uRPJWRyQEtv7yOSvU94rUmsblo5XKDLA1SzFg55kbK0,10393 +pip/_vendor/platformdirs/version.py,sha256=oH4KgTfK4AklbTYVcV_yynvJ9JLI3pyvDVay0hRsLCs,411 +pip/_vendor/platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125 +pip/_vendor/pygments/__init__.py,sha256=7N1oiaWulw_nCsTY4EEixYLz15pWY5u4uPAFFi-ielU,2983 +pip/_vendor/pygments/__main__.py,sha256=isIhBxLg65nLlXukG4VkMuPfNdd7gFzTZ_R_z3Q8diY,353 +pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/console.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/style.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/token.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc,, +pip/_vendor/pygments/__pycache__/util.cpython-312.pyc,, +pip/_vendor/pygments/cmdline.py,sha256=LIVzmAunlk9sRJJp54O4KRy9GDIN4Wu13v9p9QzfGPM,23656 +pip/_vendor/pygments/console.py,sha256=yhP9UsLAVmWKVQf2446JJewkA7AiXeeTf4Ieg3Oi2fU,1718 +pip/_vendor/pygments/filter.py,sha256=_ADNPCskD8_GmodHi6_LoVgPU3Zh336aBCT5cOeTMs0,1910 +pip/_vendor/pygments/filters/__init__.py,sha256=RdedK2KWKXlKwR7cvkfr3NUj9YiZQgMgilRMFUg2jPA,40392 +pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pygments/formatter.py,sha256=jDWBTndlBH2Z5IYZFVDnP0qn1CaTQjTWt7iAGtCnJEg,4390 +pip/_vendor/pygments/formatters/__init__.py,sha256=8No-NUs8rBTSSBJIv4hSEQt2M0cFB4hwAT0snVc2QGE,5385 +pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc,, +pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc,, +pip/_vendor/pygments/formatters/_mapping.py,sha256=1Cw37FuQlNacnxRKmtlPX4nyLoX9_ttko5ZwscNUZZ4,4176 +pip/_vendor/pygments/formatters/bbcode.py,sha256=3JQLI45tcrQ_kRUMjuab6C7Hb0XUsbVWqqbSn9cMjkI,3320 +pip/_vendor/pygments/formatters/groff.py,sha256=M39k0PaSSZRnxWjqBSVPkF0mu1-Vr7bm6RsFvs-CNN4,5106 +pip/_vendor/pygments/formatters/html.py,sha256=SE2jc3YCqbMS3rZW9EAmDlAUhdVxJ52gA4dileEvCGU,35669 +pip/_vendor/pygments/formatters/img.py,sha256=MwA4xWPLOwh6j7Yc6oHzjuqSPt0M1fh5r-5BTIIUfsU,23287 +pip/_vendor/pygments/formatters/irc.py,sha256=dp1Z0l_ObJ5NFh9MhqLGg5ptG5hgJqedT2Vkutt9v0M,4981 +pip/_vendor/pygments/formatters/latex.py,sha256=XMmhOCqUKDBQtG5mGJNAFYxApqaC5puo5cMmPfK3944,19306 +pip/_vendor/pygments/formatters/other.py,sha256=56PMJOliin-rAUdnRM0i1wsV1GdUPd_dvQq0_UPfF9c,5034 +pip/_vendor/pygments/formatters/pangomarkup.py,sha256=y16U00aVYYEFpeCfGXlYBSMacG425CbfoG8oKbKegIg,2218 +pip/_vendor/pygments/formatters/rtf.py,sha256=ZT90dmcKyJboIB0mArhL7IhE467GXRN0G7QAUgG03To,11957 +pip/_vendor/pygments/formatters/svg.py,sha256=KKsiophPupHuxm0So-MsbQEWOT54IAiSF7hZPmxtKXE,7174 +pip/_vendor/pygments/formatters/terminal.py,sha256=AojNG4MlKq2L6IsC_VnXHu4AbHCBn9Otog6u45XvxeI,4674 +pip/_vendor/pygments/formatters/terminal256.py,sha256=kGkNUVo3FpwjytIDS0if79EuUoroAprcWt3igrcIqT0,11753 +pip/_vendor/pygments/lexer.py,sha256=TYHDt___gNW4axTl2zvPZff-VQi8fPaIh5OKRcVSjUM,35349 +pip/_vendor/pygments/lexers/__init__.py,sha256=pIlxyQJuu_syh9lE080cq8ceVbEVcKp0osAFU5fawJU,12115 +pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc,, +pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc,, +pip/_vendor/pygments/lexers/_mapping.py,sha256=61-h3zr103m01OS5BUq_AfUiL9YI06Ves9ipQ7k4vr4,76097 +pip/_vendor/pygments/lexers/python.py,sha256=2J_YJrPTr_A6fJY_qKiKv0GpgPwHMrlMSeo59qN3fe4,53687 +pip/_vendor/pygments/modeline.py,sha256=gtRYZBS-CKOCDXHhGZqApboHBaZwGH8gznN3O6nuxj4,1005 +pip/_vendor/pygments/plugin.py,sha256=ioeJ3QeoJ-UQhZpY9JL7vbxsTVuwwM7BCu-Jb8nN0AU,1891 +pip/_vendor/pygments/regexopt.py,sha256=Hky4EB13rIXEHQUNkwmCrYqtIlnXDehNR3MztafZ43w,3072 +pip/_vendor/pygments/scanner.py,sha256=NDy3ofK_fHRFK4hIDvxpamG871aewqcsIb6sgTi7Fhk,3092 +pip/_vendor/pygments/sphinxext.py,sha256=iOptJBcqOGPwMEJ2p70PvwpZPIGdvdZ8dxvq6kzxDgA,7981 +pip/_vendor/pygments/style.py,sha256=rSCZWFpg1_DwFMXDU0nEVmAcBHpuQGf9RxvOPPQvKLQ,6420 +pip/_vendor/pygments/styles/__init__.py,sha256=qUk6_1z5KmT8EdJFZYgESmG6P_HJF_2vVrDD7HSCGYY,2042 +pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc,, +pip/_vendor/pygments/styles/_mapping.py,sha256=6lovFUE29tz6EsV3XYY4hgozJ7q1JL7cfO3UOlgnS8w,3312 +pip/_vendor/pygments/token.py,sha256=qZwT7LSPy5YBY3JgDjut642CCy7JdQzAfmqD9NmT5j0,6226 +pip/_vendor/pygments/unistring.py,sha256=p5c1i-HhoIhWemy9CUsaN9o39oomYHNxXll0Xfw6tEA,63208 +pip/_vendor/pygments/util.py,sha256=2tj2nS1X9_OpcuSjf8dOET2bDVZhs8cEKd_uT6-Fgg8,10031 +pip/_vendor/pyproject_hooks/__init__.py,sha256=cPB_a9LXz5xvsRbX1o2qyAdjLatZJdQ_Lc5McNX-X7Y,691 +pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc,, +pip/_vendor/pyproject_hooks/_impl.py,sha256=jY-raxnmyRyB57ruAitrJRUzEexuAhGTpgMygqx67Z4,14936 +pip/_vendor/pyproject_hooks/_in_process/__init__.py,sha256=MJNPpfIxcO-FghxpBbxkG1rFiQf6HOUbV4U5mq0HFns,557 +pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc,, +pip/_vendor/pyproject_hooks/_in_process/_in_process.py,sha256=qcXMhmx__MIJq10gGHW3mA4Tl8dy8YzHMccwnNoKlw0,12216 +pip/_vendor/pyproject_hooks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/requests/__init__.py,sha256=HlB_HzhrzGtfD_aaYUwUh1zWXLZ75_YCLyit75d0Vz8,5057 +pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/api.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/auth.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/certs.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/compat.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/help.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/models.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/packages.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/structures.cpython-312.pyc,, +pip/_vendor/requests/__pycache__/utils.cpython-312.pyc,, +pip/_vendor/requests/__version__.py,sha256=FVfglgZmNQnmYPXpOohDU58F5EUb_-VnSTaAesS187g,435 +pip/_vendor/requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495 +pip/_vendor/requests/adapters.py,sha256=J7VeVxKBvawbtlX2DERVo05J9BXTcWYLMHNd1Baa-bk,27607 +pip/_vendor/requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449 +pip/_vendor/requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186 +pip/_vendor/requests/certs.py,sha256=kHDlkK_beuHXeMPc5jta2wgl8gdKeUWt5f2nTDVrvt8,441 +pip/_vendor/requests/compat.py,sha256=Mo9f9xZpefod8Zm-n9_StJcVTmwSukXR2p3IQyyVXvU,1485 +pip/_vendor/requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590 +pip/_vendor/requests/exceptions.py,sha256=D1wqzYWne1mS2rU43tP9CeN1G7QAy7eqL9o1god6Ejw,4272 +pip/_vendor/requests/help.py,sha256=hRKaf9u0G7fdwrqMHtF3oG16RKktRf6KiwtSq2Fo1_0,3813 +pip/_vendor/requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733 +pip/_vendor/requests/models.py,sha256=x4K4CmH-lC0l2Kb-iPfMN4dRXxHEcbOaEWBL_i09AwI,35483 +pip/_vendor/requests/packages.py,sha256=_ZQDCJTJ8SP3kVWunSqBsRZNPzj2c1WFVqbdr08pz3U,1057 +pip/_vendor/requests/sessions.py,sha256=ykTI8UWGSltOfH07HKollH7kTBGw4WhiBVaQGmckTw4,30495 +pip/_vendor/requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322 +pip/_vendor/requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912 +pip/_vendor/requests/utils.py,sha256=L79vnFbzJ3SFLKtJwpoWe41Tozi3RlZv94pY1TFIyow,33631 +pip/_vendor/resolvelib/__init__.py,sha256=h509TdEcpb5-44JonaU3ex2TM15GVBLjM9CNCPwnTTs,537 +pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc,, +pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc,, +pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc,, +pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc,, +pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc,, +pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156 +pip/_vendor/resolvelib/providers.py,sha256=fuuvVrCetu5gsxPB43ERyjfO8aReS3rFQHpDgiItbs4,5871 +pip/_vendor/resolvelib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/resolvelib/reporters.py,sha256=TSbRmWzTc26w0ggsV1bxVpeWDB8QNIre6twYl7GIZBE,1601 +pip/_vendor/resolvelib/resolvers.py,sha256=G8rsLZSq64g5VmIq-lB7UcIJ1gjAxIQJmTF4REZleQ0,20511 +pip/_vendor/resolvelib/structs.py,sha256=0_1_XO8z_CLhegP3Vpf9VJ3zJcfLm0NOHRM-i0Ykz3o,4963 +pip/_vendor/rich/__init__.py,sha256=dRxjIL-SbFVY0q3IjSMrfgBTHrm1LZDgLOygVBwiYZc,6090 +pip/_vendor/rich/__main__.py,sha256=eO7Cq8JnrgG8zVoeImiAs92q3hXNMIfp0w5lMsO7Q2Y,8477 +pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/abc.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/align.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/bar.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/box.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/cells.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/color.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/columns.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/console.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/containers.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/control.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/errors.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/json.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/layout.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/live.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/logging.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/markup.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/measure.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/padding.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/pager.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/palette.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/panel.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/progress.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/region.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/repr.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/rule.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/scope.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/screen.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/segment.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/status.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/style.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/styled.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/table.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/text.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/theme.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/themes.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc,, +pip/_vendor/rich/__pycache__/tree.cpython-312.pyc,, +pip/_vendor/rich/_cell_widths.py,sha256=fbmeyetEdHjzE_Vx2l1uK7tnPOhMs2X1lJfO3vsKDpA,10209 +pip/_vendor/rich/_emoji_codes.py,sha256=hu1VL9nbVdppJrVoijVshRlcRRe_v3dju3Mmd2sKZdY,140235 +pip/_vendor/rich/_emoji_replace.py,sha256=n-kcetsEUx2ZUmhQrfeMNc-teeGhpuSQ5F8VPBsyvDo,1064 +pip/_vendor/rich/_export_format.py,sha256=RI08pSrm5tBSzPMvnbTqbD9WIalaOoN5d4M1RTmLq1Y,2128 +pip/_vendor/rich/_extension.py,sha256=Xt47QacCKwYruzjDi-gOBq724JReDj9Cm9xUi5fr-34,265 +pip/_vendor/rich/_fileno.py,sha256=HWZxP5C2ajMbHryvAQZseflVfQoGzsKOHzKGsLD8ynQ,799 +pip/_vendor/rich/_inspect.py,sha256=QM05lEFnFoTaFqpnbx-zBEI6k8oIKrD3cvjEOQNhKig,9655 +pip/_vendor/rich/_log_render.py,sha256=1ByI0PA1ZpxZY3CGJOK54hjlq4X-Bz_boIjIqCd8Kns,3225 +pip/_vendor/rich/_loop.py,sha256=hV_6CLdoPm0va22Wpw4zKqM0RYsz3TZxXj0PoS-9eDQ,1236 +pip/_vendor/rich/_null_file.py,sha256=ADGKp1yt-k70FMKV6tnqCqecB-rSJzp-WQsD7LPL-kg,1394 +pip/_vendor/rich/_palettes.py,sha256=cdev1JQKZ0JvlguV9ipHgznTdnvlIzUFDBb0It2PzjI,7063 +pip/_vendor/rich/_pick.py,sha256=evDt8QN4lF5CiwrUIXlOJCntitBCOsI3ZLPEIAVRLJU,423 +pip/_vendor/rich/_ratio.py,sha256=Zt58apszI6hAAcXPpgdWKpu3c31UBWebOeR4mbyptvU,5471 +pip/_vendor/rich/_spinners.py,sha256=U2r1_g_1zSjsjiUdAESc2iAMc3i4ri_S8PYP6kQ5z1I,19919 +pip/_vendor/rich/_stack.py,sha256=-C8OK7rxn3sIUdVwxZBBpeHhIzX0eI-VM3MemYfaXm0,351 +pip/_vendor/rich/_timer.py,sha256=zelxbT6oPFZnNrwWPpc1ktUeAT-Vc4fuFcRZLQGLtMI,417 +pip/_vendor/rich/_win32_console.py,sha256=BSaDRIMwBLITn_m0mTRLPqME5q-quGdSMuYMpYeYJwc,22755 +pip/_vendor/rich/_windows.py,sha256=aBwaD_S56SbgopIvayVmpk0Y28uwY2C5Bab1wl3Bp-I,1925 +pip/_vendor/rich/_windows_renderer.py,sha256=t74ZL3xuDCP3nmTp9pH1L5LiI2cakJuQRQleHCJerlk,2783 +pip/_vendor/rich/_wrap.py,sha256=FlSsom5EX0LVkA3KWy34yHnCfLtqX-ZIepXKh-70rpc,3404 +pip/_vendor/rich/abc.py,sha256=ON-E-ZqSSheZ88VrKX2M3PXpFbGEUUZPMa_Af0l-4f0,890 +pip/_vendor/rich/align.py,sha256=Rh-3adnDaN1Ao07EjR2PhgE62PGLPgO8SMwJBku1urQ,10469 +pip/_vendor/rich/ansi.py,sha256=Avs1LHbSdcyOvDOdpELZUoULcBiYewY76eNBp6uFBhs,6921 +pip/_vendor/rich/bar.py,sha256=ldbVHOzKJOnflVNuv1xS7g6dLX2E3wMnXkdPbpzJTcs,3263 +pip/_vendor/rich/box.py,sha256=nr5fYIUghB_iUCEq6y0Z3LlCT8gFPDrzN9u2kn7tJl4,10831 +pip/_vendor/rich/cells.py,sha256=KrQkj5-LghCCpJLSNQIyAZjndc4bnEqOEmi5YuZ9UCY,5130 +pip/_vendor/rich/color.py,sha256=3HSULVDj7qQkXUdFWv78JOiSZzfy5y1nkcYhna296V0,18211 +pip/_vendor/rich/color_triplet.py,sha256=3lhQkdJbvWPoLDO-AnYImAWmJvV5dlgYNCVZ97ORaN4,1054 +pip/_vendor/rich/columns.py,sha256=HUX0KcMm9dsKNi11fTbiM_h2iDtl8ySCaVcxlalEzq8,7131 +pip/_vendor/rich/console.py,sha256=nKjrEx_7xy8KGmDVT-BgNII0R5hm1cexhAHDwdwNVqg,100156 +pip/_vendor/rich/constrain.py,sha256=1VIPuC8AgtKWrcncQrjBdYqA3JVWysu6jZo1rrh7c7Q,1288 +pip/_vendor/rich/containers.py,sha256=c_56TxcedGYqDepHBMTuZdUIijitAQgnox-Qde0Z1qo,5502 +pip/_vendor/rich/control.py,sha256=DSkHTUQLorfSERAKE_oTAEUFefZnZp4bQb4q8rHbKws,6630 +pip/_vendor/rich/default_styles.py,sha256=dZxgaSD9VUy7SXQShO33aLYiAWspCr2sCQZFX_JK1j4,8159 +pip/_vendor/rich/diagnose.py,sha256=an6uouwhKPAlvQhYpNNpGq9EJysfMIOvvCbO3oSoR24,972 +pip/_vendor/rich/emoji.py,sha256=omTF9asaAnsM4yLY94eR_9dgRRSm1lHUszX20D1yYCQ,2501 +pip/_vendor/rich/errors.py,sha256=5pP3Kc5d4QJ_c0KFsxrfyhjiPVe7J1zOqSFbFAzcV-Y,642 +pip/_vendor/rich/file_proxy.py,sha256=Tl9THMDZ-Pk5Wm8sI1gGg_U5DhusmxD-FZ0fUbcU0W0,1683 +pip/_vendor/rich/filesize.py,sha256=_iz9lIpRgvW7MNSeCZnLg-HwzbP4GETg543WqD8SFs0,2484 +pip/_vendor/rich/highlighter.py,sha256=G_sn-8DKjM1sEjLG_oc4ovkWmiUpWvj8bXi0yed2LnY,9586 +pip/_vendor/rich/json.py,sha256=vVEoKdawoJRjAFayPwXkMBPLy7RSTs-f44wSQDR2nJ0,5031 +pip/_vendor/rich/jupyter.py,sha256=QyoKoE_8IdCbrtiSHp9TsTSNyTHY0FO5whE7jOTd9UE,3252 +pip/_vendor/rich/layout.py,sha256=ajkSFAtEVv9EFTcFs-w4uZfft7nEXhNzL7ZVdgrT5rI,14004 +pip/_vendor/rich/live.py,sha256=DhzAPEnjTxQuq9_0Y2xh2MUwQcP_aGPkenLfKETslwM,14270 +pip/_vendor/rich/live_render.py,sha256=zJtB471jGziBtEwxc54x12wEQtH4BuQr1SA8v9kU82w,3666 +pip/_vendor/rich/logging.py,sha256=ZgpKMMBY_BuMAI_BYzo-UtXak6t5oH9VK8m9Q2Lm0f4,12458 +pip/_vendor/rich/markup.py,sha256=3euGKP5s41NCQwaSjTnJxus5iZMHjxpIM0W6fCxra38,8451 +pip/_vendor/rich/measure.py,sha256=HmrIJX8sWRTHbgh8MxEay_83VkqNW_70s8aKP5ZcYI8,5305 +pip/_vendor/rich/padding.py,sha256=KVEI3tOwo9sgK1YNSuH__M1_jUWmLZwRVV_KmOtVzyM,4908 +pip/_vendor/rich/pager.py,sha256=SO_ETBFKbg3n_AgOzXm41Sv36YxXAyI3_R-KOY2_uSc,828 +pip/_vendor/rich/palette.py,sha256=lInvR1ODDT2f3UZMfL1grq7dY_pDdKHw4bdUgOGaM4Y,3396 +pip/_vendor/rich/panel.py,sha256=fFRHcviXvWhk3V3zx5Zwmsb_RL9KJ3esD-sU0NYEVyw,11235 +pip/_vendor/rich/pretty.py,sha256=gy3S72u4FRg2ytoo7N1ZDWDIvB4unbzd5iUGdgm-8fc,36391 +pip/_vendor/rich/progress.py,sha256=MtmCjTk5zYU_XtRHxRHTAEHG6hF9PeF7EMWbEPleIC0,60357 +pip/_vendor/rich/progress_bar.py,sha256=mZTPpJUwcfcdgQCTTz3kyY-fc79ddLwtx6Ghhxfo064,8162 +pip/_vendor/rich/prompt.py,sha256=l0RhQU-0UVTV9e08xW1BbIj0Jq2IXyChX4lC0lFNzt4,12447 +pip/_vendor/rich/protocol.py,sha256=5hHHDDNHckdk8iWH5zEbi-zuIVSF5hbU2jIo47R7lTE,1391 +pip/_vendor/rich/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/rich/region.py,sha256=rNT9xZrVZTYIXZC0NYn41CJQwYNbR-KecPOxTgQvB8Y,166 +pip/_vendor/rich/repr.py,sha256=5MZJZmONgC6kud-QW-_m1okXwL2aR6u6y-pUcUCJz28,4431 +pip/_vendor/rich/rule.py,sha256=0fNaS_aERa3UMRc3T5WMpN_sumtDxfaor2y3of1ftBk,4602 +pip/_vendor/rich/scope.py,sha256=TMUU8qo17thyqQCPqjDLYpg_UU1k5qVd-WwiJvnJVas,2843 +pip/_vendor/rich/screen.py,sha256=YoeReESUhx74grqb0mSSb9lghhysWmFHYhsbMVQjXO8,1591 +pip/_vendor/rich/segment.py,sha256=otnKeKGEV-WRlQVosfJVeFDcDxAKHpvJ_hLzSu5lumM,24743 +pip/_vendor/rich/spinner.py,sha256=PT5qgXPG3ZpqRj7n3EZQ6NW56mx3ldZqZCU7gEMyZk4,4364 +pip/_vendor/rich/status.py,sha256=kkPph3YeAZBo-X-4wPp8gTqZyU466NLwZBA4PZTTewo,4424 +pip/_vendor/rich/style.py,sha256=aSoUNbVgfP1PAnduAqgbbl4AMQy668qs2S1FEwr3Oqs,27067 +pip/_vendor/rich/styled.py,sha256=eZNnzGrI4ki_54pgY3Oj0T-x3lxdXTYh4_ryDB24wBU,1258 +pip/_vendor/rich/syntax.py,sha256=qqAnEUZ4K57Po81_5RBxnsuU4KRzSdvDPAhKw8ma_3E,35763 +pip/_vendor/rich/table.py,sha256=yXYUr0YsPpG466N50HCAw2bpb5ZUuuzdc-G66Zk-oTc,40103 +pip/_vendor/rich/terminal_theme.py,sha256=1j5-ufJfnvlAo5Qsi_ACZiXDmwMXzqgmFByObT9-yJY,3370 +pip/_vendor/rich/text.py,sha256=AO7JPCz6-gaN1thVLXMBntEmDPVYFgFNG1oM61_sanU,47552 +pip/_vendor/rich/theme.py,sha256=oNyhXhGagtDlbDye3tVu3esWOWk0vNkuxFw-_unlaK0,3771 +pip/_vendor/rich/themes.py,sha256=0xgTLozfabebYtcJtDdC5QkX5IVUEaviqDUJJh4YVFk,102 +pip/_vendor/rich/traceback.py,sha256=z8UoN7NbTQKW6YDDUVwOh7F8snZf6gYnUWtOrKsLE1w,31797 +pip/_vendor/rich/tree.py,sha256=yWnQ6rAvRGJ3qZGqBrxS2SW2TKBTNrP0SdY8QxOFPuw,9451 +pip/_vendor/tomli/__init__.py,sha256=PhNw_eyLgdn7McJ6nrAN8yIm3dXC75vr1sVGVVwDSpA,314 +pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc,, +pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc,, +pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc,, +pip/_vendor/tomli/_parser.py,sha256=9w8LG0jB7fwmZZWB0vVXbeejDHcl4ANIJxB2scEnDlA,25591 +pip/_vendor/tomli/_re.py,sha256=sh4sBDRgO94KJZwNIrgdcyV_qQast50YvzOAUGpRDKA,3171 +pip/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254 +pip/_vendor/tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26 +pip/_vendor/truststore/__init__.py,sha256=WIDeyzWm7EVX44g354M25vpRXbeY1lsPH6EmUJUcq4o,1264 +pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc,, +pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc,, +pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc,, +pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc,, +pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc,, +pip/_vendor/truststore/_api.py,sha256=GeXRNTlxPZ3kif4kNoh6JY0oE4QRzTGcgXr6l_X_Gk0,10555 +pip/_vendor/truststore/_macos.py,sha256=nZlLkOmszUE0g6ryRwBVGY5COzPyudcsiJtDWarM5LQ,20503 +pip/_vendor/truststore/_openssl.py,sha256=LLUZ7ZGaio-i5dpKKjKCSeSufmn6T8pi9lDcFnvSyq0,2324 +pip/_vendor/truststore/_ssl_constants.py,sha256=NUD4fVKdSD02ri7-db0tnO0VqLP9aHuzmStcW7tAl08,1130 +pip/_vendor/truststore/_windows.py,sha256=rAHyKYD8M7t-bXfG8VgOVa3TpfhVhbt4rZQlO45YuP8,17993 +pip/_vendor/truststore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/typing_extensions.py,sha256=78hFl0HpDY-ylHUVCnWdU5nTHxUP2-S-3wEZk6CQmLk,134499 +pip/_vendor/urllib3/__init__.py,sha256=iXLcYiJySn0GNbWOOZDDApgBL1JgP44EZ8i1760S8Mc,3333 +pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc,, +pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc,, +pip/_vendor/urllib3/_collections.py,sha256=pyASJJhW7wdOpqJj9QJA8FyGRfr8E8uUUhqUvhF0728,11372 +pip/_vendor/urllib3/_version.py,sha256=t9wGB6ooOTXXgiY66K1m6BZS1CJyXHAU8EoWDTe6Shk,64 +pip/_vendor/urllib3/connection.py,sha256=ttIA909BrbTUzwkqEe_TzZVh4JOOj7g61Ysei2mrwGg,20314 +pip/_vendor/urllib3/connectionpool.py,sha256=e2eiAwNbFNCKxj4bwDKNK-w7HIdSz3OmMxU_TIt-evQ,40408 +pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957 +pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=4Xk64qIkPBt09A5q-RIFUuDhNc9mXilVapm7WnYnzRw,17632 +pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=B2JBB2_NRP02xK6DCa1Pa9IuxrPwxzDzZbixQkb7U9M,13922 +pip/_vendor/urllib3/contrib/appengine.py,sha256=VR68eAVE137lxTgjBDwCna5UiBZTOKa01Aj_-5BaCz4,11036 +pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=NlfkW7WMdW8ziqudopjHoW299og1BTWi0IeIibquFwk,4528 +pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=hDJh4MhyY_p-oKlFcYcQaVQRDv6GMmBGuW9yjxyeejM,17081 +pip/_vendor/urllib3/contrib/securetransport.py,sha256=Fef1IIUUFHqpevzXiDPbIGkDKchY2FVKeVeLGR1Qq3g,34446 +pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097 +pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217 +pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579 +pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440 +pip/_vendor/urllib3/packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc,, +pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc,, +pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc,, +pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417 +pip/_vendor/urllib3/packages/backports/weakref_finalize.py,sha256=tRCal5OAhNSRyb0DhHp-38AtIlCsRP8BxF3NX-6rqIA,5343 +pip/_vendor/urllib3/packages/six.py,sha256=b9LM0wBXv7E7SrbCjAm4wwN-hrH-iNxv18LgWNMMKPo,34665 +pip/_vendor/urllib3/poolmanager.py,sha256=aWyhXRtNO4JUnCSVVqKTKQd8EXTvUm1VN9pgs2bcONo,19990 +pip/_vendor/urllib3/request.py,sha256=YTWFNr7QIwh7E1W9dde9LM77v2VWTJ5V78XuTTw7D1A,6691 +pip/_vendor/urllib3/response.py,sha256=fmDJAFkG71uFTn-sVSTh2Iw0WmcXQYqkbRjihvwBjU8,30641 +pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155 +pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc,, +pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc,, +pip/_vendor/urllib3/util/connection.py,sha256=5Lx2B1PW29KxBn2T0xkN1CBgRBa3gGVJBKoQoRogEVk,4901 +pip/_vendor/urllib3/util/proxy.py,sha256=zUvPPCJrp6dOF0N4GAVbOcl6o-4uXKSrGiTkkr5vUS4,1605 +pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498 +pip/_vendor/urllib3/util/request.py,sha256=C0OUt2tcU6LRiQJ7YYNP9GvPrSvl7ziIBekQ-5nlBZk,3997 +pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510 +pip/_vendor/urllib3/util/retry.py,sha256=6ENvOZ8PBDzh8kgixpql9lIrb2dxH-k7ZmBanJF2Ng4,22050 +pip/_vendor/urllib3/util/ssl_.py,sha256=QDuuTxPSCj1rYtZ4xpD7Ux-r20TD50aHyqKyhQ7Bq4A,17460 +pip/_vendor/urllib3/util/ssl_match_hostname.py,sha256=Ir4cZVEjmAk8gUAIHWSi7wtOO83UCYABY2xFD1Ql_WA,5758 +pip/_vendor/urllib3/util/ssltransport.py,sha256=NA-u5rMTrDFDFC8QzRKUEKMG0561hOD4qBTr3Z4pv6E,6895 +pip/_vendor/urllib3/util/timeout.py,sha256=cwq4dMk87mJHSBktK1miYJ-85G-3T3RmT20v7SFCpno,10168 +pip/_vendor/urllib3/util/url.py,sha256=lCAE7M5myA8EDdW0sJuyyZhVB9K_j38ljWhHAnFaWoE,14296 +pip/_vendor/urllib3/util/wait.py,sha256=fOX0_faozG2P7iVojQoE1mbydweNyTcm-hXEfFrTtLI,5403 +pip/_vendor/vendor.txt,sha256=EW-E3cE5XEAtVFzGInikArOMDxGP0DLUWzXpY4RZfFY,333 +pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286 diff --git a/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/REQUESTED b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/WHEEL b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/WHEEL new file mode 100644 index 0000000..505164b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.8.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/entry_points.txt b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/entry_points.txt new file mode 100644 index 0000000..25fcf7e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +pip = pip._internal.cli.main:main +pip3 = pip._internal.cli.main:main diff --git a/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/top_level.txt b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/top_level.txt new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip-25.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/pip/__init__.py b/backend/venv/Lib/site-packages/pip/__init__.py new file mode 100644 index 0000000..d628f93 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/__init__.py @@ -0,0 +1,13 @@ +from typing import List, Optional + +__version__ = "25.0.1" + + +def main(args: Optional[List[str]] = None) -> int: + """This is an internal API only meant for use by pip's own console scripts. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/backend/venv/Lib/site-packages/pip/__main__.py b/backend/venv/Lib/site-packages/pip/__main__.py new file mode 100644 index 0000000..5991326 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/__main__.py @@ -0,0 +1,24 @@ +import os +import sys + +# Remove '' and current working directory from the first entry +# of sys.path, if present to avoid using current directory +# in pip commands check, freeze, install, list and show, +# when invoked as python -m pip +if sys.path[0] in ("", os.getcwd()): + sys.path.pop(0) + +# If we are running from a wheel, add the wheel to sys.path +# This allows the usage python pip-*.whl/pip install pip-*.whl +if __package__ == "": + # __file__ is pip-*.whl/pip/__main__.py + # first dirname call strips of '/__main__.py', second strips off '/pip' + # Resulting path is the name of the wheel itself + # Add that to sys.path so we can import pip + path = os.path.dirname(os.path.dirname(__file__)) + sys.path.insert(0, path) + +if __name__ == "__main__": + from pip._internal.cli.main import main as _main + + sys.exit(_main()) diff --git a/backend/venv/Lib/site-packages/pip/__pip-runner__.py b/backend/venv/Lib/site-packages/pip/__pip-runner__.py new file mode 100644 index 0000000..c633787 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/__pip-runner__.py @@ -0,0 +1,50 @@ +"""Execute exactly this copy of pip, within a different environment. + +This file is named as it is, to ensure that this module can't be imported via +an import statement. +""" + +# /!\ This version compatibility check section must be Python 2 compatible. /!\ + +import sys + +# Copied from pyproject.toml +PYTHON_REQUIRES = (3, 8) + + +def version_str(version): # type: ignore + return ".".join(str(v) for v in version) + + +if sys.version_info[:2] < PYTHON_REQUIRES: + raise SystemExit( + "This version of pip does not support python {} (requires >={}).".format( + version_str(sys.version_info[:2]), version_str(PYTHON_REQUIRES) + ) + ) + +# From here on, we can use Python 3 features, but the syntax must remain +# Python 2 compatible. + +import runpy # noqa: E402 +from importlib.machinery import PathFinder # noqa: E402 +from os.path import dirname # noqa: E402 + +PIP_SOURCES_ROOT = dirname(dirname(__file__)) + + +class PipImportRedirectingFinder: + @classmethod + def find_spec(self, fullname, path=None, target=None): # type: ignore + if fullname != "pip": + return None + + spec = PathFinder.find_spec(fullname, [PIP_SOURCES_ROOT], target) + assert spec, (PIP_SOURCES_ROOT, fullname) + return spec + + +sys.meta_path.insert(0, PipImportRedirectingFinder()) + +assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module" +runpy.run_module("pip", run_name="__main__", alter_sys=True) diff --git a/backend/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6a447b16312538f3e4307d83574f74eba23e953 GIT binary patch literal 691 zcmX|9&ui2`6rM@4*>%?{DhTzUqaI{I6BU28NI?`qC{ z2f>TC*8e~e{71a#H5V06-YTmXPrg}OA9*kDJ-&S3o4onBu+T+d=RZ6a93%AI6$jSZ zPi8kD*+C33oTCB{ap4U;jF>m{S(^pi|C}m9i8<#L{smRSmVmK!gYn54!%C!K1l6xZ-G&Hyq>52lPN3)B%Wt*(`XuF)O$ji=oP=DBesg!~!YT~3si zV@-=fl;dP7C8!r%XB_A@fI{jz8PV)1FIfWhMzShKi4m4xQqZMiZW1?U3UFc5G*WdF z6jYSD2MQs$IR;@H{qCaH(zo7;*Y{qndc)pt%o*Pyec0jLEo(Zr3(2aSuju1Yy5*TZggqZ)`~{u;dgSDG?`PP?r(QnW W4R!}_4t+j)ZVy5IHv8pXbE>~HO}r@p literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1f601c39db667f8340726f7db496607db0daf5b GIT binary patch literal 845 zcmb7C&ubGw6n?Y2X?|BKwa`{Pn2R|Wp;Qu745c1=2u2hY!osr6Oyi{4AIz?)s~`;s zZSc?)!P--=O2B`_i?#|fMJRak7U<2BGfkEhS`WU%yzjmF=6&DJ&gX141tM~v?$bvq zz%N-u5gUS|mk3}RFksYz+90DEBB-fF)KSJTEefnCK%hA`>PM(I1S?7#*zDOen#qVg z${2dWg$x8FhLzPT0PLR7IKx9TJ7At%|AQHil%iZy{^4`tq{0AWAWBaeVBs{0)nliZ z#O-OVl$EY!5Qw`$&6(3@ML!eWPo#|?Kmp3feoOjY4m@EPmPu{H$Rn;vlpp7c<8jps zJg&K>|Adb#Jsi7zU4H%52jja>@#A$<`RPJ;Hq1kvpO@SsWUZUrZEd5T9>%??1<#9tdjHHCW3va1?8!F^EkmD%t=7K6s(oEVtjm!rkuq?H+mv z2_+=8Nt5!>6#Awwjh43QV;}q8m%}p!H!-nkAIckg5B>Ah`EGB8#I}>{eBbPRGvCa7 zznPz+(J&yjeK(?i?F0Cg3m%2)o2pF!RzZU_XhaioBuz9iEojm*q(w@mgPy_estKC! z5Kv)80ASq$P@m?Xj_&Hc9cup9!#du~sdi5Aq;>Sl$&;5zEv`U1fNLNZ%!kq;!eb5Q z!ud!#Lb!c|f3(4~@z!)yfJ>l-mO%@9e$$PZ)lv73y?pxkUdi2S1pPLy*A<=z0(74i znP~^G0#`t5@bpXkbYS|#zxau25v}o?*t+QI2$Y0meD16M+cZ&60v6q~3DKti?ek%YWbKJ2zfn z<|I?|dEJ;Czh#;kGoPm{Llxba#gdw=G(MqbW~iZ!qdYtQfj%*A={D^w;9qr;TI2XI zU5bLdlNAkvGDS%hN=~R}k{a}Of%VQEou$muO+&#DQaw2{qvovM)JuIFW3if%{SJRF zLOIcK|I*sc&->QM>c#t){<3&ImzrBJ4M& zvmm!Kdb6lA)c2mhvye<-Na11Cp1PMg5~D!O0fH`y%kH`jW7;FOluIs4Jrx`Q&F6-qPPPB_YI12v#8b* zKq->Rsg{+ehzYG0>_e!zaHHpNW}KbC&uT)p3|qeV3&HPes*2#>_nhxs1AdHOnOAi~ zQRce)RD;6~n@N79t@tog5tT+KKP|hlF^=*vZ0;c1)FO96YR<+^v`SVo;RF;#Gcy>o zh_VwKzA<)rXiypHzjl3Kq<^&5EKY;hKDv=Lo$zSM!g1GsTels5)?|6rc6{g@`#Rwc z$eccr%BvY1#*~#@3Iv~NtSIatinUreAuN}wxNol;7G*X&#?OX%-1S`A z_-XzYZd(U?-2c7oH2&lLZk3Vkh=h>mf<&Zh97trx4~c_|u@`AG4K zg;2OEN)i7KNIrjcKal8Cc=IV7{v~nf%QN@RRt|Sm5}jp;|KSgkrssfc=Kv7t int: + """This is preserved for old console scripts that may still be referencing + it. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5620f28628bf38a2de870dc948b1e1e74d0fd3f4 GIT binary patch literal 791 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ff45c42ab612c050481f86b8d3d1afdd9b08283 GIT binary patch literal 12671 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb0d4af8b22b0f68af735a820973678a173e01c9 GIT binary patch literal 17635 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 D3;7Xc7_ze$lQl6rw6A<2^Upe0!pMM<CT)p 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52757db6f82c8dc0a4fc658fc7c78e73bde56ba8 GIT binary patch literal 674 zcmX|9y=xRf6rb7MJI{O|VigM=KbiyGg&=5xq*1Iw1e3;NAjkO~9kJxCtjfj<9Wm{I||A zn5`0c%@k9-WECIqDjGzbsjiA40uJ#C%?DQrBzuYKJnsxTP1Ha2BM|hXHrdq9x4rw; zYg5Z|t4$=1T-!zP6RZo;J+YWj@Yw|lq{&qjG@o+LB6h$J*oWiQ+pHfydAl>#PS9r& z9N-j`*fS_hsYGFFXG##RKyAGfek{GHWFwr{WhsUr5cU9}E_6Lw5MW^OrE?;T=n#G0_ICGC zS_??MxJWD0U0r)XYDGGsYFrAn$Hp2Ob=V7gA`H!+V;4w-`1A12dT!B-P*xR{obMY$ z>J?xCL^mZ0gH1k^#UrRyPWd$7)Wh6q57#Y?$`QCclzAeaRZ`cfZQ3LNTqK=@+?}QH zjQw6>owaX^=U&}?x$!w!nb9DfWvkz9yS}kh0fu|Ru%nHg$2O+&=OphLE`_P^vfAG5 x%BV>R8yINA<+-aAj$+RFS9a-Vx5v-Fczl=~ZofJG<;>+HM)|wqSNP3Y{sMsKw}1cu literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adf789112f98e76ebdafa0f19fd009afaea98f27 GIT binary patch literal 5122 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 Ou6p)9^iXK3;J*RCWHAc> literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b07de0888730dd6a73fe4ea955444781e033738 GIT binary patch literal 10407 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 ncNMD}03u% Union[Tuple[str], Tuple[str, str]]: + return (a, b) if a != b else (a,) + + +class _Prefix: + def __init__(self, path: str) -> None: + self.path = path + self.setup = False + scheme = get_scheme("", prefix=path) + self.bin_dir = scheme.scripts + self.lib_dirs = _dedup(scheme.purelib, scheme.platlib) + + +def get_runnable_pip() -> str: + """Get a file to pass to a Python executable, to run the currently-running pip. + + This is used to run a pip subprocess, for installing requirements into the build + environment. + """ + source = pathlib.Path(pip_location).resolve().parent + + if not source.is_dir(): + # This would happen if someone is using pip from inside a zip file. In that + # case, we can use that directly. + return str(source) + + return os.fsdecode(source / "__pip-runner__.py") + + +def _get_system_sitepackages() -> Set[str]: + """Get system site packages + + Usually from site.getsitepackages, + but fallback on `get_purelib()/get_platlib()` if unavailable + (e.g. in a virtualenv created by virtualenv<20) + + Returns normalized set of strings. + """ + if hasattr(site, "getsitepackages"): + system_sites = site.getsitepackages() + else: + # virtualenv < 20 overwrites site.py without getsitepackages + # fallback on get_purelib/get_platlib. + # this is known to miss things, but shouldn't in the cases + # where getsitepackages() has been removed (inside a virtualenv) + system_sites = [get_purelib(), get_platlib()] + return {os.path.normcase(path) for path in system_sites} + + +class BuildEnvironment: + """Creates and manages an isolated environment to install build deps""" + + def __init__(self) -> None: + temp_dir = TempDirectory(kind=tempdir_kinds.BUILD_ENV, globally_managed=True) + + self._prefixes = OrderedDict( + (name, _Prefix(os.path.join(temp_dir.path, name))) + for name in ("normal", "overlay") + ) + + self._bin_dirs: List[str] = [] + self._lib_dirs: List[str] = [] + for prefix in reversed(list(self._prefixes.values())): + self._bin_dirs.append(prefix.bin_dir) + self._lib_dirs.extend(prefix.lib_dirs) + + # Customize site to: + # - ensure .pth files are honored + # - prevent access to system site packages + system_sites = _get_system_sitepackages() + + self._site_dir = os.path.join(temp_dir.path, "site") + if not os.path.exists(self._site_dir): + os.mkdir(self._site_dir) + with open( + os.path.join(self._site_dir, "sitecustomize.py"), "w", encoding="utf-8" + ) as fp: + fp.write( + textwrap.dedent( + """ + import os, site, sys + + # First, drop system-sites related paths. + original_sys_path = sys.path[:] + known_paths = set() + for path in {system_sites!r}: + site.addsitedir(path, known_paths=known_paths) + system_paths = set( + os.path.normcase(path) + for path in sys.path[len(original_sys_path):] + ) + original_sys_path = [ + path for path in original_sys_path + if os.path.normcase(path) not in system_paths + ] + sys.path = original_sys_path + + # Second, add lib directories. + # ensuring .pth file are processed. + for path in {lib_dirs!r}: + assert not path in sys.path + site.addsitedir(path) + """ + ).format(system_sites=system_sites, lib_dirs=self._lib_dirs) + ) + + def __enter__(self) -> None: + self._save_env = { + name: os.environ.get(name, None) + for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH") + } + + path = self._bin_dirs[:] + old_path = self._save_env["PATH"] + if old_path: + path.extend(old_path.split(os.pathsep)) + + pythonpath = [self._site_dir] + + os.environ.update( + { + "PATH": os.pathsep.join(path), + "PYTHONNOUSERSITE": "1", + "PYTHONPATH": os.pathsep.join(pythonpath), + } + ) + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + for varname, old_value in self._save_env.items(): + if old_value is None: + os.environ.pop(varname, None) + else: + os.environ[varname] = old_value + + def check_requirements( + self, reqs: Iterable[str] + ) -> Tuple[Set[Tuple[str, str]], Set[str]]: + """Return 2 sets: + - conflicting requirements: set of (installed, wanted) reqs tuples + - missing requirements: set of reqs + """ + missing = set() + conflicting = set() + if reqs: + env = ( + get_environment(self._lib_dirs) + if hasattr(self, "_lib_dirs") + else get_default_environment() + ) + for req_str in reqs: + req = get_requirement(req_str) + # We're explicitly evaluating with an empty extra value, since build + # environments are not provided any mechanism to select specific extras. + if req.marker is not None and not req.marker.evaluate({"extra": ""}): + continue + dist = env.get_distribution(req.name) + if not dist: + missing.add(req_str) + continue + if isinstance(dist.version, Version): + installed_req_str = f"{req.name}=={dist.version}" + else: + installed_req_str = f"{req.name}==={dist.version}" + if not req.specifier.contains(dist.version, prereleases=True): + conflicting.add((installed_req_str, req_str)) + # FIXME: Consider direct URL? + return conflicting, missing + + def install_requirements( + self, + finder: "PackageFinder", + requirements: Iterable[str], + prefix_as_string: str, + *, + kind: str, + ) -> None: + prefix = self._prefixes[prefix_as_string] + assert not prefix.setup + prefix.setup = True + if not requirements: + return + self._install_requirements( + get_runnable_pip(), + finder, + requirements, + prefix, + kind=kind, + ) + + @staticmethod + def _install_requirements( + pip_runnable: str, + finder: "PackageFinder", + requirements: Iterable[str], + prefix: _Prefix, + *, + kind: str, + ) -> None: + args: List[str] = [ + sys.executable, + pip_runnable, + "install", + "--ignore-installed", + "--no-user", + "--prefix", + prefix.path, + "--no-warn-script-location", + "--disable-pip-version-check", + # The prefix specified two lines above, thus + # target from config file or env var should be ignored + "--target", + "", + ] + if logger.getEffectiveLevel() <= logging.DEBUG: + args.append("-vv") + elif logger.getEffectiveLevel() <= VERBOSE: + args.append("-v") + for format_control in ("no_binary", "only_binary"): + formats = getattr(finder.format_control, format_control) + args.extend( + ( + "--" + format_control.replace("_", "-"), + ",".join(sorted(formats or {":none:"})), + ) + ) + + index_urls = finder.index_urls + if index_urls: + args.extend(["-i", index_urls[0]]) + for extra_index in index_urls[1:]: + args.extend(["--extra-index-url", extra_index]) + else: + args.append("--no-index") + for link in finder.find_links: + args.extend(["--find-links", link]) + + if finder.proxy: + args.extend(["--proxy", finder.proxy]) + for host in finder.trusted_hosts: + args.extend(["--trusted-host", host]) + if finder.custom_cert: + args.extend(["--cert", finder.custom_cert]) + if finder.client_cert: + args.extend(["--client-cert", finder.client_cert]) + if finder.allow_all_prereleases: + args.append("--pre") + if finder.prefer_binary: + args.append("--prefer-binary") + args.append("--") + args.extend(requirements) + with open_spinner(f"Installing {kind}") as spinner: + call_subprocess( + args, + command_desc=f"pip subprocess to install {kind}", + spinner=spinner, + ) + + +class NoOpBuildEnvironment(BuildEnvironment): + """A no-op drop-in replacement for BuildEnvironment""" + + def __init__(self) -> None: + pass + + def __enter__(self) -> None: + pass + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + pass + + def cleanup(self) -> None: + pass + + def install_requirements( + self, + finder: "PackageFinder", + requirements: Iterable[str], + prefix_as_string: str, + *, + kind: str, + ) -> None: + raise NotImplementedError() diff --git a/backend/venv/Lib/site-packages/pip/_internal/cache.py b/backend/venv/Lib/site-packages/pip/_internal/cache.py new file mode 100644 index 0000000..6b45126 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cache.py @@ -0,0 +1,290 @@ +"""Cache Management +""" + +import hashlib +import json +import logging +import os +from pathlib import Path +from typing import Any, Dict, List, Optional + +from pip._vendor.packaging.tags import Tag, interpreter_name, interpreter_version +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import InvalidWheelFilename +from pip._internal.models.direct_url import DirectUrl +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds +from pip._internal.utils.urls import path_to_url + +logger = logging.getLogger(__name__) + +ORIGIN_JSON_NAME = "origin.json" + + +def _hash_dict(d: Dict[str, str]) -> str: + """Return a stable sha224 of a dictionary.""" + s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + return hashlib.sha224(s.encode("ascii")).hexdigest() + + +class Cache: + """An abstract class - provides cache directories for data from links + + :param cache_dir: The root of the cache. + """ + + def __init__(self, cache_dir: str) -> None: + super().__init__() + assert not cache_dir or os.path.isabs(cache_dir) + self.cache_dir = cache_dir or None + + def _get_cache_path_parts(self, link: Link) -> List[str]: + """Get parts of part that must be os.path.joined with cache_dir""" + + # We want to generate an url to use as our cache key, we don't want to + # just reuse the URL because it might have other items in the fragment + # and we don't care about those. + key_parts = {"url": link.url_without_fragment} + if link.hash_name is not None and link.hash is not None: + key_parts[link.hash_name] = link.hash + if link.subdirectory_fragment: + key_parts["subdirectory"] = link.subdirectory_fragment + + # Include interpreter name, major and minor version in cache key + # to cope with ill-behaved sdists that build a different wheel + # depending on the python version their setup.py is being run on, + # and don't encode the difference in compatibility tags. + # https://github.com/pypa/pip/issues/7296 + key_parts["interpreter_name"] = interpreter_name() + key_parts["interpreter_version"] = interpreter_version() + + # Encode our key url with sha224, we'll use this because it has similar + # security properties to sha256, but with a shorter total output (and + # thus less secure). However the differences don't make a lot of + # difference for our use case here. + hashed = _hash_dict(key_parts) + + # We want to nest the directories some to prevent having a ton of top + # level directories where we might run out of sub directories on some + # FS. + parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] + + return parts + + def _get_candidates(self, link: Link, canonical_package_name: str) -> List[Any]: + can_not_cache = not self.cache_dir or not canonical_package_name or not link + if can_not_cache: + return [] + + path = self.get_path_for_link(link) + if os.path.isdir(path): + return [(candidate, path) for candidate in os.listdir(path)] + return [] + + def get_path_for_link(self, link: Link) -> str: + """Return a directory to store cached items in for link.""" + raise NotImplementedError() + + def get( + self, + link: Link, + package_name: Optional[str], + supported_tags: List[Tag], + ) -> Link: + """Returns a link to a cached item if it exists, otherwise returns the + passed link. + """ + raise NotImplementedError() + + +class SimpleWheelCache(Cache): + """A cache of wheels for future installs.""" + + def __init__(self, cache_dir: str) -> None: + super().__init__(cache_dir) + + def get_path_for_link(self, link: Link) -> str: + """Return a directory to store cached wheels for link + + Because there are M wheels for any one sdist, we provide a directory + to cache them in, and then consult that directory when looking up + cache hits. + + We only insert things into the cache if they have plausible version + numbers, so that we don't contaminate the cache with things that were + not unique. E.g. ./package might have dozens of installs done for it + and build a version of 0.0...and if we built and cached a wheel, we'd + end up using the same wheel even if the source has been edited. + + :param link: The link of the sdist for which this will cache wheels. + """ + parts = self._get_cache_path_parts(link) + assert self.cache_dir + # Store wheels within the root cache_dir + return os.path.join(self.cache_dir, "wheels", *parts) + + def get( + self, + link: Link, + package_name: Optional[str], + supported_tags: List[Tag], + ) -> Link: + candidates = [] + + if not package_name: + return link + + canonical_package_name = canonicalize_name(package_name) + for wheel_name, wheel_dir in self._get_candidates(link, canonical_package_name): + try: + wheel = Wheel(wheel_name) + except InvalidWheelFilename: + continue + if canonicalize_name(wheel.name) != canonical_package_name: + logger.debug( + "Ignoring cached wheel %s for %s as it " + "does not match the expected distribution name %s.", + wheel_name, + link, + package_name, + ) + continue + if not wheel.supported(supported_tags): + # Built for a different python/arch/etc + continue + candidates.append( + ( + wheel.support_index_min(supported_tags), + wheel_name, + wheel_dir, + ) + ) + + if not candidates: + return link + + _, wheel_name, wheel_dir = min(candidates) + return Link(path_to_url(os.path.join(wheel_dir, wheel_name))) + + +class EphemWheelCache(SimpleWheelCache): + """A SimpleWheelCache that creates it's own temporary cache directory""" + + def __init__(self) -> None: + self._temp_dir = TempDirectory( + kind=tempdir_kinds.EPHEM_WHEEL_CACHE, + globally_managed=True, + ) + + super().__init__(self._temp_dir.path) + + +class CacheEntry: + def __init__( + self, + link: Link, + persistent: bool, + ): + self.link = link + self.persistent = persistent + self.origin: Optional[DirectUrl] = None + origin_direct_url_path = Path(self.link.file_path).parent / ORIGIN_JSON_NAME + if origin_direct_url_path.exists(): + try: + self.origin = DirectUrl.from_json( + origin_direct_url_path.read_text(encoding="utf-8") + ) + except Exception as e: + logger.warning( + "Ignoring invalid cache entry origin file %s for %s (%s)", + origin_direct_url_path, + link.filename, + e, + ) + + +class WheelCache(Cache): + """Wraps EphemWheelCache and SimpleWheelCache into a single Cache + + This Cache allows for gracefully degradation, using the ephem wheel cache + when a certain link is not found in the simple wheel cache first. + """ + + def __init__(self, cache_dir: str) -> None: + super().__init__(cache_dir) + self._wheel_cache = SimpleWheelCache(cache_dir) + self._ephem_cache = EphemWheelCache() + + def get_path_for_link(self, link: Link) -> str: + return self._wheel_cache.get_path_for_link(link) + + def get_ephem_path_for_link(self, link: Link) -> str: + return self._ephem_cache.get_path_for_link(link) + + def get( + self, + link: Link, + package_name: Optional[str], + supported_tags: List[Tag], + ) -> Link: + cache_entry = self.get_cache_entry(link, package_name, supported_tags) + if cache_entry is None: + return link + return cache_entry.link + + def get_cache_entry( + self, + link: Link, + package_name: Optional[str], + supported_tags: List[Tag], + ) -> Optional[CacheEntry]: + """Returns a CacheEntry with a link to a cached item if it exists or + None. The cache entry indicates if the item was found in the persistent + or ephemeral cache. + """ + retval = self._wheel_cache.get( + link=link, + package_name=package_name, + supported_tags=supported_tags, + ) + if retval is not link: + return CacheEntry(retval, persistent=True) + + retval = self._ephem_cache.get( + link=link, + package_name=package_name, + supported_tags=supported_tags, + ) + if retval is not link: + return CacheEntry(retval, persistent=False) + + return None + + @staticmethod + def record_download_origin(cache_dir: str, download_info: DirectUrl) -> None: + origin_path = Path(cache_dir) / ORIGIN_JSON_NAME + if origin_path.exists(): + try: + origin = DirectUrl.from_json(origin_path.read_text(encoding="utf-8")) + except Exception as e: + logger.warning( + "Could not read origin file %s in cache entry (%s). " + "Will attempt to overwrite it.", + origin_path, + e, + ) + else: + # TODO: use DirectUrl.equivalent when + # https://github.com/pypa/pip/pull/10564 is merged. + if origin.url != download_info.url: + logger.warning( + "Origin URL %s in cache entry %s does not match download URL " + "%s. This is likely a pip bug or a cache corruption issue. " + "Will overwrite it with the new value.", + origin.url, + cache_dir, + download_info.url, + ) + origin_path.write_text(download_info.to_json(), encoding="utf-8") diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/cli/__init__.py new file mode 100644 index 0000000..e589bb9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/__init__.py @@ -0,0 +1,4 @@ +"""Subpackage containing all of pip's command line interface related code +""" + +# This file intentionally does not import submodules diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d423baeb2aadf39bbb9a24894621cd1c416104a2 GIT binary patch literal 282 zcmXv~J5B>Z4BZJ4M3Hibktk3K*d8Go3K~QK9U5umopDwc^V94kXsNjaXQ1IC+#oF% zK%}F>BPFl#d$#3g`)je7H;mKI2YTc9UBv-nPj)jV?~QGqno%q#ueXouE`fQ59;Jz) z00j!Y1m|R2$wcXF;Jo(`taKDmQYe^LU{GdsP|$MO;{1LowkKNKXte%lcGc|vuOa=8b_^WNk!|6 gG;U{CKH9az>wL_P^~jnx`!P0Xt+?DgXcg literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2513439e9790981ae85d9cdf8cd5d10c54d52b3 GIT binary patch literal 8610 zcmb_hX>c1ycJ2WN_kHm`K#?K^@zQBYBrRE%D2dTQQHNzSR6r0jqyT{c-2-0oV2j@M z)`DK82wHXsrMAjcl`5vnPE7xa>@l|D!~u%1Y%&UJoz; z#pPP-BwdA`H$AUkzkaW~-`5YnGMV%UO6}jB3kYQh{hqwYMVBMi?gBA~7}Sdxicy59 zUP^i@dKJ=B*{g)7GDHundQ}wRp+o9nO|NEH+p8Vc_3DQ8y?Uu#6*3GPdyNvU4w;6{ zz2;#{uSI&-gsj81UK`LhM)wxoYiIPVj&+p6*o=X7GDcR*YNR(UtIxI%Y8ex7x)?L- zU@Y*{0*};VP|aB3OVOmlW54$DsmM^k?~Y#aMcpHjaTarK-)J=Aj|`85*k~XUb_c>- z)E5e|jC)|x-QPbF7;zWA_V>5wza^$PA|B5dV_Rym8aClPGc12n28wjx?eJa33 zMQ!&8k>?8mr`?ZPUzGI@1HX5~hdCB|6ru^_4*S9k=Vb!^sA$eHW5kqEi`*8q%2ZwkJ%nPQMNG}3qv$foiD`HZPmdvvx~}Cl zF*Sw46peUwLh)vhS2LQc+YrL8s6&<%bjnoW$*5%c6yg=Z;=&i1Vze@c5lv8-20k^T z8$&TIuf@qInT%BOv(SN@a=Eqe%zxMOx?p9YU8WfQM+SMMqiDw9R}3M);&L0z)4&^o zRWe`UxtX@SUY3C?H}A!xtS@0z8aL;dRb20&QOpSA8gT<}1Z#t@VuomqJT{-#ltR}n zH2QzGF`Q;#V$eXMWzbRtNRdH!!^7LdhaN-%M`TklIgM)T_e6!U4IpJ3akWqPnHo`_MEID;IQ-d&CUZR zZ(+tlmOjWWfwkfQeie~0>H_<3wpUWUEd1XJ0P!wcje?&O7fsr6l|F-^MsY`p;3Yg)4VdcUsCd!3N$LqX#_TpmGNakI5RdD@Ds6lIeaeBQT#Gr0XFIYUH@;ph5n(tMY1t{{UD9PbsN@6 z#WVhQt&2nJPM*R_$j_E8c#N?Jj}$B-Q#?&}#fE*gNtEH&uWJ`?&+aSOuXcGX`APkN z({@r(i=qUrNTm*8h>?ssrg#k{l-K`Z98D-+L*tZRL6MWeFb=gu+47V7~vOEQx9>=w|&Tte@y3a-e;i!8sg4ba?cVy5_0Gb;hnVTCO$l)+|M8a`gi)cIB zb=G_M;)QPSk?zxHPjz1CJR|A}>Alo_?&$d(eT2MxOE8j%MEVLF8WE{xKzlTIB{DAR zM#DLPc>w^PJ{0l$Lf%L?G%0Fw?IJzmi(V0_7cq$_-;(N@qPbb5+@39>BEpH991;|j z01rhKHxdd&MJ3Ef)OUp$cA^vG2*z5X038A(iU~RrmE0sJ((DBA>H*;5C^sI6Ucm

        I+B00iti%H_VEv5lqH(5curPA!HW7ZS)F< ziFZYH7U+tWtO3157cU@dOt6org;t3{G@ZYA_UyUN^XI)MI!~Py_1;h0v}UbBOI=-{_GpO7 zPC0K-Q3;+C6(PS!6Vr;i!k3awIuPABOwMTVSbjN*N*G&Gzzg0HsR>axg4waGiKsD= zx++?7-pCt9C3!_uXSEh}@brd!18hj70wN7>;N8KHFB)aTEF($c2o`jIU-_@0BW-;n zI5LEN!^45_P~Uij+@gkA>}O#Oje+4Jc(QN6=f4Ve?}PWTzEgpLJ`T*@JOZu0A(rcd z+f^%YgD2pk)anlfTA#g*wTw)P#&u0Bz6gpDK+g5i2u-0?HPV*f-txirTiXRqQ$}lk zqDDsZOxtwZ%)#k{$);sP!$`F{G&TRx*J+|3W!X3W;9N^+;PR zXtsP~C`%6BGt|L&Gbg4`Bzmr&{HCrkUH5`e_rfBVs%u|zw?9V88vW;%RiwN?>7hPM z>6f&XkF>~Gvtsw8?2Yjw8C%I*iEkrbfr68(IHfHd_gZ&bSzh#UQ?+`&A+QS zoj96t6sH~af}=j|*eN)6E^b+N?9Dh!(#{6K*|0FS=vy3ExF$Fc5FK4ws#FMx~(K_-6B}G%_lzeNy6;X3O(%d^SMvybQ@2vmxNv;&m0y>1BHfRCjwJ}j8wp{sVj zJLTFF*MH-vOgriXM_t;nXW6j_W^1v}OiWMwVt=}Pr%=8#W!agr7H9Ui|I+-K`3uLt zRexE1Z~v=nN=1eJ{{B}NE+sA{{qF~E2JShxE$x5x5ov#f6gK;;1}5g*yJ|+Qdl!4| zx<0pkRw}d{NjZ-~y+>~> zJMVVg+ufNsoOu167Zx;ejbK0ayZYv3`|(>tH<_ew-nMA_wBnPByF*{^JeK8}A0k}G zAC~RP80{IOEn_T78!H84W!l&*7@OBLbh$om0Ye+hSHLHl#p;yvaJ=(=^R86U?mHLf zFC^)t@14noi}B-2MY|sqRmP8HN~)5t-_*sszOlFxzPBfnugo95`Pw{Qppustn0uAG zGS<@MdBN&V=vIujgy(Bx#bX01u3ELDZ7u1B_InNODNBdY&^}+2pyo_BOiK;zaeB$p zk?la;rU6eBxGn(zjUiY11c7 zcgMfpb^NcX`F5fBM9SQ?to^eUTJy6LZ=Q(v{Pg5^Pu@@F#)#t98~@s$OjT361B%Ad1%S(6A+f^e(>_50 z88#FqpVommz5qZ37%>YPK&gn^e}(m5&5oH(K(_tC`;;Tw?8jy+<;i~FL$+*ox^0%Y z=JSbPDVd{qTl*XtWZVs;z;`%ekd=09@hRBqKmZ$=-YW``g_S2y}Qnz(E**97R^> zx~`JAKia+J*&vsdnhh`HmP{hb04qmMmdOT|Ttv+OA17VyH;*&VgqcEo%>`XgR-PQF z4!g-Ak9{y_611PO3d#7iLi@&HhEJSZ7n;cQnR*aJL@6GoEfeB(xs-oJzI6 zoNhfWw4VOr%Ga%zu2X`e@hL|R$DiyzNPVg~Na0?1!FH%ThJy0g4Gp5kH^31mLaN5^ zXE{h#o%42|#H{pC@-ZSc zn2n}7vYWi59S?$7j-<&*WF_ULtc@C>36ttw!tfNTtO1_bQF-P24L2L!Z@$^Qph=bO z5a{BmuK2`?!!@^WcHi8g*+cUOQjX@SQx6TMnFG@Y5`DLKeX#G=zGXurNkCX^Gvm|a zX-lB-h?*7_Ty<&IHHOw~5HO)39Cl|J)?9C}- z^CJf+@RTE9`zM{|&VAHB+qXjPQDD+^##1b6yj~{a_j?2;y)+U0I4oOC2Bi{Bg|-sJ%}gZm26Tj1{K^PDe94e zqG)glWqp8j50L&hsQkBRM+)uuchvD)^wMuo+nPE^QP$O7rHis=jMju>x@%RUt7@`O v&(6i#JCzdsjS4QeZ(d$g0q^RL3aVw^v5Mfa$Vrd86JIDli#;JNl6wCG)rGd9 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e0037274bc07069167cb180cebf4494bacca60c GIT binary patch literal 10512 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e67c0017a5513bf553187aa9a6e48629d38e6698 GIT binary patch literal 30405 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 RcVbao>VEw@0zJ0d{{_p@xxWAa literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f376b2831033d165fd82350ca942abe7a8953402 GIT binary patch literal 2304 zcma)7O>7fK6rTO{`X_c`f)fk@CpZX$k~At31*H{~L=|cjP&l+~U0I8FaM$dgW;efb zAO{YKgcNQyDis`4fvVoxQ&kX^D)o|xNI?rxkxCET0!gI`E`77kW`SNhO8mb0-prdf zZ{Bq}1Ne96naF9lfu z$?2jIkt2pAOAOt|>ro>n$9yd4aU&rod@SlsMp91tIHISFX1UqNlHOvZgxTtW zz^PE;);mmNCht@eY7|R2f-}2-qW@|Pw_W7b_*Fq}pJEG5)48)mGZZqFQ*2w;%8IL5 zW)7P!nX)a-bbDjZsj-m)>+!>y<9gB=n=VoG0^=o=G1n?vhOJ{4!@S8>h=WVO7>cO^ zkt`FexNkDjSmsQN!`xb4A~ zYBoTj4EzPl+Zj>a6Y2w`GU3YeP?0m-W$xOK4LQL~ph@mLnqc70VSMw!-cUjuax=WU zT~pOUs0)x9sqsOa8RVbEU*@m<24{f`&nm=5o>P}SQLC61!PBYUL-wUgiD1VXBW3Iq zI8Ri{w3IvvN&r_ZGUbVerH<)%Ix;jmdS>)^&O_7Pr|EvptmH5)n_Rb(oA?TwIS0Eg zWp%5pz>Zi?kLFl97@~D2ZR0kNbEX`>y2d?eLLnw>a=he4O?NTbo~H-HQv9s3h(xLT z8O?NDMb}GPOG~;{semW6vy{aag-h zbl?U(Hn2(sJ4IWw`(QN$3wmB(S=aigOTG3K>4ua1pFRK%baOO|9!27_wI`|c!sPs9 zovE{PwK;w>frO@2e)lrJ`%$WGrR&Jjha-P;tRQa2kkGu!A6VuOtnde)@y%C9)_Fl_ zebRAg@yNrD_m-vXoOJ!*dNVJaWS&ULRjGYhYQLGe)p4U^kzJ7vZ%QcDQUCmhJ-@Us z^`BlzemeWf(|CGeV1A%3J&boQ@tyx{cA!M-OT>XyDZUV!k2Q?ckKTU&c6WW>id1-u zznQ+3y^&p!@|2b4rRyyV@%i}c^#~Yvy_rS{-}+0$f=AD!R^1ocf&uB06&YH&O%xPp~``b!LKkR=Hokk(-cw0T@YP!>?q-X`Z z!;K7=N`4x{CHGU;Imaa)2RY_v(|2eCNJMCZ_oRVFNBD>whbe6+&KK~r&M^%0f@K(f zLqtsSF@nG7V-$OgQh%V%ztFKYbaV~%uc4kbbogmBJJ+@v%`Qi?^$#9K^RwcMflj7t ZZnDnT&)tYFr@Gb=%ood>RFGp}|6hUcB;No4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e38326dd08e7d828c085dde784f5cab27486479 GIT binary patch literal 4910 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 OkChL;{8%UId;Bj{ZEIHm literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bafd644d708adf6a2631e2c214766d45ed027c2e GIT binary patch literal 15044 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 j@Fef&{qw$0*2&o!9L!@4sL zff@xx`G9QHAZ@jwYFDDtek2O5=wCip%}=HNn7|4;q3y1^AC1%xZ%LbN)sLP#_817e z-HUwhxo6Hf_uPA){GqBUh+rK2%|PaTfc{E1-UyX}tvUvwdq_npqoG7;WfBbReVR{a z6Rgf9IGs=Mxh$_Vy$kbNgWi~EWDsUCkDHo7nNbG&OHkTJ_laiJ?|oAR+@gwDz^(L) z8o(TGQW=#=vvi*p)!;2Iv2O?cm(%*y5YV;(xAaS9kKE?8U#+_3Pqa@mvG6mHjV{Oh zj@YAUnlhqcC(wrtOcdKBj(E`qh$2gni@TDwGp3i1b70 zmLm#D+LKxAa2Dw7_zAXi#7KerxWfmt2)~2y+j4GMeCZE`O^Mr&W?K6Jf{ZKV21fAGtKAu@p=!xy{aL*(c5`9 zRHZ3EO~H%g*`+G)C8qs({sg>u9$i3hA3$hY$P4fJ?lFMj$7z(jH1dAC)kEb4PvfPq zCyzmQ4sj?z10DXhv6EonOO)6gd65iIAxMdgek+hbT(aaze~wyc{fjyr6|NKYO9aklLLaTQxBl5u0{?Vs3+ zb#*6Z+TpZ}fk#W)e|{F+mba)=J1n*prNUkk;aJ$=(-4_9p_V3LI#I77wREbc6E!%Y>6B2T5(y?pR8%!d)gyIu>(6CX zh$e^Cun`jpH79AH6Ez{Bap4FlHx*cp=-t&3sDNZfb@k!Ms6Q-FmbsduwhA_PbVQP}e;SnWu6&va>?5_=9%8U$K5Vc3MfK^7ZHJr_4j{!9V zGGwM>DJ^r%J3I+7ZN;;bPHmE8Qt)JD15iAPgCb4vv;Gd#-_YkXs3;++Zr*+pYAtY= z3T>BGVGgx^5{hhA*U#g3rCI({siDw#ZdE$JDK#&A{XV-U9odvxR;7KLQpc*ae^Y8( zl{$(c|FPhlP^?BZ^}AT=-|62?-7ue9mD)5af{nu)T3*S6{vgai8yVHkzj^r3minh8~4Ix@a-HS;E}GU6Y4psa+Y>wP;F@D+qwhOJ+%EM z<2$KbQiR4U`M!*RMP>5n7f?g;49x8Ny!S@TSIPQ6??AIxjJrG)c%$t3@)ReVY1v_d zG0tJFNz3tDwrb{Vho2x2RWwiJtg)Dnd=pf1uWC{KWtkj>#RQ#+P3+!9 z@R8WE1#E~=J<3_Ja5l!%tZEbbh_rrvU6)M?#Kkh3$I71zws zQL3ohU+^Q7HnyB5@81Y7XAQXa#{}|~O~@&FF0I|J4cy0kfZQi2MXuNlJy%Y{XUJtB zqV>!AGfYL6VVI|=`Y8(j1@*6^{uf+`@x4Ia^v@Q=bp8o-ecXC*@kjUZuabpBCzh{& z$p7|6;m~UPC+@I&&`=d7T}^EMQV!zg+vsJ&UeloEe7Z=i2RY++`PJQ zp#b*e_iu$L_H`!8)K&Na2L3XaKzHKHTmg!Wqoc?F!AihcQ&)7?eTNnYfBt% literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7b6687896c46840425944ff3a427fec307b1a86 GIT binary patch literal 12245 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 S_d8C>f2(Kv7mNV0wEqQ^q#h;! literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e2c5c9eb0e214abfff5c7c54e6ab9a6aec0d8e6 GIT binary patch literal 7837 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53e3c8e9ab66cc5dcddab8ce821da0c770e983b3 GIT binary patch literal 379 zcmXw!F-yZh6vr=3)7DC`#Yziy6NC=hT|}s9#9+P1rKu1CN18iIFv*1^t#s?R@H4ph zMO^9@vO0AWx;c5F^$oxG{*T}BxKCNG172qz$V++uF2a8a`(fMV!y6#L0z|L`QnE@! zv_w+2%0#lHWu;f$6zZmUuqhP~3zQ4AIbg4nR}E89RKv(66(JqvvI!rc{tWRhwk8@H zn}d-GCm8Bue5admn0KC#I?;5~z_+G08sedb_I?BE_;D~+?p0&wzJo2l1b(SohR63geI5KGOt|+jLdy{6F2$Q;^WCV$B!roLRLRqRkPZ`O3E6|m7KLZ UYtYJ0yKB(Nj!(WoBR=BlA4XqnWB>pF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/autocompletion.py b/backend/venv/Lib/site-packages/pip/_internal/cli/autocompletion.py new file mode 100644 index 0000000..f3f70ac --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/autocompletion.py @@ -0,0 +1,176 @@ +"""Logic that powers autocompletion installed by ``pip completion``. +""" + +import optparse +import os +import sys +from itertools import chain +from typing import Any, Iterable, List, Optional + +from pip._internal.cli.main_parser import create_main_parser +from pip._internal.commands import commands_dict, create_command +from pip._internal.metadata import get_default_environment + + +def autocomplete() -> None: + """Entry Point for completion of main and subcommand options.""" + # Don't complete if user hasn't sourced bash_completion file. + if "PIP_AUTO_COMPLETE" not in os.environ: + return + # Don't complete if autocompletion environment variables + # are not present + if not os.environ.get("COMP_WORDS") or not os.environ.get("COMP_CWORD"): + return + cwords = os.environ["COMP_WORDS"].split()[1:] + cword = int(os.environ["COMP_CWORD"]) + try: + current = cwords[cword - 1] + except IndexError: + current = "" + + parser = create_main_parser() + subcommands = list(commands_dict) + options = [] + + # subcommand + subcommand_name: Optional[str] = None + for word in cwords: + if word in subcommands: + subcommand_name = word + break + # subcommand options + if subcommand_name is not None: + # special case: 'help' subcommand has no options + if subcommand_name == "help": + sys.exit(1) + # special case: list locally installed dists for show and uninstall + should_list_installed = not current.startswith("-") and subcommand_name in [ + "show", + "uninstall", + ] + if should_list_installed: + env = get_default_environment() + lc = current.lower() + installed = [ + dist.canonical_name + for dist in env.iter_installed_distributions(local_only=True) + if dist.canonical_name.startswith(lc) + and dist.canonical_name not in cwords[1:] + ] + # if there are no dists installed, fall back to option completion + if installed: + for dist in installed: + print(dist) + sys.exit(1) + + should_list_installables = ( + not current.startswith("-") and subcommand_name == "install" + ) + if should_list_installables: + for path in auto_complete_paths(current, "path"): + print(path) + sys.exit(1) + + subcommand = create_command(subcommand_name) + + for opt in subcommand.parser.option_list_all: + if opt.help != optparse.SUPPRESS_HELP: + options += [ + (opt_str, opt.nargs) for opt_str in opt._long_opts + opt._short_opts + ] + + # filter out previously specified options from available options + prev_opts = [x.split("=")[0] for x in cwords[1 : cword - 1]] + options = [(x, v) for (x, v) in options if x not in prev_opts] + # filter options by current input + options = [(k, v) for k, v in options if k.startswith(current)] + # get completion type given cwords and available subcommand options + completion_type = get_path_completion_type( + cwords, + cword, + subcommand.parser.option_list_all, + ) + # get completion files and directories if ``completion_type`` is + # ````, ``

        `` or ```` + if completion_type: + paths = auto_complete_paths(current, completion_type) + options = [(path, 0) for path in paths] + for option in options: + opt_label = option[0] + # append '=' to options which require args + if option[1] and option[0][:2] == "--": + opt_label += "=" + print(opt_label) + else: + # show main parser options only when necessary + + opts = [i.option_list for i in parser.option_groups] + opts.append(parser.option_list) + flattened_opts = chain.from_iterable(opts) + if current.startswith("-"): + for opt in flattened_opts: + if opt.help != optparse.SUPPRESS_HELP: + subcommands += opt._long_opts + opt._short_opts + else: + # get completion type given cwords and all available options + completion_type = get_path_completion_type(cwords, cword, flattened_opts) + if completion_type: + subcommands = list(auto_complete_paths(current, completion_type)) + + print(" ".join([x for x in subcommands if x.startswith(current)])) + sys.exit(1) + + +def get_path_completion_type( + cwords: List[str], cword: int, opts: Iterable[Any] +) -> Optional[str]: + """Get the type of path completion (``file``, ``dir``, ``path`` or None) + + :param cwords: same as the environmental variable ``COMP_WORDS`` + :param cword: same as the environmental variable ``COMP_CWORD`` + :param opts: The available options to check + :return: path completion type (``file``, ``dir``, ``path`` or None) + """ + if cword < 2 or not cwords[cword - 2].startswith("-"): + return None + for opt in opts: + if opt.help == optparse.SUPPRESS_HELP: + continue + for o in str(opt).split("/"): + if cwords[cword - 2].split("=")[0] == o: + if not opt.metavar or any( + x in ("path", "file", "dir") for x in opt.metavar.split("/") + ): + return opt.metavar + return None + + +def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]: + """If ``completion_type`` is ``file`` or ``path``, list all regular files + and directories starting with ``current``; otherwise only list directories + starting with ``current``. + + :param current: The word to be completed + :param completion_type: path completion type(``file``, ``path`` or ``dir``) + :return: A generator of regular files and/or directories + """ + directory, filename = os.path.split(current) + current_path = os.path.abspath(directory) + # Don't complete paths if they can't be accessed + if not os.access(current_path, os.R_OK): + return + filename = os.path.normcase(filename) + # list all files that start with ``filename`` + file_list = ( + x for x in os.listdir(current_path) if os.path.normcase(x).startswith(filename) + ) + for f in file_list: + opt = os.path.join(current_path, f) + comp_file = os.path.normcase(os.path.join(directory, f)) + # complete regular files when there is not ```` after option + # complete directories when there is ````, ```` or + # ````after option + if completion_type != "dir" and os.path.isfile(opt): + yield comp_file + elif os.path.isdir(opt): + yield os.path.join(comp_file, "") diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/base_command.py b/backend/venv/Lib/site-packages/pip/_internal/cli/base_command.py new file mode 100644 index 0000000..362f84b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/base_command.py @@ -0,0 +1,240 @@ +"""Base Command class, and related routines""" + +import logging +import logging.config +import optparse +import os +import sys +import traceback +from optparse import Values +from typing import List, Optional, Tuple + +from pip._vendor.rich import reconfigure +from pip._vendor.rich import traceback as rich_traceback + +from pip._internal.cli import cmdoptions +from pip._internal.cli.command_context import CommandContextMixIn +from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter +from pip._internal.cli.status_codes import ( + ERROR, + PREVIOUS_BUILD_DIR_ERROR, + UNKNOWN_ERROR, + VIRTUALENV_NOT_FOUND, +) +from pip._internal.exceptions import ( + BadCommand, + CommandError, + DiagnosticPipError, + InstallationError, + NetworkConnectionError, + PreviousBuildDirError, +) +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging +from pip._internal.utils.misc import get_prog, normalize_path +from pip._internal.utils.temp_dir import TempDirectoryTypeRegistry as TempDirRegistry +from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry +from pip._internal.utils.virtualenv import running_under_virtualenv + +__all__ = ["Command"] + +logger = logging.getLogger(__name__) + + +class Command(CommandContextMixIn): + usage: str = "" + ignore_require_venv: bool = False + + def __init__(self, name: str, summary: str, isolated: bool = False) -> None: + super().__init__() + + self.name = name + self.summary = summary + self.parser = ConfigOptionParser( + usage=self.usage, + prog=f"{get_prog()} {name}", + formatter=UpdatingDefaultsHelpFormatter(), + add_help_option=False, + name=name, + description=self.__doc__, + isolated=isolated, + ) + + self.tempdir_registry: Optional[TempDirRegistry] = None + + # Commands should add options to this option group + optgroup_name = f"{self.name.capitalize()} Options" + self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) + + # Add the general options + gen_opts = cmdoptions.make_option_group( + cmdoptions.general_group, + self.parser, + ) + self.parser.add_option_group(gen_opts) + + self.add_options() + + def add_options(self) -> None: + pass + + def handle_pip_version_check(self, options: Values) -> None: + """ + This is a no-op so that commands by default do not do the pip version + check. + """ + # Make sure we do the pip version check if the index_group options + # are present. + assert not hasattr(options, "no_index") + + def run(self, options: Values, args: List[str]) -> int: + raise NotImplementedError + + def _run_wrapper(self, level_number: int, options: Values, args: List[str]) -> int: + def _inner_run() -> int: + try: + return self.run(options, args) + finally: + self.handle_pip_version_check(options) + + if options.debug_mode: + rich_traceback.install(show_locals=True) + return _inner_run() + + try: + status = _inner_run() + assert isinstance(status, int) + return status + except DiagnosticPipError as exc: + logger.error("%s", exc, extra={"rich": True}) + logger.debug("Exception information:", exc_info=True) + + return ERROR + except PreviousBuildDirError as exc: + logger.critical(str(exc)) + logger.debug("Exception information:", exc_info=True) + + return PREVIOUS_BUILD_DIR_ERROR + except ( + InstallationError, + BadCommand, + NetworkConnectionError, + ) as exc: + logger.critical(str(exc)) + logger.debug("Exception information:", exc_info=True) + + return ERROR + except CommandError as exc: + logger.critical("%s", exc) + logger.debug("Exception information:", exc_info=True) + + return ERROR + except BrokenStdoutLoggingError: + # Bypass our logger and write any remaining messages to + # stderr because stdout no longer works. + print("ERROR: Pipe to stdout was broken", file=sys.stderr) + if level_number <= logging.DEBUG: + traceback.print_exc(file=sys.stderr) + + return ERROR + except KeyboardInterrupt: + logger.critical("Operation cancelled by user") + logger.debug("Exception information:", exc_info=True) + + return ERROR + except BaseException: + logger.critical("Exception:", exc_info=True) + + return UNKNOWN_ERROR + + def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]: + # factored out for testability + return self.parser.parse_args(args) + + def main(self, args: List[str]) -> int: + try: + with self.main_context(): + return self._main(args) + finally: + logging.shutdown() + + def _main(self, args: List[str]) -> int: + # We must initialize this before the tempdir manager, otherwise the + # configuration would not be accessible by the time we clean up the + # tempdir manager. + self.tempdir_registry = self.enter_context(tempdir_registry()) + # Intentionally set as early as possible so globally-managed temporary + # directories are available to the rest of the code. + self.enter_context(global_tempdir_manager()) + + options, args = self.parse_args(args) + + # Set verbosity so that it can be used elsewhere. + self.verbosity = options.verbose - options.quiet + + reconfigure(no_color=options.no_color) + level_number = setup_logging( + verbosity=self.verbosity, + no_color=options.no_color, + user_log_file=options.log, + ) + + always_enabled_features = set(options.features_enabled) & set( + cmdoptions.ALWAYS_ENABLED_FEATURES + ) + if always_enabled_features: + logger.warning( + "The following features are always enabled: %s. ", + ", ".join(sorted(always_enabled_features)), + ) + + # Make sure that the --python argument isn't specified after the + # subcommand. We can tell, because if --python was specified, + # we should only reach this point if we're running in the created + # subprocess, which has the _PIP_RUNNING_IN_SUBPROCESS environment + # variable set. + if options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ: + logger.critical( + "The --python option must be placed before the pip subcommand name" + ) + sys.exit(ERROR) + + # TODO: Try to get these passing down from the command? + # without resorting to os.environ to hold these. + # This also affects isolated builds and it should. + + if options.no_input: + os.environ["PIP_NO_INPUT"] = "1" + + if options.exists_action: + os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action) + + if options.require_venv and not self.ignore_require_venv: + # If a venv is required check if it can really be found + if not running_under_virtualenv(): + logger.critical("Could not find an activated virtualenv (required).") + sys.exit(VIRTUALENV_NOT_FOUND) + + if options.cache_dir: + options.cache_dir = normalize_path(options.cache_dir) + if not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "or is not writable by the current user. The cache " + "has been disabled. Check the permissions and owner of " + "that directory. If executing pip with sudo, you should " + "use sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + if options.no_python_version_warning: + deprecated( + reason="--no-python-version-warning is deprecated.", + replacement="to remove the flag as it's a no-op", + gone_in="25.1", + issue=13154, + ) + + return self._run_wrapper(level_number, options, args) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py b/backend/venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py new file mode 100644 index 0000000..eeb7e65 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py @@ -0,0 +1,1075 @@ +""" +shared options and groups + +The principle here is to define options once, but *not* instantiate them +globally. One reason being that options with action='append' can carry state +between parses. pip parses general options twice internally, and shouldn't +pass on state. To be consistent, all options will follow this design. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import importlib.util +import logging +import os +import textwrap +from functools import partial +from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values +from textwrap import dedent +from typing import Any, Callable, Dict, Optional, Tuple + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli.parser import ConfigOptionParser +from pip._internal.exceptions import CommandError +from pip._internal.locations import USER_CACHE_DIR, get_src_prefix +from pip._internal.models.format_control import FormatControl +from pip._internal.models.index import PyPI +from pip._internal.models.target_python import TargetPython +from pip._internal.utils.hashes import STRONG_HASHES +from pip._internal.utils.misc import strtobool + +logger = logging.getLogger(__name__) + + +def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None: + """ + Raise an option parsing error using parser.error(). + + Args: + parser: an OptionParser instance. + option: an Option instance. + msg: the error text. + """ + msg = f"{option} error: {msg}" + msg = textwrap.fill(" ".join(msg.split())) + parser.error(msg) + + +def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup: + """ + Return an OptionGroup object + group -- assumed to be dict with 'name' and 'options' keys + parser -- an optparse Parser + """ + option_group = OptionGroup(parser, group["name"]) + for option in group["options"]: + option_group.add_option(option()) + return option_group + + +def check_dist_restriction(options: Values, check_target: bool = False) -> None: + """Function for determining if custom platform options are allowed. + + :param options: The OptionParser options. + :param check_target: Whether or not to check if --target is being used. + """ + dist_restriction_set = any( + [ + options.python_version, + options.platforms, + options.abis, + options.implementation, + ] + ) + + binary_only = FormatControl(set(), {":all:"}) + sdist_dependencies_allowed = ( + options.format_control != binary_only and not options.ignore_dependencies + ) + + # Installations or downloads using dist restrictions must not combine + # source distributions and dist-specific wheels, as they are not + # guaranteed to be locally compatible. + if dist_restriction_set and sdist_dependencies_allowed: + raise CommandError( + "When restricting platform and interpreter constraints using " + "--python-version, --platform, --abi, or --implementation, " + "either --no-deps must be set, or --only-binary=:all: must be " + "set and --no-binary must not be set (or must be set to " + ":none:)." + ) + + if check_target: + if not options.dry_run and dist_restriction_set and not options.target_dir: + raise CommandError( + "Can not use any platform or abi specific options unless " + "installing via '--target' or using '--dry-run'" + ) + + +def _path_option_check(option: Option, opt: str, value: str) -> str: + return os.path.expanduser(value) + + +def _package_name_option_check(option: Option, opt: str, value: str) -> str: + return canonicalize_name(value) + + +class PipOption(Option): + TYPES = Option.TYPES + ("path", "package_name") + TYPE_CHECKER = Option.TYPE_CHECKER.copy() + TYPE_CHECKER["package_name"] = _package_name_option_check + TYPE_CHECKER["path"] = _path_option_check + + +########### +# options # +########### + +help_: Callable[..., Option] = partial( + Option, + "-h", + "--help", + dest="help", + action="help", + help="Show help.", +) + +debug_mode: Callable[..., Option] = partial( + Option, + "--debug", + dest="debug_mode", + action="store_true", + default=False, + help=( + "Let unhandled exceptions propagate outside the main subroutine, " + "instead of logging them to stderr." + ), +) + +isolated_mode: Callable[..., Option] = partial( + Option, + "--isolated", + dest="isolated_mode", + action="store_true", + default=False, + help=( + "Run pip in an isolated mode, ignoring environment variables and user " + "configuration." + ), +) + +require_virtualenv: Callable[..., Option] = partial( + Option, + "--require-virtualenv", + "--require-venv", + dest="require_venv", + action="store_true", + default=False, + help=( + "Allow pip to only run in a virtual environment; " + "exit with an error otherwise." + ), +) + +override_externally_managed: Callable[..., Option] = partial( + Option, + "--break-system-packages", + dest="override_externally_managed", + action="store_true", + help="Allow pip to modify an EXTERNALLY-MANAGED Python installation", +) + +python: Callable[..., Option] = partial( + Option, + "--python", + dest="python", + help="Run pip with the specified Python interpreter.", +) + +verbose: Callable[..., Option] = partial( + Option, + "-v", + "--verbose", + dest="verbose", + action="count", + default=0, + help="Give more output. Option is additive, and can be used up to 3 times.", +) + +no_color: Callable[..., Option] = partial( + Option, + "--no-color", + dest="no_color", + action="store_true", + default=False, + help="Suppress colored output.", +) + +version: Callable[..., Option] = partial( + Option, + "-V", + "--version", + dest="version", + action="store_true", + help="Show version and exit.", +) + +quiet: Callable[..., Option] = partial( + Option, + "-q", + "--quiet", + dest="quiet", + action="count", + default=0, + help=( + "Give less output. Option is additive, and can be used up to 3" + " times (corresponding to WARNING, ERROR, and CRITICAL logging" + " levels)." + ), +) + +progress_bar: Callable[..., Option] = partial( + Option, + "--progress-bar", + dest="progress_bar", + type="choice", + choices=["on", "off", "raw"], + default="on", + help="Specify whether the progress bar should be used [on, off, raw] (default: on)", +) + +log: Callable[..., Option] = partial( + PipOption, + "--log", + "--log-file", + "--local-log", + dest="log", + metavar="path", + type="path", + help="Path to a verbose appending log.", +) + +no_input: Callable[..., Option] = partial( + Option, + # Don't ask for input + "--no-input", + dest="no_input", + action="store_true", + default=False, + help="Disable prompting for input.", +) + +keyring_provider: Callable[..., Option] = partial( + Option, + "--keyring-provider", + dest="keyring_provider", + choices=["auto", "disabled", "import", "subprocess"], + default="auto", + help=( + "Enable the credential lookup via the keyring library if user input is allowed." + " Specify which mechanism to use [auto, disabled, import, subprocess]." + " (default: %default)" + ), +) + +proxy: Callable[..., Option] = partial( + Option, + "--proxy", + dest="proxy", + type="str", + default="", + help="Specify a proxy in the form scheme://[user:passwd@]proxy.server:port.", +) + +retries: Callable[..., Option] = partial( + Option, + "--retries", + dest="retries", + type="int", + default=5, + help="Maximum number of retries each connection should attempt " + "(default %default times).", +) + +timeout: Callable[..., Option] = partial( + Option, + "--timeout", + "--default-timeout", + metavar="sec", + dest="timeout", + type="float", + default=15, + help="Set the socket timeout (default %default seconds).", +) + + +def exists_action() -> Option: + return Option( + # Option when path already exist + "--exists-action", + dest="exists_action", + type="choice", + choices=["s", "i", "w", "b", "a"], + default=[], + action="append", + metavar="action", + help="Default action when a path already exists: " + "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", + ) + + +cert: Callable[..., Option] = partial( + PipOption, + "--cert", + dest="cert", + type="path", + metavar="path", + help=( + "Path to PEM-encoded CA certificate bundle. " + "If provided, overrides the default. " + "See 'SSL Certificate Verification' in pip documentation " + "for more information." + ), +) + +client_cert: Callable[..., Option] = partial( + PipOption, + "--client-cert", + dest="client_cert", + type="path", + default=None, + metavar="path", + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM format.", +) + +index_url: Callable[..., Option] = partial( + Option, + "-i", + "--index-url", + "--pypi-url", + dest="index_url", + metavar="URL", + default=PyPI.simple_url, + help="Base URL of the Python Package Index (default %default). " + "This should point to a repository compliant with PEP 503 " + "(the simple repository API) or a local directory laid out " + "in the same format.", +) + + +def extra_index_url() -> Option: + return Option( + "--extra-index-url", + dest="extra_index_urls", + metavar="URL", + action="append", + default=[], + help="Extra URLs of package indexes to use in addition to " + "--index-url. Should follow the same rules as " + "--index-url.", + ) + + +no_index: Callable[..., Option] = partial( + Option, + "--no-index", + dest="no_index", + action="store_true", + default=False, + help="Ignore package index (only looking at --find-links URLs instead).", +) + + +def find_links() -> Option: + return Option( + "-f", + "--find-links", + dest="find_links", + action="append", + default=[], + metavar="url", + help="If a URL or path to an html file, then parse for links to " + "archives such as sdist (.tar.gz) or wheel (.whl) files. " + "If a local path or file:// URL that's a directory, " + "then look for archives in the directory listing. " + "Links to VCS project URLs are not supported.", + ) + + +def trusted_host() -> Option: + return Option( + "--trusted-host", + dest="trusted_hosts", + action="append", + metavar="HOSTNAME", + default=[], + help="Mark this host or host:port pair as trusted, even though it " + "does not have valid or any HTTPS.", + ) + + +def constraints() -> Option: + return Option( + "-c", + "--constraint", + dest="constraints", + action="append", + default=[], + metavar="file", + help="Constrain versions using the given constraints file. " + "This option can be used multiple times.", + ) + + +def requirements() -> Option: + return Option( + "-r", + "--requirement", + dest="requirements", + action="append", + default=[], + metavar="file", + help="Install from the given requirements file. " + "This option can be used multiple times.", + ) + + +def editable() -> Option: + return Option( + "-e", + "--editable", + dest="editables", + action="append", + default=[], + metavar="path/url", + help=( + "Install a project in editable mode (i.e. setuptools " + '"develop mode") from a local project path or a VCS url.' + ), + ) + + +def _handle_src(option: Option, opt_str: str, value: str, parser: OptionParser) -> None: + value = os.path.abspath(value) + setattr(parser.values, option.dest, value) + + +src: Callable[..., Option] = partial( + PipOption, + "--src", + "--source", + "--source-dir", + "--source-directory", + dest="src_dir", + type="path", + metavar="dir", + default=get_src_prefix(), + action="callback", + callback=_handle_src, + help="Directory to check out editable projects into. " + 'The default in a virtualenv is "/src". ' + 'The default for global installs is "/src".', +) + + +def _get_format_control(values: Values, option: Option) -> Any: + """Get a format_control object.""" + return getattr(values, option.dest) + + +def _handle_no_binary( + option: Option, opt_str: str, value: str, parser: OptionParser +) -> None: + existing = _get_format_control(parser.values, option) + FormatControl.handle_mutual_excludes( + value, + existing.no_binary, + existing.only_binary, + ) + + +def _handle_only_binary( + option: Option, opt_str: str, value: str, parser: OptionParser +) -> None: + existing = _get_format_control(parser.values, option) + FormatControl.handle_mutual_excludes( + value, + existing.only_binary, + existing.no_binary, + ) + + +def no_binary() -> Option: + format_control = FormatControl(set(), set()) + return Option( + "--no-binary", + dest="format_control", + action="callback", + callback=_handle_no_binary, + type="str", + default=format_control, + help="Do not use binary packages. Can be supplied multiple times, and " + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all binary packages, ":none:" to empty the set (notice ' + "the colons), or one or more package names with commas between " + "them (no colons). Note that some packages are tricky to compile " + "and may fail to install when this option is used on them.", + ) + + +def only_binary() -> Option: + format_control = FormatControl(set(), set()) + return Option( + "--only-binary", + dest="format_control", + action="callback", + callback=_handle_only_binary, + type="str", + default=format_control, + help="Do not use source packages. Can be supplied multiple times, and " + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all source packages, ":none:" to empty the set, or one ' + "or more package names with commas between them. Packages " + "without binary distributions will fail to install when this " + "option is used on them.", + ) + + +platforms: Callable[..., Option] = partial( + Option, + "--platform", + dest="platforms", + metavar="platform", + action="append", + default=None, + help=( + "Only use wheels compatible with . Defaults to the " + "platform of the running system. Use this option multiple times to " + "specify multiple platforms supported by the target interpreter." + ), +) + + +# This was made a separate function for unit-testing purposes. +def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]: + """ + Convert a version string like "3", "37", or "3.7.3" into a tuple of ints. + + :return: A 2-tuple (version_info, error_msg), where `error_msg` is + non-None if and only if there was a parsing error. + """ + if not value: + # The empty string is the same as not providing a value. + return (None, None) + + parts = value.split(".") + if len(parts) > 3: + return ((), "at most three version parts are allowed") + + if len(parts) == 1: + # Then we are in the case of "3" or "37". + value = parts[0] + if len(value) > 1: + parts = [value[0], value[1:]] + + try: + version_info = tuple(int(part) for part in parts) + except ValueError: + return ((), "each version part must be an integer") + + return (version_info, None) + + +def _handle_python_version( + option: Option, opt_str: str, value: str, parser: OptionParser +) -> None: + """ + Handle a provided --python-version value. + """ + version_info, error_msg = _convert_python_version(value) + if error_msg is not None: + msg = f"invalid --python-version value: {value!r}: {error_msg}" + raise_option_error(parser, option=option, msg=msg) + + parser.values.python_version = version_info + + +python_version: Callable[..., Option] = partial( + Option, + "--python-version", + dest="python_version", + metavar="python_version", + action="callback", + callback=_handle_python_version, + type="str", + default=None, + help=dedent( + """\ + The Python interpreter version to use for wheel and "Requires-Python" + compatibility checks. Defaults to a version derived from the running + interpreter. The version can be specified using up to three dot-separated + integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor + version can also be given as a string without dots (e.g. "37" for 3.7.0). + """ + ), +) + + +implementation: Callable[..., Option] = partial( + Option, + "--implementation", + dest="implementation", + metavar="implementation", + default=None, + help=( + "Only use wheels compatible with Python " + "implementation , e.g. 'pp', 'jy', 'cp', " + " or 'ip'. If not specified, then the current " + "interpreter implementation is used. Use 'py' to force " + "implementation-agnostic wheels." + ), +) + + +abis: Callable[..., Option] = partial( + Option, + "--abi", + dest="abis", + metavar="abi", + action="append", + default=None, + help=( + "Only use wheels compatible with Python abi , e.g. 'pypy_41'. " + "If not specified, then the current interpreter abi tag is used. " + "Use this option multiple times to specify multiple abis supported " + "by the target interpreter. Generally you will need to specify " + "--implementation, --platform, and --python-version when using this " + "option." + ), +) + + +def add_target_python_options(cmd_opts: OptionGroup) -> None: + cmd_opts.add_option(platforms()) + cmd_opts.add_option(python_version()) + cmd_opts.add_option(implementation()) + cmd_opts.add_option(abis()) + + +def make_target_python(options: Values) -> TargetPython: + target_python = TargetPython( + platforms=options.platforms, + py_version_info=options.python_version, + abis=options.abis, + implementation=options.implementation, + ) + + return target_python + + +def prefer_binary() -> Option: + return Option( + "--prefer-binary", + dest="prefer_binary", + action="store_true", + default=False, + help=( + "Prefer binary packages over source packages, even if the " + "source packages are newer." + ), + ) + + +cache_dir: Callable[..., Option] = partial( + PipOption, + "--cache-dir", + dest="cache_dir", + default=USER_CACHE_DIR, + metavar="dir", + type="path", + help="Store the cache data in .", +) + + +def _handle_no_cache_dir( + option: Option, opt: str, value: str, parser: OptionParser +) -> None: + """ + Process a value provided for the --no-cache-dir option. + + This is an optparse.Option callback for the --no-cache-dir option. + """ + # The value argument will be None if --no-cache-dir is passed via the + # command-line, since the option doesn't accept arguments. However, + # the value can be non-None if the option is triggered e.g. by an + # environment variable, like PIP_NO_CACHE_DIR=true. + if value is not None: + # Then parse the string value to get argument error-checking. + try: + strtobool(value) + except ValueError as exc: + raise_option_error(parser, option=option, msg=str(exc)) + + # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool() + # converted to 0 (like "false" or "no") caused cache_dir to be disabled + # rather than enabled (logic would say the latter). Thus, we disable + # the cache directory not just on values that parse to True, but (for + # backwards compatibility reasons) also on values that parse to False. + # In other words, always set it to False if the option is provided in + # some (valid) form. + parser.values.cache_dir = False + + +no_cache: Callable[..., Option] = partial( + Option, + "--no-cache-dir", + dest="cache_dir", + action="callback", + callback=_handle_no_cache_dir, + help="Disable the cache.", +) + +no_deps: Callable[..., Option] = partial( + Option, + "--no-deps", + "--no-dependencies", + dest="ignore_dependencies", + action="store_true", + default=False, + help="Don't install package dependencies.", +) + +ignore_requires_python: Callable[..., Option] = partial( + Option, + "--ignore-requires-python", + dest="ignore_requires_python", + action="store_true", + help="Ignore the Requires-Python information.", +) + +no_build_isolation: Callable[..., Option] = partial( + Option, + "--no-build-isolation", + dest="build_isolation", + action="store_false", + default=True, + help="Disable isolation when building a modern source distribution. " + "Build dependencies specified by PEP 518 must be already installed " + "if this option is used.", +) + +check_build_deps: Callable[..., Option] = partial( + Option, + "--check-build-dependencies", + dest="check_build_deps", + action="store_true", + default=False, + help="Check the build dependencies when PEP517 is used.", +) + + +def _handle_no_use_pep517( + option: Option, opt: str, value: str, parser: OptionParser +) -> None: + """ + Process a value provided for the --no-use-pep517 option. + + This is an optparse.Option callback for the no_use_pep517 option. + """ + # Since --no-use-pep517 doesn't accept arguments, the value argument + # will be None if --no-use-pep517 is passed via the command-line. + # However, the value can be non-None if the option is triggered e.g. + # by an environment variable, for example "PIP_NO_USE_PEP517=true". + if value is not None: + msg = """A value was passed for --no-use-pep517, + probably using either the PIP_NO_USE_PEP517 environment variable + or the "no-use-pep517" config file option. Use an appropriate value + of the PIP_USE_PEP517 environment variable or the "use-pep517" + config file option instead. + """ + raise_option_error(parser, option=option, msg=msg) + + # If user doesn't wish to use pep517, we check if setuptools and wheel are installed + # and raise error if it is not. + packages = ("setuptools", "wheel") + if not all(importlib.util.find_spec(package) for package in packages): + msg = ( + f"It is not possible to use --no-use-pep517 " + f"without {' and '.join(packages)} installed." + ) + raise_option_error(parser, option=option, msg=msg) + + # Otherwise, --no-use-pep517 was passed via the command-line. + parser.values.use_pep517 = False + + +use_pep517: Any = partial( + Option, + "--use-pep517", + dest="use_pep517", + action="store_true", + default=None, + help="Use PEP 517 for building source distributions " + "(use --no-use-pep517 to force legacy behaviour).", +) + +no_use_pep517: Any = partial( + Option, + "--no-use-pep517", + dest="use_pep517", + action="callback", + callback=_handle_no_use_pep517, + default=None, + help=SUPPRESS_HELP, +) + + +def _handle_config_settings( + option: Option, opt_str: str, value: str, parser: OptionParser +) -> None: + key, sep, val = value.partition("=") + if sep != "=": + parser.error(f"Arguments to {opt_str} must be of the form KEY=VAL") + dest = getattr(parser.values, option.dest) + if dest is None: + dest = {} + setattr(parser.values, option.dest, dest) + if key in dest: + if isinstance(dest[key], list): + dest[key].append(val) + else: + dest[key] = [dest[key], val] + else: + dest[key] = val + + +config_settings: Callable[..., Option] = partial( + Option, + "-C", + "--config-settings", + dest="config_settings", + type=str, + action="callback", + callback=_handle_config_settings, + metavar="settings", + help="Configuration settings to be passed to the PEP 517 build backend. " + "Settings take the form KEY=VALUE. Use multiple --config-settings options " + "to pass multiple keys to the backend.", +) + +build_options: Callable[..., Option] = partial( + Option, + "--build-option", + dest="build_options", + metavar="options", + action="append", + help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", +) + +global_options: Callable[..., Option] = partial( + Option, + "--global-option", + dest="global_options", + action="append", + metavar="options", + help="Extra global options to be supplied to the setup.py " + "call before the install or bdist_wheel command.", +) + +no_clean: Callable[..., Option] = partial( + Option, + "--no-clean", + action="store_true", + default=False, + help="Don't clean up build directories.", +) + +pre: Callable[..., Option] = partial( + Option, + "--pre", + action="store_true", + default=False, + help="Include pre-release and development versions. By default, " + "pip only finds stable versions.", +) + +disable_pip_version_check: Callable[..., Option] = partial( + Option, + "--disable-pip-version-check", + dest="disable_pip_version_check", + action="store_true", + default=False, + help="Don't periodically check PyPI to determine whether a new version " + "of pip is available for download. Implied with --no-index.", +) + +root_user_action: Callable[..., Option] = partial( + Option, + "--root-user-action", + dest="root_user_action", + default="warn", + choices=["warn", "ignore"], + help="Action if pip is run as a root user [warn, ignore] (default: warn)", +) + + +def _handle_merge_hash( + option: Option, opt_str: str, value: str, parser: OptionParser +) -> None: + """Given a value spelled "algo:digest", append the digest to a list + pointed to in a dict by the algo name.""" + if not parser.values.hashes: + parser.values.hashes = {} + try: + algo, digest = value.split(":", 1) + except ValueError: + parser.error( + f"Arguments to {opt_str} must be a hash name " + "followed by a value, like --hash=sha256:" + "abcde..." + ) + if algo not in STRONG_HASHES: + parser.error( + "Allowed hash algorithms for {} are {}.".format( + opt_str, ", ".join(STRONG_HASHES) + ) + ) + parser.values.hashes.setdefault(algo, []).append(digest) + + +hash: Callable[..., Option] = partial( + Option, + "--hash", + # Hash values eventually end up in InstallRequirement.hashes due to + # __dict__ copying in process_line(). + dest="hashes", + action="callback", + callback=_handle_merge_hash, + type="string", + help="Verify that the package's archive matches this " + "hash before installing. Example: --hash=sha256:abcdef...", +) + + +require_hashes: Callable[..., Option] = partial( + Option, + "--require-hashes", + dest="require_hashes", + action="store_true", + default=False, + help="Require a hash to check each requirement against, for " + "repeatable installs. This option is implied when any package in a " + "requirements file has a --hash option.", +) + + +list_path: Callable[..., Option] = partial( + PipOption, + "--path", + dest="path", + type="path", + action="append", + help="Restrict to the specified installation path for listing " + "packages (can be used multiple times).", +) + + +def check_list_path_option(options: Values) -> None: + if options.path and (options.user or options.local): + raise CommandError("Cannot combine '--path' with '--user' or '--local'") + + +list_exclude: Callable[..., Option] = partial( + PipOption, + "--exclude", + dest="excludes", + action="append", + metavar="package", + type="package_name", + help="Exclude specified package from the output", +) + + +no_python_version_warning: Callable[..., Option] = partial( + Option, + "--no-python-version-warning", + dest="no_python_version_warning", + action="store_true", + default=False, + help="Silence deprecation warnings for upcoming unsupported Pythons.", +) + + +# Features that are now always on. A warning is printed if they are used. +ALWAYS_ENABLED_FEATURES = [ + "truststore", # always on since 24.2 + "no-binary-enable-wheel-cache", # always on since 23.1 +] + +use_new_feature: Callable[..., Option] = partial( + Option, + "--use-feature", + dest="features_enabled", + metavar="feature", + action="append", + default=[], + choices=[ + "fast-deps", + ] + + ALWAYS_ENABLED_FEATURES, + help="Enable new functionality, that may be backward incompatible.", +) + +use_deprecated_feature: Callable[..., Option] = partial( + Option, + "--use-deprecated", + dest="deprecated_features_enabled", + metavar="feature", + action="append", + default=[], + choices=[ + "legacy-resolver", + "legacy-certs", + ], + help=("Enable deprecated functionality, that will be removed in the future."), +) + + +########## +# groups # +########## + +general_group: Dict[str, Any] = { + "name": "General Options", + "options": [ + help_, + debug_mode, + isolated_mode, + require_virtualenv, + python, + verbose, + version, + quiet, + log, + no_input, + keyring_provider, + proxy, + retries, + timeout, + exists_action, + trusted_host, + cert, + client_cert, + cache_dir, + no_cache, + disable_pip_version_check, + no_color, + no_python_version_warning, + use_new_feature, + use_deprecated_feature, + ], +} + +index_group: Dict[str, Any] = { + "name": "Package Index Options", + "options": [ + index_url, + extra_index_url, + no_index, + find_links, + ], +} diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/command_context.py b/backend/venv/Lib/site-packages/pip/_internal/cli/command_context.py new file mode 100644 index 0000000..139995a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/command_context.py @@ -0,0 +1,27 @@ +from contextlib import ExitStack, contextmanager +from typing import ContextManager, Generator, TypeVar + +_T = TypeVar("_T", covariant=True) + + +class CommandContextMixIn: + def __init__(self) -> None: + super().__init__() + self._in_main_context = False + self._main_context = ExitStack() + + @contextmanager + def main_context(self) -> Generator[None, None, None]: + assert not self._in_main_context + + self._in_main_context = True + try: + with self._main_context: + yield + finally: + self._in_main_context = False + + def enter_context(self, context_provider: ContextManager[_T]) -> _T: + assert self._in_main_context + + return self._main_context.enter_context(context_provider) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/index_command.py b/backend/venv/Lib/site-packages/pip/_internal/cli/index_command.py new file mode 100644 index 0000000..295108e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/index_command.py @@ -0,0 +1,171 @@ +""" +Contains command classes which may interact with an index / the network. + +Unlike its sister module, req_command, this module still uses lazy imports +so commands which don't always hit the network (e.g. list w/o --outdated or +--uptodate) don't need waste time importing PipSession and friends. +""" + +import logging +import os +import sys +from optparse import Values +from typing import TYPE_CHECKING, List, Optional + +from pip._vendor import certifi + +from pip._internal.cli.base_command import Command +from pip._internal.cli.command_context import CommandContextMixIn + +if TYPE_CHECKING: + from ssl import SSLContext + + from pip._internal.network.session import PipSession + +logger = logging.getLogger(__name__) + + +def _create_truststore_ssl_context() -> Optional["SSLContext"]: + if sys.version_info < (3, 10): + logger.debug("Disabling truststore because Python version isn't 3.10+") + return None + + try: + import ssl + except ImportError: + logger.warning("Disabling truststore since ssl support is missing") + return None + + try: + from pip._vendor import truststore + except ImportError: + logger.warning("Disabling truststore because platform isn't supported") + return None + + ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.load_verify_locations(certifi.where()) + return ctx + + +class SessionCommandMixin(CommandContextMixIn): + """ + A class mixin for command classes needing _build_session(). + """ + + def __init__(self) -> None: + super().__init__() + self._session: Optional[PipSession] = None + + @classmethod + def _get_index_urls(cls, options: Values) -> Optional[List[str]]: + """Return a list of index urls from user-provided options.""" + index_urls = [] + if not getattr(options, "no_index", False): + url = getattr(options, "index_url", None) + if url: + index_urls.append(url) + urls = getattr(options, "extra_index_urls", None) + if urls: + index_urls.extend(urls) + # Return None rather than an empty list + return index_urls or None + + def get_default_session(self, options: Values) -> "PipSession": + """Get a default-managed session.""" + if self._session is None: + self._session = self.enter_context(self._build_session(options)) + # there's no type annotation on requests.Session, so it's + # automatically ContextManager[Any] and self._session becomes Any, + # then https://github.com/python/mypy/issues/7696 kicks in + assert self._session is not None + return self._session + + def _build_session( + self, + options: Values, + retries: Optional[int] = None, + timeout: Optional[int] = None, + ) -> "PipSession": + from pip._internal.network.session import PipSession + + cache_dir = options.cache_dir + assert not cache_dir or os.path.isabs(cache_dir) + + if "legacy-certs" not in options.deprecated_features_enabled: + ssl_context = _create_truststore_ssl_context() + else: + ssl_context = None + + session = PipSession( + cache=os.path.join(cache_dir, "http-v2") if cache_dir else None, + retries=retries if retries is not None else options.retries, + trusted_hosts=options.trusted_hosts, + index_urls=self._get_index_urls(options), + ssl_context=ssl_context, + ) + + # Handle custom ca-bundles from the user + if options.cert: + session.verify = options.cert + + # Handle SSL client certificate + if options.client_cert: + session.cert = options.client_cert + + # Handle timeouts + if options.timeout or timeout: + session.timeout = timeout if timeout is not None else options.timeout + + # Handle configured proxies + if options.proxy: + session.proxies = { + "http": options.proxy, + "https": options.proxy, + } + session.trust_env = False + session.pip_proxy = options.proxy + + # Determine if we can prompt the user for authentication or not + session.auth.prompting = not options.no_input + session.auth.keyring_provider = options.keyring_provider + + return session + + +def _pip_self_version_check(session: "PipSession", options: Values) -> None: + from pip._internal.self_outdated_check import pip_self_version_check as check + + check(session, options) + + +class IndexGroupCommand(Command, SessionCommandMixin): + """ + Abstract base class for commands with the index_group options. + + This also corresponds to the commands that permit the pip version check. + """ + + def handle_pip_version_check(self, options: Values) -> None: + """ + Do the pip version check if not disabled. + + This overrides the default behavior of not doing the check. + """ + # Make sure the index_group options are present. + assert hasattr(options, "no_index") + + if options.disable_pip_version_check or options.no_index: + return + + try: + # Otherwise, check if we're using the latest version of pip available. + session = self._build_session( + options, + retries=0, + timeout=min(5, options.timeout), + ) + with session: + _pip_self_version_check(session, options) + except Exception: + logger.warning("There was an error checking the latest version of pip.") + logger.debug("See below for error", exc_info=True) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/main.py b/backend/venv/Lib/site-packages/pip/_internal/cli/main.py new file mode 100644 index 0000000..563ac79 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/main.py @@ -0,0 +1,80 @@ +"""Primary application entrypoint. +""" + +import locale +import logging +import os +import sys +import warnings +from typing import List, Optional + +from pip._internal.cli.autocompletion import autocomplete +from pip._internal.cli.main_parser import parse_command +from pip._internal.commands import create_command +from pip._internal.exceptions import PipError +from pip._internal.utils import deprecation + +logger = logging.getLogger(__name__) + + +# Do not import and use main() directly! Using it directly is actively +# discouraged by pip's maintainers. The name, location and behavior of +# this function is subject to change, so calling it directly is not +# portable across different pip versions. + +# In addition, running pip in-process is unsupported and unsafe. This is +# elaborated in detail at +# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program. +# That document also provides suggestions that should work for nearly +# all users that are considering importing and using main() directly. + +# However, we know that certain users will still want to invoke pip +# in-process. If you understand and accept the implications of using pip +# in an unsupported manner, the best approach is to use runpy to avoid +# depending on the exact location of this entry point. + +# The following example shows how to use runpy to invoke pip in that +# case: +# +# sys.argv = ["pip", your, args, here] +# runpy.run_module("pip", run_name="__main__") +# +# Note that this will exit the process after running, unlike a direct +# call to main. As it is not safe to do any processing after calling +# main, this should not be an issue in practice. + + +def main(args: Optional[List[str]] = None) -> int: + if args is None: + args = sys.argv[1:] + + # Suppress the pkg_resources deprecation warning + # Note - we use a module of .*pkg_resources to cover + # the normal case (pip._vendor.pkg_resources) and the + # devendored case (a bare pkg_resources) + warnings.filterwarnings( + action="ignore", category=DeprecationWarning, module=".*pkg_resources" + ) + + # Configure our deprecation warnings to be sent through loggers + deprecation.install_warning_logger() + + autocomplete() + + try: + cmd_name, cmd_args = parse_command(args) + except PipError as exc: + sys.stderr.write(f"ERROR: {exc}") + sys.stderr.write(os.linesep) + sys.exit(1) + + # Needed for locale.getpreferredencoding(False) to work + # in pip._internal.utils.encoding.auto_decode + try: + locale.setlocale(locale.LC_ALL, "") + except locale.Error as e: + # setlocale can apparently crash if locale are uninitialized + logger.debug("Ignoring error %s when setting locale", e) + command = create_command(cmd_name, isolated=("--isolated" in cmd_args)) + + return command.main(cmd_args) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/main_parser.py b/backend/venv/Lib/site-packages/pip/_internal/cli/main_parser.py new file mode 100644 index 0000000..5ade356 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/main_parser.py @@ -0,0 +1,134 @@ +"""A single place for constructing and exposing the main parser +""" + +import os +import subprocess +import sys +from typing import List, Optional, Tuple + +from pip._internal.build_env import get_runnable_pip +from pip._internal.cli import cmdoptions +from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter +from pip._internal.commands import commands_dict, get_similar_commands +from pip._internal.exceptions import CommandError +from pip._internal.utils.misc import get_pip_version, get_prog + +__all__ = ["create_main_parser", "parse_command"] + + +def create_main_parser() -> ConfigOptionParser: + """Creates and returns the main parser for pip's CLI""" + + parser = ConfigOptionParser( + usage="\n%prog [options]", + add_help_option=False, + formatter=UpdatingDefaultsHelpFormatter(), + name="global", + prog=get_prog(), + ) + parser.disable_interspersed_args() + + parser.version = get_pip_version() + + # add the general options + gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) + parser.add_option_group(gen_opts) + + # so the help formatter knows + parser.main = True # type: ignore + + # create command listing for description + description = [""] + [ + f"{name:27} {command_info.summary}" + for name, command_info in commands_dict.items() + ] + parser.description = "\n".join(description) + + return parser + + +def identify_python_interpreter(python: str) -> Optional[str]: + # If the named file exists, use it. + # If it's a directory, assume it's a virtual environment and + # look for the environment's Python executable. + if os.path.exists(python): + if os.path.isdir(python): + # bin/python for Unix, Scripts/python.exe for Windows + # Try both in case of odd cases like cygwin. + for exe in ("bin/python", "Scripts/python.exe"): + py = os.path.join(python, exe) + if os.path.exists(py): + return py + else: + return python + + # Could not find the interpreter specified + return None + + +def parse_command(args: List[str]) -> Tuple[str, List[str]]: + parser = create_main_parser() + + # Note: parser calls disable_interspersed_args(), so the result of this + # call is to split the initial args into the general options before the + # subcommand and everything else. + # For example: + # args: ['--timeout=5', 'install', '--user', 'INITools'] + # general_options: ['--timeout==5'] + # args_else: ['install', '--user', 'INITools'] + general_options, args_else = parser.parse_args(args) + + # --python + if general_options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ: + # Re-invoke pip using the specified Python interpreter + interpreter = identify_python_interpreter(general_options.python) + if interpreter is None: + raise CommandError( + f"Could not locate Python interpreter {general_options.python}" + ) + + pip_cmd = [ + interpreter, + get_runnable_pip(), + ] + pip_cmd.extend(args) + + # Set a flag so the child doesn't re-invoke itself, causing + # an infinite loop. + os.environ["_PIP_RUNNING_IN_SUBPROCESS"] = "1" + returncode = 0 + try: + proc = subprocess.run(pip_cmd) + returncode = proc.returncode + except (subprocess.SubprocessError, OSError) as exc: + raise CommandError(f"Failed to run pip under {interpreter}: {exc}") + sys.exit(returncode) + + # --version + if general_options.version: + sys.stdout.write(parser.version) + sys.stdout.write(os.linesep) + sys.exit() + + # pip || pip help -> print_help() + if not args_else or (args_else[0] == "help" and len(args_else) == 1): + parser.print_help() + sys.exit() + + # the subcommand name + cmd_name = args_else[0] + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = [f'unknown command "{cmd_name}"'] + if guess: + msg.append(f'maybe you meant "{guess}"') + + raise CommandError(" - ".join(msg)) + + # all the args without the subcommand + cmd_args = args[:] + cmd_args.remove(cmd_name) + + return cmd_name, cmd_args diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/parser.py b/backend/venv/Lib/site-packages/pip/_internal/cli/parser.py new file mode 100644 index 0000000..bc4aca0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/parser.py @@ -0,0 +1,294 @@ +"""Base option parser setup""" + +import logging +import optparse +import shutil +import sys +import textwrap +from contextlib import suppress +from typing import Any, Dict, Generator, List, NoReturn, Optional, Tuple + +from pip._internal.cli.status_codes import UNKNOWN_ERROR +from pip._internal.configuration import Configuration, ConfigurationError +from pip._internal.utils.misc import redact_auth_from_url, strtobool + +logger = logging.getLogger(__name__) + + +class PrettyHelpFormatter(optparse.IndentedHelpFormatter): + """A prettier/less verbose help formatter for optparse.""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + # help position must be aligned with __init__.parseopts.description + kwargs["max_help_position"] = 30 + kwargs["indent_increment"] = 1 + kwargs["width"] = shutil.get_terminal_size()[0] - 2 + super().__init__(*args, **kwargs) + + def format_option_strings(self, option: optparse.Option) -> str: + return self._format_option_strings(option) + + def _format_option_strings( + self, option: optparse.Option, mvarfmt: str = " <{}>", optsep: str = ", " + ) -> str: + """ + Return a comma-separated list of option strings and metavars. + + :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') + :param mvarfmt: metavar format string + :param optsep: separator + """ + opts = [] + + if option._short_opts: + opts.append(option._short_opts[0]) + if option._long_opts: + opts.append(option._long_opts[0]) + if len(opts) > 1: + opts.insert(1, optsep) + + if option.takes_value(): + assert option.dest is not None + metavar = option.metavar or option.dest.lower() + opts.append(mvarfmt.format(metavar.lower())) + + return "".join(opts) + + def format_heading(self, heading: str) -> str: + if heading == "Options": + return "" + return heading + ":\n" + + def format_usage(self, usage: str) -> str: + """ + Ensure there is only one newline between usage and the first heading + if there is no description. + """ + msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " ")) + return msg + + def format_description(self, description: Optional[str]) -> str: + # leave full control over description to us + if description: + if hasattr(self.parser, "main"): + label = "Commands" + else: + label = "Description" + # some doc strings have initial newlines, some don't + description = description.lstrip("\n") + # some doc strings have final newlines and spaces, some don't + description = description.rstrip() + # dedent, then reindent + description = self.indent_lines(textwrap.dedent(description), " ") + description = f"{label}:\n{description}\n" + return description + else: + return "" + + def format_epilog(self, epilog: Optional[str]) -> str: + # leave full control over epilog to us + if epilog: + return epilog + else: + return "" + + def indent_lines(self, text: str, indent: str) -> str: + new_lines = [indent + line for line in text.split("\n")] + return "\n".join(new_lines) + + +class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): + """Custom help formatter for use in ConfigOptionParser. + + This is updates the defaults before expanding them, allowing + them to show up correctly in the help listing. + + Also redact auth from url type options + """ + + def expand_default(self, option: optparse.Option) -> str: + default_values = None + if self.parser is not None: + assert isinstance(self.parser, ConfigOptionParser) + self.parser._update_defaults(self.parser.defaults) + assert option.dest is not None + default_values = self.parser.defaults.get(option.dest) + help_text = super().expand_default(option) + + if default_values and option.metavar == "URL": + if isinstance(default_values, str): + default_values = [default_values] + + # If its not a list, we should abort and just return the help text + if not isinstance(default_values, list): + default_values = [] + + for val in default_values: + help_text = help_text.replace(val, redact_auth_from_url(val)) + + return help_text + + +class CustomOptionParser(optparse.OptionParser): + def insert_option_group( + self, idx: int, *args: Any, **kwargs: Any + ) -> optparse.OptionGroup: + """Insert an OptionGroup at a given position.""" + group = self.add_option_group(*args, **kwargs) + + self.option_groups.pop() + self.option_groups.insert(idx, group) + + return group + + @property + def option_list_all(self) -> List[optparse.Option]: + """Get a list of all options, including those in option groups.""" + res = self.option_list[:] + for i in self.option_groups: + res.extend(i.option_list) + + return res + + +class ConfigOptionParser(CustomOptionParser): + """Custom option parser which updates its defaults by checking the + configuration files and environmental variables""" + + def __init__( + self, + *args: Any, + name: str, + isolated: bool = False, + **kwargs: Any, + ) -> None: + self.name = name + self.config = Configuration(isolated) + + assert self.name + super().__init__(*args, **kwargs) + + def check_default(self, option: optparse.Option, key: str, val: Any) -> Any: + try: + return option.check_value(key, val) + except optparse.OptionValueError as exc: + print(f"An error occurred during configuration: {exc}") + sys.exit(3) + + def _get_ordered_configuration_items( + self, + ) -> Generator[Tuple[str, Any], None, None]: + # Configuration gives keys in an unordered manner. Order them. + override_order = ["global", self.name, ":env:"] + + # Pool the options into different groups + section_items: Dict[str, List[Tuple[str, Any]]] = { + name: [] for name in override_order + } + for section_key, val in self.config.items(): + # ignore empty values + if not val: + logger.debug( + "Ignoring configuration key '%s' as it's value is empty.", + section_key, + ) + continue + + section, key = section_key.split(".", 1) + if section in override_order: + section_items[section].append((key, val)) + + # Yield each group in their override order + for section in override_order: + for key, val in section_items[section]: + yield key, val + + def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]: + """Updates the given defaults with values from the config files and + the environ. Does a little special handling for certain types of + options (lists).""" + + # Accumulate complex default state. + self.values = optparse.Values(self.defaults) + late_eval = set() + # Then set the options with those values + for key, val in self._get_ordered_configuration_items(): + # '--' because configuration supports only long names + option = self.get_option("--" + key) + + # Ignore options not present in this parser. E.g. non-globals put + # in [global] by users that want them to apply to all applicable + # commands. + if option is None: + continue + + assert option.dest is not None + + if option.action in ("store_true", "store_false"): + try: + val = strtobool(val) + except ValueError: + self.error( + f"{val} is not a valid value for {key} option, " + "please specify a boolean value like yes/no, " + "true/false or 1/0 instead." + ) + elif option.action == "count": + with suppress(ValueError): + val = strtobool(val) + with suppress(ValueError): + val = int(val) + if not isinstance(val, int) or val < 0: + self.error( + f"{val} is not a valid value for {key} option, " + "please instead specify either a non-negative integer " + "or a boolean value like yes/no or false/true " + "which is equivalent to 1/0." + ) + elif option.action == "append": + val = val.split() + val = [self.check_default(option, key, v) for v in val] + elif option.action == "callback": + assert option.callback is not None + late_eval.add(option.dest) + opt_str = option.get_opt_string() + val = option.convert_value(opt_str, val) + # From take_action + args = option.callback_args or () + kwargs = option.callback_kwargs or {} + option.callback(option, opt_str, val, self, *args, **kwargs) + else: + val = self.check_default(option, key, val) + + defaults[option.dest] = val + + for key in late_eval: + defaults[key] = getattr(self.values, key) + self.values = None + return defaults + + def get_default_values(self) -> optparse.Values: + """Overriding to make updating the defaults after instantiation of + the option parser possible, _update_defaults() does the dirty work.""" + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return optparse.Values(self.defaults) + + # Load the configuration, or error out in case of an error + try: + self.config.load() + except ConfigurationError as err: + self.exit(UNKNOWN_ERROR, str(err)) + + defaults = self._update_defaults(self.defaults.copy()) # ours + for option in self._get_all_options(): + assert option.dest is not None + default = defaults.get(option.dest) + if isinstance(default, str): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + return optparse.Values(defaults) + + def error(self, msg: str) -> NoReturn: + self.print_usage(sys.stderr) + self.exit(UNKNOWN_ERROR, f"{msg}\n") diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/progress_bars.py b/backend/venv/Lib/site-packages/pip/_internal/cli/progress_bars.py new file mode 100644 index 0000000..3d9dde8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/progress_bars.py @@ -0,0 +1,94 @@ +import functools +import sys +from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple + +from pip._vendor.rich.progress import ( + BarColumn, + DownloadColumn, + FileSizeColumn, + Progress, + ProgressColumn, + SpinnerColumn, + TextColumn, + TimeElapsedColumn, + TimeRemainingColumn, + TransferSpeedColumn, +) + +from pip._internal.cli.spinners import RateLimiter +from pip._internal.utils.logging import get_indentation + +DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]] + + +def _rich_progress_bar( + iterable: Iterable[bytes], + *, + bar_type: str, + size: Optional[int], +) -> Generator[bytes, None, None]: + assert bar_type == "on", "This should only be used in the default mode." + + if not size: + total = float("inf") + columns: Tuple[ProgressColumn, ...] = ( + TextColumn("[progress.description]{task.description}"), + SpinnerColumn("line", speed=1.5), + FileSizeColumn(), + TransferSpeedColumn(), + TimeElapsedColumn(), + ) + else: + total = size + columns = ( + TextColumn("[progress.description]{task.description}"), + BarColumn(), + DownloadColumn(), + TransferSpeedColumn(), + TextColumn("eta"), + TimeRemainingColumn(), + ) + + progress = Progress(*columns, refresh_per_second=5) + task_id = progress.add_task(" " * (get_indentation() + 2), total=total) + with progress: + for chunk in iterable: + yield chunk + progress.update(task_id, advance=len(chunk)) + + +def _raw_progress_bar( + iterable: Iterable[bytes], + *, + size: Optional[int], +) -> Generator[bytes, None, None]: + def write_progress(current: int, total: int) -> None: + sys.stdout.write(f"Progress {current} of {total}\n") + sys.stdout.flush() + + current = 0 + total = size or 0 + rate_limiter = RateLimiter(0.25) + + write_progress(current, total) + for chunk in iterable: + current += len(chunk) + if rate_limiter.ready() or current == total: + write_progress(current, total) + rate_limiter.reset() + yield chunk + + +def get_download_progress_renderer( + *, bar_type: str, size: Optional[int] = None +) -> DownloadProgressRenderer: + """Get an object that can be used to render the download progress. + + Returns a callable, that takes an iterable to "wrap". + """ + if bar_type == "on": + return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size) + elif bar_type == "raw": + return functools.partial(_raw_progress_bar, size=size) + else: + return iter # no-op, when passed an iterator diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/req_command.py b/backend/venv/Lib/site-packages/pip/_internal/cli/req_command.py new file mode 100644 index 0000000..92900f9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/req_command.py @@ -0,0 +1,329 @@ +"""Contains the RequirementCommand base class. + +This class is in a separate module so the commands that do not always +need PackageFinder capability don't unnecessarily import the +PackageFinder machinery and all its vendored dependencies, etc. +""" + +import logging +from functools import partial +from optparse import Values +from typing import Any, List, Optional, Tuple + +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.index_command import IndexGroupCommand +from pip._internal.cli.index_command import SessionCommandMixin as SessionCommandMixin +from pip._internal.exceptions import CommandError, PreviousBuildDirError +from pip._internal.index.collector import LinkCollector +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.network.session import PipSession +from pip._internal.operations.build.build_tracker import BuildTracker +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, + install_req_from_parsed_requirement, + install_req_from_req_string, +) +from pip._internal.req.req_file import parse_requirements +from pip._internal.req.req_install import InstallRequirement +from pip._internal.resolution.base import BaseResolver +from pip._internal.utils.temp_dir import ( + TempDirectory, + TempDirectoryTypeRegistry, + tempdir_kinds, +) + +logger = logging.getLogger(__name__) + + +KEEPABLE_TEMPDIR_TYPES = [ + tempdir_kinds.BUILD_ENV, + tempdir_kinds.EPHEM_WHEEL_CACHE, + tempdir_kinds.REQ_BUILD, +] + + +def with_cleanup(func: Any) -> Any: + """Decorator for common logic related to managing temporary + directories. + """ + + def configure_tempdir_registry(registry: TempDirectoryTypeRegistry) -> None: + for t in KEEPABLE_TEMPDIR_TYPES: + registry.set_delete(t, False) + + def wrapper( + self: RequirementCommand, options: Values, args: List[Any] + ) -> Optional[int]: + assert self.tempdir_registry is not None + if options.no_clean: + configure_tempdir_registry(self.tempdir_registry) + + try: + return func(self, options, args) + except PreviousBuildDirError: + # This kind of conflict can occur when the user passes an explicit + # build directory with a pre-existing folder. In that case we do + # not want to accidentally remove it. + configure_tempdir_registry(self.tempdir_registry) + raise + + return wrapper + + +class RequirementCommand(IndexGroupCommand): + def __init__(self, *args: Any, **kw: Any) -> None: + super().__init__(*args, **kw) + + self.cmd_opts.add_option(cmdoptions.no_clean()) + + @staticmethod + def determine_resolver_variant(options: Values) -> str: + """Determines which resolver should be used, based on the given options.""" + if "legacy-resolver" in options.deprecated_features_enabled: + return "legacy" + + return "resolvelib" + + @classmethod + def make_requirement_preparer( + cls, + temp_build_dir: TempDirectory, + options: Values, + build_tracker: BuildTracker, + session: PipSession, + finder: PackageFinder, + use_user_site: bool, + download_dir: Optional[str] = None, + verbosity: int = 0, + ) -> RequirementPreparer: + """ + Create a RequirementPreparer instance for the given parameters. + """ + temp_build_dir_path = temp_build_dir.path + assert temp_build_dir_path is not None + legacy_resolver = False + + resolver_variant = cls.determine_resolver_variant(options) + if resolver_variant == "resolvelib": + lazy_wheel = "fast-deps" in options.features_enabled + if lazy_wheel: + logger.warning( + "pip is using lazily downloaded wheels using HTTP " + "range requests to obtain dependency information. " + "This experimental feature is enabled through " + "--use-feature=fast-deps and it is not ready for " + "production." + ) + else: + legacy_resolver = True + lazy_wheel = False + if "fast-deps" in options.features_enabled: + logger.warning( + "fast-deps has no effect when used with the legacy resolver." + ) + + return RequirementPreparer( + build_dir=temp_build_dir_path, + src_dir=options.src_dir, + download_dir=download_dir, + build_isolation=options.build_isolation, + check_build_deps=options.check_build_deps, + build_tracker=build_tracker, + session=session, + progress_bar=options.progress_bar, + finder=finder, + require_hashes=options.require_hashes, + use_user_site=use_user_site, + lazy_wheel=lazy_wheel, + verbosity=verbosity, + legacy_resolver=legacy_resolver, + ) + + @classmethod + def make_resolver( + cls, + preparer: RequirementPreparer, + finder: PackageFinder, + options: Values, + wheel_cache: Optional[WheelCache] = None, + use_user_site: bool = False, + ignore_installed: bool = True, + ignore_requires_python: bool = False, + force_reinstall: bool = False, + upgrade_strategy: str = "to-satisfy-only", + use_pep517: Optional[bool] = None, + py_version_info: Optional[Tuple[int, ...]] = None, + ) -> BaseResolver: + """ + Create a Resolver instance for the given parameters. + """ + make_install_req = partial( + install_req_from_req_string, + isolated=options.isolated_mode, + use_pep517=use_pep517, + ) + resolver_variant = cls.determine_resolver_variant(options) + # The long import name and duplicated invocation is needed to convince + # Mypy into correctly typechecking. Otherwise it would complain the + # "Resolver" class being redefined. + if resolver_variant == "resolvelib": + import pip._internal.resolution.resolvelib.resolver + + return pip._internal.resolution.resolvelib.resolver.Resolver( + preparer=preparer, + finder=finder, + wheel_cache=wheel_cache, + make_install_req=make_install_req, + use_user_site=use_user_site, + ignore_dependencies=options.ignore_dependencies, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + force_reinstall=force_reinstall, + upgrade_strategy=upgrade_strategy, + py_version_info=py_version_info, + ) + import pip._internal.resolution.legacy.resolver + + return pip._internal.resolution.legacy.resolver.Resolver( + preparer=preparer, + finder=finder, + wheel_cache=wheel_cache, + make_install_req=make_install_req, + use_user_site=use_user_site, + ignore_dependencies=options.ignore_dependencies, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + force_reinstall=force_reinstall, + upgrade_strategy=upgrade_strategy, + py_version_info=py_version_info, + ) + + def get_requirements( + self, + args: List[str], + options: Values, + finder: PackageFinder, + session: PipSession, + ) -> List[InstallRequirement]: + """ + Parse command-line arguments into the corresponding requirements. + """ + requirements: List[InstallRequirement] = [] + for filename in options.constraints: + for parsed_req in parse_requirements( + filename, + constraint=True, + finder=finder, + options=options, + session=session, + ): + req_to_add = install_req_from_parsed_requirement( + parsed_req, + isolated=options.isolated_mode, + user_supplied=False, + ) + requirements.append(req_to_add) + + for req in args: + req_to_add = install_req_from_line( + req, + comes_from=None, + isolated=options.isolated_mode, + use_pep517=options.use_pep517, + user_supplied=True, + config_settings=getattr(options, "config_settings", None), + ) + requirements.append(req_to_add) + + for req in options.editables: + req_to_add = install_req_from_editable( + req, + user_supplied=True, + isolated=options.isolated_mode, + use_pep517=options.use_pep517, + config_settings=getattr(options, "config_settings", None), + ) + requirements.append(req_to_add) + + # NOTE: options.require_hashes may be set if --require-hashes is True + for filename in options.requirements: + for parsed_req in parse_requirements( + filename, finder=finder, options=options, session=session + ): + req_to_add = install_req_from_parsed_requirement( + parsed_req, + isolated=options.isolated_mode, + use_pep517=options.use_pep517, + user_supplied=True, + config_settings=( + parsed_req.options.get("config_settings") + if parsed_req.options + else None + ), + ) + requirements.append(req_to_add) + + # If any requirement has hash options, enable hash checking. + if any(req.has_hash_options for req in requirements): + options.require_hashes = True + + if not (args or options.editables or options.requirements): + opts = {"name": self.name} + if options.find_links: + raise CommandError( + "You must give at least one requirement to {name} " + '(maybe you meant "pip {name} {links}"?)'.format( + **dict(opts, links=" ".join(options.find_links)) + ) + ) + else: + raise CommandError( + "You must give at least one requirement to {name} " + '(see "pip help {name}")'.format(**opts) + ) + + return requirements + + @staticmethod + def trace_basic_info(finder: PackageFinder) -> None: + """ + Trace basic information about the provided objects. + """ + # Display where finder is looking for packages + search_scope = finder.search_scope + locations = search_scope.get_formatted_locations() + if locations: + logger.info(locations) + + def _build_package_finder( + self, + options: Values, + session: PipSession, + target_python: Optional[TargetPython] = None, + ignore_requires_python: Optional[bool] = None, + ) -> PackageFinder: + """ + Create a package finder appropriate to this requirement command. + + :param ignore_requires_python: Whether to ignore incompatible + "Requires-Python" values in links. Defaults to False. + """ + link_collector = LinkCollector.create(session, options=options) + selection_prefs = SelectionPreferences( + allow_yanked=True, + format_control=options.format_control, + allow_all_prereleases=options.pre, + prefer_binary=options.prefer_binary, + ignore_requires_python=ignore_requires_python, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + target_python=target_python, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/spinners.py b/backend/venv/Lib/site-packages/pip/_internal/cli/spinners.py new file mode 100644 index 0000000..cf2b976 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/spinners.py @@ -0,0 +1,159 @@ +import contextlib +import itertools +import logging +import sys +import time +from typing import IO, Generator, Optional + +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.logging import get_indentation + +logger = logging.getLogger(__name__) + + +class SpinnerInterface: + def spin(self) -> None: + raise NotImplementedError() + + def finish(self, final_status: str) -> None: + raise NotImplementedError() + + +class InteractiveSpinner(SpinnerInterface): + def __init__( + self, + message: str, + file: Optional[IO[str]] = None, + spin_chars: str = "-\\|/", + # Empirically, 8 updates/second looks nice + min_update_interval_seconds: float = 0.125, + ): + self._message = message + if file is None: + file = sys.stdout + self._file = file + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._finished = False + + self._spin_cycle = itertools.cycle(spin_chars) + + self._file.write(" " * get_indentation() + self._message + " ... ") + self._width = 0 + + def _write(self, status: str) -> None: + assert not self._finished + # Erase what we wrote before by backspacing to the beginning, writing + # spaces to overwrite the old text, and then backspacing again + backup = "\b" * self._width + self._file.write(backup + " " * self._width + backup) + # Now we have a blank slate to add our status + self._file.write(status) + self._width = len(status) + self._file.flush() + self._rate_limiter.reset() + + def spin(self) -> None: + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._write(next(self._spin_cycle)) + + def finish(self, final_status: str) -> None: + if self._finished: + return + self._write(final_status) + self._file.write("\n") + self._file.flush() + self._finished = True + + +# Used for dumb terminals, non-interactive installs (no tty), etc. +# We still print updates occasionally (once every 60 seconds by default) to +# act as a keep-alive for systems like Travis-CI that take lack-of-output as +# an indication that a task has frozen. +class NonInteractiveSpinner(SpinnerInterface): + def __init__(self, message: str, min_update_interval_seconds: float = 60.0) -> None: + self._message = message + self._finished = False + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._update("started") + + def _update(self, status: str) -> None: + assert not self._finished + self._rate_limiter.reset() + logger.info("%s: %s", self._message, status) + + def spin(self) -> None: + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._update("still running...") + + def finish(self, final_status: str) -> None: + if self._finished: + return + self._update(f"finished with status '{final_status}'") + self._finished = True + + +class RateLimiter: + def __init__(self, min_update_interval_seconds: float) -> None: + self._min_update_interval_seconds = min_update_interval_seconds + self._last_update: float = 0 + + def ready(self) -> bool: + now = time.time() + delta = now - self._last_update + return delta >= self._min_update_interval_seconds + + def reset(self) -> None: + self._last_update = time.time() + + +@contextlib.contextmanager +def open_spinner(message: str) -> Generator[SpinnerInterface, None, None]: + # Interactive spinner goes directly to sys.stdout rather than being routed + # through the logging system, but it acts like it has level INFO, + # i.e. it's only displayed if we're at level INFO or better. + # Non-interactive spinner goes through the logging system, so it is always + # in sync with logging configuration. + if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: + spinner: SpinnerInterface = InteractiveSpinner(message) + else: + spinner = NonInteractiveSpinner(message) + try: + with hidden_cursor(sys.stdout): + yield spinner + except KeyboardInterrupt: + spinner.finish("canceled") + raise + except Exception: + spinner.finish("error") + raise + else: + spinner.finish("done") + + +HIDE_CURSOR = "\x1b[?25l" +SHOW_CURSOR = "\x1b[?25h" + + +@contextlib.contextmanager +def hidden_cursor(file: IO[str]) -> Generator[None, None, None]: + # The Windows terminal does not support the hide/show cursor ANSI codes, + # even via colorama. So don't even try. + if WINDOWS: + yield + # We don't want to clutter the output with control characters if we're + # writing to a file, or if the user is running with --quiet. + # See https://github.com/pypa/pip/issues/3418 + elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: + yield + else: + file.write(HIDE_CURSOR) + try: + yield + finally: + file.write(SHOW_CURSOR) diff --git a/backend/venv/Lib/site-packages/pip/_internal/cli/status_codes.py b/backend/venv/Lib/site-packages/pip/_internal/cli/status_codes.py new file mode 100644 index 0000000..5e29502 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/cli/status_codes.py @@ -0,0 +1,6 @@ +SUCCESS = 0 +ERROR = 1 +UNKNOWN_ERROR = 2 +VIRTUALENV_NOT_FOUND = 3 +PREVIOUS_BUILD_DIR_ERROR = 4 +NO_MATCHES_FOUND = 23 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/commands/__init__.py new file mode 100644 index 0000000..858a410 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/__init__.py @@ -0,0 +1,132 @@ +""" +Package containing all pip commands +""" + +import importlib +from collections import namedtuple +from typing import Any, Dict, Optional + +from pip._internal.cli.base_command import Command + +CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary") + +# This dictionary does a bunch of heavy lifting for help output: +# - Enables avoiding additional (costly) imports for presenting `--help`. +# - The ordering matters for help display. +# +# Even though the module path starts with the same "pip._internal.commands" +# prefix, the full path makes testing easier (specifically when modifying +# `commands_dict` in test setup / teardown). +commands_dict: Dict[str, CommandInfo] = { + "install": CommandInfo( + "pip._internal.commands.install", + "InstallCommand", + "Install packages.", + ), + "download": CommandInfo( + "pip._internal.commands.download", + "DownloadCommand", + "Download packages.", + ), + "uninstall": CommandInfo( + "pip._internal.commands.uninstall", + "UninstallCommand", + "Uninstall packages.", + ), + "freeze": CommandInfo( + "pip._internal.commands.freeze", + "FreezeCommand", + "Output installed packages in requirements format.", + ), + "inspect": CommandInfo( + "pip._internal.commands.inspect", + "InspectCommand", + "Inspect the python environment.", + ), + "list": CommandInfo( + "pip._internal.commands.list", + "ListCommand", + "List installed packages.", + ), + "show": CommandInfo( + "pip._internal.commands.show", + "ShowCommand", + "Show information about installed packages.", + ), + "check": CommandInfo( + "pip._internal.commands.check", + "CheckCommand", + "Verify installed packages have compatible dependencies.", + ), + "config": CommandInfo( + "pip._internal.commands.configuration", + "ConfigurationCommand", + "Manage local and global configuration.", + ), + "search": CommandInfo( + "pip._internal.commands.search", + "SearchCommand", + "Search PyPI for packages.", + ), + "cache": CommandInfo( + "pip._internal.commands.cache", + "CacheCommand", + "Inspect and manage pip's wheel cache.", + ), + "index": CommandInfo( + "pip._internal.commands.index", + "IndexCommand", + "Inspect information available from package indexes.", + ), + "wheel": CommandInfo( + "pip._internal.commands.wheel", + "WheelCommand", + "Build wheels from your requirements.", + ), + "hash": CommandInfo( + "pip._internal.commands.hash", + "HashCommand", + "Compute hashes of package archives.", + ), + "completion": CommandInfo( + "pip._internal.commands.completion", + "CompletionCommand", + "A helper command used for command completion.", + ), + "debug": CommandInfo( + "pip._internal.commands.debug", + "DebugCommand", + "Show information useful for debugging.", + ), + "help": CommandInfo( + "pip._internal.commands.help", + "HelpCommand", + "Show help for commands.", + ), +} + + +def create_command(name: str, **kwargs: Any) -> Command: + """ + Create an instance of the Command class with the given name. + """ + module_path, class_name, summary = commands_dict[name] + module = importlib.import_module(module_path) + command_class = getattr(module, class_name) + command = command_class(name=name, summary=summary, **kwargs) + + return command + + +def get_similar_commands(name: str) -> Optional[str]: + """Command name auto-correct.""" + from difflib import get_close_matches + + name = name.lower() + + close_commands = get_close_matches(name, commands_dict.keys()) + + if close_commands: + return close_commands[0] + else: + return None diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5762b053c6344f8fad5becedc5334b95702250fa GIT binary patch literal 4006 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35eddf3a821bdc51889dc19ee7b98e499f10ac23 GIT binary patch literal 2596 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 J#X(~)_Fp?Q7GVGY literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ee794cfe57e350da9265ce9b46ac64728dc9be5 GIT binary patch literal 13167 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 T-!&iS*?xBU;O`k)ptJrD;pHd! literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a975b91bbef1a14ab2ba722ddd1747c051001a90 GIT binary patch literal 10072 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 apQwZn-VMGCzUB3_KWRJkABGaDO0pw+yOZ| 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 M_x~gDr_k~L0M@n(u>b%7 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..938f9fa1884e7a3a2f080773dbc75956c105bb18 GIT binary patch literal 2972 zcmai0T}&L;6~6PkGyB6&`B{E!cU+8|iOSMOwOyka$-*RVg0KW6mA6FGVdt_to0*-> zy|X5)LFK^@AT@IO1P^^kq)Ne}YV*+NDtW0Y^(BZT&>JF0YAdyG8$lH*Pd#^L7jTQz z3w!Q4=brm_&Uen8zhp8=1a0VdGwuf}LVx2ztAQM~qd!8oi5%nz9?HkPkQX9Z%!|;A zp5)7US>R)mr}%1Kjd`RKhxo^9U&I;-6DD!Ioc!S=vdp4n%W*GiF=(C{L;90QFStpDA*Na0UI@n9b?H2OUB4ZG~KPh zbb{Zixdi*T5>jK)^{^2Jh7*9kitW%|@Nl$}TcM%tc{CSE^?~6k35v$gf@p;n$YIOJ z$Wh9AOMlusYB_Z(wYbw2cADpE^}kK*Bw{OppDW#(aoU&LPx%(-Xy@NyM~p25w2VxB zx-O2`_0-6S?G*#SOvz{ZDXY*hAh>=7;uJ^pWQa!r0ybs@70l!OaJ4Re-!K&>JD7$n zQ78p&0aK>h1s(yGaPXpC^Fk(>{O zdSqJ9o=Jw>nSlW~4z+-+p#v@bIJ1%2*Nk1wI7oLKr27v#FC2DXKIj_YwDZP(=lE{t z_(4barv5Aa*CTr!&mBqPciI~5NWXlHl6tbyi}cLn)JAGwySl4g-4?cg^!r;+ZhfZR zJc2C{OEmG$WSbOe;VfEtb&c@-Ctv{IA{{*+ALn8G6r1G}Z1WA{*21ZPLLRlK&7u{d z998s|Chk|I74Z&w1KhGIhdk$^<_IhDiWHupm`g33?ldz?K)<{oqp+hjXBL^_biHGk zjwR!IaSPaCYU*SVOjxQ)AaquZLe*gsT?Q!9(7}WdegndnAv_CN#^M3Bf<=p$2*NYX zRLDg>ewmZ+al*}+T(!dzRe7SKWjA-NU=x!|VDN-F@qK4%2-H9YgQUZQuNZ|IwX4 zn|s&i{w;}_wuXdy`j0i#kzH>i1}tofqz$@hGtD&1s@OiZES9t^KX7Uu=hK$;R?YUB zBMHlLf&!?O*dbkRu>zTGHLI(|Gk|;-79<=agu5J^77`|b6Nw4p6BO+mU7GN~MTAF; z-T?9leJv`A)@VZ+b8Yfq;L;~@_DD`EV~q<*CA)RKfuP&&-Yz`pkJt|>09wh$Yevg) zpT%L}7b`TY6tD>Kh(*|K0JDk0le)bEUji+hTtlm3c!KzH6E%E#tE~tvq^?R~v!Wu% zgq9X?*~M|WBAr*YSLBu*AhAbAI(%*Lzt;Xxo2B#W`c8BESu})xh^Vk63g|u(;O`gz z$Np{UK3Wn?seXATda#VJRfZk62vs(IUpZ=XOe71_rpn}?ilNwYM0@T6lPY+L@GN9% zt?JkzW_k&~9nS`kpSYYQn(s1{XPC;A_%q^JsFSO(P(-c)Lw^or4gFoutUK@C`Bd-U z`srbN@8gFX54UdawGXe$hdsu7+0T2-^~omwx0KJ)m%f%z@AKa%C^^v35ah-9#`s=p z@Dq9P8~uNE-%_5T@7%b3QTq6za{F4s>?7Af!xCOlEJ9r;!(7s!>cvk34?k1G`c*@R#W=yo$xEQ) zc|h+2X-I+~e1Y1c|Kyiw@Jp2a2YTTty7?4MJVoPQ=>zN8eSKh8AK3cwo_=LbJywT= d?7LTw5p<0yK@~1+Neu+ucHDg^9djw#`ajD^yYv76 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39847c7458101af10bcbfebb2f2ac6c442147508 GIT binary patch literal 1677 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 BJAwcJ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd0a0a91336e4fb740e2be2e3f8d92f9b426d86d GIT binary patch literal 3984 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 K1~;)`O7y?+c!GNClF% zKkmI*E=kdH8{7aKzIpTJ&6}AwGw;3G|FBw36r_%SI~9Jng`$3o1vRlnV9iTY)D4QK zcsfFj;lCzAM>S&_8ewfj8)e3rsBTOb)sN|;hA~5w9b==$F(avGBBrQ$%uHZi#1gfR zSqZF<*rN6^JAn-mN3>?FCh8n>k}?}{McrfWXzf@nDH|hoQO}r%rZkj5P4%b(mj8wN zJ0K&bu?7uwgyK!FP`p{N-_aJajRb1}tW{u3*e2d47=-3}AmZ%;BQ)_ePfuvEJi+je zSD3LDzDCdqO@zWJwDKmaTv!4! z?$qId?od2B9SH|x2`(B8N4N_@kQYQw;qNESlAYv__B`*Rgz6XoumtZ@@#o2S?pbSEcKL_PY=SITg=OobIZdFCjO^2s<0X6JB z*i^f)J!}(cmjwFepPrS?WznRhr$R6N6%~yjjx+?>6)MkKu34{Ib1au;xxB@Zx76lq zym?n^-d&%sIaaVz#u&@3Z^XfDt7dis~ja zL2*(FRceY3>WOas6o4C4N+UHUunkF@>(rg1Zqihuq(!Hp<(xKA(x8-9rJ7?BMwMTR zNzqf}=vOhyKVU5zF<5$AqaK-(zOtu;O{G0e`Lv@+KRJZ@xRVh9&K?d{@lu!X~(086Wg#_ zE6&7{_DYQaL>JUZMSNZ#R|*M08Xx-^qYf-r<0=N~#c3>!?8i}X@ zvKEeiSqt+c?tj`*QT1Sk+6FG(8S4t=ZrnRpiD_ds8+Vqvuw#hi7C3^%*}!xh)JoZJqdtR(R++dP zv&S%d5;EBy2n1uXc!G>m3Is$ve~4m=dlAA-peQ367b0d)z)yM=vcIMBChN;b^H#^p zBY9iR%g6JrUCY`x=Q7OByv@1Ldo`S4Jo%d1h0yi-4AYReJ6|5n*8vCzatT>(?5tam zuKO}fW8Pwac{uN^%`mkJZ*L=F%k^g0!r-Fo`q8wxCCjuZG7|B+QAXUb8%zQ`L~$Hz z3~abp>xL;Bls!>08ty<9ra2mpR&`4#D3Yu7gVZ%mNE4<)n)7y`)}%C>83rlM8=BW@ z7@(Td{ID)XK`U)YGl{L>gxvhtzpi=B&QNm<)RvC_gjp3KMWq z0xW)Q!l_d7OaiBzqy(PrBqt3s=VebDa#bzQ&ovKzHKVeSb@uqDgr2~b1-L1*{*1L^PD|q zu9!Dlsl6TA?|iuZoFnC!!uzEv@s>%dG!HdEgU3Tv;;p=`MB_|3B{5YqNS%+u8n{xf zsopAbDDrmR@pg^chUlmpXx&qIbW|mEWK(#(RVCh8?s?OCS4I84s>V=MdC%3RYI*lX zFgaj{oClfz94+{_F`A(gPpSO)oneZvg?YtWqbj{Y^L0>jpb8B|sPRC}(+}6YL`&$G z+knCg6o($BfSUT03G#-N8S+M;8r+ns32F{MTvO3Q^CQ;1rM&LYL+c|}o-5BUP`Oi1 z$lFpikhedgMaPB~osXc}vVm&rBdEGIP;Gkzm2U&p_LLQ*+mW)rLH`~7_w)^#hEwOY zeukPghhWz6RK5&3fwV=4oRpX0ib#0Xx$LAwhNhm!wl7?!UeZ2KU8akzjD(V_pzH?Y zzI1NGir`&Sl~hgq*5`?d^nG0I8)V~DmLQt}^v5ts&zT9;feI=#t4RVXJxxtgb5=sL zQ>FP=?Pc26o%~-D8q`OE;ADy%4+cs&B5@O9JX+yp@)eN@$LvpzY6BVJOvjU{R(@Po+=py9z8KbypG1(#p&zF{00o4v(Jr?&zpbC)-MaG2%hVH4q07 zA<8uk(E%YA3Ja2G2JRxBxH79+%Mhs0_|Z?7nxpm9Iy3YfhI zlFw}Bc>4FFHb$fa{s6|+6kP*fwd9_b2}+#KVK*VjzWyKT>nl`&(m71O@oryW^7h7@ zeS6xzJ>R=0*LyVGdot1d@*iQdT)4^u;1G)`Bh_&b;x`<&) z4H_verur!)9pH!Tt?z5*xlE!Di%Yi5mxH*(e z@B9Ll5Xqy#mn4V_!cuq3bU+*eG*Ji_9e*C{C4l3<;dYQuk2Fvl54)LJ45t zS>WpwaS7!*qR|ioRSuA1G*=Q~FH=OfWxW&^69O-5li_L6hv@CtkeLD(O+;f{#2u>m zWbCjoJ0yy6Q9O${vMqFx_+>#9(Up;FNpE8C@`gPm8$}4E1`@(c5V$5&841TAz*ut_ z;*6v5#9=(~2-_k9UH~^#6nKa;LjW2!;d98`fI9_7B5MJVb;_EsAqW;t#3MWgWu_y+ zkN`E%Xqq^LGK;bh-`R{%@h+%Xw9-=fJRvng(PdIFHXvaXc$~s z2rHdOa#Oh;!au@`Wi60vDwU6no~)5n*wdHW^K5$0 zv)MhTGmbOqJ*Srw3+`M^XS$|yiBH#TU)ggy?KpGg=x2NOXPo`-&MYUguFj=1_g&lX z&RiK@arUp;+^enaOHVBC$hJP2WlyAApSsk*YW=I_xeVE=w4}k@*aC)O{=l% zuN?VOPqFq@)^^Qy)wbf5dQ1OeXu);E z`-XRAOMlvNVAbuparFApbpzwI%|BCcXpJ4K4P3fy?|be{+kuY;etGnRquGYh`QZY~ z7+dmO=Plb!+sdwk8Sc=Er8(cYGuOB$-MHud+LgvVnZ_gYBL$YKYsl5^O4shn)b5@) z<;}G#=H|Sw`|8l=?uNy_jC*)HRtI{d%Bjbcg2jSZ{Cu3HQv~N zegBeq`BcW$GtYiz_pF&HZ|8zG-`07n{$~Ah?|U^%^_jM(uG zZ_U0r`wxG;@XTlK`hp!gT6a?R#;+)s-2~B&8_lmb7qkFBaC>v^&U^08f(}Z+pswM@ z`RnKJ)oxoF|GHp697}cW$ZZ|Gw{@^!gz}drs;;GAM#w_dcNVNjW1~EcH)5~H3U(|x zsFwCz^JD4e$L=-ny$gJ55bLDsiwF2}(_Jy^?JKwt?WSs*Z;V_YS*l+?ly&ba)B^I$ zI_$%Pke6!MTBt|D2Fl$;rjT83&$_w`jfiZb8rt7#db4RMc6U5mzpv1Y$d)RWt%&3( zZrfX_H&ZJ+pMJkR+d5Qe1MHXW$i4%iPRiviYyoJUav4ou3N+~7H(#|;HD~E>WM}_3 zzhzH+z0Oe%?^hIUtd%Y9f)@V&^p%CG`Oeo6sCBes1yRmLKG(80-Lf~+()W?}m&Ol_ zS+~%b%oQz$SjVd6c4; z+{69MzZ(GhxpPFrd|<5u@PiJ^h{5zh4}h2VK0FjEys80KJ6m#b{gRw1ooSc_v=30N8tT5!u<%#)(!Tth;auJbKmfwfnEz5 zw`-@sR)qIs8X{0ds}SNoB@2;6Zhl;hHZgNL9-c2!@UD0f?pe{CKn^7FjA~PYM+6*| zRDS44lq}1XZnLM2DTt6&Ctj!WRO1P1c}`!^vmQ8>o;u1r)HWbbSxN)Y;)Y% z@`z$}71TDMZc_P_|I5@Bw05A~B+^!G-VzY{nhZ!&3tX((5dn+ z|EpTFDJRz>Ic+U-P@#u8r8MGCE97#61Zb#LrA>RT1=?*@gizd+wodIC9;J0tXg^jZ zh{|DP)KDRdCuJz}!pLYvop%GjO`?Xt57vH;t!U#(v75ya?-V7e=&NNzU!|`^&;wCMMqc&Bv^Q27Q ze$>Eu5oFbZ%iok7Frn$FgibJOQTZjsp9{Ar0SYB}arg{*xld}lyTLc|Ct38cF?NwO zKc~DXDTSiHLkiZCn?;Hy#n&OQqtfp|j8F3g`juaxbDgYv*y$my%tbsYSVoF3W2DqP zRD2!7=VW{xD+PfR;#11&r-UVO6g#mOQGECKETM59FTRm=SB}W4MvFv+QQ5^Y*;i zGXLTapIEhc7i+VY*3a9v{GnDQb%JmGVdxk$A$n>1dbUmACJGH{Le9pQT z#+KY@jAz*$t57<>GcI=j^&U(29=mTD{v1SXUS{60+_q#bPawDN zFP*t{{^t2C+nYDrb7o)K>{~J8Q1Xslcip+&C(^r5tZOw^8`z!3T0;K(&F7aB@66qv z%WUb-vImG1TY;(Zw()Lf?y*DZ#|~w-4P@ED-bEUdiUY11w~qHUG99xf7_q6 z?88z^*0L=RR(y*;+u~m^tvZ?(pIaKc@8|(XqjeWb+?uuc^7YNR`t8~J?F%}E;_R&# zZocr7^Y!1JNr`$iZcYf_%|(>>q1-|!a9iLfMgCAE>>r1?MWFa?k!XQVHzR_t z*Ag=lkioZ8{S-eK3wp zq9!EPLm~$Lgn zzryzK)3j-cSvq~wSfCJI4!>u4pZ|DpW$($f|JgNyD;&~3K{tY1y*QF~`3hKg;BXgo W@DFaR%~>!Y#8P_Gx)C6v9sdV5=kZ4X literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4103c350dba5e50c9d3c40d8eb4cb7c0176f28a GIT binary patch literal 4713 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/cache.py b/backend/venv/Lib/site-packages/pip/_internal/commands/cache.py new file mode 100644 index 0000000..ad65641 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/cache.py @@ -0,0 +1,228 @@ +import os +import textwrap +from optparse import Values +from typing import Any, List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.exceptions import CommandError, PipError +from pip._internal.utils import filesystem +from pip._internal.utils.logging import getLogger +from pip._internal.utils.misc import format_size + +logger = getLogger(__name__) + + +class CacheCommand(Command): + """ + Inspect and manage pip's wheel cache. + + Subcommands: + + - dir: Show the cache directory. + - info: Show information about the cache. + - list: List filenames of packages stored in the cache. + - remove: Remove one or more package from the cache. + - purge: Remove all items from the cache. + + ```` can be a glob expression or a package name. + """ + + ignore_require_venv = True + usage = """ + %prog dir + %prog info + %prog list [] [--format=[human, abspath]] + %prog remove + %prog purge + """ + + def add_options(self) -> None: + self.cmd_opts.add_option( + "--format", + action="store", + dest="list_format", + default="human", + choices=("human", "abspath"), + help="Select the output format among: human (default) or abspath", + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + handlers = { + "dir": self.get_cache_dir, + "info": self.get_cache_info, + "list": self.list_cache_items, + "remove": self.remove_cache_items, + "purge": self.purge_cache, + } + + if not options.cache_dir: + logger.error("pip cache commands can not function since cache is disabled.") + return ERROR + + # Determine action + if not args or args[0] not in handlers: + logger.error( + "Need an action (%s) to perform.", + ", ".join(sorted(handlers)), + ) + return ERROR + + action = args[0] + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def get_cache_dir(self, options: Values, args: List[Any]) -> None: + if args: + raise CommandError("Too many arguments") + + logger.info(options.cache_dir) + + def get_cache_info(self, options: Values, args: List[Any]) -> None: + if args: + raise CommandError("Too many arguments") + + num_http_files = len(self._find_http_files(options)) + num_packages = len(self._find_wheels(options, "*")) + + http_cache_location = self._cache_dir(options, "http-v2") + old_http_cache_location = self._cache_dir(options, "http") + wheels_cache_location = self._cache_dir(options, "wheels") + http_cache_size = filesystem.format_size( + filesystem.directory_size(http_cache_location) + + filesystem.directory_size(old_http_cache_location) + ) + wheels_cache_size = filesystem.format_directory_size(wheels_cache_location) + + message = ( + textwrap.dedent( + """ + Package index page cache location (pip v23.3+): {http_cache_location} + Package index page cache location (older pips): {old_http_cache_location} + Package index page cache size: {http_cache_size} + Number of HTTP files: {num_http_files} + Locally built wheels location: {wheels_cache_location} + Locally built wheels size: {wheels_cache_size} + Number of locally built wheels: {package_count} + """ # noqa: E501 + ) + .format( + http_cache_location=http_cache_location, + old_http_cache_location=old_http_cache_location, + http_cache_size=http_cache_size, + num_http_files=num_http_files, + wheels_cache_location=wheels_cache_location, + package_count=num_packages, + wheels_cache_size=wheels_cache_size, + ) + .strip() + ) + + logger.info(message) + + def list_cache_items(self, options: Values, args: List[Any]) -> None: + if len(args) > 1: + raise CommandError("Too many arguments") + + if args: + pattern = args[0] + else: + pattern = "*" + + files = self._find_wheels(options, pattern) + if options.list_format == "human": + self.format_for_human(files) + else: + self.format_for_abspath(files) + + def format_for_human(self, files: List[str]) -> None: + if not files: + logger.info("No locally built wheels cached.") + return + + results = [] + for filename in files: + wheel = os.path.basename(filename) + size = filesystem.format_file_size(filename) + results.append(f" - {wheel} ({size})") + logger.info("Cache contents:\n") + logger.info("\n".join(sorted(results))) + + def format_for_abspath(self, files: List[str]) -> None: + if files: + logger.info("\n".join(sorted(files))) + + def remove_cache_items(self, options: Values, args: List[Any]) -> None: + if len(args) > 1: + raise CommandError("Too many arguments") + + if not args: + raise CommandError("Please provide a pattern") + + files = self._find_wheels(options, args[0]) + + no_matching_msg = "No matching packages" + if args[0] == "*": + # Only fetch http files if no specific pattern given + files += self._find_http_files(options) + else: + # Add the pattern to the log message + no_matching_msg += f' for pattern "{args[0]}"' + + if not files: + logger.warning(no_matching_msg) + + bytes_removed = 0 + for filename in files: + bytes_removed += os.stat(filename).st_size + os.unlink(filename) + logger.verbose("Removed %s", filename) + logger.info("Files removed: %s (%s)", len(files), format_size(bytes_removed)) + + def purge_cache(self, options: Values, args: List[Any]) -> None: + if args: + raise CommandError("Too many arguments") + + return self.remove_cache_items(options, ["*"]) + + def _cache_dir(self, options: Values, subdir: str) -> str: + return os.path.join(options.cache_dir, subdir) + + def _find_http_files(self, options: Values) -> List[str]: + old_http_dir = self._cache_dir(options, "http") + new_http_dir = self._cache_dir(options, "http-v2") + return filesystem.find_files(old_http_dir, "*") + filesystem.find_files( + new_http_dir, "*" + ) + + def _find_wheels(self, options: Values, pattern: str) -> List[str]: + wheel_dir = self._cache_dir(options, "wheels") + + # The wheel filename format, as specified in PEP 427, is: + # {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl + # + # Additionally, non-alphanumeric values in the distribution are + # normalized to underscores (_), meaning hyphens can never occur + # before `-{version}`. + # + # Given that information: + # - If the pattern we're given contains a hyphen (-), the user is + # providing at least the version. Thus, we can just append `*.whl` + # to match the rest of it. + # - If the pattern we're given doesn't contain a hyphen (-), the + # user is only providing the name. Thus, we append `-*.whl` to + # match the hyphen before the version, followed by anything else. + # + # PEP 427: https://www.python.org/dev/peps/pep-0427/ + pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl") + + return filesystem.find_files(wheel_dir, pattern) diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/check.py b/backend/venv/Lib/site-packages/pip/_internal/commands/check.py new file mode 100644 index 0000000..f54a16d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/check.py @@ -0,0 +1,67 @@ +import logging +from optparse import Values +from typing import List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.metadata import get_default_environment +from pip._internal.operations.check import ( + check_package_set, + check_unsupported, + create_package_set_from_installed, +) +from pip._internal.utils.compatibility_tags import get_supported +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class CheckCommand(Command): + """Verify installed packages have compatible dependencies.""" + + ignore_require_venv = True + usage = """ + %prog [options]""" + + def run(self, options: Values, args: List[str]) -> int: + package_set, parsing_probs = create_package_set_from_installed() + missing, conflicting = check_package_set(package_set) + unsupported = list( + check_unsupported( + get_default_environment().iter_installed_distributions(), + get_supported(), + ) + ) + + for project_name in missing: + version = package_set[project_name].version + for dependency in missing[project_name]: + write_output( + "%s %s requires %s, which is not installed.", + project_name, + version, + dependency[0], + ) + + for project_name in conflicting: + version = package_set[project_name].version + for dep_name, dep_version, req in conflicting[project_name]: + write_output( + "%s %s has requirement %s, but you have %s %s.", + project_name, + version, + req, + dep_name, + dep_version, + ) + for package in unsupported: + write_output( + "%s %s is not supported on this platform", + package.raw_name, + package.version, + ) + if missing or conflicting or parsing_probs or unsupported: + return ERROR + else: + write_output("No broken requirements found.") + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/completion.py b/backend/venv/Lib/site-packages/pip/_internal/commands/completion.py new file mode 100644 index 0000000..9e89e27 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/completion.py @@ -0,0 +1,130 @@ +import sys +import textwrap +from optparse import Values +from typing import List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.utils.misc import get_prog + +BASE_COMPLETION = """ +# pip {shell} completion start{script}# pip {shell} completion end +""" + +COMPLETION_SCRIPTS = { + "bash": """ + _pip_completion() + {{ + COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) + }} + complete -o default -F _pip_completion {prog} + """, + "zsh": """ + #compdef -P pip[0-9.]# + __pip() {{ + compadd $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$((CURRENT-1)) \\ + PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null ) + }} + if [[ $zsh_eval_context[-1] == loadautofunc ]]; then + # autoload from fpath, call function directly + __pip "$@" + else + # eval/source/. command, register function for later + compdef __pip -P 'pip[0-9.]#' + fi + """, + "fish": """ + function __fish_complete_pip + set -lx COMP_WORDS (commandline -o) "" + set -lx COMP_CWORD ( \\ + math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ + ) + set -lx PIP_AUTO_COMPLETE 1 + string split \\ -- (eval $COMP_WORDS[1]) + end + complete -fa "(__fish_complete_pip)" -c {prog} + """, + "powershell": """ + if ((Test-Path Function:\\TabExpansion) -and -not ` + (Test-Path Function:\\_pip_completeBackup)) {{ + Rename-Item Function:\\TabExpansion _pip_completeBackup + }} + function TabExpansion($line, $lastWord) {{ + $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart() + if ($lastBlock.StartsWith("{prog} ")) {{ + $Env:COMP_WORDS=$lastBlock + $Env:COMP_CWORD=$lastBlock.Split().Length - 1 + $Env:PIP_AUTO_COMPLETE=1 + (& {prog}).Split() + Remove-Item Env:COMP_WORDS + Remove-Item Env:COMP_CWORD + Remove-Item Env:PIP_AUTO_COMPLETE + }} + elseif (Test-Path Function:\\_pip_completeBackup) {{ + # Fall back on existing tab expansion + _pip_completeBackup $line $lastWord + }} + }} + """, +} + + +class CompletionCommand(Command): + """A helper command to be used for command completion.""" + + ignore_require_venv = True + + def add_options(self) -> None: + self.cmd_opts.add_option( + "--bash", + "-b", + action="store_const", + const="bash", + dest="shell", + help="Emit completion code for bash", + ) + self.cmd_opts.add_option( + "--zsh", + "-z", + action="store_const", + const="zsh", + dest="shell", + help="Emit completion code for zsh", + ) + self.cmd_opts.add_option( + "--fish", + "-f", + action="store_const", + const="fish", + dest="shell", + help="Emit completion code for fish", + ) + self.cmd_opts.add_option( + "--powershell", + "-p", + action="store_const", + const="powershell", + dest="shell", + help="Emit completion code for powershell", + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ["--" + shell for shell in sorted(shells)] + if options.shell in shells: + script = textwrap.dedent( + COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog()) + ) + print(BASE_COMPLETION.format(script=script, shell=options.shell)) + return SUCCESS + else: + sys.stderr.write( + "ERROR: You must pass {}\n".format(" or ".join(shell_options)) + ) + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/configuration.py b/backend/venv/Lib/site-packages/pip/_internal/commands/configuration.py new file mode 100644 index 0000000..1a1dc6b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/configuration.py @@ -0,0 +1,280 @@ +import logging +import os +import subprocess +from optparse import Values +from typing import Any, List, Optional + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.configuration import ( + Configuration, + Kind, + get_configuration_files, + kinds, +) +from pip._internal.exceptions import PipError +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import get_prog, write_output + +logger = logging.getLogger(__name__) + + +class ConfigurationCommand(Command): + """ + Manage local and global configuration. + + Subcommands: + + - list: List the active configuration (or from the file specified) + - edit: Edit the configuration file in an editor + - get: Get the value associated with command.option + - set: Set the command.option=value + - unset: Unset the value associated with command.option + - debug: List the configuration files and values defined under them + + Configuration keys should be dot separated command and option name, + with the special prefix "global" affecting any command. For example, + "pip config set global.index-url https://example.org/" would configure + the index url for all commands, but "pip config set download.timeout 10" + would configure a 10 second timeout only for "pip download" commands. + + If none of --user, --global and --site are passed, a virtual + environment configuration file is used if one is active and the file + exists. Otherwise, all modifications happen to the user file by + default. + """ + + ignore_require_venv = True + usage = """ + %prog [] list + %prog [] [--editor ] edit + + %prog [] get command.option + %prog [] set command.option value + %prog [] unset command.option + %prog [] debug + """ + + def add_options(self) -> None: + self.cmd_opts.add_option( + "--editor", + dest="editor", + action="store", + default=None, + help=( + "Editor to use to edit the file. Uses VISUAL or EDITOR " + "environment variables if not provided." + ), + ) + + self.cmd_opts.add_option( + "--global", + dest="global_file", + action="store_true", + default=False, + help="Use the system-wide configuration file only", + ) + + self.cmd_opts.add_option( + "--user", + dest="user_file", + action="store_true", + default=False, + help="Use the user configuration file only", + ) + + self.cmd_opts.add_option( + "--site", + dest="site_file", + action="store_true", + default=False, + help="Use the current environment configuration file only", + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + handlers = { + "list": self.list_values, + "edit": self.open_in_editor, + "get": self.get_name, + "set": self.set_name_value, + "unset": self.unset_name, + "debug": self.list_config_values, + } + + # Determine action + if not args or args[0] not in handlers: + logger.error( + "Need an action (%s) to perform.", + ", ".join(sorted(handlers)), + ) + return ERROR + + action = args[0] + + # Determine which configuration files are to be loaded + # Depends on whether the command is modifying. + try: + load_only = self._determine_file( + options, need_value=(action in ["get", "set", "unset", "edit"]) + ) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + # Load a new configuration + self.configuration = Configuration( + isolated=options.isolated_mode, load_only=load_only + ) + self.configuration.load() + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _determine_file(self, options: Values, need_value: bool) -> Optional[Kind]: + file_options = [ + key + for key, value in ( + (kinds.USER, options.user_file), + (kinds.GLOBAL, options.global_file), + (kinds.SITE, options.site_file), + ) + if value + ] + + if not file_options: + if not need_value: + return None + # Default to user, unless there's a site file. + elif any( + os.path.exists(site_config_file) + for site_config_file in get_configuration_files()[kinds.SITE] + ): + return kinds.SITE + else: + return kinds.USER + elif len(file_options) == 1: + return file_options[0] + + raise PipError( + "Need exactly one file to operate upon " + "(--user, --site, --global) to perform." + ) + + def list_values(self, options: Values, args: List[str]) -> None: + self._get_n_args(args, "list", n=0) + + for key, value in sorted(self.configuration.items()): + write_output("%s=%r", key, value) + + def get_name(self, options: Values, args: List[str]) -> None: + key = self._get_n_args(args, "get [name]", n=1) + value = self.configuration.get_value(key) + + write_output("%s", value) + + def set_name_value(self, options: Values, args: List[str]) -> None: + key, value = self._get_n_args(args, "set [name] [value]", n=2) + self.configuration.set_value(key, value) + + self._save_configuration() + + def unset_name(self, options: Values, args: List[str]) -> None: + key = self._get_n_args(args, "unset [name]", n=1) + self.configuration.unset_value(key) + + self._save_configuration() + + def list_config_values(self, options: Values, args: List[str]) -> None: + """List config key-value pairs across different config files""" + self._get_n_args(args, "debug", n=0) + + self.print_env_var_values() + # Iterate over config files and print if they exist, and the + # key-value pairs present in them if they do + for variant, files in sorted(self.configuration.iter_config_files()): + write_output("%s:", variant) + for fname in files: + with indent_log(): + file_exists = os.path.exists(fname) + write_output("%s, exists: %r", fname, file_exists) + if file_exists: + self.print_config_file_values(variant) + + def print_config_file_values(self, variant: Kind) -> None: + """Get key-value pairs from the file of a variant""" + for name, value in self.configuration.get_values_in_config(variant).items(): + with indent_log(): + write_output("%s: %s", name, value) + + def print_env_var_values(self) -> None: + """Get key-values pairs present as environment variables""" + write_output("%s:", "env_var") + with indent_log(): + for key, value in sorted(self.configuration.get_environ_vars()): + env_var = f"PIP_{key.upper()}" + write_output("%s=%r", env_var, value) + + def open_in_editor(self, options: Values, args: List[str]) -> None: + editor = self._determine_editor(options) + + fname = self.configuration.get_file_to_edit() + if fname is None: + raise PipError("Could not determine appropriate file.") + elif '"' in fname: + # This shouldn't happen, unless we see a username like that. + # If that happens, we'd appreciate a pull request fixing this. + raise PipError( + f'Can not open an editor for a file name containing "\n{fname}' + ) + + try: + subprocess.check_call(f'{editor} "{fname}"', shell=True) + except FileNotFoundError as e: + if not e.filename: + e.filename = editor + raise + except subprocess.CalledProcessError as e: + raise PipError(f"Editor Subprocess exited with exit code {e.returncode}") + + def _get_n_args(self, args: List[str], example: str, n: int) -> Any: + """Helper to make sure the command got the right number of arguments""" + if len(args) != n: + msg = ( + f"Got unexpected number of arguments, expected {n}. " + f'(example: "{get_prog()} config {example}")' + ) + raise PipError(msg) + + if n == 1: + return args[0] + else: + return args + + def _save_configuration(self) -> None: + # We successfully ran a modifying command. Need to save the + # configuration. + try: + self.configuration.save() + except Exception: + logger.exception( + "Unable to save configuration. Please report this as a bug." + ) + raise PipError("Internal Error.") + + def _determine_editor(self, options: Values) -> str: + if options.editor is not None: + return options.editor + elif "VISUAL" in os.environ: + return os.environ["VISUAL"] + elif "EDITOR" in os.environ: + return os.environ["EDITOR"] + else: + raise PipError("Could not determine editor to use.") diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/debug.py b/backend/venv/Lib/site-packages/pip/_internal/commands/debug.py new file mode 100644 index 0000000..567ca96 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/debug.py @@ -0,0 +1,201 @@ +import locale +import logging +import os +import sys +from optparse import Values +from types import ModuleType +from typing import Any, Dict, List, Optional + +import pip._vendor +from pip._vendor.certifi import where +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.configuration import Configuration +from pip._internal.metadata import get_environment +from pip._internal.utils.compat import open_text_resource +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import get_pip_version + +logger = logging.getLogger(__name__) + + +def show_value(name: str, value: Any) -> None: + logger.info("%s: %s", name, value) + + +def show_sys_implementation() -> None: + logger.info("sys.implementation:") + implementation_name = sys.implementation.name + with indent_log(): + show_value("name", implementation_name) + + +def create_vendor_txt_map() -> Dict[str, str]: + with open_text_resource("pip._vendor", "vendor.txt") as f: + # Purge non version specifying lines. + # Also, remove any space prefix or suffixes (including comments). + lines = [ + line.strip().split(" ", 1)[0] for line in f.readlines() if "==" in line + ] + + # Transform into "module" -> version dict. + return dict(line.split("==", 1) for line in lines) + + +def get_module_from_module_name(module_name: str) -> Optional[ModuleType]: + # Module name can be uppercase in vendor.txt for some reason... + module_name = module_name.lower().replace("-", "_") + # PATCH: setuptools is actually only pkg_resources. + if module_name == "setuptools": + module_name = "pkg_resources" + + try: + __import__(f"pip._vendor.{module_name}", globals(), locals(), level=0) + return getattr(pip._vendor, module_name) + except ImportError: + # We allow 'truststore' to fail to import due + # to being unavailable on Python 3.9 and earlier. + if module_name == "truststore" and sys.version_info < (3, 10): + return None + raise + + +def get_vendor_version_from_module(module_name: str) -> Optional[str]: + module = get_module_from_module_name(module_name) + version = getattr(module, "__version__", None) + + if module and not version: + # Try to find version in debundled module info. + assert module.__file__ is not None + env = get_environment([os.path.dirname(module.__file__)]) + dist = env.get_distribution(module_name) + if dist: + version = str(dist.version) + + return version + + +def show_actual_vendor_versions(vendor_txt_versions: Dict[str, str]) -> None: + """Log the actual version and print extra info if there is + a conflict or if the actual version could not be imported. + """ + for module_name, expected_version in vendor_txt_versions.items(): + extra_message = "" + actual_version = get_vendor_version_from_module(module_name) + if not actual_version: + extra_message = ( + " (Unable to locate actual module version, using" + " vendor.txt specified version)" + ) + actual_version = expected_version + elif parse_version(actual_version) != parse_version(expected_version): + extra_message = ( + " (CONFLICT: vendor.txt suggests version should" + f" be {expected_version})" + ) + logger.info("%s==%s%s", module_name, actual_version, extra_message) + + +def show_vendor_versions() -> None: + logger.info("vendored library versions:") + + vendor_txt_versions = create_vendor_txt_map() + with indent_log(): + show_actual_vendor_versions(vendor_txt_versions) + + +def show_tags(options: Values) -> None: + tag_limit = 10 + + target_python = make_target_python(options) + tags = target_python.get_sorted_tags() + + # Display the target options that were explicitly provided. + formatted_target = target_python.format_given() + suffix = "" + if formatted_target: + suffix = f" (target: {formatted_target})" + + msg = f"Compatible tags: {len(tags)}{suffix}" + logger.info(msg) + + if options.verbose < 1 and len(tags) > tag_limit: + tags_limited = True + tags = tags[:tag_limit] + else: + tags_limited = False + + with indent_log(): + for tag in tags: + logger.info(str(tag)) + + if tags_limited: + msg = f"...\n[First {tag_limit} tags shown. Pass --verbose to show all.]" + logger.info(msg) + + +def ca_bundle_info(config: Configuration) -> str: + levels = {key.split(".", 1)[0] for key, _ in config.items()} + if not levels: + return "Not specified" + + levels_that_override_global = ["install", "wheel", "download"] + global_overriding_level = [ + level for level in levels if level in levels_that_override_global + ] + if not global_overriding_level: + return "global" + + if "global" in levels: + levels.remove("global") + return ", ".join(levels) + + +class DebugCommand(Command): + """ + Display debug information. + """ + + usage = """ + %prog """ + ignore_require_venv = True + + def add_options(self) -> None: + cmdoptions.add_target_python_options(self.cmd_opts) + self.parser.insert_option_group(0, self.cmd_opts) + self.parser.config.load() + + def run(self, options: Values, args: List[str]) -> int: + logger.warning( + "This command is only meant for debugging. " + "Do not use this with automation for parsing and getting these " + "details, since the output and options of this command may " + "change without notice." + ) + show_value("pip version", get_pip_version()) + show_value("sys.version", sys.version) + show_value("sys.executable", sys.executable) + show_value("sys.getdefaultencoding", sys.getdefaultencoding()) + show_value("sys.getfilesystemencoding", sys.getfilesystemencoding()) + show_value( + "locale.getpreferredencoding", + locale.getpreferredencoding(), + ) + show_value("sys.platform", sys.platform) + show_sys_implementation() + + show_value("'cert' config value", ca_bundle_info(self.parser.config)) + show_value("REQUESTS_CA_BUNDLE", os.environ.get("REQUESTS_CA_BUNDLE")) + show_value("CURL_CA_BUNDLE", os.environ.get("CURL_CA_BUNDLE")) + show_value("pip._vendor.certifi.where()", where()) + show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) + + show_vendor_versions() + + show_tags(options) + + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/download.py b/backend/venv/Lib/site-packages/pip/_internal/commands/download.py new file mode 100644 index 0000000..917bbb9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/download.py @@ -0,0 +1,146 @@ +import logging +import os +from optparse import Values +from typing import List + +from pip._internal.cli import cmdoptions +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.operations.build.build_tracker import get_build_tracker +from pip._internal.req.req_install import check_legacy_setup_py_options +from pip._internal.utils.misc import ensure_dir, normalize_path, write_output +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +class DownloadCommand(RequirementCommand): + """ + Download packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports downloading from "requirements files", which provide + an easy way to specify a whole environment to be downloaded. + """ + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] ... + %prog [options] ... + %prog [options] ...""" + + def add_options(self) -> None: + self.cmd_opts.add_option(cmdoptions.constraints()) + self.cmd_opts.add_option(cmdoptions.requirements()) + self.cmd_opts.add_option(cmdoptions.no_deps()) + self.cmd_opts.add_option(cmdoptions.global_options()) + self.cmd_opts.add_option(cmdoptions.no_binary()) + self.cmd_opts.add_option(cmdoptions.only_binary()) + self.cmd_opts.add_option(cmdoptions.prefer_binary()) + self.cmd_opts.add_option(cmdoptions.src()) + self.cmd_opts.add_option(cmdoptions.pre()) + self.cmd_opts.add_option(cmdoptions.require_hashes()) + self.cmd_opts.add_option(cmdoptions.progress_bar()) + self.cmd_opts.add_option(cmdoptions.no_build_isolation()) + self.cmd_opts.add_option(cmdoptions.use_pep517()) + self.cmd_opts.add_option(cmdoptions.no_use_pep517()) + self.cmd_opts.add_option(cmdoptions.check_build_deps()) + self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) + + self.cmd_opts.add_option( + "-d", + "--dest", + "--destination-dir", + "--destination-directory", + dest="download_dir", + metavar="dir", + default=os.curdir, + help="Download packages into .", + ) + + cmdoptions.add_target_python_options(self.cmd_opts) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + @with_cleanup + def run(self, options: Values, args: List[str]) -> int: + options.ignore_installed = True + # editable doesn't really make sense for `pip download`, but the bowels + # of the RequirementSet code require that property. + options.editables = [] + + cmdoptions.check_dist_restriction(options) + + options.download_dir = normalize_path(options.download_dir) + ensure_dir(options.download_dir) + + session = self.get_default_session(options) + + target_python = make_target_python(options) + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ignore_requires_python=options.ignore_requires_python, + ) + + build_tracker = self.enter_context(get_build_tracker()) + + directory = TempDirectory( + delete=not options.no_clean, + kind="download", + globally_managed=True, + ) + + reqs = self.get_requirements(args, options, finder, session) + check_legacy_setup_py_options(options, reqs) + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + build_tracker=build_tracker, + session=session, + finder=finder, + download_dir=options.download_dir, + use_user_site=False, + verbosity=self.verbosity, + ) + + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + ignore_requires_python=options.ignore_requires_python, + use_pep517=options.use_pep517, + py_version_info=options.python_version, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve(reqs, check_supported_wheels=True) + + downloaded: List[str] = [] + for req in requirement_set.requirements.values(): + if req.satisfied_by is None: + assert req.name is not None + preparer.save_linked_requirement(req) + downloaded.append(req.name) + + preparer.prepare_linked_requirements_more(requirement_set.requirements.values()) + + if downloaded: + write_output("Successfully downloaded %s", " ".join(downloaded)) + + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/freeze.py b/backend/venv/Lib/site-packages/pip/_internal/commands/freeze.py new file mode 100644 index 0000000..885fdfe --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/freeze.py @@ -0,0 +1,109 @@ +import sys +from optparse import Values +from typing import AbstractSet, List + +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.operations.freeze import freeze +from pip._internal.utils.compat import stdlib_pkgs + + +def _should_suppress_build_backends() -> bool: + return sys.version_info < (3, 12) + + +def _dev_pkgs() -> AbstractSet[str]: + pkgs = {"pip"} + + if _should_suppress_build_backends(): + pkgs |= {"setuptools", "distribute", "wheel"} + + return pkgs + + +class FreezeCommand(Command): + """ + Output installed packages in requirements format. + + packages are listed in a case-insensitive sorted order. + """ + + ignore_require_venv = True + usage = """ + %prog [options]""" + log_streams = ("ext://sys.stderr", "ext://sys.stderr") + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-r", + "--requirement", + dest="requirements", + action="append", + default=[], + metavar="file", + help=( + "Use the order in the given requirements file and its " + "comments when generating output. This option can be " + "used multiple times." + ), + ) + self.cmd_opts.add_option( + "-l", + "--local", + dest="local", + action="store_true", + default=False, + help=( + "If in a virtualenv that has global access, do not output " + "globally-installed packages." + ), + ) + self.cmd_opts.add_option( + "--user", + dest="user", + action="store_true", + default=False, + help="Only output packages installed in user-site.", + ) + self.cmd_opts.add_option(cmdoptions.list_path()) + self.cmd_opts.add_option( + "--all", + dest="freeze_all", + action="store_true", + help=( + "Do not skip these packages in the output:" + " {}".format(", ".join(_dev_pkgs())) + ), + ) + self.cmd_opts.add_option( + "--exclude-editable", + dest="exclude_editable", + action="store_true", + help="Exclude editable package from output.", + ) + self.cmd_opts.add_option(cmdoptions.list_exclude()) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + skip = set(stdlib_pkgs) + if not options.freeze_all: + skip.update(_dev_pkgs()) + + if options.excludes: + skip.update(options.excludes) + + cmdoptions.check_list_path_option(options) + + for line in freeze( + requirement=options.requirements, + local_only=options.local, + user_only=options.user, + paths=options.path, + isolated=options.isolated_mode, + skip=skip, + exclude_editable=options.exclude_editable, + ): + sys.stdout.write(line + "\n") + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/hash.py b/backend/venv/Lib/site-packages/pip/_internal/commands/hash.py new file mode 100644 index 0000000..042dac8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/hash.py @@ -0,0 +1,59 @@ +import hashlib +import logging +import sys +from optparse import Values +from typing import List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES +from pip._internal.utils.misc import read_chunks, write_output + +logger = logging.getLogger(__name__) + + +class HashCommand(Command): + """ + Compute a hash of a local package archive. + + These can be used with --hash in a requirements file to do repeatable + installs. + """ + + usage = "%prog [options] ..." + ignore_require_venv = True + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-a", + "--algorithm", + dest="algorithm", + choices=STRONG_HASHES, + action="store", + default=FAVORITE_HASH, + help="The hash algorithm to use: one of {}".format( + ", ".join(STRONG_HASHES) + ), + ) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + if not args: + self.parser.print_usage(sys.stderr) + return ERROR + + algorithm = options.algorithm + for path in args: + write_output( + "%s:\n--hash=%s:%s", path, algorithm, _hash_of_file(path, algorithm) + ) + return SUCCESS + + +def _hash_of_file(path: str, algorithm: str) -> str: + """Return the hash digest of a file.""" + with open(path, "rb") as archive: + hash = hashlib.new(algorithm) + for chunk in read_chunks(archive): + hash.update(chunk) + return hash.hexdigest() diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/help.py b/backend/venv/Lib/site-packages/pip/_internal/commands/help.py new file mode 100644 index 0000000..6206631 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/help.py @@ -0,0 +1,41 @@ +from optparse import Values +from typing import List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import CommandError + + +class HelpCommand(Command): + """Show help for commands""" + + usage = """ + %prog """ + ignore_require_venv = True + + def run(self, options: Values, args: List[str]) -> int: + from pip._internal.commands import ( + commands_dict, + create_command, + get_similar_commands, + ) + + try: + # 'pip help' with no args is handled by pip.__init__.parseopt() + cmd_name = args[0] # the command we need help for + except IndexError: + return SUCCESS + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = [f'unknown command "{cmd_name}"'] + if guess: + msg.append(f'maybe you meant "{guess}"') + + raise CommandError(" - ".join(msg)) + + command = create_command(cmd_name) + command.parser.print_help() + + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/index.py b/backend/venv/Lib/site-packages/pip/_internal/commands/index.py new file mode 100644 index 0000000..2e2661b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/index.py @@ -0,0 +1,139 @@ +import logging +from optparse import Values +from typing import Any, Iterable, List, Optional + +from pip._vendor.packaging.version import Version + +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import IndexGroupCommand +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.commands.search import print_dist_installation_info +from pip._internal.exceptions import CommandError, DistributionNotFound, PipError +from pip._internal.index.collector import LinkCollector +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.network.session import PipSession +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class IndexCommand(IndexGroupCommand): + """ + Inspect information available from package indexes. + """ + + ignore_require_venv = True + usage = """ + %prog versions + """ + + def add_options(self) -> None: + cmdoptions.add_target_python_options(self.cmd_opts) + + self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) + self.cmd_opts.add_option(cmdoptions.pre()) + self.cmd_opts.add_option(cmdoptions.no_binary()) + self.cmd_opts.add_option(cmdoptions.only_binary()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + handlers = { + "versions": self.get_available_package_versions, + } + + logger.warning( + "pip index is currently an experimental command. " + "It may be removed/changed in a future release " + "without prior warning." + ) + + # Determine action + if not args or args[0] not in handlers: + logger.error( + "Need an action (%s) to perform.", + ", ".join(sorted(handlers)), + ) + return ERROR + + action = args[0] + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _build_package_finder( + self, + options: Values, + session: PipSession, + target_python: Optional[TargetPython] = None, + ignore_requires_python: Optional[bool] = None, + ) -> PackageFinder: + """ + Create a package finder appropriate to the index command. + """ + link_collector = LinkCollector.create(session, options=options) + + # Pass allow_yanked=False to ignore yanked versions. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=options.pre, + ignore_requires_python=ignore_requires_python, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + target_python=target_python, + ) + + def get_available_package_versions(self, options: Values, args: List[Any]) -> None: + if len(args) != 1: + raise CommandError("You need to specify exactly one argument") + + target_python = cmdoptions.make_target_python(options) + query = args[0] + + with self._build_session(options) as session: + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ignore_requires_python=options.ignore_requires_python, + ) + + versions: Iterable[Version] = ( + candidate.version for candidate in finder.find_all_candidates(query) + ) + + if not options.pre: + # Remove prereleases + versions = ( + version for version in versions if not version.is_prerelease + ) + versions = set(versions) + + if not versions: + raise DistributionNotFound( + f"No matching distribution found for {query}" + ) + + formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)] + latest = formatted_versions[0] + + write_output(f"{query} ({latest})") + write_output("Available versions: {}".format(", ".join(formatted_versions))) + print_dist_installation_info(query, latest) diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/inspect.py b/backend/venv/Lib/site-packages/pip/_internal/commands/inspect.py new file mode 100644 index 0000000..e810c13 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/inspect.py @@ -0,0 +1,92 @@ +import logging +from optparse import Values +from typing import Any, Dict, List + +from pip._vendor.packaging.markers import default_environment +from pip._vendor.rich import print_json + +from pip import __version__ +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.metadata import BaseDistribution, get_environment +from pip._internal.utils.compat import stdlib_pkgs +from pip._internal.utils.urls import path_to_url + +logger = logging.getLogger(__name__) + + +class InspectCommand(Command): + """ + Inspect the content of a Python environment and produce a report in JSON format. + """ + + ignore_require_venv = True + usage = """ + %prog [options]""" + + def add_options(self) -> None: + self.cmd_opts.add_option( + "--local", + action="store_true", + default=False, + help=( + "If in a virtualenv that has global access, do not list " + "globally-installed packages." + ), + ) + self.cmd_opts.add_option( + "--user", + dest="user", + action="store_true", + default=False, + help="Only output packages installed in user-site.", + ) + self.cmd_opts.add_option(cmdoptions.list_path()) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + cmdoptions.check_list_path_option(options) + dists = get_environment(options.path).iter_installed_distributions( + local_only=options.local, + user_only=options.user, + skip=set(stdlib_pkgs), + ) + output = { + "version": "1", + "pip_version": __version__, + "installed": [self._dist_to_dict(dist) for dist in dists], + "environment": default_environment(), + # TODO tags? scheme? + } + print_json(data=output) + return SUCCESS + + def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]: + res: Dict[str, Any] = { + "metadata": dist.metadata_dict, + "metadata_location": dist.info_location, + } + # direct_url. Note that we don't have download_info (as in the installation + # report) since it is not recorded in installed metadata. + direct_url = dist.direct_url + if direct_url is not None: + res["direct_url"] = direct_url.to_dict() + else: + # Emulate direct_url for legacy editable installs. + editable_project_location = dist.editable_project_location + if editable_project_location is not None: + res["direct_url"] = { + "url": path_to_url(editable_project_location), + "dir_info": { + "editable": True, + }, + } + # installer + installer = dist.installer + if dist.installer: + res["installer"] = installer + # requested + if dist.installed_with_dist_info: + res["requested"] = dist.requested + return res diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/install.py b/backend/venv/Lib/site-packages/pip/_internal/commands/install.py new file mode 100644 index 0000000..232a34a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/install.py @@ -0,0 +1,784 @@ +import errno +import json +import operator +import os +import shutil +import site +from optparse import SUPPRESS_HELP, Values +from typing import List, Optional + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.rich import print_json + +# Eagerly import self_outdated_check to avoid crashes. Otherwise, +# this module would be imported *after* pip was replaced, resulting +# in crashes if the new self_outdated_check module was incompatible +# with the rest of pip that's already imported, or allowing a +# wheel to execute arbitrary code on install by replacing +# self_outdated_check. +import pip._internal.self_outdated_check # noqa: F401 +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.req_command import ( + RequirementCommand, + with_cleanup, +) +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.exceptions import CommandError, InstallationError +from pip._internal.locations import get_scheme +from pip._internal.metadata import get_environment +from pip._internal.models.installation_report import InstallationReport +from pip._internal.operations.build.build_tracker import get_build_tracker +from pip._internal.operations.check import ConflictDetails, check_install_conflicts +from pip._internal.req import install_given_reqs +from pip._internal.req.req_install import ( + InstallRequirement, + check_legacy_setup_py_options, +) +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.filesystem import test_writable_dir +from pip._internal.utils.logging import getLogger +from pip._internal.utils.misc import ( + check_externally_managed, + ensure_dir, + get_pip_version, + protect_pip_from_modification_on_windows, + warn_if_run_as_root, + write_output, +) +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.virtualenv import ( + running_under_virtualenv, + virtualenv_no_global, +) +from pip._internal.wheel_builder import build, should_build_for_install_command + +logger = getLogger(__name__) + + +class InstallCommand(RequirementCommand): + """ + Install packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports installing from "requirements files", which provide + an easy way to specify a whole environment to be installed. + """ + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + def add_options(self) -> None: + self.cmd_opts.add_option(cmdoptions.requirements()) + self.cmd_opts.add_option(cmdoptions.constraints()) + self.cmd_opts.add_option(cmdoptions.no_deps()) + self.cmd_opts.add_option(cmdoptions.pre()) + + self.cmd_opts.add_option(cmdoptions.editable()) + self.cmd_opts.add_option( + "--dry-run", + action="store_true", + dest="dry_run", + default=False, + help=( + "Don't actually install anything, just print what would be. " + "Can be used in combination with --ignore-installed " + "to 'resolve' the requirements." + ), + ) + self.cmd_opts.add_option( + "-t", + "--target", + dest="target_dir", + metavar="dir", + default=None, + help=( + "Install packages into . " + "By default this will not replace existing files/folders in " + ". Use --upgrade to replace existing packages in " + "with new versions." + ), + ) + cmdoptions.add_target_python_options(self.cmd_opts) + + self.cmd_opts.add_option( + "--user", + dest="use_user_site", + action="store_true", + help=( + "Install to the Python user install directory for your " + "platform. Typically ~/.local/, or %APPDATA%\\Python on " + "Windows. (See the Python documentation for site.USER_BASE " + "for full details.)" + ), + ) + self.cmd_opts.add_option( + "--no-user", + dest="use_user_site", + action="store_false", + help=SUPPRESS_HELP, + ) + self.cmd_opts.add_option( + "--root", + dest="root_path", + metavar="dir", + default=None, + help="Install everything relative to this alternate root directory.", + ) + self.cmd_opts.add_option( + "--prefix", + dest="prefix_path", + metavar="dir", + default=None, + help=( + "Installation prefix where lib, bin and other top-level " + "folders are placed. Note that the resulting installation may " + "contain scripts and other resources which reference the " + "Python interpreter of pip, and not that of ``--prefix``. " + "See also the ``--python`` option if the intention is to " + "install packages into another (possibly pip-free) " + "environment." + ), + ) + + self.cmd_opts.add_option(cmdoptions.src()) + + self.cmd_opts.add_option( + "-U", + "--upgrade", + dest="upgrade", + action="store_true", + help=( + "Upgrade all specified packages to the newest available " + "version. The handling of dependencies depends on the " + "upgrade-strategy used." + ), + ) + + self.cmd_opts.add_option( + "--upgrade-strategy", + dest="upgrade_strategy", + default="only-if-needed", + choices=["only-if-needed", "eager"], + help=( + "Determines how dependency upgrading should be handled " + "[default: %default]. " + '"eager" - dependencies are upgraded regardless of ' + "whether the currently installed version satisfies the " + "requirements of the upgraded package(s). " + '"only-if-needed" - are upgraded only when they do not ' + "satisfy the requirements of the upgraded package(s)." + ), + ) + + self.cmd_opts.add_option( + "--force-reinstall", + dest="force_reinstall", + action="store_true", + help="Reinstall all packages even if they are already up-to-date.", + ) + + self.cmd_opts.add_option( + "-I", + "--ignore-installed", + dest="ignore_installed", + action="store_true", + help=( + "Ignore the installed packages, overwriting them. " + "This can break your system if the existing package " + "is of a different version or was installed " + "with a different package manager!" + ), + ) + + self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) + self.cmd_opts.add_option(cmdoptions.no_build_isolation()) + self.cmd_opts.add_option(cmdoptions.use_pep517()) + self.cmd_opts.add_option(cmdoptions.no_use_pep517()) + self.cmd_opts.add_option(cmdoptions.check_build_deps()) + self.cmd_opts.add_option(cmdoptions.override_externally_managed()) + + self.cmd_opts.add_option(cmdoptions.config_settings()) + self.cmd_opts.add_option(cmdoptions.global_options()) + + self.cmd_opts.add_option( + "--compile", + action="store_true", + dest="compile", + default=True, + help="Compile Python source files to bytecode", + ) + + self.cmd_opts.add_option( + "--no-compile", + action="store_false", + dest="compile", + help="Do not compile Python source files to bytecode", + ) + + self.cmd_opts.add_option( + "--no-warn-script-location", + action="store_false", + dest="warn_script_location", + default=True, + help="Do not warn when installing scripts outside PATH", + ) + self.cmd_opts.add_option( + "--no-warn-conflicts", + action="store_false", + dest="warn_about_conflicts", + default=True, + help="Do not warn about broken dependencies", + ) + self.cmd_opts.add_option(cmdoptions.no_binary()) + self.cmd_opts.add_option(cmdoptions.only_binary()) + self.cmd_opts.add_option(cmdoptions.prefer_binary()) + self.cmd_opts.add_option(cmdoptions.require_hashes()) + self.cmd_opts.add_option(cmdoptions.progress_bar()) + self.cmd_opts.add_option(cmdoptions.root_user_action()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + self.cmd_opts.add_option( + "--report", + dest="json_report_file", + metavar="file", + default=None, + help=( + "Generate a JSON file describing what pip did to install " + "the provided requirements. " + "Can be used in combination with --dry-run and --ignore-installed " + "to 'resolve' the requirements. " + "When - is used as file name it writes to stdout. " + "When writing to stdout, please combine with the --quiet option " + "to avoid mixing pip logging output with JSON output." + ), + ) + + @with_cleanup + def run(self, options: Values, args: List[str]) -> int: + if options.use_user_site and options.target_dir is not None: + raise CommandError("Can not combine '--user' and '--target'") + + # Check whether the environment we're installing into is externally + # managed, as specified in PEP 668. Specifying --root, --target, or + # --prefix disables the check, since there's no reliable way to locate + # the EXTERNALLY-MANAGED file for those cases. An exception is also + # made specifically for "--dry-run --report" for convenience. + installing_into_current_environment = ( + not (options.dry_run and options.json_report_file) + and options.root_path is None + and options.target_dir is None + and options.prefix_path is None + ) + if ( + installing_into_current_environment + and not options.override_externally_managed + ): + check_externally_managed() + + upgrade_strategy = "to-satisfy-only" + if options.upgrade: + upgrade_strategy = options.upgrade_strategy + + cmdoptions.check_dist_restriction(options, check_target=True) + + logger.verbose("Using %s", get_pip_version()) + options.use_user_site = decide_user_install( + options.use_user_site, + prefix_path=options.prefix_path, + target_dir=options.target_dir, + root_path=options.root_path, + isolated_mode=options.isolated_mode, + ) + + target_temp_dir: Optional[TempDirectory] = None + target_temp_dir_path: Optional[str] = None + if options.target_dir: + options.ignore_installed = True + options.target_dir = os.path.abspath(options.target_dir) + if ( + # fmt: off + os.path.exists(options.target_dir) and + not os.path.isdir(options.target_dir) + # fmt: on + ): + raise CommandError( + "Target path exists but is not a directory, will not continue." + ) + + # Create a target directory for using with the target option + target_temp_dir = TempDirectory(kind="target") + target_temp_dir_path = target_temp_dir.path + self.enter_context(target_temp_dir) + + global_options = options.global_options or [] + + session = self.get_default_session(options) + + target_python = make_target_python(options) + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ignore_requires_python=options.ignore_requires_python, + ) + build_tracker = self.enter_context(get_build_tracker()) + + directory = TempDirectory( + delete=not options.no_clean, + kind="install", + globally_managed=True, + ) + + try: + reqs = self.get_requirements(args, options, finder, session) + check_legacy_setup_py_options(options, reqs) + + wheel_cache = WheelCache(options.cache_dir) + + # Only when installing is it permitted to use PEP 660. + # In other circumstances (pip wheel, pip download) we generate + # regular (i.e. non editable) metadata and wheels. + for req in reqs: + req.permit_editable_wheels = True + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + build_tracker=build_tracker, + session=session, + finder=finder, + use_user_site=options.use_user_site, + verbosity=self.verbosity, + ) + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + wheel_cache=wheel_cache, + use_user_site=options.use_user_site, + ignore_installed=options.ignore_installed, + ignore_requires_python=options.ignore_requires_python, + force_reinstall=options.force_reinstall, + upgrade_strategy=upgrade_strategy, + use_pep517=options.use_pep517, + py_version_info=options.python_version, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve( + reqs, check_supported_wheels=not options.target_dir + ) + + if options.json_report_file: + report = InstallationReport(requirement_set.requirements_to_install) + if options.json_report_file == "-": + print_json(data=report.to_dict()) + else: + with open(options.json_report_file, "w", encoding="utf-8") as f: + json.dump(report.to_dict(), f, indent=2, ensure_ascii=False) + + if options.dry_run: + would_install_items = sorted( + (r.metadata["name"], r.metadata["version"]) + for r in requirement_set.requirements_to_install + ) + if would_install_items: + write_output( + "Would install %s", + " ".join("-".join(item) for item in would_install_items), + ) + return SUCCESS + + try: + pip_req = requirement_set.get_requirement("pip") + except KeyError: + modifying_pip = False + else: + # If we're not replacing an already installed pip, + # we're not modifying it. + modifying_pip = pip_req.satisfied_by is None + protect_pip_from_modification_on_windows(modifying_pip=modifying_pip) + + reqs_to_build = [ + r + for r in requirement_set.requirements.values() + if should_build_for_install_command(r) + ] + + _, build_failures = build( + reqs_to_build, + wheel_cache=wheel_cache, + verify=True, + build_options=[], + global_options=global_options, + ) + + if build_failures: + raise InstallationError( + "Failed to build installable wheels for some " + "pyproject.toml based projects ({})".format( + ", ".join(r.name for r in build_failures) # type: ignore + ) + ) + + to_install = resolver.get_installation_order(requirement_set) + + # Check for conflicts in the package set we're installing. + conflicts: Optional[ConflictDetails] = None + should_warn_about_conflicts = ( + not options.ignore_dependencies and options.warn_about_conflicts + ) + if should_warn_about_conflicts: + conflicts = self._determine_conflicts(to_install) + + # Don't warn about script install locations if + # --target or --prefix has been specified + warn_script_location = options.warn_script_location + if options.target_dir or options.prefix_path: + warn_script_location = False + + installed = install_given_reqs( + to_install, + global_options, + root=options.root_path, + home=target_temp_dir_path, + prefix=options.prefix_path, + warn_script_location=warn_script_location, + use_user_site=options.use_user_site, + pycompile=options.compile, + ) + + lib_locations = get_lib_location_guesses( + user=options.use_user_site, + home=target_temp_dir_path, + root=options.root_path, + prefix=options.prefix_path, + isolated=options.isolated_mode, + ) + env = get_environment(lib_locations) + + # Display a summary of installed packages, with extra care to + # display a package name as it was requested by the user. + installed.sort(key=operator.attrgetter("name")) + summary = [] + installed_versions = {} + for distribution in env.iter_all_distributions(): + installed_versions[distribution.canonical_name] = distribution.version + for package in installed: + display_name = package.name + version = installed_versions.get(canonicalize_name(display_name), None) + if version: + text = f"{display_name}-{version}" + else: + text = display_name + summary.append(text) + + if conflicts is not None: + self._warn_about_conflicts( + conflicts, + resolver_variant=self.determine_resolver_variant(options), + ) + + installed_desc = " ".join(summary) + if installed_desc: + write_output( + "Successfully installed %s", + installed_desc, + ) + except OSError as error: + show_traceback = self.verbosity >= 1 + + message = create_os_error_message( + error, + show_traceback, + options.use_user_site, + ) + logger.error(message, exc_info=show_traceback) + + return ERROR + + if options.target_dir: + assert target_temp_dir + self._handle_target_dir( + options.target_dir, target_temp_dir, options.upgrade + ) + if options.root_user_action == "warn": + warn_if_run_as_root() + return SUCCESS + + def _handle_target_dir( + self, target_dir: str, target_temp_dir: TempDirectory, upgrade: bool + ) -> None: + ensure_dir(target_dir) + + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + lib_dir_list = [] + + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + scheme = get_scheme("", home=target_temp_dir.path) + purelib_dir = scheme.purelib + platlib_dir = scheme.platlib + data_dir = scheme.data + + if os.path.exists(purelib_dir): + lib_dir_list.append(purelib_dir) + if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: + lib_dir_list.append(platlib_dir) + if os.path.exists(data_dir): + lib_dir_list.append(data_dir) + + for lib_dir in lib_dir_list: + for item in os.listdir(lib_dir): + if lib_dir == data_dir: + ddir = os.path.join(data_dir, item) + if any(s.startswith(ddir) for s in lib_dir_list[:-1]): + continue + target_item_dir = os.path.join(target_dir, item) + if os.path.exists(target_item_dir): + if not upgrade: + logger.warning( + "Target directory %s already exists. Specify " + "--upgrade to force replacement.", + target_item_dir, + ) + continue + if os.path.islink(target_item_dir): + logger.warning( + "Target directory %s already exists and is " + "a link. pip will not automatically replace " + "links, please remove if replacement is " + "desired.", + target_item_dir, + ) + continue + if os.path.isdir(target_item_dir): + shutil.rmtree(target_item_dir) + else: + os.remove(target_item_dir) + + shutil.move(os.path.join(lib_dir, item), target_item_dir) + + def _determine_conflicts( + self, to_install: List[InstallRequirement] + ) -> Optional[ConflictDetails]: + try: + return check_install_conflicts(to_install) + except Exception: + logger.exception( + "Error while checking for conflicts. Please file an issue on " + "pip's issue tracker: https://github.com/pypa/pip/issues/new" + ) + return None + + def _warn_about_conflicts( + self, conflict_details: ConflictDetails, resolver_variant: str + ) -> None: + package_set, (missing, conflicting) = conflict_details + if not missing and not conflicting: + return + + parts: List[str] = [] + if resolver_variant == "legacy": + parts.append( + "pip's legacy dependency resolver does not consider dependency " + "conflicts when selecting packages. This behaviour is the " + "source of the following dependency conflicts." + ) + else: + assert resolver_variant == "resolvelib" + parts.append( + "pip's dependency resolver does not currently take into account " + "all the packages that are installed. This behaviour is the " + "source of the following dependency conflicts." + ) + + # NOTE: There is some duplication here, with commands/check.py + for project_name in missing: + version = package_set[project_name][0] + for dependency in missing[project_name]: + message = ( + f"{project_name} {version} requires {dependency[1]}, " + "which is not installed." + ) + parts.append(message) + + for project_name in conflicting: + version = package_set[project_name][0] + for dep_name, dep_version, req in conflicting[project_name]: + message = ( + "{name} {version} requires {requirement}, but {you} have " + "{dep_name} {dep_version} which is incompatible." + ).format( + name=project_name, + version=version, + requirement=req, + dep_name=dep_name, + dep_version=dep_version, + you=("you" if resolver_variant == "resolvelib" else "you'll"), + ) + parts.append(message) + + logger.critical("\n".join(parts)) + + +def get_lib_location_guesses( + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + isolated: bool = False, + prefix: Optional[str] = None, +) -> List[str]: + scheme = get_scheme( + "", + user=user, + home=home, + root=root, + isolated=isolated, + prefix=prefix, + ) + return [scheme.purelib, scheme.platlib] + + +def site_packages_writable(root: Optional[str], isolated: bool) -> bool: + return all( + test_writable_dir(d) + for d in set(get_lib_location_guesses(root=root, isolated=isolated)) + ) + + +def decide_user_install( + use_user_site: Optional[bool], + prefix_path: Optional[str] = None, + target_dir: Optional[str] = None, + root_path: Optional[str] = None, + isolated_mode: bool = False, +) -> bool: + """Determine whether to do a user install based on the input options. + + If use_user_site is False, no additional checks are done. + If use_user_site is True, it is checked for compatibility with other + options. + If use_user_site is None, the default behaviour depends on the environment, + which is provided by the other arguments. + """ + # In some cases (config from tox), use_user_site can be set to an integer + # rather than a bool, which 'use_user_site is False' wouldn't catch. + if (use_user_site is not None) and (not use_user_site): + logger.debug("Non-user install by explicit request") + return False + + if use_user_site: + if prefix_path: + raise CommandError( + "Can not combine '--user' and '--prefix' as they imply " + "different installation locations" + ) + if virtualenv_no_global(): + raise InstallationError( + "Can not perform a '--user' install. User site-packages " + "are not visible in this virtualenv." + ) + logger.debug("User install by explicit request") + return True + + # If we are here, user installs have not been explicitly requested/avoided + assert use_user_site is None + + # user install incompatible with --prefix/--target + if prefix_path or target_dir: + logger.debug("Non-user install due to --prefix or --target option") + return False + + # If user installs are not enabled, choose a non-user install + if not site.ENABLE_USER_SITE: + logger.debug("Non-user install because user site-packages disabled") + return False + + # If we have permission for a non-user install, do that, + # otherwise do a user install. + if site_packages_writable(root=root_path, isolated=isolated_mode): + logger.debug("Non-user install because site-packages writeable") + return False + + logger.info( + "Defaulting to user installation because normal site-packages " + "is not writeable" + ) + return True + + +def create_os_error_message( + error: OSError, show_traceback: bool, using_user_site: bool +) -> str: + """Format an error message for an OSError + + It may occur anytime during the execution of the install command. + """ + parts = [] + + # Mention the error if we are not going to show a traceback + parts.append("Could not install packages due to an OSError") + if not show_traceback: + parts.append(": ") + parts.append(str(error)) + else: + parts.append(".") + + # Spilt the error indication from a helper message (if any) + parts[-1] += "\n" + + # Suggest useful actions to the user: + # (1) using user site-packages or (2) verifying the permissions + if error.errno == errno.EACCES: + user_option_part = "Consider using the `--user` option" + permissions_part = "Check the permissions" + + if not running_under_virtualenv() and not using_user_site: + parts.extend( + [ + user_option_part, + " or ", + permissions_part.lower(), + ] + ) + else: + parts.append(permissions_part) + parts.append(".\n") + + # Suggest the user to enable Long Paths if path length is + # more than 260 + if ( + WINDOWS + and error.errno == errno.ENOENT + and error.filename + and len(error.filename) > 260 + ): + parts.append( + "HINT: This error might have occurred since " + "this system does not have Windows Long Path " + "support enabled. You can find information on " + "how to enable this at " + "https://pip.pypa.io/warnings/enable-long-paths\n" + ) + + return "".join(parts).strip() + "\n" diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/list.py b/backend/venv/Lib/site-packages/pip/_internal/commands/list.py new file mode 100644 index 0000000..8494370 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/list.py @@ -0,0 +1,375 @@ +import json +import logging +from optparse import Values +from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import Version + +from pip._internal.cli import cmdoptions +from pip._internal.cli.index_command import IndexGroupCommand +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import CommandError +from pip._internal.metadata import BaseDistribution, get_environment +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.utils.compat import stdlib_pkgs +from pip._internal.utils.misc import tabulate, write_output + +if TYPE_CHECKING: + from pip._internal.index.package_finder import PackageFinder + from pip._internal.network.session import PipSession + + class _DistWithLatestInfo(BaseDistribution): + """Give the distribution object a couple of extra fields. + + These will be populated during ``get_outdated()``. This is dirty but + makes the rest of the code much cleaner. + """ + + latest_version: Version + latest_filetype: str + + _ProcessedDists = Sequence[_DistWithLatestInfo] + + +logger = logging.getLogger(__name__) + + +class ListCommand(IndexGroupCommand): + """ + List installed packages, including editables. + + Packages are listed in a case-insensitive sorted order. + """ + + ignore_require_venv = True + usage = """ + %prog [options]""" + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-o", + "--outdated", + action="store_true", + default=False, + help="List outdated packages", + ) + self.cmd_opts.add_option( + "-u", + "--uptodate", + action="store_true", + default=False, + help="List uptodate packages", + ) + self.cmd_opts.add_option( + "-e", + "--editable", + action="store_true", + default=False, + help="List editable projects.", + ) + self.cmd_opts.add_option( + "-l", + "--local", + action="store_true", + default=False, + help=( + "If in a virtualenv that has global access, do not list " + "globally-installed packages." + ), + ) + self.cmd_opts.add_option( + "--user", + dest="user", + action="store_true", + default=False, + help="Only output packages installed in user-site.", + ) + self.cmd_opts.add_option(cmdoptions.list_path()) + self.cmd_opts.add_option( + "--pre", + action="store_true", + default=False, + help=( + "Include pre-release and development versions. By default, " + "pip only finds stable versions." + ), + ) + + self.cmd_opts.add_option( + "--format", + action="store", + dest="list_format", + default="columns", + choices=("columns", "freeze", "json"), + help=( + "Select the output format among: columns (default), freeze, or json. " + "The 'freeze' format cannot be used with the --outdated option." + ), + ) + + self.cmd_opts.add_option( + "--not-required", + action="store_true", + dest="not_required", + help="List packages that are not dependencies of installed packages.", + ) + + self.cmd_opts.add_option( + "--exclude-editable", + action="store_false", + dest="include_editable", + help="Exclude editable package from output.", + ) + self.cmd_opts.add_option( + "--include-editable", + action="store_true", + dest="include_editable", + help="Include editable package from output.", + default=True, + ) + self.cmd_opts.add_option(cmdoptions.list_exclude()) + index_opts = cmdoptions.make_option_group(cmdoptions.index_group, self.parser) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + def handle_pip_version_check(self, options: Values) -> None: + if options.outdated or options.uptodate: + super().handle_pip_version_check(options) + + def _build_package_finder( + self, options: Values, session: "PipSession" + ) -> "PackageFinder": + """ + Create a package finder appropriate to this list command. + """ + # Lazy import the heavy index modules as most list invocations won't need 'em. + from pip._internal.index.collector import LinkCollector + from pip._internal.index.package_finder import PackageFinder + + link_collector = LinkCollector.create(session, options=options) + + # Pass allow_yanked=False to ignore yanked versions. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=options.pre, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + ) + + def run(self, options: Values, args: List[str]) -> int: + if options.outdated and options.uptodate: + raise CommandError("Options --outdated and --uptodate cannot be combined.") + + if options.outdated and options.list_format == "freeze": + raise CommandError( + "List format 'freeze' cannot be used with the --outdated option." + ) + + cmdoptions.check_list_path_option(options) + + skip = set(stdlib_pkgs) + if options.excludes: + skip.update(canonicalize_name(n) for n in options.excludes) + + packages: _ProcessedDists = [ + cast("_DistWithLatestInfo", d) + for d in get_environment(options.path).iter_installed_distributions( + local_only=options.local, + user_only=options.user, + editables_only=options.editable, + include_editables=options.include_editable, + skip=skip, + ) + ] + + # get_not_required must be called firstly in order to find and + # filter out all dependencies correctly. Otherwise a package + # can't be identified as requirement because some parent packages + # could be filtered out before. + if options.not_required: + packages = self.get_not_required(packages, options) + + if options.outdated: + packages = self.get_outdated(packages, options) + elif options.uptodate: + packages = self.get_uptodate(packages, options) + + self.output_package_listing(packages, options) + return SUCCESS + + def get_outdated( + self, packages: "_ProcessedDists", options: Values + ) -> "_ProcessedDists": + return [ + dist + for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version > dist.version + ] + + def get_uptodate( + self, packages: "_ProcessedDists", options: Values + ) -> "_ProcessedDists": + return [ + dist + for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version == dist.version + ] + + def get_not_required( + self, packages: "_ProcessedDists", options: Values + ) -> "_ProcessedDists": + dep_keys = { + canonicalize_name(dep.name) + for dist in packages + for dep in (dist.iter_dependencies() or ()) + } + + # Create a set to remove duplicate packages, and cast it to a list + # to keep the return type consistent with get_outdated and + # get_uptodate + return list({pkg for pkg in packages if pkg.canonical_name not in dep_keys}) + + def iter_packages_latest_infos( + self, packages: "_ProcessedDists", options: Values + ) -> Generator["_DistWithLatestInfo", None, None]: + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + + def latest_info( + dist: "_DistWithLatestInfo", + ) -> Optional["_DistWithLatestInfo"]: + all_candidates = finder.find_all_candidates(dist.canonical_name) + if not options.pre: + # Remove prereleases + all_candidates = [ + candidate + for candidate in all_candidates + if not candidate.version.is_prerelease + ] + + evaluator = finder.make_candidate_evaluator( + project_name=dist.canonical_name, + ) + best_candidate = evaluator.sort_best_candidate(all_candidates) + if best_candidate is None: + return None + + remote_version = best_candidate.version + if best_candidate.link.is_wheel: + typ = "wheel" + else: + typ = "sdist" + dist.latest_version = remote_version + dist.latest_filetype = typ + return dist + + for dist in map(latest_info, packages): + if dist is not None: + yield dist + + def output_package_listing( + self, packages: "_ProcessedDists", options: Values + ) -> None: + packages = sorted( + packages, + key=lambda dist: dist.canonical_name, + ) + if options.list_format == "columns" and packages: + data, header = format_for_columns(packages, options) + self.output_package_listing_columns(data, header) + elif options.list_format == "freeze": + for dist in packages: + if options.verbose >= 1: + write_output( + "%s==%s (%s)", dist.raw_name, dist.version, dist.location + ) + else: + write_output("%s==%s", dist.raw_name, dist.version) + elif options.list_format == "json": + write_output(format_for_json(packages, options)) + + def output_package_listing_columns( + self, data: List[List[str]], header: List[str] + ) -> None: + # insert the header first: we need to know the size of column names + if len(data) > 0: + data.insert(0, header) + + pkg_strings, sizes = tabulate(data) + + # Create and add a separator. + if len(data) > 0: + pkg_strings.insert(1, " ".join("-" * x for x in sizes)) + + for val in pkg_strings: + write_output(val) + + +def format_for_columns( + pkgs: "_ProcessedDists", options: Values +) -> Tuple[List[List[str]], List[str]]: + """ + Convert the package data into something usable + by output_package_listing_columns. + """ + header = ["Package", "Version"] + + running_outdated = options.outdated + if running_outdated: + header.extend(["Latest", "Type"]) + + has_editables = any(x.editable for x in pkgs) + if has_editables: + header.append("Editable project location") + + if options.verbose >= 1: + header.append("Location") + if options.verbose >= 1: + header.append("Installer") + + data = [] + for proj in pkgs: + # if we're working on the 'outdated' list, separate out the + # latest_version and type + row = [proj.raw_name, proj.raw_version] + + if running_outdated: + row.append(str(proj.latest_version)) + row.append(proj.latest_filetype) + + if has_editables: + row.append(proj.editable_project_location or "") + + if options.verbose >= 1: + row.append(proj.location or "") + if options.verbose >= 1: + row.append(proj.installer) + + data.append(row) + + return data, header + + +def format_for_json(packages: "_ProcessedDists", options: Values) -> str: + data = [] + for dist in packages: + info = { + "name": dist.raw_name, + "version": str(dist.version), + } + if options.verbose >= 1: + info["location"] = dist.location or "" + info["installer"] = dist.installer + if options.outdated: + info["latest_version"] = str(dist.latest_version) + info["latest_filetype"] = dist.latest_filetype + editable_project_location = dist.editable_project_location + if editable_project_location: + info["editable_project_location"] = editable_project_location + data.append(info) + return json.dumps(data) diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/search.py b/backend/venv/Lib/site-packages/pip/_internal/commands/search.py new file mode 100644 index 0000000..74b8d65 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/search.py @@ -0,0 +1,172 @@ +import logging +import shutil +import sys +import textwrap +import xmlrpc.client +from collections import OrderedDict +from optparse import Values +from typing import TYPE_CHECKING, Dict, List, Optional, TypedDict + +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.cli.base_command import Command +from pip._internal.cli.req_command import SessionCommandMixin +from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS +from pip._internal.exceptions import CommandError +from pip._internal.metadata import get_default_environment +from pip._internal.models.index import PyPI +from pip._internal.network.xmlrpc import PipXmlrpcTransport +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import write_output + +if TYPE_CHECKING: + + class TransformedHit(TypedDict): + name: str + summary: str + versions: List[str] + + +logger = logging.getLogger(__name__) + + +class SearchCommand(Command, SessionCommandMixin): + """Search for PyPI packages whose name or summary contains .""" + + usage = """ + %prog [options] """ + ignore_require_venv = True + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-i", + "--index", + dest="index", + metavar="URL", + default=PyPI.pypi_url, + help="Base URL of Python Package Index (default %default)", + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + if not args: + raise CommandError("Missing required argument (search query).") + query = args + pypi_hits = self.search(query, options) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = shutil.get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + if pypi_hits: + return SUCCESS + return NO_MATCHES_FOUND + + def search(self, query: List[str], options: Values) -> List[Dict[str, str]]: + index_url = options.index + + session = self.get_default_session(options) + + transport = PipXmlrpcTransport(index_url, session) + pypi = xmlrpc.client.ServerProxy(index_url, transport) + try: + hits = pypi.search({"name": query, "summary": query}, "or") + except xmlrpc.client.Fault as fault: + message = ( + f"XMLRPC request failed [code: {fault.faultCode}]\n{fault.faultString}" + ) + raise CommandError(message) + assert isinstance(hits, list) + return hits + + +def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]: + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages: Dict[str, TransformedHit] = OrderedDict() + for hit in hits: + name = hit["name"] + summary = hit["summary"] + version = hit["version"] + + if name not in packages.keys(): + packages[name] = { + "name": name, + "summary": summary, + "versions": [version], + } + else: + packages[name]["versions"].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]["versions"]): + packages[name]["summary"] = summary + + return list(packages.values()) + + +def print_dist_installation_info(name: str, latest: str) -> None: + env = get_default_environment() + dist = env.get_distribution(name) + if dist is not None: + with indent_log(): + if dist.version == latest: + write_output("INSTALLED: %s (latest)", dist.version) + else: + write_output("INSTALLED: %s", dist.version) + if parse_version(latest).pre: + write_output( + "LATEST: %s (pre-release; install" + " with `pip install --pre`)", + latest, + ) + else: + write_output("LATEST: %s", latest) + + +def print_results( + hits: List["TransformedHit"], + name_column_width: Optional[int] = None, + terminal_width: Optional[int] = None, +) -> None: + if not hits: + return + if name_column_width is None: + name_column_width = ( + max( + [ + len(hit["name"]) + len(highest_version(hit.get("versions", ["-"]))) + for hit in hits + ] + ) + + 4 + ) + + for hit in hits: + name = hit["name"] + summary = hit["summary"] or "" + latest = highest_version(hit.get("versions", ["-"])) + if terminal_width is not None: + target_width = terminal_width - name_column_width - 5 + if target_width > 10: + # wrap and indent summary to fit terminal + summary_lines = textwrap.wrap(summary, target_width) + summary = ("\n" + " " * (name_column_width + 3)).join(summary_lines) + + name_latest = f"{name} ({latest})" + line = f"{name_latest:{name_column_width}} - {summary}" + try: + write_output(line) + print_dist_installation_info(name, latest) + except UnicodeEncodeError: + pass + + +def highest_version(versions: List[str]) -> str: + return max(versions, key=parse_version) diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/show.py b/backend/venv/Lib/site-packages/pip/_internal/commands/show.py new file mode 100644 index 0000000..b47500c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/show.py @@ -0,0 +1,224 @@ +import logging +from optparse import Values +from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional + +from pip._vendor.packaging.requirements import InvalidRequirement +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.metadata import BaseDistribution, get_default_environment +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class ShowCommand(Command): + """ + Show information about one or more installed packages. + + The output is in RFC-compliant mail header format. + """ + + usage = """ + %prog [options] ...""" + ignore_require_venv = True + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-f", + "--files", + dest="files", + action="store_true", + default=False, + help="Show the full list of installed files for each package.", + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + if not args: + logger.warning("ERROR: Please provide a package name or names.") + return ERROR + query = args + + results = search_packages_info(query) + if not print_results( + results, list_files=options.files, verbose=options.verbose + ): + return ERROR + return SUCCESS + + +class _PackageInfo(NamedTuple): + name: str + version: str + location: str + editable_project_location: Optional[str] + requires: List[str] + required_by: List[str] + installer: str + metadata_version: str + classifiers: List[str] + summary: str + homepage: str + project_urls: List[str] + author: str + author_email: str + license: str + license_expression: str + entry_points: List[str] + files: Optional[List[str]] + + +def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]: + """ + Gather details from installed distributions. Print distribution name, + version, location, and installed files. Installed files requires a + pip generated 'installed-files.txt' in the distributions '.egg-info' + directory. + """ + env = get_default_environment() + + installed = {dist.canonical_name: dist for dist in env.iter_all_distributions()} + query_names = [canonicalize_name(name) for name in query] + missing = sorted( + [name for name, pkg in zip(query, query_names) if pkg not in installed] + ) + if missing: + logger.warning("Package(s) not found: %s", ", ".join(missing)) + + def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]: + return ( + dist.metadata["Name"] or "UNKNOWN" + for dist in installed.values() + if current_dist.canonical_name + in {canonicalize_name(d.name) for d in dist.iter_dependencies()} + ) + + for query_name in query_names: + try: + dist = installed[query_name] + except KeyError: + continue + + try: + requires = sorted( + # Avoid duplicates in requirements (e.g. due to environment markers). + {req.name for req in dist.iter_dependencies()}, + key=str.lower, + ) + except InvalidRequirement: + requires = sorted(dist.iter_raw_dependencies(), key=str.lower) + + try: + required_by = sorted(_get_requiring_packages(dist), key=str.lower) + except InvalidRequirement: + required_by = ["#N/A"] + + try: + entry_points_text = dist.read_text("entry_points.txt") + entry_points = entry_points_text.splitlines(keepends=False) + except FileNotFoundError: + entry_points = [] + + files_iter = dist.iter_declared_entries() + if files_iter is None: + files: Optional[List[str]] = None + else: + files = sorted(files_iter) + + metadata = dist.metadata + + project_urls = metadata.get_all("Project-URL", []) + homepage = metadata.get("Home-page", "") + if not homepage: + # It's common that there is a "homepage" Project-URL, but Home-page + # remains unset (especially as PEP 621 doesn't surface the field). + # + # This logic was taken from PyPI's codebase. + for url in project_urls: + url_label, url = url.split(",", maxsplit=1) + normalized_label = ( + url_label.casefold().replace("-", "").replace("_", "").strip() + ) + if normalized_label == "homepage": + homepage = url.strip() + break + + yield _PackageInfo( + name=dist.raw_name, + version=dist.raw_version, + location=dist.location or "", + editable_project_location=dist.editable_project_location, + requires=requires, + required_by=required_by, + installer=dist.installer, + metadata_version=dist.metadata_version or "", + classifiers=metadata.get_all("Classifier", []), + summary=metadata.get("Summary", ""), + homepage=homepage, + project_urls=project_urls, + author=metadata.get("Author", ""), + author_email=metadata.get("Author-email", ""), + license=metadata.get("License", ""), + license_expression=metadata.get("License-Expression", ""), + entry_points=entry_points, + files=files, + ) + + +def print_results( + distributions: Iterable[_PackageInfo], + list_files: bool, + verbose: bool, +) -> bool: + """ + Print the information from installed distributions found. + """ + results_printed = False + for i, dist in enumerate(distributions): + results_printed = True + if i > 0: + write_output("---") + + metadata_version_tuple = tuple(map(int, dist.metadata_version.split("."))) + + write_output("Name: %s", dist.name) + write_output("Version: %s", dist.version) + write_output("Summary: %s", dist.summary) + write_output("Home-page: %s", dist.homepage) + write_output("Author: %s", dist.author) + write_output("Author-email: %s", dist.author_email) + if metadata_version_tuple >= (2, 4) and dist.license_expression: + write_output("License-Expression: %s", dist.license_expression) + else: + write_output("License: %s", dist.license) + write_output("Location: %s", dist.location) + if dist.editable_project_location is not None: + write_output( + "Editable project location: %s", dist.editable_project_location + ) + write_output("Requires: %s", ", ".join(dist.requires)) + write_output("Required-by: %s", ", ".join(dist.required_by)) + + if verbose: + write_output("Metadata-Version: %s", dist.metadata_version) + write_output("Installer: %s", dist.installer) + write_output("Classifiers:") + for classifier in dist.classifiers: + write_output(" %s", classifier) + write_output("Entry-points:") + for entry in dist.entry_points: + write_output(" %s", entry.strip()) + write_output("Project-URLs:") + for project_url in dist.project_urls: + write_output(" %s", project_url) + if list_files: + write_output("Files:") + if dist.files is None: + write_output("Cannot locate RECORD or installed-files.txt") + else: + for line in dist.files: + write_output(" %s", line.strip()) + return results_printed diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/uninstall.py b/backend/venv/Lib/site-packages/pip/_internal/commands/uninstall.py new file mode 100644 index 0000000..bc0edea --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/uninstall.py @@ -0,0 +1,114 @@ +import logging +from optparse import Values +from typing import List + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.index_command import SessionCommandMixin +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import InstallationError +from pip._internal.req import parse_requirements +from pip._internal.req.constructors import ( + install_req_from_line, + install_req_from_parsed_requirement, +) +from pip._internal.utils.misc import ( + check_externally_managed, + protect_pip_from_modification_on_windows, + warn_if_run_as_root, +) + +logger = logging.getLogger(__name__) + + +class UninstallCommand(Command, SessionCommandMixin): + """ + Uninstall packages. + + pip is able to uninstall most installed packages. Known exceptions are: + + - Pure distutils packages installed with ``python setup.py install``, which + leave behind no metadata to determine what files were installed. + - Script wrappers installed by ``python setup.py develop``. + """ + + usage = """ + %prog [options] ... + %prog [options] -r ...""" + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-r", + "--requirement", + dest="requirements", + action="append", + default=[], + metavar="file", + help=( + "Uninstall all the packages listed in the given requirements " + "file. This option can be used multiple times." + ), + ) + self.cmd_opts.add_option( + "-y", + "--yes", + dest="yes", + action="store_true", + help="Don't ask for confirmation of uninstall deletions.", + ) + self.cmd_opts.add_option(cmdoptions.root_user_action()) + self.cmd_opts.add_option(cmdoptions.override_externally_managed()) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + session = self.get_default_session(options) + + reqs_to_uninstall = {} + for name in args: + req = install_req_from_line( + name, + isolated=options.isolated_mode, + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + else: + logger.warning( + "Invalid requirement: %r ignored -" + " the uninstall command expects named" + " requirements.", + name, + ) + for filename in options.requirements: + for parsed_req in parse_requirements( + filename, options=options, session=session + ): + req = install_req_from_parsed_requirement( + parsed_req, isolated=options.isolated_mode + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + if not reqs_to_uninstall: + raise InstallationError( + f"You must give at least one requirement to {self.name} (see " + f'"pip help {self.name}")' + ) + + if not options.override_externally_managed: + check_externally_managed() + + protect_pip_from_modification_on_windows( + modifying_pip="pip" in reqs_to_uninstall + ) + + for req in reqs_to_uninstall.values(): + uninstall_pathset = req.uninstall( + auto_confirm=options.yes, + verbose=self.verbosity > 0, + ) + if uninstall_pathset: + uninstall_pathset.commit() + if options.root_user_action == "warn": + warn_if_run_as_root() + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/commands/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/commands/wheel.py new file mode 100644 index 0000000..278719f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/commands/wheel.py @@ -0,0 +1,182 @@ +import logging +import os +import shutil +from optparse import Values +from typing import List + +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import CommandError +from pip._internal.operations.build.build_tracker import get_build_tracker +from pip._internal.req.req_install import ( + InstallRequirement, + check_legacy_setup_py_options, +) +from pip._internal.utils.misc import ensure_dir, normalize_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel_builder import build, should_build_for_wheel_command + +logger = logging.getLogger(__name__) + + +class WheelCommand(RequirementCommand): + """ + Build Wheel archives for your requirements and dependencies. + + Wheel is a built-package format, and offers the advantage of not + recompiling your software during every install. For more details, see the + wheel docs: https://wheel.readthedocs.io/en/latest/ + + 'pip wheel' uses the build system interface as described here: + https://pip.pypa.io/en/stable/reference/build-system/ + + """ + + usage = """ + %prog [options] ... + %prog [options] -r ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + def add_options(self) -> None: + self.cmd_opts.add_option( + "-w", + "--wheel-dir", + dest="wheel_dir", + metavar="dir", + default=os.curdir, + help=( + "Build wheels into , where the default is the " + "current working directory." + ), + ) + self.cmd_opts.add_option(cmdoptions.no_binary()) + self.cmd_opts.add_option(cmdoptions.only_binary()) + self.cmd_opts.add_option(cmdoptions.prefer_binary()) + self.cmd_opts.add_option(cmdoptions.no_build_isolation()) + self.cmd_opts.add_option(cmdoptions.use_pep517()) + self.cmd_opts.add_option(cmdoptions.no_use_pep517()) + self.cmd_opts.add_option(cmdoptions.check_build_deps()) + self.cmd_opts.add_option(cmdoptions.constraints()) + self.cmd_opts.add_option(cmdoptions.editable()) + self.cmd_opts.add_option(cmdoptions.requirements()) + self.cmd_opts.add_option(cmdoptions.src()) + self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) + self.cmd_opts.add_option(cmdoptions.no_deps()) + self.cmd_opts.add_option(cmdoptions.progress_bar()) + + self.cmd_opts.add_option( + "--no-verify", + dest="no_verify", + action="store_true", + default=False, + help="Don't verify if built wheel is valid.", + ) + + self.cmd_opts.add_option(cmdoptions.config_settings()) + self.cmd_opts.add_option(cmdoptions.build_options()) + self.cmd_opts.add_option(cmdoptions.global_options()) + + self.cmd_opts.add_option( + "--pre", + action="store_true", + default=False, + help=( + "Include pre-release and development versions. By default, " + "pip only finds stable versions." + ), + ) + + self.cmd_opts.add_option(cmdoptions.require_hashes()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + @with_cleanup + def run(self, options: Values, args: List[str]) -> int: + session = self.get_default_session(options) + + finder = self._build_package_finder(options, session) + + options.wheel_dir = normalize_path(options.wheel_dir) + ensure_dir(options.wheel_dir) + + build_tracker = self.enter_context(get_build_tracker()) + + directory = TempDirectory( + delete=not options.no_clean, + kind="wheel", + globally_managed=True, + ) + + reqs = self.get_requirements(args, options, finder, session) + check_legacy_setup_py_options(options, reqs) + + wheel_cache = WheelCache(options.cache_dir) + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + build_tracker=build_tracker, + session=session, + finder=finder, + download_dir=options.wheel_dir, + use_user_site=False, + verbosity=self.verbosity, + ) + + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + wheel_cache=wheel_cache, + ignore_requires_python=options.ignore_requires_python, + use_pep517=options.use_pep517, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve(reqs, check_supported_wheels=True) + + reqs_to_build: List[InstallRequirement] = [] + for req in requirement_set.requirements.values(): + if req.is_wheel: + preparer.save_linked_requirement(req) + elif should_build_for_wheel_command(req): + reqs_to_build.append(req) + + preparer.prepare_linked_requirements_more(requirement_set.requirements.values()) + + # build wheels + build_successes, build_failures = build( + reqs_to_build, + wheel_cache=wheel_cache, + verify=(not options.no_verify), + build_options=options.build_options or [], + global_options=options.global_options or [], + ) + for req in build_successes: + assert req.link and req.link.is_wheel + assert req.local_file_path + # copy from cache to target directory + try: + shutil.copy(req.local_file_path, options.wheel_dir) + except OSError as e: + logger.warning( + "Building wheel for %s failed: %s", + req.name, + e, + ) + build_failures.append(req) + if len(build_failures) != 0: + raise CommandError("Failed to build one or more wheels") + + return SUCCESS diff --git a/backend/venv/Lib/site-packages/pip/_internal/configuration.py b/backend/venv/Lib/site-packages/pip/_internal/configuration.py new file mode 100644 index 0000000..ffeda1d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/configuration.py @@ -0,0 +1,383 @@ +"""Configuration management setup + +Some terminology: +- name + As written in config files. +- value + Value associated with a name +- key + Name combined with it's section (section.name) +- variant + A single word describing where the configuration key-value pair came from +""" + +import configparser +import locale +import os +import sys +from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple + +from pip._internal.exceptions import ( + ConfigurationError, + ConfigurationFileCouldNotBeLoaded, +) +from pip._internal.utils import appdirs +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.logging import getLogger +from pip._internal.utils.misc import ensure_dir, enum + +RawConfigParser = configparser.RawConfigParser # Shorthand +Kind = NewType("Kind", str) + +CONFIG_BASENAME = "pip.ini" if WINDOWS else "pip.conf" +ENV_NAMES_IGNORED = "version", "help" + +# The kinds of configurations there are. +kinds = enum( + USER="user", # User Specific + GLOBAL="global", # System Wide + SITE="site", # [Virtual] Environment Specific + ENV="env", # from PIP_CONFIG_FILE + ENV_VAR="env-var", # from Environment Variables +) +OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR +VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.SITE + +logger = getLogger(__name__) + + +# NOTE: Maybe use the optionx attribute to normalize keynames. +def _normalize_name(name: str) -> str: + """Make a name consistent regardless of source (environment or file)""" + name = name.lower().replace("_", "-") + if name.startswith("--"): + name = name[2:] # only prefer long opts + return name + + +def _disassemble_key(name: str) -> List[str]: + if "." not in name: + error_message = ( + "Key does not contain dot separated section and key. " + f"Perhaps you wanted to use 'global.{name}' instead?" + ) + raise ConfigurationError(error_message) + return name.split(".", 1) + + +def get_configuration_files() -> Dict[Kind, List[str]]: + global_config_files = [ + os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip") + ] + + site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) + legacy_config_file = os.path.join( + os.path.expanduser("~"), + "pip" if WINDOWS else ".pip", + CONFIG_BASENAME, + ) + new_config_file = os.path.join(appdirs.user_config_dir("pip"), CONFIG_BASENAME) + return { + kinds.GLOBAL: global_config_files, + kinds.SITE: [site_config_file], + kinds.USER: [legacy_config_file, new_config_file], + } + + +class Configuration: + """Handles management of configuration. + + Provides an interface to accessing and managing configuration files. + + This class converts provides an API that takes "section.key-name" style + keys and stores the value associated with it as "key-name" under the + section "section". + + This allows for a clean interface wherein the both the section and the + key-name are preserved in an easy to manage form in the configuration files + and the data stored is also nice. + """ + + def __init__(self, isolated: bool, load_only: Optional[Kind] = None) -> None: + super().__init__() + + if load_only is not None and load_only not in VALID_LOAD_ONLY: + raise ConfigurationError( + "Got invalid value for load_only - should be one of {}".format( + ", ".join(map(repr, VALID_LOAD_ONLY)) + ) + ) + self.isolated = isolated + self.load_only = load_only + + # Because we keep track of where we got the data from + self._parsers: Dict[Kind, List[Tuple[str, RawConfigParser]]] = { + variant: [] for variant in OVERRIDE_ORDER + } + self._config: Dict[Kind, Dict[str, Any]] = { + variant: {} for variant in OVERRIDE_ORDER + } + self._modified_parsers: List[Tuple[str, RawConfigParser]] = [] + + def load(self) -> None: + """Loads configuration from configuration files and environment""" + self._load_config_files() + if not self.isolated: + self._load_environment_vars() + + def get_file_to_edit(self) -> Optional[str]: + """Returns the file with highest priority in configuration""" + assert self.load_only is not None, "Need to be specified a file to be editing" + + try: + return self._get_parser_to_modify()[0] + except IndexError: + return None + + def items(self) -> Iterable[Tuple[str, Any]]: + """Returns key-value pairs like dict.items() representing the loaded + configuration + """ + return self._dictionary.items() + + def get_value(self, key: str) -> Any: + """Get a value from the configuration.""" + orig_key = key + key = _normalize_name(key) + try: + return self._dictionary[key] + except KeyError: + # disassembling triggers a more useful error message than simply + # "No such key" in the case that the key isn't in the form command.option + _disassemble_key(key) + raise ConfigurationError(f"No such key - {orig_key}") + + def set_value(self, key: str, value: Any) -> None: + """Modify a value in the configuration.""" + key = _normalize_name(key) + self._ensure_have_load_only() + + assert self.load_only + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Modify the parser and the configuration + if not parser.has_section(section): + parser.add_section(section) + parser.set(section, name, value) + + self._config[self.load_only][key] = value + self._mark_as_modified(fname, parser) + + def unset_value(self, key: str) -> None: + """Unset a value in the configuration.""" + orig_key = key + key = _normalize_name(key) + self._ensure_have_load_only() + + assert self.load_only + if key not in self._config[self.load_only]: + raise ConfigurationError(f"No such key - {orig_key}") + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + if not ( + parser.has_section(section) and parser.remove_option(section, name) + ): + # The option was not removed. + raise ConfigurationError( + "Fatal Internal error [id=1]. Please report as a bug." + ) + + # The section may be empty after the option was removed. + if not parser.items(section): + parser.remove_section(section) + self._mark_as_modified(fname, parser) + + del self._config[self.load_only][key] + + def save(self) -> None: + """Save the current in-memory state.""" + self._ensure_have_load_only() + + for fname, parser in self._modified_parsers: + logger.info("Writing to %s", fname) + + # Ensure directory exists. + ensure_dir(os.path.dirname(fname)) + + # Ensure directory's permission(need to be writeable) + try: + with open(fname, "w") as f: + parser.write(f) + except OSError as error: + raise ConfigurationError( + f"An error occurred while writing to the configuration file " + f"{fname}: {error}" + ) + + # + # Private routines + # + + def _ensure_have_load_only(self) -> None: + if self.load_only is None: + raise ConfigurationError("Needed a specific file to be modifying.") + logger.debug("Will be working with %s variant only", self.load_only) + + @property + def _dictionary(self) -> Dict[str, Any]: + """A dictionary representing the loaded configuration.""" + # NOTE: Dictionaries are not populated if not loaded. So, conditionals + # are not needed here. + retval = {} + + for variant in OVERRIDE_ORDER: + retval.update(self._config[variant]) + + return retval + + def _load_config_files(self) -> None: + """Loads configuration from configuration files""" + config_files = dict(self.iter_config_files()) + if config_files[kinds.ENV][0:1] == [os.devnull]: + logger.debug( + "Skipping loading configuration files due to " + "environment's PIP_CONFIG_FILE being os.devnull" + ) + return + + for variant, files in config_files.items(): + for fname in files: + # If there's specific variant set in `load_only`, load only + # that variant, not the others. + if self.load_only is not None and variant != self.load_only: + logger.debug("Skipping file '%s' (variant: %s)", fname, variant) + continue + + parser = self._load_file(variant, fname) + + # Keeping track of the parsers used + self._parsers[variant].append((fname, parser)) + + def _load_file(self, variant: Kind, fname: str) -> RawConfigParser: + logger.verbose("For variant '%s', will try loading '%s'", variant, fname) + parser = self._construct_parser(fname) + + for section in parser.sections(): + items = parser.items(section) + self._config[variant].update(self._normalized_keys(section, items)) + + return parser + + def _construct_parser(self, fname: str) -> RawConfigParser: + parser = configparser.RawConfigParser() + # If there is no such file, don't bother reading it but create the + # parser anyway, to hold the data. + # Doing this is useful when modifying and saving files, where we don't + # need to construct a parser. + if os.path.exists(fname): + locale_encoding = locale.getpreferredencoding(False) + try: + parser.read(fname, encoding=locale_encoding) + except UnicodeDecodeError: + # See https://github.com/pypa/pip/issues/4963 + raise ConfigurationFileCouldNotBeLoaded( + reason=f"contains invalid {locale_encoding} characters", + fname=fname, + ) + except configparser.Error as error: + # See https://github.com/pypa/pip/issues/4893 + raise ConfigurationFileCouldNotBeLoaded(error=error) + return parser + + def _load_environment_vars(self) -> None: + """Loads configuration from environment variables""" + self._config[kinds.ENV_VAR].update( + self._normalized_keys(":env:", self.get_environ_vars()) + ) + + def _normalized_keys( + self, section: str, items: Iterable[Tuple[str, Any]] + ) -> Dict[str, Any]: + """Normalizes items to construct a dictionary with normalized keys. + + This routine is where the names become keys and are made the same + regardless of source - configuration files or environment. + """ + normalized = {} + for name, val in items: + key = section + "." + _normalize_name(name) + normalized[key] = val + return normalized + + def get_environ_vars(self) -> Iterable[Tuple[str, str]]: + """Returns a generator with all environmental vars with prefix PIP_""" + for key, val in os.environ.items(): + if key.startswith("PIP_"): + name = key[4:].lower() + if name not in ENV_NAMES_IGNORED: + yield name, val + + # XXX: This is patched in the tests. + def iter_config_files(self) -> Iterable[Tuple[Kind, List[str]]]: + """Yields variant and configuration files associated with it. + + This should be treated like items of a dictionary. The order + here doesn't affect what gets overridden. That is controlled + by OVERRIDE_ORDER. However this does control the order they are + displayed to the user. It's probably most ergonomic to display + things in the same order as OVERRIDE_ORDER + """ + # SMELL: Move the conditions out of this function + + env_config_file = os.environ.get("PIP_CONFIG_FILE", None) + config_files = get_configuration_files() + + yield kinds.GLOBAL, config_files[kinds.GLOBAL] + + # per-user config is not loaded when env_config_file exists + should_load_user_config = not self.isolated and not ( + env_config_file and os.path.exists(env_config_file) + ) + if should_load_user_config: + # The legacy config file is overridden by the new config file + yield kinds.USER, config_files[kinds.USER] + + # virtualenv config + yield kinds.SITE, config_files[kinds.SITE] + + if env_config_file is not None: + yield kinds.ENV, [env_config_file] + else: + yield kinds.ENV, [] + + def get_values_in_config(self, variant: Kind) -> Dict[str, Any]: + """Get values present in a config file""" + return self._config[variant] + + def _get_parser_to_modify(self) -> Tuple[str, RawConfigParser]: + # Determine which parser to modify + assert self.load_only + parsers = self._parsers[self.load_only] + if not parsers: + # This should not happen if everything works correctly. + raise ConfigurationError( + "Fatal Internal error [id=2]. Please report as a bug." + ) + + # Use the highest priority parser. + return parsers[-1] + + # XXX: This is patched in the tests. + def _mark_as_modified(self, fname: str, parser: RawConfigParser) -> None: + file_parser_tuple = (fname, parser) + if file_parser_tuple not in self._modified_parsers: + self._modified_parsers.append(file_parser_tuple) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self._dictionary!r})" diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/distributions/__init__.py new file mode 100644 index 0000000..9a89a83 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/distributions/__init__.py @@ -0,0 +1,21 @@ +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.distributions.sdist import SourceDistribution +from pip._internal.distributions.wheel import WheelDistribution +from pip._internal.req.req_install import InstallRequirement + + +def make_distribution_for_install_requirement( + install_req: InstallRequirement, +) -> AbstractDistribution: + """Returns a Distribution for the given InstallRequirement""" + # Editable requirements will always be source distributions. They use the + # legacy logic until we create a modern standard for them. + if install_req.editable: + return SourceDistribution(install_req) + + # If it's a wheel, it's a WheelDistribution + if install_req.is_wheel: + return WheelDistribution(install_req) + + # Otherwise, a SourceDistribution + return SourceDistribution(install_req) diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f24d6bde498d58985e6fa884c1209fb65e895bf0 GIT binary patch literal 945 zcmaJ;&ubGw6rSn+tVtSLdy$}QDG1w=&9R_GE%qXahxQ;W3(IbHnvU5Y>CB`h(t`*8 zhkEQ)1pg5)!5oyufZ)knAU%2V&6?F1r4MG`_uhQ-_IvMrsMT&Du+8@e)Kw7rCWF${ z8JO+^xIht#aEub{Vl44eyp$-eQeY)k6V25Mtj2m`xCUU27?Do!ks2AVRo5Jt_VRaG z(#HAvUdROt+G3xAr(s{vEQS2qVb*7DvXEVUeoRQbkX(C`auLMw0XgYYMiP>Wyh4BF zd`3=koe|MzX&cYlkPccb&Qt)nKjvP&;EZ6 z8^7E+D0Fcvu;yE`jxuJ6V`6paDM_t=yR+5YBoP%s7!xLiL8sPKKKH^}WI=n{Ya-iL00P;5wUqg)ZIfx1HGeE_e}q>9X& zpNz&wqw%G_ak)LJJ44f%=yO@?vN5VRhi3CiN7XxTx}(b0P~DosbM(w!&Mgq>{1)lV zi{MTeaKhv=^Ns6hym(d2^jhAZVduC1t_LkTaLSgM4*x8AeT&$N#8oN6+)c8mACm`c r9YVP%eiuFy1!Fu$dt>xyj2@2B?nGa~+n-lACkptl+N~=Md{O5oS&s-w literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f076d8f6af7f9ff930e5fa98a263318a82c12ec1 GIT binary patch literal 2897 zcmb7G&2Jk;6rWvt?X?p-?gwp?eq?Ba8kfc`9|u$rY8pz3fKau);6~c4cgD#!>)q|_ zx~ZccB2> zz2ExFLLpD!+4tEg`|k`Pzu+W!w2rXmgK(WN!W4&8@vS;aL#?WfR5hjGJmsVtT2+&B z+Q~Gs)vQ9eDl)LAIeH^k%_&4BCkV@2CM?Uzxvj}1>+etXTd8&X-wpI5kCR z*TFofB(+;<#rDL4|F(+Rr7X`>m0v2Oq)MGTr?lwLBrX6*{fh?by=w+=-??FHDAN0WWu)hFdW}KdyK{ zm+WwX20U!~eX$(u`er(TmpGVQ|FEC7=rfjwdd)D&9;U-&%#NX%9MW}R938@F1Beg~ zG6T=Wbcv=r5!$fCxX%HZu4VI}{G{YrU>rg&X>Wz8S33vkq5Pun1?UP~mH1%RybDkR z9-7Py&Gi)7b&TKToXMJabjcHo5RP=S*0dd12P7?Wv7V@&BF=M{i`bK^ztPnKUFINLhC;N!5EwSy}#Ok|tGKFhd&G6MC&vK!7Ba&<3=wGXd5Y@!SWL z1YFR)({(!Ix%?n1A*8?>gNF7EsN2CBwiuvfL&O0&B><*#a}{53-xS>FO`MTndb~V0 z2mRa+8hSBg? z(?NOAFwQqkr?Zna4CYxt8t^}f$X<<7X3dI9X6KU&90BYSwgko!rJ$q44wQwIi4ojM*F4V=qbL?Sykl|4F^sYzHo>X{!BGiOf&WtEfaME5gyF$u@`qZ|^!Avl zZNI&%(kAf!{KY@<)z(QS_pLU3M;mUdnl^T0{F4`MPTV6PuBAw3L@u_AQfd1g&{q|0 z?Dn%S-y`rwjU95Oo$1lYXk$N>M%x;^VSQvzJByM|c8<1lDCJ4Mcy9nCX@6e@Np^zt z8vcUiuwNy)mIuWc1Q2DymJf_7kfGwN?F62zba}Fpba(|RQYJ3i)UN@QBnuMl?O#VU zU#xWK*XRXzcJkQN+u(_GYn8+gcn%ywdI-c2 z93qqhoH*tRH>yhfBV3F)fL4lB331@I;Bw)_%&r~mC{!J3=lynO-p6ld-uto9s1cCY zf4J{;6+(W)pSfr=Fzo_3CX`UgCxK*15@Okx1I1DbtoUl6Sz3WrUk@r)MIti!fKcs- zP@O4HU~Lr3NGomQ4}@(gGd_+JFA5zW@P)g5k#NUN-t%De`Xls!y>ZWR_nkfVz86x) z!O(ig5o|HY#nt9w%)s;>fMddlB~fC@RI(JNQkiK?zXYCvOqC<`$t>8afX4uvdZb!a zs<9fJd4*Qslc_Ne82)sRZzzyC6A@u$DlG*Fn=I0)cnVP_jWJl(H?h# zzzg?!pGOfa9Wd@P+Y287wTP#^KJZ~7?ZN+}-bY@)C%lB+nz0nU*o(IyI$<2DxYf}JZiK`5Tg6j~#G5LZ# zz>qWY0He;xVWkTVK5vOHr5B(132Do_;|(k+^zR6|BmJ)f+H$5qF|)dW8j69(sNGL_ z12!-7&XG`dX^$m#z!HZ#iDNJ3ZM=1UUjBE&8ZO-dbx3|~u6=Xx^}#RA&7Yc^ljios z=uY13{tUXgz3ekK`Ac{XeNbGptXZbr6OmuEUeSl>D!jSAZ>1KTXJZ=lmQzcM@(TDxeNYUMJN?L9pG(4BHN! zfZ29dv+W?FBOh_ywjV;}W}b>|)5rz00XHIMJV`mS%M^H;cnc8MQLUrGUd+^f6#4uz z{v+pNuYwuJ2dPj9#Al$6$e*&R8E`0lHJ2sr!nZfR-}&y=Uj*P(nHzIm*4~)hd}~Tz z%ne;@JZ)XgH5hZ9T)vi95EpdJ}GE=k#`V z7Q0Mz`tYi9EK2s;au_zmL1%Wu?Xo{g(i_Wx^Y$%sQ}ABSMP}S7^Zhoz4jbXKBd&qU g6-km#$d%v8-4k->gzP-i*QLhfmF>R?j0K^80SEueumAu6 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccc11793226f12ed20c52cb44ff32183c7b2e872 GIT binary patch literal 8431 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 OR_gCO@)v None: + super().__init__() + self.req = req + + @abc.abstractproperty + def build_tracker_id(self) -> Optional[str]: + """A string that uniquely identifies this requirement to the build tracker. + + If None, then this dist has no work to do in the build tracker, and + ``.prepare_distribution_metadata()`` will not be called.""" + raise NotImplementedError() + + @abc.abstractmethod + def get_metadata_distribution(self) -> BaseDistribution: + raise NotImplementedError() + + @abc.abstractmethod + def prepare_distribution_metadata( + self, + finder: "PackageFinder", + build_isolation: bool, + check_build_deps: bool, + ) -> None: + raise NotImplementedError() diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/installed.py b/backend/venv/Lib/site-packages/pip/_internal/distributions/installed.py new file mode 100644 index 0000000..ab8d53b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/distributions/installed.py @@ -0,0 +1,29 @@ +from typing import Optional + +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import BaseDistribution + + +class InstalledDistribution(AbstractDistribution): + """Represents an installed package. + + This does not need any preparation as the required information has already + been computed. + """ + + @property + def build_tracker_id(self) -> Optional[str]: + return None + + def get_metadata_distribution(self) -> BaseDistribution: + assert self.req.satisfied_by is not None, "not actually installed" + return self.req.satisfied_by + + def prepare_distribution_metadata( + self, + finder: PackageFinder, + build_isolation: bool, + check_build_deps: bool, + ) -> None: + pass diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/sdist.py b/backend/venv/Lib/site-packages/pip/_internal/distributions/sdist.py new file mode 100644 index 0000000..28ea5ce --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/distributions/sdist.py @@ -0,0 +1,158 @@ +import logging +from typing import TYPE_CHECKING, Iterable, Optional, Set, Tuple + +from pip._internal.build_env import BuildEnvironment +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.exceptions import InstallationError +from pip._internal.metadata import BaseDistribution +from pip._internal.utils.subprocess import runner_with_spinner_message + +if TYPE_CHECKING: + from pip._internal.index.package_finder import PackageFinder + +logger = logging.getLogger(__name__) + + +class SourceDistribution(AbstractDistribution): + """Represents a source distribution. + + The preparation step for these needs metadata for the packages to be + generated, either using PEP 517 or using the legacy `setup.py egg_info`. + """ + + @property + def build_tracker_id(self) -> Optional[str]: + """Identify this requirement uniquely by its link.""" + assert self.req.link + return self.req.link.url_without_fragment + + def get_metadata_distribution(self) -> BaseDistribution: + return self.req.get_dist() + + def prepare_distribution_metadata( + self, + finder: "PackageFinder", + build_isolation: bool, + check_build_deps: bool, + ) -> None: + # Load pyproject.toml, to determine whether PEP 517 is to be used + self.req.load_pyproject_toml() + + # Set up the build isolation, if this requirement should be isolated + should_isolate = self.req.use_pep517 and build_isolation + if should_isolate: + # Setup an isolated environment and install the build backend static + # requirements in it. + self._prepare_build_backend(finder) + # Check that if the requirement is editable, it either supports PEP 660 or + # has a setup.py or a setup.cfg. This cannot be done earlier because we need + # to setup the build backend to verify it supports build_editable, nor can + # it be done later, because we want to avoid installing build requirements + # needlessly. Doing it here also works around setuptools generating + # UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory + # without setup.py nor setup.cfg. + self.req.isolated_editable_sanity_check() + # Install the dynamic build requirements. + self._install_build_reqs(finder) + # Check if the current environment provides build dependencies + should_check_deps = self.req.use_pep517 and check_build_deps + if should_check_deps: + pyproject_requires = self.req.pyproject_requires + assert pyproject_requires is not None + conflicting, missing = self.req.build_env.check_requirements( + pyproject_requires + ) + if conflicting: + self._raise_conflicts("the backend dependencies", conflicting) + if missing: + self._raise_missing_reqs(missing) + self.req.prepare_metadata() + + def _prepare_build_backend(self, finder: "PackageFinder") -> None: + # Isolate in a BuildEnvironment and install the build-time + # requirements. + pyproject_requires = self.req.pyproject_requires + assert pyproject_requires is not None + + self.req.build_env = BuildEnvironment() + self.req.build_env.install_requirements( + finder, pyproject_requires, "overlay", kind="build dependencies" + ) + conflicting, missing = self.req.build_env.check_requirements( + self.req.requirements_to_check + ) + if conflicting: + self._raise_conflicts("PEP 517/518 supported requirements", conflicting) + if missing: + logger.warning( + "Missing build requirements in pyproject.toml for %s.", + self.req, + ) + logger.warning( + "The project does not specify a build backend, and " + "pip cannot fall back to setuptools without %s.", + " and ".join(map(repr, sorted(missing))), + ) + + def _get_build_requires_wheel(self) -> Iterable[str]: + with self.req.build_env: + runner = runner_with_spinner_message("Getting requirements to build wheel") + backend = self.req.pep517_backend + assert backend is not None + with backend.subprocess_runner(runner): + return backend.get_requires_for_build_wheel() + + def _get_build_requires_editable(self) -> Iterable[str]: + with self.req.build_env: + runner = runner_with_spinner_message( + "Getting requirements to build editable" + ) + backend = self.req.pep517_backend + assert backend is not None + with backend.subprocess_runner(runner): + return backend.get_requires_for_build_editable() + + def _install_build_reqs(self, finder: "PackageFinder") -> None: + # Install any extra build dependencies that the backend requests. + # This must be done in a second pass, as the pyproject.toml + # dependencies must be installed before we can call the backend. + if ( + self.req.editable + and self.req.permit_editable_wheels + and self.req.supports_pyproject_editable + ): + build_reqs = self._get_build_requires_editable() + else: + build_reqs = self._get_build_requires_wheel() + conflicting, missing = self.req.build_env.check_requirements(build_reqs) + if conflicting: + self._raise_conflicts("the backend dependencies", conflicting) + self.req.build_env.install_requirements( + finder, missing, "normal", kind="backend dependencies" + ) + + def _raise_conflicts( + self, conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]] + ) -> None: + format_string = ( + "Some build dependencies for {requirement} " + "conflict with {conflicting_with}: {description}." + ) + error_message = format_string.format( + requirement=self.req, + conflicting_with=conflicting_with, + description=", ".join( + f"{installed} is incompatible with {wanted}" + for installed, wanted in sorted(conflicting_reqs) + ), + ) + raise InstallationError(error_message) + + def _raise_missing_reqs(self, missing: Set[str]) -> None: + format_string = ( + "Some build dependencies for {requirement} are missing: {missing}." + ) + error_message = format_string.format( + requirement=self.req, missing=", ".join(map(repr, sorted(missing))) + ) + raise InstallationError(error_message) diff --git a/backend/venv/Lib/site-packages/pip/_internal/distributions/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/distributions/wheel.py new file mode 100644 index 0000000..bfadd39 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/distributions/wheel.py @@ -0,0 +1,42 @@ +from typing import TYPE_CHECKING, Optional + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.metadata import ( + BaseDistribution, + FilesystemWheel, + get_wheel_distribution, +) + +if TYPE_CHECKING: + from pip._internal.index.package_finder import PackageFinder + + +class WheelDistribution(AbstractDistribution): + """Represents a wheel distribution. + + This does not need any preparation as wheels can be directly unpacked. + """ + + @property + def build_tracker_id(self) -> Optional[str]: + return None + + def get_metadata_distribution(self) -> BaseDistribution: + """Loads the metadata from the wheel file into memory and returns a + Distribution that uses it, not relying on the wheel file or + requirement. + """ + assert self.req.local_file_path, "Set as part of preparation during download" + assert self.req.name, "Wheels are never unnamed" + wheel = FilesystemWheel(self.req.local_file_path) + return get_wheel_distribution(wheel, canonicalize_name(self.req.name)) + + def prepare_distribution_metadata( + self, + finder: "PackageFinder", + build_isolation: bool, + check_build_deps: bool, + ) -> None: + pass diff --git a/backend/venv/Lib/site-packages/pip/_internal/exceptions.py b/backend/venv/Lib/site-packages/pip/_internal/exceptions.py new file mode 100644 index 0000000..45a876a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/exceptions.py @@ -0,0 +1,809 @@ +"""Exceptions used throughout package. + +This module MUST NOT try to import from anything within `pip._internal` to +operate. This is expected to be importable from any/all files within the +subpackage and, thus, should not depend on them. +""" + +import configparser +import contextlib +import locale +import logging +import pathlib +import re +import sys +from itertools import chain, groupby, repeat +from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Union + +from pip._vendor.packaging.requirements import InvalidRequirement +from pip._vendor.packaging.version import InvalidVersion +from pip._vendor.rich.console import Console, ConsoleOptions, RenderResult +from pip._vendor.rich.markup import escape +from pip._vendor.rich.text import Text + +if TYPE_CHECKING: + from hashlib import _Hash + + from pip._vendor.requests.models import Request, Response + + from pip._internal.metadata import BaseDistribution + from pip._internal.req.req_install import InstallRequirement + +logger = logging.getLogger(__name__) + + +# +# Scaffolding +# +def _is_kebab_case(s: str) -> bool: + return re.match(r"^[a-z]+(-[a-z]+)*$", s) is not None + + +def _prefix_with_indent( + s: Union[Text, str], + console: Console, + *, + prefix: str, + indent: str, +) -> Text: + if isinstance(s, Text): + text = s + else: + text = console.render_str(s) + + return console.render_str(prefix, overflow="ignore") + console.render_str( + f"\n{indent}", overflow="ignore" + ).join(text.split(allow_blank=True)) + + +class PipError(Exception): + """The base pip error.""" + + +class DiagnosticPipError(PipError): + """An error, that presents diagnostic information to the user. + + This contains a bunch of logic, to enable pretty presentation of our error + messages. Each error gets a unique reference. Each error can also include + additional context, a hint and/or a note -- which are presented with the + main error message in a consistent style. + + This is adapted from the error output styling in `sphinx-theme-builder`. + """ + + reference: str + + def __init__( + self, + *, + kind: 'Literal["error", "warning"]' = "error", + reference: Optional[str] = None, + message: Union[str, Text], + context: Optional[Union[str, Text]], + hint_stmt: Optional[Union[str, Text]], + note_stmt: Optional[Union[str, Text]] = None, + link: Optional[str] = None, + ) -> None: + # Ensure a proper reference is provided. + if reference is None: + assert hasattr(self, "reference"), "error reference not provided!" + reference = self.reference + assert _is_kebab_case(reference), "error reference must be kebab-case!" + + self.kind = kind + self.reference = reference + + self.message = message + self.context = context + + self.note_stmt = note_stmt + self.hint_stmt = hint_stmt + + self.link = link + + super().__init__(f"<{self.__class__.__name__}: {self.reference}>") + + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__}(" + f"reference={self.reference!r}, " + f"message={self.message!r}, " + f"context={self.context!r}, " + f"note_stmt={self.note_stmt!r}, " + f"hint_stmt={self.hint_stmt!r}" + ")>" + ) + + def __rich_console__( + self, + console: Console, + options: ConsoleOptions, + ) -> RenderResult: + colour = "red" if self.kind == "error" else "yellow" + + yield f"[{colour} bold]{self.kind}[/]: [bold]{self.reference}[/]" + yield "" + + if not options.ascii_only: + # Present the main message, with relevant context indented. + if self.context is not None: + yield _prefix_with_indent( + self.message, + console, + prefix=f"[{colour}]×[/] ", + indent=f"[{colour}]│[/] ", + ) + yield _prefix_with_indent( + self.context, + console, + prefix=f"[{colour}]╰─>[/] ", + indent=f"[{colour}] [/] ", + ) + else: + yield _prefix_with_indent( + self.message, + console, + prefix="[red]×[/] ", + indent=" ", + ) + else: + yield self.message + if self.context is not None: + yield "" + yield self.context + + if self.note_stmt is not None or self.hint_stmt is not None: + yield "" + + if self.note_stmt is not None: + yield _prefix_with_indent( + self.note_stmt, + console, + prefix="[magenta bold]note[/]: ", + indent=" ", + ) + if self.hint_stmt is not None: + yield _prefix_with_indent( + self.hint_stmt, + console, + prefix="[cyan bold]hint[/]: ", + indent=" ", + ) + + if self.link is not None: + yield "" + yield f"Link: {self.link}" + + +# +# Actual Errors +# +class ConfigurationError(PipError): + """General exception in configuration""" + + +class InstallationError(PipError): + """General exception during installation""" + + +class MissingPyProjectBuildRequires(DiagnosticPipError): + """Raised when pyproject.toml has `build-system`, but no `build-system.requires`.""" + + reference = "missing-pyproject-build-system-requires" + + def __init__(self, *, package: str) -> None: + super().__init__( + message=f"Can not process {escape(package)}", + context=Text( + "This package has an invalid pyproject.toml file.\n" + "The [build-system] table is missing the mandatory `requires` key." + ), + note_stmt="This is an issue with the package mentioned above, not pip.", + hint_stmt=Text("See PEP 518 for the detailed specification."), + ) + + +class InvalidPyProjectBuildRequires(DiagnosticPipError): + """Raised when pyproject.toml an invalid `build-system.requires`.""" + + reference = "invalid-pyproject-build-system-requires" + + def __init__(self, *, package: str, reason: str) -> None: + super().__init__( + message=f"Can not process {escape(package)}", + context=Text( + "This package has an invalid `build-system.requires` key in " + f"pyproject.toml.\n{reason}" + ), + note_stmt="This is an issue with the package mentioned above, not pip.", + hint_stmt=Text("See PEP 518 for the detailed specification."), + ) + + +class NoneMetadataError(PipError): + """Raised when accessing a Distribution's "METADATA" or "PKG-INFO". + + This signifies an inconsistency, when the Distribution claims to have + the metadata file (if not, raise ``FileNotFoundError`` instead), but is + not actually able to produce its content. This may be due to permission + errors. + """ + + def __init__( + self, + dist: "BaseDistribution", + metadata_name: str, + ) -> None: + """ + :param dist: A Distribution object. + :param metadata_name: The name of the metadata being accessed + (can be "METADATA" or "PKG-INFO"). + """ + self.dist = dist + self.metadata_name = metadata_name + + def __str__(self) -> str: + # Use `dist` in the error message because its stringification + # includes more information, like the version and location. + return f"None {self.metadata_name} metadata found for distribution: {self.dist}" + + +class UserInstallationInvalid(InstallationError): + """A --user install is requested on an environment without user site.""" + + def __str__(self) -> str: + return "User base directory is not specified" + + +class InvalidSchemeCombination(InstallationError): + def __str__(self) -> str: + before = ", ".join(str(a) for a in self.args[:-1]) + return f"Cannot set {before} and {self.args[-1]} together" + + +class DistributionNotFound(InstallationError): + """Raised when a distribution cannot be found to satisfy a requirement""" + + +class RequirementsFileParseError(InstallationError): + """Raised when a general error occurs parsing a requirements file line.""" + + +class BestVersionAlreadyInstalled(PipError): + """Raised when the most up-to-date version of a package is already + installed.""" + + +class BadCommand(PipError): + """Raised when virtualenv or a command is not found""" + + +class CommandError(PipError): + """Raised when there is an error in command-line arguments""" + + +class PreviousBuildDirError(PipError): + """Raised when there's a previous conflicting build directory""" + + +class NetworkConnectionError(PipError): + """HTTP connection error""" + + def __init__( + self, + error_msg: str, + response: Optional["Response"] = None, + request: Optional["Request"] = None, + ) -> None: + """ + Initialize NetworkConnectionError with `request` and `response` + objects. + """ + self.response = response + self.request = request + self.error_msg = error_msg + if ( + self.response is not None + and not self.request + and hasattr(response, "request") + ): + self.request = self.response.request + super().__init__(error_msg, response, request) + + def __str__(self) -> str: + return str(self.error_msg) + + +class InvalidWheelFilename(InstallationError): + """Invalid wheel filename.""" + + +class UnsupportedWheel(InstallationError): + """Unsupported wheel.""" + + +class InvalidWheel(InstallationError): + """Invalid (e.g. corrupt) wheel.""" + + def __init__(self, location: str, name: str): + self.location = location + self.name = name + + def __str__(self) -> str: + return f"Wheel '{self.name}' located at {self.location} is invalid." + + +class MetadataInconsistent(InstallationError): + """Built metadata contains inconsistent information. + + This is raised when the metadata contains values (e.g. name and version) + that do not match the information previously obtained from sdist filename, + user-supplied ``#egg=`` value, or an install requirement name. + """ + + def __init__( + self, ireq: "InstallRequirement", field: str, f_val: str, m_val: str + ) -> None: + self.ireq = ireq + self.field = field + self.f_val = f_val + self.m_val = m_val + + def __str__(self) -> str: + return ( + f"Requested {self.ireq} has inconsistent {self.field}: " + f"expected {self.f_val!r}, but metadata has {self.m_val!r}" + ) + + +class MetadataInvalid(InstallationError): + """Metadata is invalid.""" + + def __init__(self, ireq: "InstallRequirement", error: str) -> None: + self.ireq = ireq + self.error = error + + def __str__(self) -> str: + return f"Requested {self.ireq} has invalid metadata: {self.error}" + + +class InstallationSubprocessError(DiagnosticPipError, InstallationError): + """A subprocess call failed.""" + + reference = "subprocess-exited-with-error" + + def __init__( + self, + *, + command_description: str, + exit_code: int, + output_lines: Optional[List[str]], + ) -> None: + if output_lines is None: + output_prompt = Text("See above for output.") + else: + output_prompt = ( + Text.from_markup(f"[red][{len(output_lines)} lines of output][/]\n") + + Text("".join(output_lines)) + + Text.from_markup(R"[red]\[end of output][/]") + ) + + super().__init__( + message=( + f"[green]{escape(command_description)}[/] did not run successfully.\n" + f"exit code: {exit_code}" + ), + context=output_prompt, + hint_stmt=None, + note_stmt=( + "This error originates from a subprocess, and is likely not a " + "problem with pip." + ), + ) + + self.command_description = command_description + self.exit_code = exit_code + + def __str__(self) -> str: + return f"{self.command_description} exited with {self.exit_code}" + + +class MetadataGenerationFailed(InstallationSubprocessError, InstallationError): + reference = "metadata-generation-failed" + + def __init__( + self, + *, + package_details: str, + ) -> None: + super(InstallationSubprocessError, self).__init__( + message="Encountered error while generating package metadata.", + context=escape(package_details), + hint_stmt="See above for details.", + note_stmt="This is an issue with the package mentioned above, not pip.", + ) + + def __str__(self) -> str: + return "metadata generation failed" + + +class HashErrors(InstallationError): + """Multiple HashError instances rolled into one for reporting""" + + def __init__(self) -> None: + self.errors: List[HashError] = [] + + def append(self, error: "HashError") -> None: + self.errors.append(error) + + def __str__(self) -> str: + lines = [] + self.errors.sort(key=lambda e: e.order) + for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): + lines.append(cls.head) + lines.extend(e.body() for e in errors_of_cls) + if lines: + return "\n".join(lines) + return "" + + def __bool__(self) -> bool: + return bool(self.errors) + + +class HashError(InstallationError): + """ + A failure to verify a package against known-good hashes + + :cvar order: An int sorting hash exception classes by difficulty of + recovery (lower being harder), so the user doesn't bother fretting + about unpinned packages when he has deeper issues, like VCS + dependencies, to deal with. Also keeps error reports in a + deterministic order. + :cvar head: A section heading for display above potentially many + exceptions of this kind + :ivar req: The InstallRequirement that triggered this error. This is + pasted on after the exception is instantiated, because it's not + typically available earlier. + + """ + + req: Optional["InstallRequirement"] = None + head = "" + order: int = -1 + + def body(self) -> str: + """Return a summary of me for display under the heading. + + This default implementation simply prints a description of the + triggering requirement. + + :param req: The InstallRequirement that provoked this error, with + its link already populated by the resolver's _populate_link(). + + """ + return f" {self._requirement_name()}" + + def __str__(self) -> str: + return f"{self.head}\n{self.body()}" + + def _requirement_name(self) -> str: + """Return a description of the requirement that triggered me. + + This default implementation returns long description of the req, with + line numbers + + """ + return str(self.req) if self.req else "unknown package" + + +class VcsHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 0 + head = ( + "Can't verify hashes for these requirements because we don't " + "have a way to hash version control repositories:" + ) + + +class DirectoryUrlHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 1 + head = ( + "Can't verify hashes for these file:// requirements because they " + "point to directories:" + ) + + +class HashMissing(HashError): + """A hash was needed for a requirement but is absent.""" + + order = 2 + head = ( + "Hashes are required in --require-hashes mode, but they are " + "missing from some requirements. Here is a list of those " + "requirements along with the hashes their downloaded archives " + "actually had. Add lines like these to your requirements files to " + "prevent tampering. (If you did not enable --require-hashes " + "manually, note that it turns on automatically when any package " + "has a hash.)" + ) + + def __init__(self, gotten_hash: str) -> None: + """ + :param gotten_hash: The hash of the (possibly malicious) archive we + just downloaded + """ + self.gotten_hash = gotten_hash + + def body(self) -> str: + # Dodge circular import. + from pip._internal.utils.hashes import FAVORITE_HASH + + package = None + if self.req: + # In the case of URL-based requirements, display the original URL + # seen in the requirements file rather than the package name, + # so the output can be directly copied into the requirements file. + package = ( + self.req.original_link + if self.req.is_direct + # In case someone feeds something downright stupid + # to InstallRequirement's constructor. + else getattr(self.req, "req", None) + ) + return " {} --hash={}:{}".format( + package or "unknown package", FAVORITE_HASH, self.gotten_hash + ) + + +class HashUnpinned(HashError): + """A requirement had a hash specified but was not pinned to a specific + version.""" + + order = 3 + head = ( + "In --require-hashes mode, all requirements must have their " + "versions pinned with ==. These do not:" + ) + + +class HashMismatch(HashError): + """ + Distribution file hash values don't match. + + :ivar package_name: The name of the package that triggered the hash + mismatch. Feel free to write to this after the exception is raise to + improve its error message. + + """ + + order = 4 + head = ( + "THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS " + "FILE. If you have updated the package versions, please update " + "the hashes. Otherwise, examine the package contents carefully; " + "someone may have tampered with them." + ) + + def __init__(self, allowed: Dict[str, List[str]], gots: Dict[str, "_Hash"]) -> None: + """ + :param allowed: A dict of algorithm names pointing to lists of allowed + hex digests + :param gots: A dict of algorithm names pointing to hashes we + actually got from the files under suspicion + """ + self.allowed = allowed + self.gots = gots + + def body(self) -> str: + return f" {self._requirement_name()}:\n{self._hash_comparison()}" + + def _hash_comparison(self) -> str: + """ + Return a comparison of actual and expected hash values. + + Example:: + + Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde + or 123451234512345123451234512345123451234512345 + Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef + + """ + + def hash_then_or(hash_name: str) -> "chain[str]": + # For now, all the decent hashes have 6-char names, so we can get + # away with hard-coding space literals. + return chain([hash_name], repeat(" or")) + + lines: List[str] = [] + for hash_name, expecteds in self.allowed.items(): + prefix = hash_then_or(hash_name) + lines.extend((f" Expected {next(prefix)} {e}") for e in expecteds) + lines.append( + f" Got {self.gots[hash_name].hexdigest()}\n" + ) + return "\n".join(lines) + + +class UnsupportedPythonVersion(InstallationError): + """Unsupported python version according to Requires-Python package + metadata.""" + + +class ConfigurationFileCouldNotBeLoaded(ConfigurationError): + """When there are errors while loading a configuration file""" + + def __init__( + self, + reason: str = "could not be loaded", + fname: Optional[str] = None, + error: Optional[configparser.Error] = None, + ) -> None: + super().__init__(error) + self.reason = reason + self.fname = fname + self.error = error + + def __str__(self) -> str: + if self.fname is not None: + message_part = f" in {self.fname}." + else: + assert self.error is not None + message_part = f".\n{self.error}\n" + return f"Configuration file {self.reason}{message_part}" + + +_DEFAULT_EXTERNALLY_MANAGED_ERROR = f"""\ +The Python environment under {sys.prefix} is managed externally, and may not be +manipulated by the user. Please use specific tooling from the distributor of +the Python installation to interact with this environment instead. +""" + + +class ExternallyManagedEnvironment(DiagnosticPipError): + """The current environment is externally managed. + + This is raised when the current environment is externally managed, as + defined by `PEP 668`_. The ``EXTERNALLY-MANAGED`` configuration is checked + and displayed when the error is bubbled up to the user. + + :param error: The error message read from ``EXTERNALLY-MANAGED``. + """ + + reference = "externally-managed-environment" + + def __init__(self, error: Optional[str]) -> None: + if error is None: + context = Text(_DEFAULT_EXTERNALLY_MANAGED_ERROR) + else: + context = Text(error) + super().__init__( + message="This environment is externally managed", + context=context, + note_stmt=( + "If you believe this is a mistake, please contact your " + "Python installation or OS distribution provider. " + "You can override this, at the risk of breaking your Python " + "installation or OS, by passing --break-system-packages." + ), + hint_stmt=Text("See PEP 668 for the detailed specification."), + ) + + @staticmethod + def _iter_externally_managed_error_keys() -> Iterator[str]: + # LC_MESSAGES is in POSIX, but not the C standard. The most common + # platform that does not implement this category is Windows, where + # using other categories for console message localization is equally + # unreliable, so we fall back to the locale-less vendor message. This + # can always be re-evaluated when a vendor proposes a new alternative. + try: + category = locale.LC_MESSAGES + except AttributeError: + lang: Optional[str] = None + else: + lang, _ = locale.getlocale(category) + if lang is not None: + yield f"Error-{lang}" + for sep in ("-", "_"): + before, found, _ = lang.partition(sep) + if not found: + continue + yield f"Error-{before}" + yield "Error" + + @classmethod + def from_config( + cls, + config: Union[pathlib.Path, str], + ) -> "ExternallyManagedEnvironment": + parser = configparser.ConfigParser(interpolation=None) + try: + parser.read(config, encoding="utf-8") + section = parser["externally-managed"] + for key in cls._iter_externally_managed_error_keys(): + with contextlib.suppress(KeyError): + return cls(section[key]) + except KeyError: + pass + except (OSError, UnicodeDecodeError, configparser.ParsingError): + from pip._internal.utils._log import VERBOSE + + exc_info = logger.isEnabledFor(VERBOSE) + logger.warning("Failed to read %s", config, exc_info=exc_info) + return cls(None) + + +class UninstallMissingRecord(DiagnosticPipError): + reference = "uninstall-no-record-file" + + def __init__(self, *, distribution: "BaseDistribution") -> None: + installer = distribution.installer + if not installer or installer == "pip": + dep = f"{distribution.raw_name}=={distribution.version}" + hint = Text.assemble( + "You might be able to recover from this via: ", + (f"pip install --force-reinstall --no-deps {dep}", "green"), + ) + else: + hint = Text( + f"The package was installed by {installer}. " + "You should check if it can uninstall the package." + ) + + super().__init__( + message=Text(f"Cannot uninstall {distribution}"), + context=( + "The package's contents are unknown: " + f"no RECORD file was found for {distribution.raw_name}." + ), + hint_stmt=hint, + ) + + +class LegacyDistutilsInstall(DiagnosticPipError): + reference = "uninstall-distutils-installed-package" + + def __init__(self, *, distribution: "BaseDistribution") -> None: + super().__init__( + message=Text(f"Cannot uninstall {distribution}"), + context=( + "It is a distutils installed project and thus we cannot accurately " + "determine which files belong to it which would lead to only a partial " + "uninstall." + ), + hint_stmt=None, + ) + + +class InvalidInstalledPackage(DiagnosticPipError): + reference = "invalid-installed-package" + + def __init__( + self, + *, + dist: "BaseDistribution", + invalid_exc: Union[InvalidRequirement, InvalidVersion], + ) -> None: + installed_location = dist.installed_location + + if isinstance(invalid_exc, InvalidRequirement): + invalid_type = "requirement" + else: + invalid_type = "version" + + super().__init__( + message=Text( + f"Cannot process installed package {dist} " + + (f"in {installed_location!r} " if installed_location else "") + + f"because it has an invalid {invalid_type}:\n{invalid_exc.args[0]}" + ), + context=( + "Starting with pip 24.1, packages with invalid " + f"{invalid_type}s can not be processed." + ), + hint_stmt="To proceed this package must be uninstalled.", + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/index/__init__.py new file mode 100644 index 0000000..7a17b7b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/index/__init__.py @@ -0,0 +1,2 @@ +"""Index interaction code +""" diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b878c04f762295f621c579e10c8229402ceb8e6 GIT binary patch literal 236 zcmX@j%ge<81j_4zGUb5uV-N=h7@>^M96-i&h7^VtJ_IlCC-s}IbKjEtX{7#UfLSb$sr D^!!Bx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..965d4c82bad54c0aa12405c836ffb132151102a1 GIT binary patch literal 21621 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 Yh@YP#4L=`rr%pfnKlVMOFrx_mZ?R~pzyJUM literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f2e38f6bd6515de4672d319d07b11cc01cb5a37 GIT binary patch literal 12528 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/collector.py b/backend/venv/Lib/site-packages/pip/_internal/index/collector.py new file mode 100644 index 0000000..5f8fdee --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/index/collector.py @@ -0,0 +1,494 @@ +""" +The main purpose of this module is to expose LinkCollector.collect_sources(). +""" + +import collections +import email.message +import functools +import itertools +import json +import logging +import os +import urllib.parse +import urllib.request +from dataclasses import dataclass +from html.parser import HTMLParser +from optparse import Values +from typing import ( + Callable, + Dict, + Iterable, + List, + MutableMapping, + NamedTuple, + Optional, + Protocol, + Sequence, + Tuple, + Union, +) + +from pip._vendor import requests +from pip._vendor.requests import Response +from pip._vendor.requests.exceptions import RetryError, SSLError + +from pip._internal.exceptions import NetworkConnectionError +from pip._internal.models.link import Link +from pip._internal.models.search_scope import SearchScope +from pip._internal.network.session import PipSession +from pip._internal.network.utils import raise_for_status +from pip._internal.utils.filetypes import is_archive_file +from pip._internal.utils.misc import redact_auth_from_url +from pip._internal.vcs import vcs + +from .sources import CandidatesFromPage, LinkSource, build_source + +logger = logging.getLogger(__name__) + +ResponseHeaders = MutableMapping[str, str] + + +def _match_vcs_scheme(url: str) -> Optional[str]: + """Look for VCS schemes in the URL. + + Returns the matched VCS scheme, or None if there's no match. + """ + for scheme in vcs.schemes: + if url.lower().startswith(scheme) and url[len(scheme)] in "+:": + return scheme + return None + + +class _NotAPIContent(Exception): + def __init__(self, content_type: str, request_desc: str) -> None: + super().__init__(content_type, request_desc) + self.content_type = content_type + self.request_desc = request_desc + + +def _ensure_api_header(response: Response) -> None: + """ + Check the Content-Type header to ensure the response contains a Simple + API Response. + + Raises `_NotAPIContent` if the content type is not a valid content-type. + """ + content_type = response.headers.get("Content-Type", "Unknown") + + content_type_l = content_type.lower() + if content_type_l.startswith( + ( + "text/html", + "application/vnd.pypi.simple.v1+html", + "application/vnd.pypi.simple.v1+json", + ) + ): + return + + raise _NotAPIContent(content_type, response.request.method) + + +class _NotHTTP(Exception): + pass + + +def _ensure_api_response(url: str, session: PipSession) -> None: + """ + Send a HEAD request to the URL, and ensure the response contains a simple + API Response. + + Raises `_NotHTTP` if the URL is not available for a HEAD request, or + `_NotAPIContent` if the content type is not a valid content type. + """ + scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url) + if scheme not in {"http", "https"}: + raise _NotHTTP() + + resp = session.head(url, allow_redirects=True) + raise_for_status(resp) + + _ensure_api_header(resp) + + +def _get_simple_response(url: str, session: PipSession) -> Response: + """Access an Simple API response with GET, and return the response. + + This consists of three parts: + + 1. If the URL looks suspiciously like an archive, send a HEAD first to + check the Content-Type is HTML or Simple API, to avoid downloading a + large file. Raise `_NotHTTP` if the content type cannot be determined, or + `_NotAPIContent` if it is not HTML or a Simple API. + 2. Actually perform the request. Raise HTTP exceptions on network failures. + 3. Check the Content-Type header to make sure we got a Simple API response, + and raise `_NotAPIContent` otherwise. + """ + if is_archive_file(Link(url).filename): + _ensure_api_response(url, session=session) + + logger.debug("Getting page %s", redact_auth_from_url(url)) + + resp = session.get( + url, + headers={ + "Accept": ", ".join( + [ + "application/vnd.pypi.simple.v1+json", + "application/vnd.pypi.simple.v1+html; q=0.1", + "text/html; q=0.01", + ] + ), + # We don't want to blindly returned cached data for + # /simple/, because authors generally expecting that + # twine upload && pip install will function, but if + # they've done a pip install in the last ~10 minutes + # it won't. Thus by setting this to zero we will not + # blindly use any cached data, however the benefit of + # using max-age=0 instead of no-cache, is that we will + # still support conditional requests, so we will still + # minimize traffic sent in cases where the page hasn't + # changed at all, we will just always incur the round + # trip for the conditional GET now instead of only + # once per 10 minutes. + # For more information, please see pypa/pip#5670. + "Cache-Control": "max-age=0", + }, + ) + raise_for_status(resp) + + # The check for archives above only works if the url ends with + # something that looks like an archive. However that is not a + # requirement of an url. Unless we issue a HEAD request on every + # url we cannot know ahead of time for sure if something is a + # Simple API response or not. However we can check after we've + # downloaded it. + _ensure_api_header(resp) + + logger.debug( + "Fetched page %s as %s", + redact_auth_from_url(url), + resp.headers.get("Content-Type", "Unknown"), + ) + + return resp + + +def _get_encoding_from_headers(headers: ResponseHeaders) -> Optional[str]: + """Determine if we have any encoding information in our headers.""" + if headers and "Content-Type" in headers: + m = email.message.Message() + m["content-type"] = headers["Content-Type"] + charset = m.get_param("charset") + if charset: + return str(charset) + return None + + +class CacheablePageContent: + def __init__(self, page: "IndexContent") -> None: + assert page.cache_link_parsing + self.page = page + + def __eq__(self, other: object) -> bool: + return isinstance(other, type(self)) and self.page.url == other.page.url + + def __hash__(self) -> int: + return hash(self.page.url) + + +class ParseLinks(Protocol): + def __call__(self, page: "IndexContent") -> Iterable[Link]: ... + + +def with_cached_index_content(fn: ParseLinks) -> ParseLinks: + """ + Given a function that parses an Iterable[Link] from an IndexContent, cache the + function's result (keyed by CacheablePageContent), unless the IndexContent + `page` has `page.cache_link_parsing == False`. + """ + + @functools.lru_cache(maxsize=None) + def wrapper(cacheable_page: CacheablePageContent) -> List[Link]: + return list(fn(cacheable_page.page)) + + @functools.wraps(fn) + def wrapper_wrapper(page: "IndexContent") -> List[Link]: + if page.cache_link_parsing: + return wrapper(CacheablePageContent(page)) + return list(fn(page)) + + return wrapper_wrapper + + +@with_cached_index_content +def parse_links(page: "IndexContent") -> Iterable[Link]: + """ + Parse a Simple API's Index Content, and yield its anchor elements as Link objects. + """ + + content_type_l = page.content_type.lower() + if content_type_l.startswith("application/vnd.pypi.simple.v1+json"): + data = json.loads(page.content) + for file in data.get("files", []): + link = Link.from_json(file, page.url) + if link is None: + continue + yield link + return + + parser = HTMLLinkParser(page.url) + encoding = page.encoding or "utf-8" + parser.feed(page.content.decode(encoding)) + + url = page.url + base_url = parser.base_url or url + for anchor in parser.anchors: + link = Link.from_element(anchor, page_url=url, base_url=base_url) + if link is None: + continue + yield link + + +@dataclass(frozen=True) +class IndexContent: + """Represents one response (or page), along with its URL. + + :param encoding: the encoding to decode the given content. + :param url: the URL from which the HTML was downloaded. + :param cache_link_parsing: whether links parsed from this page's url + should be cached. PyPI index urls should + have this set to False, for example. + """ + + content: bytes + content_type: str + encoding: Optional[str] + url: str + cache_link_parsing: bool = True + + def __str__(self) -> str: + return redact_auth_from_url(self.url) + + +class HTMLLinkParser(HTMLParser): + """ + HTMLParser that keeps the first base HREF and a list of all anchor + elements' attributes. + """ + + def __init__(self, url: str) -> None: + super().__init__(convert_charrefs=True) + + self.url: str = url + self.base_url: Optional[str] = None + self.anchors: List[Dict[str, Optional[str]]] = [] + + def handle_starttag(self, tag: str, attrs: List[Tuple[str, Optional[str]]]) -> None: + if tag == "base" and self.base_url is None: + href = self.get_href(attrs) + if href is not None: + self.base_url = href + elif tag == "a": + self.anchors.append(dict(attrs)) + + def get_href(self, attrs: List[Tuple[str, Optional[str]]]) -> Optional[str]: + for name, value in attrs: + if name == "href": + return value + return None + + +def _handle_get_simple_fail( + link: Link, + reason: Union[str, Exception], + meth: Optional[Callable[..., None]] = None, +) -> None: + if meth is None: + meth = logger.debug + meth("Could not fetch URL %s: %s - skipping", link, reason) + + +def _make_index_content( + response: Response, cache_link_parsing: bool = True +) -> IndexContent: + encoding = _get_encoding_from_headers(response.headers) + return IndexContent( + response.content, + response.headers["Content-Type"], + encoding=encoding, + url=response.url, + cache_link_parsing=cache_link_parsing, + ) + + +def _get_index_content(link: Link, *, session: PipSession) -> Optional["IndexContent"]: + url = link.url.split("#", 1)[0] + + # Check for VCS schemes that do not support lookup as web pages. + vcs_scheme = _match_vcs_scheme(url) + if vcs_scheme: + logger.warning( + "Cannot look at %s URL %s because it does not support lookup as web pages.", + vcs_scheme, + link, + ) + return None + + # Tack index.html onto file:// URLs that point to directories + scheme, _, path, _, _, _ = urllib.parse.urlparse(url) + if scheme == "file" and os.path.isdir(urllib.request.url2pathname(path)): + # add trailing slash if not present so urljoin doesn't trim + # final segment + if not url.endswith("/"): + url += "/" + # TODO: In the future, it would be nice if pip supported PEP 691 + # style responses in the file:// URLs, however there's no + # standard file extension for application/vnd.pypi.simple.v1+json + # so we'll need to come up with something on our own. + url = urllib.parse.urljoin(url, "index.html") + logger.debug(" file: URL is directory, getting %s", url) + + try: + resp = _get_simple_response(url, session=session) + except _NotHTTP: + logger.warning( + "Skipping page %s because it looks like an archive, and cannot " + "be checked by a HTTP HEAD request.", + link, + ) + except _NotAPIContent as exc: + logger.warning( + "Skipping page %s because the %s request got Content-Type: %s. " + "The only supported Content-Types are application/vnd.pypi.simple.v1+json, " + "application/vnd.pypi.simple.v1+html, and text/html", + link, + exc.request_desc, + exc.content_type, + ) + except NetworkConnectionError as exc: + _handle_get_simple_fail(link, exc) + except RetryError as exc: + _handle_get_simple_fail(link, exc) + except SSLError as exc: + reason = "There was a problem confirming the ssl certificate: " + reason += str(exc) + _handle_get_simple_fail(link, reason, meth=logger.info) + except requests.ConnectionError as exc: + _handle_get_simple_fail(link, f"connection error: {exc}") + except requests.Timeout: + _handle_get_simple_fail(link, "timed out") + else: + return _make_index_content(resp, cache_link_parsing=link.cache_link_parsing) + return None + + +class CollectedSources(NamedTuple): + find_links: Sequence[Optional[LinkSource]] + index_urls: Sequence[Optional[LinkSource]] + + +class LinkCollector: + """ + Responsible for collecting Link objects from all configured locations, + making network requests as needed. + + The class's main method is its collect_sources() method. + """ + + def __init__( + self, + session: PipSession, + search_scope: SearchScope, + ) -> None: + self.search_scope = search_scope + self.session = session + + @classmethod + def create( + cls, + session: PipSession, + options: Values, + suppress_no_index: bool = False, + ) -> "LinkCollector": + """ + :param session: The Session to use to make requests. + :param suppress_no_index: Whether to ignore the --no-index option + when constructing the SearchScope object. + """ + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index and not suppress_no_index: + logger.debug( + "Ignoring indexes: %s", + ",".join(redact_auth_from_url(url) for url in index_urls), + ) + index_urls = [] + + # Make sure find_links is a list before passing to create(). + find_links = options.find_links or [] + + search_scope = SearchScope.create( + find_links=find_links, + index_urls=index_urls, + no_index=options.no_index, + ) + link_collector = LinkCollector( + session=session, + search_scope=search_scope, + ) + return link_collector + + @property + def find_links(self) -> List[str]: + return self.search_scope.find_links + + def fetch_response(self, location: Link) -> Optional[IndexContent]: + """ + Fetch an HTML page containing package links. + """ + return _get_index_content(location, session=self.session) + + def collect_sources( + self, + project_name: str, + candidates_from_page: CandidatesFromPage, + ) -> CollectedSources: + # The OrderedDict calls deduplicate sources by URL. + index_url_sources = collections.OrderedDict( + build_source( + loc, + candidates_from_page=candidates_from_page, + page_validator=self.session.is_secure_origin, + expand_dir=False, + cache_link_parsing=False, + project_name=project_name, + ) + for loc in self.search_scope.get_index_urls_locations(project_name) + ).values() + find_links_sources = collections.OrderedDict( + build_source( + loc, + candidates_from_page=candidates_from_page, + page_validator=self.session.is_secure_origin, + expand_dir=True, + cache_link_parsing=True, + project_name=project_name, + ) + for loc in self.find_links + ).values() + + if logger.isEnabledFor(logging.DEBUG): + lines = [ + f"* {s.link}" + for s in itertools.chain(find_links_sources, index_url_sources) + if s is not None and s.link is not None + ] + lines = [ + f"{len(lines)} location(s) to search " + f"for versions of {project_name}:" + ] + lines + logger.debug("\n".join(lines)) + + return CollectedSources( + find_links=list(find_links_sources), + index_urls=list(index_url_sources), + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/package_finder.py b/backend/venv/Lib/site-packages/pip/_internal/index/package_finder.py new file mode 100644 index 0000000..85628ee --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/index/package_finder.py @@ -0,0 +1,1029 @@ +"""Routines related to PyPI, indexes""" + +import enum +import functools +import itertools +import logging +import re +from dataclasses import dataclass +from typing import TYPE_CHECKING, FrozenSet, Iterable, List, Optional, Set, Tuple, Union + +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.tags import Tag +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import InvalidVersion, _BaseVersion +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, + DistributionNotFound, + InvalidWheelFilename, + UnsupportedWheel, +) +from pip._internal.index.collector import LinkCollector, parse_links +from pip._internal.models.candidate import InstallationCandidate +from pip._internal.models.format_control import FormatControl +from pip._internal.models.link import Link +from pip._internal.models.search_scope import SearchScope +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.models.wheel import Wheel +from pip._internal.req import InstallRequirement +from pip._internal.utils._log import getLogger +from pip._internal.utils.filetypes import WHEEL_EXTENSION +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import build_netloc +from pip._internal.utils.packaging import check_requires_python +from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS + +if TYPE_CHECKING: + from pip._vendor.typing_extensions import TypeGuard + +__all__ = ["FormatControl", "BestCandidateResult", "PackageFinder"] + + +logger = getLogger(__name__) + +BuildTag = Union[Tuple[()], Tuple[int, str]] +CandidateSortingKey = Tuple[int, int, int, _BaseVersion, Optional[int], BuildTag] + + +def _check_link_requires_python( + link: Link, + version_info: Tuple[int, int, int], + ignore_requires_python: bool = False, +) -> bool: + """ + Return whether the given Python version is compatible with a link's + "Requires-Python" value. + + :param version_info: A 3-tuple of ints representing the Python + major-minor-micro version to check. + :param ignore_requires_python: Whether to ignore the "Requires-Python" + value if the given Python version isn't compatible. + """ + try: + is_compatible = check_requires_python( + link.requires_python, + version_info=version_info, + ) + except specifiers.InvalidSpecifier: + logger.debug( + "Ignoring invalid Requires-Python (%r) for link: %s", + link.requires_python, + link, + ) + else: + if not is_compatible: + version = ".".join(map(str, version_info)) + if not ignore_requires_python: + logger.verbose( + "Link requires a different Python (%s not in: %r): %s", + version, + link.requires_python, + link, + ) + return False + + logger.debug( + "Ignoring failed Requires-Python check (%s not in: %r) for link: %s", + version, + link.requires_python, + link, + ) + + return True + + +class LinkType(enum.Enum): + candidate = enum.auto() + different_project = enum.auto() + yanked = enum.auto() + format_unsupported = enum.auto() + format_invalid = enum.auto() + platform_mismatch = enum.auto() + requires_python_mismatch = enum.auto() + + +class LinkEvaluator: + """ + Responsible for evaluating links for a particular project. + """ + + _py_version_re = re.compile(r"-py([123]\.?[0-9]?)$") + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + def __init__( + self, + project_name: str, + canonical_name: str, + formats: FrozenSet[str], + target_python: TargetPython, + allow_yanked: bool, + ignore_requires_python: Optional[bool] = None, + ) -> None: + """ + :param project_name: The user supplied package name. + :param canonical_name: The canonical package name. + :param formats: The formats allowed for this package. Should be a set + with 'binary' or 'source' or both in it. + :param target_python: The target Python interpreter to use when + evaluating link compatibility. This is used, for example, to + check wheel compatibility, as well as when checking the Python + version, e.g. the Python version embedded in a link filename + (or egg fragment) and against an HTML link's optional PEP 503 + "data-requires-python" attribute. + :param allow_yanked: Whether files marked as yanked (in the sense + of PEP 592) are permitted to be candidates for install. + :param ignore_requires_python: Whether to ignore incompatible + PEP 503 "data-requires-python" values in HTML links. Defaults + to False. + """ + if ignore_requires_python is None: + ignore_requires_python = False + + self._allow_yanked = allow_yanked + self._canonical_name = canonical_name + self._ignore_requires_python = ignore_requires_python + self._formats = formats + self._target_python = target_python + + self.project_name = project_name + + def evaluate_link(self, link: Link) -> Tuple[LinkType, str]: + """ + Determine whether a link is a candidate for installation. + + :return: A tuple (result, detail), where *result* is an enum + representing whether the evaluation found a candidate, or the reason + why one is not found. If a candidate is found, *detail* will be the + candidate's version string; if one is not found, it contains the + reason the link fails to qualify. + """ + version = None + if link.is_yanked and not self._allow_yanked: + reason = link.yanked_reason or "" + return (LinkType.yanked, f"yanked for reason: {reason}") + + if link.egg_fragment: + egg_info = link.egg_fragment + ext = link.ext + else: + egg_info, ext = link.splitext() + if not ext: + return (LinkType.format_unsupported, "not a file") + if ext not in SUPPORTED_EXTENSIONS: + return ( + LinkType.format_unsupported, + f"unsupported archive format: {ext}", + ) + if "binary" not in self._formats and ext == WHEEL_EXTENSION: + reason = f"No binaries permitted for {self.project_name}" + return (LinkType.format_unsupported, reason) + if "macosx10" in link.path and ext == ".zip": + return (LinkType.format_unsupported, "macosx10 one") + if ext == WHEEL_EXTENSION: + try: + wheel = Wheel(link.filename) + except InvalidWheelFilename: + return ( + LinkType.format_invalid, + "invalid wheel filename", + ) + if canonicalize_name(wheel.name) != self._canonical_name: + reason = f"wrong project name (not {self.project_name})" + return (LinkType.different_project, reason) + + supported_tags = self._target_python.get_unsorted_tags() + if not wheel.supported(supported_tags): + # Include the wheel's tags in the reason string to + # simplify troubleshooting compatibility issues. + file_tags = ", ".join(wheel.get_formatted_file_tags()) + reason = ( + f"none of the wheel's tags ({file_tags}) are compatible " + f"(run pip debug --verbose to show compatible tags)" + ) + return (LinkType.platform_mismatch, reason) + + version = wheel.version + + # This should be up by the self.ok_binary check, but see issue 2700. + if "source" not in self._formats and ext != WHEEL_EXTENSION: + reason = f"No sources permitted for {self.project_name}" + return (LinkType.format_unsupported, reason) + + if not version: + version = _extract_version_from_fragment( + egg_info, + self._canonical_name, + ) + if not version: + reason = f"Missing project version for {self.project_name}" + return (LinkType.format_invalid, reason) + + match = self._py_version_re.search(version) + if match: + version = version[: match.start()] + py_version = match.group(1) + if py_version != self._target_python.py_version: + return ( + LinkType.platform_mismatch, + "Python version is incorrect", + ) + + supports_python = _check_link_requires_python( + link, + version_info=self._target_python.py_version_info, + ignore_requires_python=self._ignore_requires_python, + ) + if not supports_python: + reason = f"{version} Requires-Python {link.requires_python}" + return (LinkType.requires_python_mismatch, reason) + + logger.debug("Found link %s, version: %s", link, version) + + return (LinkType.candidate, version) + + +def filter_unallowed_hashes( + candidates: List[InstallationCandidate], + hashes: Optional[Hashes], + project_name: str, +) -> List[InstallationCandidate]: + """ + Filter out candidates whose hashes aren't allowed, and return a new + list of candidates. + + If at least one candidate has an allowed hash, then all candidates with + either an allowed hash or no hash specified are returned. Otherwise, + the given candidates are returned. + + Including the candidates with no hash specified when there is a match + allows a warning to be logged if there is a more preferred candidate + with no hash specified. Returning all candidates in the case of no + matches lets pip report the hash of the candidate that would otherwise + have been installed (e.g. permitting the user to more easily update + their requirements file with the desired hash). + """ + if not hashes: + logger.debug( + "Given no hashes to check %s links for project %r: " + "discarding no candidates", + len(candidates), + project_name, + ) + # Make sure we're not returning back the given value. + return list(candidates) + + matches_or_no_digest = [] + # Collect the non-matches for logging purposes. + non_matches = [] + match_count = 0 + for candidate in candidates: + link = candidate.link + if not link.has_hash: + pass + elif link.is_hash_allowed(hashes=hashes): + match_count += 1 + else: + non_matches.append(candidate) + continue + + matches_or_no_digest.append(candidate) + + if match_count: + filtered = matches_or_no_digest + else: + # Make sure we're not returning back the given value. + filtered = list(candidates) + + if len(filtered) == len(candidates): + discard_message = "discarding no candidates" + else: + discard_message = "discarding {} non-matches:\n {}".format( + len(non_matches), + "\n ".join(str(candidate.link) for candidate in non_matches), + ) + + logger.debug( + "Checked %s links for project %r against %s hashes " + "(%s matches, %s no digest): %s", + len(candidates), + project_name, + hashes.digest_count, + match_count, + len(matches_or_no_digest) - match_count, + discard_message, + ) + + return filtered + + +@dataclass +class CandidatePreferences: + """ + Encapsulates some of the preferences for filtering and sorting + InstallationCandidate objects. + """ + + prefer_binary: bool = False + allow_all_prereleases: bool = False + + +@dataclass(frozen=True) +class BestCandidateResult: + """A collection of candidates, returned by `PackageFinder.find_best_candidate`. + + This class is only intended to be instantiated by CandidateEvaluator's + `compute_best_candidate()` method. + + :param all_candidates: A sequence of all available candidates found. + :param applicable_candidates: The applicable candidates. + :param best_candidate: The most preferred candidate found, or None + if no applicable candidates were found. + """ + + all_candidates: List[InstallationCandidate] + applicable_candidates: List[InstallationCandidate] + best_candidate: Optional[InstallationCandidate] + + def __post_init__(self) -> None: + assert set(self.applicable_candidates) <= set(self.all_candidates) + + if self.best_candidate is None: + assert not self.applicable_candidates + else: + assert self.best_candidate in self.applicable_candidates + + +class CandidateEvaluator: + """ + Responsible for filtering and sorting candidates for installation based + on what tags are valid. + """ + + @classmethod + def create( + cls, + project_name: str, + target_python: Optional[TargetPython] = None, + prefer_binary: bool = False, + allow_all_prereleases: bool = False, + specifier: Optional[specifiers.BaseSpecifier] = None, + hashes: Optional[Hashes] = None, + ) -> "CandidateEvaluator": + """Create a CandidateEvaluator object. + + :param target_python: The target Python interpreter to use when + checking compatibility. If None (the default), a TargetPython + object will be constructed from the running Python. + :param specifier: An optional object implementing `filter` + (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable + versions. + :param hashes: An optional collection of allowed hashes. + """ + if target_python is None: + target_python = TargetPython() + if specifier is None: + specifier = specifiers.SpecifierSet() + + supported_tags = target_python.get_sorted_tags() + + return cls( + project_name=project_name, + supported_tags=supported_tags, + specifier=specifier, + prefer_binary=prefer_binary, + allow_all_prereleases=allow_all_prereleases, + hashes=hashes, + ) + + def __init__( + self, + project_name: str, + supported_tags: List[Tag], + specifier: specifiers.BaseSpecifier, + prefer_binary: bool = False, + allow_all_prereleases: bool = False, + hashes: Optional[Hashes] = None, + ) -> None: + """ + :param supported_tags: The PEP 425 tags supported by the target + Python in order of preference (most preferred first). + """ + self._allow_all_prereleases = allow_all_prereleases + self._hashes = hashes + self._prefer_binary = prefer_binary + self._project_name = project_name + self._specifier = specifier + self._supported_tags = supported_tags + # Since the index of the tag in the _supported_tags list is used + # as a priority, precompute a map from tag to index/priority to be + # used in wheel.find_most_preferred_tag. + self._wheel_tag_preferences = { + tag: idx for idx, tag in enumerate(supported_tags) + } + + def get_applicable_candidates( + self, + candidates: List[InstallationCandidate], + ) -> List[InstallationCandidate]: + """ + Return the applicable candidates from a list of candidates. + """ + # Using None infers from the specifier instead. + allow_prereleases = self._allow_all_prereleases or None + specifier = self._specifier + + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + candidates_and_versions = [(c, str(c.version)) for c in candidates] + versions = set( + specifier.filter( + (v for _, v in candidates_and_versions), + prereleases=allow_prereleases, + ) + ) + + applicable_candidates = [c for c, v in candidates_and_versions if v in versions] + filtered_applicable_candidates = filter_unallowed_hashes( + candidates=applicable_candidates, + hashes=self._hashes, + project_name=self._project_name, + ) + + return sorted(filtered_applicable_candidates, key=self._sort_key) + + def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey: + """ + Function to pass as the `key` argument to a call to sorted() to sort + InstallationCandidates by preference. + + Returns a tuple such that tuples sorting as greater using Python's + default comparison operator are more preferred. + + The preference is as follows: + + First and foremost, candidates with allowed (matching) hashes are + always preferred over candidates without matching hashes. This is + because e.g. if the only candidate with an allowed hash is yanked, + we still want to use that candidate. + + Second, excepting hash considerations, candidates that have been + yanked (in the sense of PEP 592) are always less preferred than + candidates that haven't been yanked. Then: + + If not finding wheels, they are sorted by version only. + If finding wheels, then the sort order is by version, then: + 1. existing installs + 2. wheels ordered via Wheel.support_index_min(self._supported_tags) + 3. source archives + If prefer_binary was set, then all wheels are sorted above sources. + + Note: it was considered to embed this logic into the Link + comparison operators, but then different sdist links + with the same version, would have to be considered equal + """ + valid_tags = self._supported_tags + support_num = len(valid_tags) + build_tag: BuildTag = () + binary_preference = 0 + link = candidate.link + if link.is_wheel: + # can raise InvalidWheelFilename + wheel = Wheel(link.filename) + try: + pri = -( + wheel.find_most_preferred_tag( + valid_tags, self._wheel_tag_preferences + ) + ) + except ValueError: + raise UnsupportedWheel( + f"{wheel.filename} is not a supported wheel for this platform. It " + "can't be sorted." + ) + if self._prefer_binary: + binary_preference = 1 + if wheel.build_tag is not None: + match = re.match(r"^(\d+)(.*)$", wheel.build_tag) + assert match is not None, "guaranteed by filename validation" + build_tag_groups = match.groups() + build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) + else: # sdist + pri = -(support_num) + has_allowed_hash = int(link.is_hash_allowed(self._hashes)) + yank_value = -1 * int(link.is_yanked) # -1 for yanked. + return ( + has_allowed_hash, + yank_value, + binary_preference, + candidate.version, + pri, + build_tag, + ) + + def sort_best_candidate( + self, + candidates: List[InstallationCandidate], + ) -> Optional[InstallationCandidate]: + """ + Return the best candidate per the instance's sort order, or None if + no candidate is acceptable. + """ + if not candidates: + return None + best_candidate = max(candidates, key=self._sort_key) + return best_candidate + + def compute_best_candidate( + self, + candidates: List[InstallationCandidate], + ) -> BestCandidateResult: + """ + Compute and return a `BestCandidateResult` instance. + """ + applicable_candidates = self.get_applicable_candidates(candidates) + + best_candidate = self.sort_best_candidate(applicable_candidates) + + return BestCandidateResult( + candidates, + applicable_candidates=applicable_candidates, + best_candidate=best_candidate, + ) + + +class PackageFinder: + """This finds packages. + + This is meant to match easy_install's technique for looking for + packages, by reading pages and looking for appropriate links. + """ + + def __init__( + self, + link_collector: LinkCollector, + target_python: TargetPython, + allow_yanked: bool, + format_control: Optional[FormatControl] = None, + candidate_prefs: Optional[CandidatePreferences] = None, + ignore_requires_python: Optional[bool] = None, + ) -> None: + """ + This constructor is primarily meant to be used by the create() class + method and from tests. + + :param format_control: A FormatControl object, used to control + the selection of source packages / binary packages when consulting + the index and links. + :param candidate_prefs: Options to use when creating a + CandidateEvaluator object. + """ + if candidate_prefs is None: + candidate_prefs = CandidatePreferences() + + format_control = format_control or FormatControl(set(), set()) + + self._allow_yanked = allow_yanked + self._candidate_prefs = candidate_prefs + self._ignore_requires_python = ignore_requires_python + self._link_collector = link_collector + self._target_python = target_python + + self.format_control = format_control + + # These are boring links that have already been logged somehow. + self._logged_links: Set[Tuple[Link, LinkType, str]] = set() + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + @classmethod + def create( + cls, + link_collector: LinkCollector, + selection_prefs: SelectionPreferences, + target_python: Optional[TargetPython] = None, + ) -> "PackageFinder": + """Create a PackageFinder. + + :param selection_prefs: The candidate selection preferences, as a + SelectionPreferences object. + :param target_python: The target Python interpreter to use when + checking compatibility. If None (the default), a TargetPython + object will be constructed from the running Python. + """ + if target_python is None: + target_python = TargetPython() + + candidate_prefs = CandidatePreferences( + prefer_binary=selection_prefs.prefer_binary, + allow_all_prereleases=selection_prefs.allow_all_prereleases, + ) + + return cls( + candidate_prefs=candidate_prefs, + link_collector=link_collector, + target_python=target_python, + allow_yanked=selection_prefs.allow_yanked, + format_control=selection_prefs.format_control, + ignore_requires_python=selection_prefs.ignore_requires_python, + ) + + @property + def target_python(self) -> TargetPython: + return self._target_python + + @property + def search_scope(self) -> SearchScope: + return self._link_collector.search_scope + + @search_scope.setter + def search_scope(self, search_scope: SearchScope) -> None: + self._link_collector.search_scope = search_scope + + @property + def find_links(self) -> List[str]: + return self._link_collector.find_links + + @property + def index_urls(self) -> List[str]: + return self.search_scope.index_urls + + @property + def proxy(self) -> Optional[str]: + return self._link_collector.session.pip_proxy + + @property + def trusted_hosts(self) -> Iterable[str]: + for host_port in self._link_collector.session.pip_trusted_origins: + yield build_netloc(*host_port) + + @property + def custom_cert(self) -> Optional[str]: + # session.verify is either a boolean (use default bundle/no SSL + # verification) or a string path to a custom CA bundle to use. We only + # care about the latter. + verify = self._link_collector.session.verify + return verify if isinstance(verify, str) else None + + @property + def client_cert(self) -> Optional[str]: + cert = self._link_collector.session.cert + assert not isinstance(cert, tuple), "pip only supports PEM client certs" + return cert + + @property + def allow_all_prereleases(self) -> bool: + return self._candidate_prefs.allow_all_prereleases + + def set_allow_all_prereleases(self) -> None: + self._candidate_prefs.allow_all_prereleases = True + + @property + def prefer_binary(self) -> bool: + return self._candidate_prefs.prefer_binary + + def set_prefer_binary(self) -> None: + self._candidate_prefs.prefer_binary = True + + def requires_python_skipped_reasons(self) -> List[str]: + reasons = { + detail + for _, result, detail in self._logged_links + if result == LinkType.requires_python_mismatch + } + return sorted(reasons) + + def make_link_evaluator(self, project_name: str) -> LinkEvaluator: + canonical_name = canonicalize_name(project_name) + formats = self.format_control.get_allowed_formats(canonical_name) + + return LinkEvaluator( + project_name=project_name, + canonical_name=canonical_name, + formats=formats, + target_python=self._target_python, + allow_yanked=self._allow_yanked, + ignore_requires_python=self._ignore_requires_python, + ) + + def _sort_links(self, links: Iterable[Link]) -> List[Link]: + """ + Returns elements of links in order, non-egg links first, egg links + second, while eliminating duplicates + """ + eggs, no_eggs = [], [] + seen: Set[Link] = set() + for link in links: + if link not in seen: + seen.add(link) + if link.egg_fragment: + eggs.append(link) + else: + no_eggs.append(link) + return no_eggs + eggs + + def _log_skipped_link(self, link: Link, result: LinkType, detail: str) -> None: + # This is a hot method so don't waste time hashing links unless we're + # actually going to log 'em. + if not logger.isEnabledFor(logging.DEBUG): + return + + entry = (link, result, detail) + if entry not in self._logged_links: + # Put the link at the end so the reason is more visible and because + # the link string is usually very long. + logger.debug("Skipping link: %s: %s", detail, link) + self._logged_links.add(entry) + + def get_install_candidate( + self, link_evaluator: LinkEvaluator, link: Link + ) -> Optional[InstallationCandidate]: + """ + If the link is a candidate for install, convert it to an + InstallationCandidate and return it. Otherwise, return None. + """ + result, detail = link_evaluator.evaluate_link(link) + if result != LinkType.candidate: + self._log_skipped_link(link, result, detail) + return None + + try: + return InstallationCandidate( + name=link_evaluator.project_name, + link=link, + version=detail, + ) + except InvalidVersion: + return None + + def evaluate_links( + self, link_evaluator: LinkEvaluator, links: Iterable[Link] + ) -> List[InstallationCandidate]: + """ + Convert links that are candidates to InstallationCandidate objects. + """ + candidates = [] + for link in self._sort_links(links): + candidate = self.get_install_candidate(link_evaluator, link) + if candidate is not None: + candidates.append(candidate) + + return candidates + + def process_project_url( + self, project_url: Link, link_evaluator: LinkEvaluator + ) -> List[InstallationCandidate]: + logger.debug( + "Fetching project page and analyzing links: %s", + project_url, + ) + index_response = self._link_collector.fetch_response(project_url) + if index_response is None: + return [] + + page_links = list(parse_links(index_response)) + + with indent_log(): + package_links = self.evaluate_links( + link_evaluator, + links=page_links, + ) + + return package_links + + @functools.lru_cache(maxsize=None) + def find_all_candidates(self, project_name: str) -> List[InstallationCandidate]: + """Find all available InstallationCandidate for project_name + + This checks index_urls and find_links. + All versions found are returned as an InstallationCandidate list. + + See LinkEvaluator.evaluate_link() for details on which files + are accepted. + """ + link_evaluator = self.make_link_evaluator(project_name) + + collected_sources = self._link_collector.collect_sources( + project_name=project_name, + candidates_from_page=functools.partial( + self.process_project_url, + link_evaluator=link_evaluator, + ), + ) + + page_candidates_it = itertools.chain.from_iterable( + source.page_candidates() + for sources in collected_sources + for source in sources + if source is not None + ) + page_candidates = list(page_candidates_it) + + file_links_it = itertools.chain.from_iterable( + source.file_links() + for sources in collected_sources + for source in sources + if source is not None + ) + file_candidates = self.evaluate_links( + link_evaluator, + sorted(file_links_it, reverse=True), + ) + + if logger.isEnabledFor(logging.DEBUG) and file_candidates: + paths = [] + for candidate in file_candidates: + assert candidate.link.url # we need to have a URL + try: + paths.append(candidate.link.file_path) + except Exception: + paths.append(candidate.link.url) # it's not a local file + + logger.debug("Local files found: %s", ", ".join(paths)) + + # This is an intentional priority ordering + return file_candidates + page_candidates + + def make_candidate_evaluator( + self, + project_name: str, + specifier: Optional[specifiers.BaseSpecifier] = None, + hashes: Optional[Hashes] = None, + ) -> CandidateEvaluator: + """Create a CandidateEvaluator object to use.""" + candidate_prefs = self._candidate_prefs + return CandidateEvaluator.create( + project_name=project_name, + target_python=self._target_python, + prefer_binary=candidate_prefs.prefer_binary, + allow_all_prereleases=candidate_prefs.allow_all_prereleases, + specifier=specifier, + hashes=hashes, + ) + + @functools.lru_cache(maxsize=None) + def find_best_candidate( + self, + project_name: str, + specifier: Optional[specifiers.BaseSpecifier] = None, + hashes: Optional[Hashes] = None, + ) -> BestCandidateResult: + """Find matches for the given project and specifier. + + :param specifier: An optional object implementing `filter` + (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable + versions. + + :return: A `BestCandidateResult` instance. + """ + candidates = self.find_all_candidates(project_name) + candidate_evaluator = self.make_candidate_evaluator( + project_name=project_name, + specifier=specifier, + hashes=hashes, + ) + return candidate_evaluator.compute_best_candidate(candidates) + + def find_requirement( + self, req: InstallRequirement, upgrade: bool + ) -> Optional[InstallationCandidate]: + """Try to find a Link matching req + + Expects req, an InstallRequirement and upgrade, a boolean + Returns a InstallationCandidate if found, + Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise + """ + hashes = req.hashes(trust_internet=False) + best_candidate_result = self.find_best_candidate( + req.name, + specifier=req.specifier, + hashes=hashes, + ) + best_candidate = best_candidate_result.best_candidate + + installed_version: Optional[_BaseVersion] = None + if req.satisfied_by is not None: + installed_version = req.satisfied_by.version + + def _format_versions(cand_iter: Iterable[InstallationCandidate]) -> str: + # This repeated parse_version and str() conversion is needed to + # handle different vendoring sources from pip and pkg_resources. + # If we stop using the pkg_resources provided specifier and start + # using our own, we can drop the cast to str(). + return ( + ", ".join( + sorted( + {str(c.version) for c in cand_iter}, + key=parse_version, + ) + ) + or "none" + ) + + if installed_version is None and best_candidate is None: + logger.critical( + "Could not find a version that satisfies the requirement %s " + "(from versions: %s)", + req, + _format_versions(best_candidate_result.all_candidates), + ) + + raise DistributionNotFound(f"No matching distribution found for {req}") + + def _should_install_candidate( + candidate: Optional[InstallationCandidate], + ) -> "TypeGuard[InstallationCandidate]": + if installed_version is None: + return True + if best_candidate is None: + return False + return best_candidate.version > installed_version + + if not upgrade and installed_version is not None: + if _should_install_candidate(best_candidate): + logger.debug( + "Existing installed version (%s) satisfies requirement " + "(most up-to-date version is %s)", + installed_version, + best_candidate.version, + ) + else: + logger.debug( + "Existing installed version (%s) is most up-to-date and " + "satisfies requirement", + installed_version, + ) + return None + + if _should_install_candidate(best_candidate): + logger.debug( + "Using version %s (newest of versions: %s)", + best_candidate.version, + _format_versions(best_candidate_result.applicable_candidates), + ) + return best_candidate + + # We have an existing version, and its the best version + logger.debug( + "Installed version (%s) is most up-to-date (past versions: %s)", + installed_version, + _format_versions(best_candidate_result.applicable_candidates), + ) + raise BestVersionAlreadyInstalled + + +def _find_name_version_sep(fragment: str, canonical_name: str) -> int: + """Find the separator's index based on the package's canonical name. + + :param fragment: A + filename "fragment" (stem) or + egg fragment. + :param canonical_name: The package's canonical name. + + This function is needed since the canonicalized name does not necessarily + have the same length as the egg info's name part. An example:: + + >>> fragment = 'foo__bar-1.0' + >>> canonical_name = 'foo-bar' + >>> _find_name_version_sep(fragment, canonical_name) + 8 + """ + # Project name and version must be separated by one single dash. Find all + # occurrences of dashes; if the string in front of it matches the canonical + # name, this is the one separating the name and version parts. + for i, c in enumerate(fragment): + if c != "-": + continue + if canonicalize_name(fragment[:i]) == canonical_name: + return i + raise ValueError(f"{fragment} does not match {canonical_name}") + + +def _extract_version_from_fragment(fragment: str, canonical_name: str) -> Optional[str]: + """Parse the version string from a + filename + "fragment" (stem) or egg fragment. + + :param fragment: The string to parse. E.g. foo-2.1 + :param canonical_name: The canonicalized name of the package this + belongs to. + """ + try: + version_start = _find_name_version_sep(fragment, canonical_name) + 1 + except ValueError: + return None + version = fragment[version_start:] + if not version: + return None + return version diff --git a/backend/venv/Lib/site-packages/pip/_internal/index/sources.py b/backend/venv/Lib/site-packages/pip/_internal/index/sources.py new file mode 100644 index 0000000..3dafb30 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/index/sources.py @@ -0,0 +1,284 @@ +import logging +import mimetypes +import os +from collections import defaultdict +from typing import Callable, Dict, Iterable, List, Optional, Tuple + +from pip._vendor.packaging.utils import ( + InvalidSdistFilename, + InvalidWheelFilename, + canonicalize_name, + parse_sdist_filename, + parse_wheel_filename, +) + +from pip._internal.models.candidate import InstallationCandidate +from pip._internal.models.link import Link +from pip._internal.utils.urls import path_to_url, url_to_path +from pip._internal.vcs import is_url + +logger = logging.getLogger(__name__) + +FoundCandidates = Iterable[InstallationCandidate] +FoundLinks = Iterable[Link] +CandidatesFromPage = Callable[[Link], Iterable[InstallationCandidate]] +PageValidator = Callable[[Link], bool] + + +class LinkSource: + @property + def link(self) -> Optional[Link]: + """Returns the underlying link, if there's one.""" + raise NotImplementedError() + + def page_candidates(self) -> FoundCandidates: + """Candidates found by parsing an archive listing HTML file.""" + raise NotImplementedError() + + def file_links(self) -> FoundLinks: + """Links found by specifying archives directly.""" + raise NotImplementedError() + + +def _is_html_file(file_url: str) -> bool: + return mimetypes.guess_type(file_url, strict=False)[0] == "text/html" + + +class _FlatDirectoryToUrls: + """Scans directory and caches results""" + + def __init__(self, path: str) -> None: + self._path = path + self._page_candidates: List[str] = [] + self._project_name_to_urls: Dict[str, List[str]] = defaultdict(list) + self._scanned_directory = False + + def _scan_directory(self) -> None: + """Scans directory once and populates both page_candidates + and project_name_to_urls at the same time + """ + for entry in os.scandir(self._path): + url = path_to_url(entry.path) + if _is_html_file(url): + self._page_candidates.append(url) + continue + + # File must have a valid wheel or sdist name, + # otherwise not worth considering as a package + try: + project_filename = parse_wheel_filename(entry.name)[0] + except InvalidWheelFilename: + try: + project_filename = parse_sdist_filename(entry.name)[0] + except InvalidSdistFilename: + continue + + self._project_name_to_urls[project_filename].append(url) + self._scanned_directory = True + + @property + def page_candidates(self) -> List[str]: + if not self._scanned_directory: + self._scan_directory() + + return self._page_candidates + + @property + def project_name_to_urls(self) -> Dict[str, List[str]]: + if not self._scanned_directory: + self._scan_directory() + + return self._project_name_to_urls + + +class _FlatDirectorySource(LinkSource): + """Link source specified by ``--find-links=``. + + This looks the content of the directory, and returns: + + * ``page_candidates``: Links listed on each HTML file in the directory. + * ``file_candidates``: Archives in the directory. + """ + + _paths_to_urls: Dict[str, _FlatDirectoryToUrls] = {} + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + path: str, + project_name: str, + ) -> None: + self._candidates_from_page = candidates_from_page + self._project_name = canonicalize_name(project_name) + + # Get existing instance of _FlatDirectoryToUrls if it exists + if path in self._paths_to_urls: + self._path_to_urls = self._paths_to_urls[path] + else: + self._path_to_urls = _FlatDirectoryToUrls(path=path) + self._paths_to_urls[path] = self._path_to_urls + + @property + def link(self) -> Optional[Link]: + return None + + def page_candidates(self) -> FoundCandidates: + for url in self._path_to_urls.page_candidates: + yield from self._candidates_from_page(Link(url)) + + def file_links(self) -> FoundLinks: + for url in self._path_to_urls.project_name_to_urls[self._project_name]: + yield Link(url) + + +class _LocalFileSource(LinkSource): + """``--find-links=`` or ``--[extra-]index-url=``. + + If a URL is supplied, it must be a ``file:`` URL. If a path is supplied to + the option, it is converted to a URL first. This returns: + + * ``page_candidates``: Links listed on an HTML file. + * ``file_candidates``: The non-HTML file. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + if not _is_html_file(self._link.url): + return + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + if _is_html_file(self._link.url): + return + yield self._link + + +class _RemoteFileSource(LinkSource): + """``--find-links=`` or ``--[extra-]index-url=``. + + This returns: + + * ``page_candidates``: Links listed on an HTML file. + * ``file_candidates``: The non-HTML file. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + page_validator: PageValidator, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._page_validator = page_validator + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + if not self._page_validator(self._link): + return + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + yield self._link + + +class _IndexDirectorySource(LinkSource): + """``--[extra-]index-url=``. + + This is treated like a remote URL; ``candidates_from_page`` contains logic + for this by appending ``index.html`` to the link. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + return () + + +def build_source( + location: str, + *, + candidates_from_page: CandidatesFromPage, + page_validator: PageValidator, + expand_dir: bool, + cache_link_parsing: bool, + project_name: str, +) -> Tuple[Optional[str], Optional[LinkSource]]: + path: Optional[str] = None + url: Optional[str] = None + if os.path.exists(location): # Is a local path. + url = path_to_url(location) + path = location + elif location.startswith("file:"): # A file: URL. + url = location + path = url_to_path(location) + elif is_url(location): + url = location + + if url is None: + msg = ( + "Location '%s' is ignored: " + "it is either a non-existing path or lacks a specific scheme." + ) + logger.warning(msg, location) + return (None, None) + + if path is None: + source: LinkSource = _RemoteFileSource( + candidates_from_page=candidates_from_page, + page_validator=page_validator, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + + if os.path.isdir(path): + if expand_dir: + source = _FlatDirectorySource( + candidates_from_page=candidates_from_page, + path=path, + project_name=project_name, + ) + else: + source = _IndexDirectorySource( + candidates_from_page=candidates_from_page, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + elif os.path.isfile(path): + source = _LocalFileSource( + candidates_from_page=candidates_from_page, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + logger.warning( + "Location '%s' is ignored: it is neither a file nor a directory.", + location, + ) + return (url, None) diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/locations/__init__.py new file mode 100644 index 0000000..32382be --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/locations/__init__.py @@ -0,0 +1,456 @@ +import functools +import logging +import os +import pathlib +import sys +import sysconfig +from typing import Any, Dict, Generator, Optional, Tuple + +from pip._internal.models.scheme import SCHEME_KEYS, Scheme +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.virtualenv import running_under_virtualenv + +from . import _sysconfig +from .base import ( + USER_CACHE_DIR, + get_major_minor_version, + get_src_prefix, + is_osx_framework, + site_packages, + user_site, +) + +__all__ = [ + "USER_CACHE_DIR", + "get_bin_prefix", + "get_bin_user", + "get_major_minor_version", + "get_platlib", + "get_purelib", + "get_scheme", + "get_src_prefix", + "site_packages", + "user_site", +] + + +logger = logging.getLogger(__name__) + + +_PLATLIBDIR: str = getattr(sys, "platlibdir", "lib") + +_USE_SYSCONFIG_DEFAULT = sys.version_info >= (3, 10) + + +def _should_use_sysconfig() -> bool: + """This function determines the value of _USE_SYSCONFIG. + + By default, pip uses sysconfig on Python 3.10+. + But Python distributors can override this decision by setting: + sysconfig._PIP_USE_SYSCONFIG = True / False + Rationale in https://github.com/pypa/pip/issues/10647 + + This is a function for testability, but should be constant during any one + run. + """ + return bool(getattr(sysconfig, "_PIP_USE_SYSCONFIG", _USE_SYSCONFIG_DEFAULT)) + + +_USE_SYSCONFIG = _should_use_sysconfig() + +if not _USE_SYSCONFIG: + # Import distutils lazily to avoid deprecation warnings, + # but import it soon enough that it is in memory and available during + # a pip reinstall. + from . import _distutils + +# Be noisy about incompatibilities if this platforms "should" be using +# sysconfig, but is explicitly opting out and using distutils instead. +if _USE_SYSCONFIG_DEFAULT and not _USE_SYSCONFIG: + _MISMATCH_LEVEL = logging.WARNING +else: + _MISMATCH_LEVEL = logging.DEBUG + + +def _looks_like_bpo_44860() -> bool: + """The resolution to bpo-44860 will change this incorrect platlib. + + See . + """ + from distutils.command.install import INSTALL_SCHEMES + + try: + unix_user_platlib = INSTALL_SCHEMES["unix_user"]["platlib"] + except KeyError: + return False + return unix_user_platlib == "$usersite" + + +def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool: + platlib = scheme["platlib"] + if "/$platlibdir/" in platlib: + platlib = platlib.replace("/$platlibdir/", f"/{_PLATLIBDIR}/") + if "/lib64/" not in platlib: + return False + unpatched = platlib.replace("/lib64/", "/lib/") + return unpatched.replace("$platbase/", "$base/") == scheme["purelib"] + + +@functools.lru_cache(maxsize=None) +def _looks_like_red_hat_lib() -> bool: + """Red Hat patches platlib in unix_prefix and unix_home, but not purelib. + + This is the only way I can see to tell a Red Hat-patched Python. + """ + from distutils.command.install import INSTALL_SCHEMES + + return all( + k in INSTALL_SCHEMES + and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k]) + for k in ("unix_prefix", "unix_home") + ) + + +@functools.lru_cache(maxsize=None) +def _looks_like_debian_scheme() -> bool: + """Debian adds two additional schemes.""" + from distutils.command.install import INSTALL_SCHEMES + + return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES + + +@functools.lru_cache(maxsize=None) +def _looks_like_red_hat_scheme() -> bool: + """Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``. + + Red Hat's ``00251-change-user-install-location.patch`` changes the install + command's ``prefix`` and ``exec_prefix`` to append ``"/local"``. This is + (fortunately?) done quite unconditionally, so we create a default command + object without any configuration to detect this. + """ + from distutils.command.install import install + from distutils.dist import Distribution + + cmd: Any = install(Distribution()) + cmd.finalize_options() + return ( + cmd.exec_prefix == f"{os.path.normpath(sys.exec_prefix)}/local" + and cmd.prefix == f"{os.path.normpath(sys.prefix)}/local" + ) + + +@functools.lru_cache(maxsize=None) +def _looks_like_slackware_scheme() -> bool: + """Slackware patches sysconfig but fails to patch distutils and site. + + Slackware changes sysconfig's user scheme to use ``"lib64"`` for the lib + path, but does not do the same to the site module. + """ + if user_site is None: # User-site not available. + return False + try: + paths = sysconfig.get_paths(scheme="posix_user", expand=False) + except KeyError: # User-site not available. + return False + return "/lib64/" in paths["purelib"] and "/lib64/" not in user_site + + +@functools.lru_cache(maxsize=None) +def _looks_like_msys2_mingw_scheme() -> bool: + """MSYS2 patches distutils and sysconfig to use a UNIX-like scheme. + + However, MSYS2 incorrectly patches sysconfig ``nt`` scheme. The fix is + likely going to be included in their 3.10 release, so we ignore the warning. + See msys2/MINGW-packages#9319. + + MSYS2 MINGW's patch uses lowercase ``"lib"`` instead of the usual uppercase, + and is missing the final ``"site-packages"``. + """ + paths = sysconfig.get_paths("nt", expand=False) + return all( + "Lib" not in p and "lib" in p and not p.endswith("site-packages") + for p in (paths[key] for key in ("platlib", "purelib")) + ) + + +def _fix_abiflags(parts: Tuple[str]) -> Generator[str, None, None]: + ldversion = sysconfig.get_config_var("LDVERSION") + abiflags = getattr(sys, "abiflags", None) + + # LDVERSION does not end with sys.abiflags. Just return the path unchanged. + if not ldversion or not abiflags or not ldversion.endswith(abiflags): + yield from parts + return + + # Strip sys.abiflags from LDVERSION-based path components. + for part in parts: + if part.endswith(ldversion): + part = part[: (0 - len(abiflags))] + yield part + + +@functools.lru_cache(maxsize=None) +def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None: + issue_url = "https://github.com/pypa/pip/issues/10151" + message = ( + "Value for %s does not match. Please report this to <%s>" + "\ndistutils: %s" + "\nsysconfig: %s" + ) + logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new) + + +def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool: + if old == new: + return False + _warn_mismatched(old, new, key=key) + return True + + +@functools.lru_cache(maxsize=None) +def _log_context( + *, + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + prefix: Optional[str] = None, +) -> None: + parts = [ + "Additional context:", + "user = %r", + "home = %r", + "root = %r", + "prefix = %r", + ] + + logger.log(_MISMATCH_LEVEL, "\n".join(parts), user, home, root, prefix) + + +def get_scheme( + dist_name: str, + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + isolated: bool = False, + prefix: Optional[str] = None, +) -> Scheme: + new = _sysconfig.get_scheme( + dist_name, + user=user, + home=home, + root=root, + isolated=isolated, + prefix=prefix, + ) + if _USE_SYSCONFIG: + return new + + old = _distutils.get_scheme( + dist_name, + user=user, + home=home, + root=root, + isolated=isolated, + prefix=prefix, + ) + + warning_contexts = [] + for k in SCHEME_KEYS: + old_v = pathlib.Path(getattr(old, k)) + new_v = pathlib.Path(getattr(new, k)) + + if old_v == new_v: + continue + + # distutils incorrectly put PyPy packages under ``site-packages/python`` + # in the ``posix_home`` scheme, but PyPy devs said they expect the + # directory name to be ``pypy`` instead. So we treat this as a bug fix + # and not warn about it. See bpo-43307 and python/cpython#24628. + skip_pypy_special_case = ( + sys.implementation.name == "pypy" + and home is not None + and k in ("platlib", "purelib") + and old_v.parent == new_v.parent + and old_v.name.startswith("python") + and new_v.name.startswith("pypy") + ) + if skip_pypy_special_case: + continue + + # sysconfig's ``osx_framework_user`` does not include ``pythonX.Y`` in + # the ``include`` value, but distutils's ``headers`` does. We'll let + # CPython decide whether this is a bug or feature. See bpo-43948. + skip_osx_framework_user_special_case = ( + user + and is_osx_framework() + and k == "headers" + and old_v.parent.parent == new_v.parent + and old_v.parent.name.startswith("python") + ) + if skip_osx_framework_user_special_case: + continue + + # On Red Hat and derived Linux distributions, distutils is patched to + # use "lib64" instead of "lib" for platlib. + if k == "platlib" and _looks_like_red_hat_lib(): + continue + + # On Python 3.9+, sysconfig's posix_user scheme sets platlib against + # sys.platlibdir, but distutils's unix_user incorrectly coninutes + # using the same $usersite for both platlib and purelib. This creates a + # mismatch when sys.platlibdir is not "lib". + skip_bpo_44860 = ( + user + and k == "platlib" + and not WINDOWS + and sys.version_info >= (3, 9) + and _PLATLIBDIR != "lib" + and _looks_like_bpo_44860() + ) + if skip_bpo_44860: + continue + + # Slackware incorrectly patches posix_user to use lib64 instead of lib, + # but not usersite to match the location. + skip_slackware_user_scheme = ( + user + and k in ("platlib", "purelib") + and not WINDOWS + and _looks_like_slackware_scheme() + ) + if skip_slackware_user_scheme: + continue + + # Both Debian and Red Hat patch Python to place the system site under + # /usr/local instead of /usr. Debian also places lib in dist-packages + # instead of site-packages, but the /usr/local check should cover it. + skip_linux_system_special_case = ( + not (user or home or prefix or running_under_virtualenv()) + and old_v.parts[1:3] == ("usr", "local") + and len(new_v.parts) > 1 + and new_v.parts[1] == "usr" + and (len(new_v.parts) < 3 or new_v.parts[2] != "local") + and (_looks_like_red_hat_scheme() or _looks_like_debian_scheme()) + ) + if skip_linux_system_special_case: + continue + + # MSYS2 MINGW's sysconfig patch does not include the "site-packages" + # part of the path. This is incorrect and will be fixed in MSYS. + skip_msys2_mingw_bug = ( + WINDOWS and k in ("platlib", "purelib") and _looks_like_msys2_mingw_scheme() + ) + if skip_msys2_mingw_bug: + continue + + # CPython's POSIX install script invokes pip (via ensurepip) against the + # interpreter located in the source tree, not the install site. This + # triggers special logic in sysconfig that's not present in distutils. + # https://github.com/python/cpython/blob/8c21941ddaf/Lib/sysconfig.py#L178-L194 + skip_cpython_build = ( + sysconfig.is_python_build(check_home=True) + and not WINDOWS + and k in ("headers", "include", "platinclude") + ) + if skip_cpython_build: + continue + + warning_contexts.append((old_v, new_v, f"scheme.{k}")) + + if not warning_contexts: + return old + + # Check if this path mismatch is caused by distutils config files. Those + # files will no longer work once we switch to sysconfig, so this raises a + # deprecation message for them. + default_old = _distutils.distutils_scheme( + dist_name, + user, + home, + root, + isolated, + prefix, + ignore_config_files=True, + ) + if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS): + deprecated( + reason=( + "Configuring installation scheme with distutils config files " + "is deprecated and will no longer work in the near future. If you " + "are using a Homebrew or Linuxbrew Python, please see discussion " + "at https://github.com/Homebrew/homebrew-core/issues/76621" + ), + replacement=None, + gone_in=None, + ) + return old + + # Post warnings about this mismatch so user can report them back. + for old_v, new_v, key in warning_contexts: + _warn_mismatched(old_v, new_v, key=key) + _log_context(user=user, home=home, root=root, prefix=prefix) + + return old + + +def get_bin_prefix() -> str: + new = _sysconfig.get_bin_prefix() + if _USE_SYSCONFIG: + return new + + old = _distutils.get_bin_prefix() + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="bin_prefix"): + _log_context() + return old + + +def get_bin_user() -> str: + return _sysconfig.get_scheme("", user=True).scripts + + +def _looks_like_deb_system_dist_packages(value: str) -> bool: + """Check if the value is Debian's APT-controlled dist-packages. + + Debian's ``distutils.sysconfig.get_python_lib()`` implementation returns the + default package path controlled by APT, but does not patch ``sysconfig`` to + do the same. This is similar to the bug worked around in ``get_scheme()``, + but here the default is ``deb_system`` instead of ``unix_local``. Ultimately + we can't do anything about this Debian bug, and this detection allows us to + skip the warning when needed. + """ + if not _looks_like_debian_scheme(): + return False + if value == "/usr/lib/python3/dist-packages": + return True + return False + + +def get_purelib() -> str: + """Return the default pure-Python lib location.""" + new = _sysconfig.get_purelib() + if _USE_SYSCONFIG: + return new + + old = _distutils.get_purelib() + if _looks_like_deb_system_dist_packages(old): + return old + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="purelib"): + _log_context() + return old + + +def get_platlib() -> str: + """Return the default platform-shared lib location.""" + new = _sysconfig.get_platlib() + if _USE_SYSCONFIG: + return new + + from . import _distutils + + old = _distutils.get_platlib() + if _looks_like_deb_system_dist_packages(old): + return old + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="platlib"): + _log_context() + return old diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e691f35d3277f40ce4498a9eb2868fbd639bd73 GIT binary patch literal 16444 zcmch8Yfv0lmS$#E*1MpJrvM?85=a7xhh$_)R_kE|NJ2tb7Lp%W-l8BAC{zz7vq}e3o-I8VcDMFe*-0{5^h_w}lHLg*}BVZx0tmihGKYcSz1~Nu;!=l;vIF zO_8#mvPgMPd8DGJBC@$>bELATGP0#-3(pO5lKZE8PnCs}`Qc+GOS!u&e!}ZdJ=;)b zyDUf^$@_`bcvmgg$UCIGBY2dB;m%w=GbiO=xy*4ryCk1nJ7AIg?+QJ2pi}pWQJ`nH zyj!)S#|7x|o}N8CC+|{xc$bI%yk=6#-Fq6MUVH(~^;b`W(MBQKXp)L#C;C=1U@1pI z_C=72@ntVs=Z5>%*G3usUWv)8L8hk9kJ>h1py^~zV(d;UAr zt5{X@}VWCB(Cbs z3(_A&2QucAwxO?w|De8ZCm!*y`i>yg$hFcA*=>x#&TMX1Hb=d5OSSLXvoi5L7ia#H zo|Edp$+M{J2K7~xk03SS`MB|IFY+%M z`F+T@jPiBOU(s-P)!8&_OLSBd+Cu$t&2>tS%1SUEQ#9vGBk@oy8VqZ;i;0o2TxZcd z-L0qF&$S26w!hx3*}MCPruKNcMb4c6JU{7c>K7Xqyx``>zBCWmR(} zRJ2d;>f8z`UY$f=C~A`M5=nZdl8T>-c<9wgI2aFy`izH!BGZGLwa?gB3Q$xjqNJEA zxs3`^NYSjUV&Hsd%f-%)6X2-M@)c>ouV_=y?1~&uDA9i8vzG%oDzQQ;^)?qbbSTHg z4b6!hb_@NI__*E7o0`?sMBQASC3qdxFAjxNaUc=xr@0g*IW8+0OIa1;L$Y`^7*5Dy zY(NZPMnsH^DrVxe(MvRTe{0aVQ=iQ4cpY4Tj=FiN41ESfpuWbR^gW z9-2a`nvm6|eR~h=Kd5ub1_=EL=0<5CrigJ_jR*Te;ZS_EUIY`OIuuKUC9zKyA+Pur zjf+x3L9fMNbQFW3cLV~j4}@0ubkFMqP3Vio!kPo}6O6|d&6QHIS`6om7^Hu(aU`hcsVLv#`D$7ouR(V zB=QaBGPq15fYOiwEbFFl4C@p#pf&~YG87L48b?O8l7P-BEri_aRO--)M*OK2NG7-^ zrJUFQ=Z-tBRQ17y7han8pP%==mzt!eOz0C>R|yWG@u$k10@7anV?QN*U+}Cc-b~qzgZ6!;UduGq3D-X?;rz=}i&hm_%^KO~(q&<65 z!k*tfv2otwWsbL%{MuKXvEu%F)e8!f&JylNu5H#Cew$UZt4#m(XH^smkUC_8OODd%U1`U*rNZ*tO}Cn6n(n{+m*2l1 zd9W|l+&*7;a?-Kn@J~C^j;%|+;wAs4+rC@A8Q1K=d4Kan$C9Ub(NmfBR8C)>Jv8sx zKWCpCO&{t=dpc4=2V2b8r5%yrbu~05Z@iKZp*!!bTFdWaEyrzm$*xImfS0WAIwhfv zGXc;ih74envW?xkAWP!uAeJKITQ!#?X>um?`W_E0E9uWev52gz8hvCYGAWRf0ys7vSGBVzJTO+|BL(G1ef6i zpZ&3&D{P!>$=EoTdoqx6R$`I6I{Am*gLA%L@##Zn=DlZEtn}))1r7hAlCu8SRoi$% zeygU!&~G#kkn(*fr0XavsV^EfmFD+Fz4M!%(PQNl%1BhW1_?U&wHM0iOHckvwxcT! zbQzCcJ34Q(Gih8Sf}|p7J*{jNdGA1Sk@eBp{$`G0KE= z=pgF)Ol@Rpo$*0vwvYC}xE#^kYy{XaLn&vu&M|DP>GIVKqduAo=%kgi=%z}4q#(et z9UMRMY??lv^6dW1(>0r%dn?t{l@hw1W|gLbvD%5TUB@ccSJ)D#->sQ)1 z=|vZ4th>x|JcsYhRk5}}oYX$MhV#u_?mkS|cij~)G+%5)&s+%5@xo6mq=B(yjwGGes=v++a}23dIYc%3K#sEU7*04jts1&}qRKMa(s#>8ttw~CCyP>}}q zH@m~A#rlQ`HC+R;jsX)B^3|=k1Z+kFcae>OG6eEh=~LQ93?`BFwwcBODvjCozSnv5 zWpxf>pylTf66KUGdg&hs0k~o(3dERgs%oB9BcfSiswQA`hcqXw#R$t;F^`&EA4X^^ zqOH@i_D9z3#uckqu43%Q#?mF1()aPFQi7#h$l0FzLfG?LU+JynpZ)2)Z|6kolHgbr z%F;sFf>80u>G`4WhVM?_M}r>>E><!*e@R6)kBmw6=94C79I=6X+RC zMx^>R!H@E;Rfgj*m0WiLdGYshSc|Dj$wpfiQ=U#zo;iwFd4|NZMrRg@^I0TrAN!kb zV4y44f{L8o(X&PlGo%KBFbYU^**Xxj^UM|*;bRkwXX%&=B})fOgO-+|vWXTRX%R5M zhBY8E6AmB%FPPwxEa;#?iouE{=faX-?IXuG_vQgtI+Z2sGqH?vQsV1N1HW5Iz zAL38FhyhyLG)(^WWwb{ z=>1jDPZHkc82qyV{@HWzFPHly2Lv6#8+bSeAH;K6xmhO~rl-i9@1S_8tK+o>vUv7-QUphR9AYAm6`!zL!MEwF<1j0?if zaB)Q7{a}1B9-&Ez%o+~?Z6B|Gq;0u7w$~x~8)-C8u0QMTP7jwCYK6?J#b>kD33m<+kMq zHXDq^QDE~n?o9~6xHW0rkOFV^25ngB2rupdBkami9|KOWU^EPw*-bKYkh|HeFP$#U z)!Ft+`-Sd~m%213e3%2_;GoK^nmW6_M=}4o4%`A)gNj09rd*;#LIS_F9L1hCOnFyW zGQ93egr0$~FzTcQXn)jgyu1K3W+2;=f{(wzpPEF%))L#YYSaGO+0FC*=O;QI`bz&? zojx-w%=;Q9PQxnomV9t}wqvpWSi1h$-1UX}(@RBVi_Wr?vuw$kzhdVKN+*RSkMD;^ zZycR2U+`2f6>UnDHB9fjqs|=qa6G-aK2_8>*|wBl_;1{g9Vnf_`AYfkRkB6iY2jO5 z;D2f5TMi1p6!s&pSz}>Ivqt4>${-5#o0}R*u@ir^URO>dAvz>3z@d8|!|BdF2Vg?0}oxgewv9R5Xg`*)D_K zW(2q%8XsyM+tQI8>M?hAyF84F?krfMC%6~v;n?7yOotM&LCqI9*U^2hs*`X);Xf#YA|Ppv~T z!9DUHp6JL37FPvSsLlHX?nlpiXWl+@^Q{@jY|(6Ju4u0RbK!(;?XI4MECi_s9dfcH zd9oGZ1LSk-ncgNX_blf6#7JA~gszi!dB(v->|WF#sL!>mt#!c_=uCtLvV16iiduhz zKb5v0INBWU$^Li70KXmz#Z%qW)iceX3%ekVtluZ^!l_SSR1?S{q6tbY7FS+DO=W_T zw<&pt5_;E*Ac_~9{jM254K9m<%CI5D!sj-K@xjyNi!@op%Ht7u!fM#*&~nlKEM1WB5pH*5K3 zx@5ilc(GLs28<3UKR~T{{HeQCE%!_;P*USlX(u0$q z3uoCRXfBfdKon43bB1sTKo2W6eqL( zY;(THU4Llpqqlh({VZgW!G@lpJTq^xZ&bl-pom+Hzz>e9EnR15PThZ zr(|V7up4>TaH&~7cTc)EdTaQG4zXGrv^Pvf>bgtH%0AlOjGFF^db(lF?A|@@NqQ9i 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 bSfN{HyNCBpb(1{%GL?Che}Y-j0}K8SooF&N literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d63bf1e05ddc64cc89b36cb180bd2a6f4e0726cc GIT binary patch literal 6795 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 HN%Q{!1iA2p literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2728f1429dae1c76225b540f7e851c1e9bc6ce0a GIT binary patch literal 3785 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 Dict[str, str]: + """ + Return a distutils install scheme + """ + from distutils.dist import Distribution + + dist_args: Dict[str, Union[str, List[str]]] = {"name": dist_name} + if isolated: + dist_args["script_args"] = ["--no-user-cfg"] + + d = Distribution(dist_args) + if not ignore_config_files: + try: + d.parse_config_files() + except UnicodeDecodeError: + paths = d.find_config_files() + logger.warning( + "Ignore distutils configs in %s due to encoding errors.", + ", ".join(os.path.basename(p) for p in paths), + ) + obj: Optional[DistutilsCommand] = None + obj = d.get_command_obj("install", create=True) + assert obj is not None + i: distutils_install_command = obj + # NOTE: setting user or home has the side-effect of creating the home dir + # or user base for installations during finalize_options() + # ideally, we'd prefer a scheme class that has no side-effects. + assert not (user and prefix), f"user={user} prefix={prefix}" + assert not (home and prefix), f"home={home} prefix={prefix}" + i.user = user or i.user + if user or home: + i.prefix = "" + i.prefix = prefix or i.prefix + i.home = home or i.home + i.root = root or i.root + i.finalize_options() + + scheme: Dict[str, str] = {} + for key in SCHEME_KEYS: + scheme[key] = getattr(i, "install_" + key) + + # install_lib specified in setup.cfg should install *everything* + # into there (i.e. it takes precedence over both purelib and + # platlib). Note, i.install_lib is *always* set after + # finalize_options(); we only want to override here if the user + # has explicitly requested it hence going back to the config + if "install_lib" in d.get_option_dict("install"): + scheme.update({"purelib": i.install_lib, "platlib": i.install_lib}) + + if running_under_virtualenv(): + if home: + prefix = home + elif user: + prefix = i.install_userbase + else: + prefix = i.prefix + scheme["headers"] = os.path.join( + prefix, + "include", + "site", + f"python{get_major_minor_version()}", + dist_name, + ) + + if root is not None: + path_no_drive = os.path.splitdrive(os.path.abspath(scheme["headers"]))[1] + scheme["headers"] = os.path.join(root, path_no_drive[1:]) + + return scheme + + +def get_scheme( + dist_name: str, + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + isolated: bool = False, + prefix: Optional[str] = None, +) -> Scheme: + """ + Get the "scheme" corresponding to the input parameters. The distutils + documentation provides the context for the available schemes: + https://docs.python.org/3/install/index.html#alternate-installation + + :param dist_name: the name of the package to retrieve the scheme for, used + in the headers scheme path + :param user: indicates to use the "user" scheme + :param home: indicates to use the "home" scheme and provides the base + directory for the same + :param root: root under which other directories are re-based + :param isolated: equivalent to --no-user-cfg, i.e. do not consider + ~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for + scheme paths + :param prefix: indicates to use the "prefix" scheme and provides the + base directory for the same + """ + scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix) + return Scheme( + platlib=scheme["platlib"], + purelib=scheme["purelib"], + headers=scheme["headers"], + scripts=scheme["scripts"], + data=scheme["data"], + ) + + +def get_bin_prefix() -> str: + # XXX: In old virtualenv versions, sys.prefix can contain '..' components, + # so we need to call normpath to eliminate them. + prefix = os.path.normpath(sys.prefix) + if WINDOWS: + bin_py = os.path.join(prefix, "Scripts") + # buildout uses 'bin' on Windows too? + if not os.path.exists(bin_py): + bin_py = os.path.join(prefix, "bin") + return bin_py + # Forcing to use /usr/local/bin for standard macOS framework installs + # Also log to ~/Library/Logs/ for use with the Console.app log viewer + if sys.platform[:6] == "darwin" and prefix[:16] == "/System/Library/": + return "/usr/local/bin" + return os.path.join(prefix, "bin") + + +def get_purelib() -> str: + return get_python_lib(plat_specific=False) + + +def get_platlib() -> str: + return get_python_lib(plat_specific=True) diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py b/backend/venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py new file mode 100644 index 0000000..ca860ea --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py @@ -0,0 +1,214 @@ +import logging +import os +import sys +import sysconfig +import typing + +from pip._internal.exceptions import InvalidSchemeCombination, UserInstallationInvalid +from pip._internal.models.scheme import SCHEME_KEYS, Scheme +from pip._internal.utils.virtualenv import running_under_virtualenv + +from .base import change_root, get_major_minor_version, is_osx_framework + +logger = logging.getLogger(__name__) + + +# Notes on _infer_* functions. +# Unfortunately ``get_default_scheme()`` didn't exist before 3.10, so there's no +# way to ask things like "what is the '_prefix' scheme on this platform". These +# functions try to answer that with some heuristics while accounting for ad-hoc +# platforms not covered by CPython's default sysconfig implementation. If the +# ad-hoc implementation does not fully implement sysconfig, we'll fall back to +# a POSIX scheme. + +_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names()) + +_PREFERRED_SCHEME_API = getattr(sysconfig, "get_preferred_scheme", None) + + +def _should_use_osx_framework_prefix() -> bool: + """Check for Apple's ``osx_framework_library`` scheme. + + Python distributed by Apple's Command Line Tools has this special scheme + that's used when: + + * This is a framework build. + * We are installing into the system prefix. + + This does not account for ``pip install --prefix`` (also means we're not + installing to the system prefix), which should use ``posix_prefix``, but + logic here means ``_infer_prefix()`` outputs ``osx_framework_library``. But + since ``prefix`` is not available for ``sysconfig.get_default_scheme()``, + which is the stdlib replacement for ``_infer_prefix()``, presumably Apple + wouldn't be able to magically switch between ``osx_framework_library`` and + ``posix_prefix``. ``_infer_prefix()`` returning ``osx_framework_library`` + means its behavior is consistent whether we use the stdlib implementation + or our own, and we deal with this special case in ``get_scheme()`` instead. + """ + return ( + "osx_framework_library" in _AVAILABLE_SCHEMES + and not running_under_virtualenv() + and is_osx_framework() + ) + + +def _infer_prefix() -> str: + """Try to find a prefix scheme for the current platform. + + This tries: + + * A special ``osx_framework_library`` for Python distributed by Apple's + Command Line Tools, when not running in a virtual environment. + * Implementation + OS, used by PyPy on Windows (``pypy_nt``). + * Implementation without OS, used by PyPy on POSIX (``pypy``). + * OS + "prefix", used by CPython on POSIX (``posix_prefix``). + * Just the OS name, used by CPython on Windows (``nt``). + + If none of the above works, fall back to ``posix_prefix``. + """ + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("prefix") + if _should_use_osx_framework_prefix(): + return "osx_framework_library" + implementation_suffixed = f"{sys.implementation.name}_{os.name}" + if implementation_suffixed in _AVAILABLE_SCHEMES: + return implementation_suffixed + if sys.implementation.name in _AVAILABLE_SCHEMES: + return sys.implementation.name + suffixed = f"{os.name}_prefix" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + if os.name in _AVAILABLE_SCHEMES: # On Windows, prefx is just called "nt". + return os.name + return "posix_prefix" + + +def _infer_user() -> str: + """Try to find a user scheme for the current platform.""" + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("user") + if is_osx_framework() and not running_under_virtualenv(): + suffixed = "osx_framework_user" + else: + suffixed = f"{os.name}_user" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + if "posix_user" not in _AVAILABLE_SCHEMES: # User scheme unavailable. + raise UserInstallationInvalid() + return "posix_user" + + +def _infer_home() -> str: + """Try to find a home for the current platform.""" + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("home") + suffixed = f"{os.name}_home" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + return "posix_home" + + +# Update these keys if the user sets a custom home. +_HOME_KEYS = [ + "installed_base", + "base", + "installed_platbase", + "platbase", + "prefix", + "exec_prefix", +] +if sysconfig.get_config_var("userbase") is not None: + _HOME_KEYS.append("userbase") + + +def get_scheme( + dist_name: str, + user: bool = False, + home: typing.Optional[str] = None, + root: typing.Optional[str] = None, + isolated: bool = False, + prefix: typing.Optional[str] = None, +) -> Scheme: + """ + Get the "scheme" corresponding to the input parameters. + + :param dist_name: the name of the package to retrieve the scheme for, used + in the headers scheme path + :param user: indicates to use the "user" scheme + :param home: indicates to use the "home" scheme + :param root: root under which other directories are re-based + :param isolated: ignored, but kept for distutils compatibility (where + this controls whether the user-site pydistutils.cfg is honored) + :param prefix: indicates to use the "prefix" scheme and provides the + base directory for the same + """ + if user and prefix: + raise InvalidSchemeCombination("--user", "--prefix") + if home and prefix: + raise InvalidSchemeCombination("--home", "--prefix") + + if home is not None: + scheme_name = _infer_home() + elif user: + scheme_name = _infer_user() + else: + scheme_name = _infer_prefix() + + # Special case: When installing into a custom prefix, use posix_prefix + # instead of osx_framework_library. See _should_use_osx_framework_prefix() + # docstring for details. + if prefix is not None and scheme_name == "osx_framework_library": + scheme_name = "posix_prefix" + + if home is not None: + variables = {k: home for k in _HOME_KEYS} + elif prefix is not None: + variables = {k: prefix for k in _HOME_KEYS} + else: + variables = {} + + paths = sysconfig.get_paths(scheme=scheme_name, vars=variables) + + # Logic here is very arbitrary, we're doing it for compatibility, don't ask. + # 1. Pip historically uses a special header path in virtual environments. + # 2. If the distribution name is not known, distutils uses 'UNKNOWN'. We + # only do the same when not running in a virtual environment because + # pip's historical header path logic (see point 1) did not do this. + if running_under_virtualenv(): + if user: + base = variables.get("userbase", sys.prefix) + else: + base = variables.get("base", sys.prefix) + python_xy = f"python{get_major_minor_version()}" + paths["include"] = os.path.join(base, "include", "site", python_xy) + elif not dist_name: + dist_name = "UNKNOWN" + + scheme = Scheme( + platlib=paths["platlib"], + purelib=paths["purelib"], + headers=os.path.join(paths["include"], dist_name), + scripts=paths["scripts"], + data=paths["data"], + ) + if root is not None: + converted_keys = {} + for key in SCHEME_KEYS: + converted_keys[key] = change_root(root, getattr(scheme, key)) + scheme = Scheme(**converted_keys) + return scheme + + +def get_bin_prefix() -> str: + # Forcing to use /usr/local/bin for standard macOS framework installs. + if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/": + return "/usr/local/bin" + return sysconfig.get_paths()["scripts"] + + +def get_purelib() -> str: + return sysconfig.get_paths()["purelib"] + + +def get_platlib() -> str: + return sysconfig.get_paths()["platlib"] diff --git a/backend/venv/Lib/site-packages/pip/_internal/locations/base.py b/backend/venv/Lib/site-packages/pip/_internal/locations/base.py new file mode 100644 index 0000000..3f9f896 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/locations/base.py @@ -0,0 +1,81 @@ +import functools +import os +import site +import sys +import sysconfig +import typing + +from pip._internal.exceptions import InstallationError +from pip._internal.utils import appdirs +from pip._internal.utils.virtualenv import running_under_virtualenv + +# Application Directories +USER_CACHE_DIR = appdirs.user_cache_dir("pip") + +# FIXME doesn't account for venv linked to global site-packages +site_packages: str = sysconfig.get_path("purelib") + + +def get_major_minor_version() -> str: + """ + Return the major-minor version of the current Python as a string, e.g. + "3.7" or "3.10". + """ + return "{}.{}".format(*sys.version_info) + + +def change_root(new_root: str, pathname: str) -> str: + """Return 'pathname' with 'new_root' prepended. + + If 'pathname' is relative, this is equivalent to os.path.join(new_root, pathname). + Otherwise, it requires making 'pathname' relative and then joining the + two, which is tricky on DOS/Windows and Mac OS. + + This is borrowed from Python's standard library's distutils module. + """ + if os.name == "posix": + if not os.path.isabs(pathname): + return os.path.join(new_root, pathname) + else: + return os.path.join(new_root, pathname[1:]) + + elif os.name == "nt": + (drive, path) = os.path.splitdrive(pathname) + if path[0] == "\\": + path = path[1:] + return os.path.join(new_root, path) + + else: + raise InstallationError( + f"Unknown platform: {os.name}\n" + "Can not change root path prefix on unknown platform." + ) + + +def get_src_prefix() -> str: + if running_under_virtualenv(): + src_prefix = os.path.join(sys.prefix, "src") + else: + # FIXME: keep src in cwd for now (it is not a temporary folder) + try: + src_prefix = os.path.join(os.getcwd(), "src") + except OSError: + # In case the current working directory has been renamed or deleted + sys.exit("The folder you are executing pip from can no longer be found.") + + # under macOS + virtualenv sys.prefix is not properly resolved + # it is something like /path/to/python/bin/.. + return os.path.abspath(src_prefix) + + +try: + # Use getusersitepackages if this is present, as it ensures that the + # value is initialised properly. + user_site: typing.Optional[str] = site.getusersitepackages() +except AttributeError: + user_site = site.USER_SITE + + +@functools.lru_cache(maxsize=None) +def is_osx_framework() -> bool: + return bool(sysconfig.get_config_var("PYTHONFRAMEWORK")) diff --git a/backend/venv/Lib/site-packages/pip/_internal/main.py b/backend/venv/Lib/site-packages/pip/_internal/main.py new file mode 100644 index 0000000..33c6d24 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/main.py @@ -0,0 +1,12 @@ +from typing import List, Optional + + +def main(args: Optional[List[str]] = None) -> int: + """This is preserved for old console scripts that may still be referencing + it. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/__init__.py new file mode 100644 index 0000000..1ea1e7f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/__init__.py @@ -0,0 +1,128 @@ +import contextlib +import functools +import os +import sys +from typing import TYPE_CHECKING, List, Optional, Type, cast + +from pip._internal.utils.misc import strtobool + +from .base import BaseDistribution, BaseEnvironment, FilesystemWheel, MemoryWheel, Wheel + +if TYPE_CHECKING: + from typing import Literal, Protocol +else: + Protocol = object + +__all__ = [ + "BaseDistribution", + "BaseEnvironment", + "FilesystemWheel", + "MemoryWheel", + "Wheel", + "get_default_environment", + "get_environment", + "get_wheel_distribution", + "select_backend", +] + + +def _should_use_importlib_metadata() -> bool: + """Whether to use the ``importlib.metadata`` or ``pkg_resources`` backend. + + By default, pip uses ``importlib.metadata`` on Python 3.11+, and + ``pkg_resources`` otherwise. This can be overridden by a couple of ways: + + * If environment variable ``_PIP_USE_IMPORTLIB_METADATA`` is set, it + dictates whether ``importlib.metadata`` is used, regardless of Python + version. + * On Python 3.11+, Python distributors can patch ``importlib.metadata`` + to add a global constant ``_PIP_USE_IMPORTLIB_METADATA = False``. This + makes pip use ``pkg_resources`` (unless the user set the aforementioned + environment variable to *True*). + """ + with contextlib.suppress(KeyError, ValueError): + return bool(strtobool(os.environ["_PIP_USE_IMPORTLIB_METADATA"])) + if sys.version_info < (3, 11): + return False + import importlib.metadata + + return bool(getattr(importlib.metadata, "_PIP_USE_IMPORTLIB_METADATA", True)) + + +class Backend(Protocol): + NAME: 'Literal["importlib", "pkg_resources"]' + Distribution: Type[BaseDistribution] + Environment: Type[BaseEnvironment] + + +@functools.lru_cache(maxsize=None) +def select_backend() -> Backend: + if _should_use_importlib_metadata(): + from . import importlib + + return cast(Backend, importlib) + from . import pkg_resources + + return cast(Backend, pkg_resources) + + +def get_default_environment() -> BaseEnvironment: + """Get the default representation for the current environment. + + This returns an Environment instance from the chosen backend. The default + Environment instance should be built from ``sys.path`` and may use caching + to share instance state across calls. + """ + return select_backend().Environment.default() + + +def get_environment(paths: Optional[List[str]]) -> BaseEnvironment: + """Get a representation of the environment specified by ``paths``. + + This returns an Environment instance from the chosen backend based on the + given import paths. The backend must build a fresh instance representing + the state of installed distributions when this function is called. + """ + return select_backend().Environment.from_paths(paths) + + +def get_directory_distribution(directory: str) -> BaseDistribution: + """Get the distribution metadata representation in the specified directory. + + This returns a Distribution instance from the chosen backend based on + the given on-disk ``.dist-info`` directory. + """ + return select_backend().Distribution.from_directory(directory) + + +def get_wheel_distribution(wheel: Wheel, canonical_name: str) -> BaseDistribution: + """Get the representation of the specified wheel's distribution metadata. + + This returns a Distribution instance from the chosen backend based on + the given wheel's ``.dist-info`` directory. + + :param canonical_name: Normalized project name of the given wheel. + """ + return select_backend().Distribution.from_wheel(wheel, canonical_name) + + +def get_metadata_distribution( + metadata_contents: bytes, + filename: str, + canonical_name: str, +) -> BaseDistribution: + """Get the dist representation of the specified METADATA file contents. + + This returns a Distribution instance from the chosen backend sourced from the data + in `metadata_contents`. + + :param metadata_contents: Contents of a METADATA file within a dist, or one served + via PEP 658. + :param filename: Filename for the dist this metadata represents. + :param canonical_name: Normalized project name of the given dist. + """ + return select_backend().Distribution.from_metadata_file_contents( + metadata_contents, + filename, + canonical_name, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..980814f04cdadf6d7080b57ba9a902cdee3c198e GIT binary patch literal 5871 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 XyjDiAlv+#LouSgghsU2WG&t@5=s4+N literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..610d5f7ba9a5a2e9cb6a6395d1015b6040a3afe2 GIT binary patch literal 35202 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 HvGMx<^dH60 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..154168d1c71fd2bd3e091ba2fd3d24f3db8996cf GIT binary patch literal 16088 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 Yp1#Kn79OAEwzDJGNB)t42c^~j2l%z~+yDRo literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/_json.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/_json.py new file mode 100644 index 0000000..f3aeab3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/_json.py @@ -0,0 +1,86 @@ +# Extracted from https://github.com/pfmoore/pkg_metadata + +from email.header import Header, decode_header, make_header +from email.message import Message +from typing import Any, Dict, List, Union, cast + +METADATA_FIELDS = [ + # Name, Multiple-Use + ("Metadata-Version", False), + ("Name", False), + ("Version", False), + ("Dynamic", True), + ("Platform", True), + ("Supported-Platform", True), + ("Summary", False), + ("Description", False), + ("Description-Content-Type", False), + ("Keywords", False), + ("Home-page", False), + ("Download-URL", False), + ("Author", False), + ("Author-email", False), + ("Maintainer", False), + ("Maintainer-email", False), + ("License", False), + ("License-Expression", False), + ("License-File", True), + ("Classifier", True), + ("Requires-Dist", True), + ("Requires-Python", False), + ("Requires-External", True), + ("Project-URL", True), + ("Provides-Extra", True), + ("Provides-Dist", True), + ("Obsoletes-Dist", True), +] + + +def json_name(field: str) -> str: + return field.lower().replace("-", "_") + + +def msg_to_json(msg: Message) -> Dict[str, Any]: + """Convert a Message object into a JSON-compatible dictionary.""" + + def sanitise_header(h: Union[Header, str]) -> str: + if isinstance(h, Header): + chunks = [] + for bytes, encoding in decode_header(h): + if encoding == "unknown-8bit": + try: + # See if UTF-8 works + bytes.decode("utf-8") + encoding = "utf-8" + except UnicodeDecodeError: + # If not, latin1 at least won't fail + encoding = "latin1" + chunks.append((bytes, encoding)) + return str(make_header(chunks)) + return str(h) + + result = {} + for field, multi in METADATA_FIELDS: + if field not in msg: + continue + key = json_name(field) + if multi: + value: Union[str, List[str]] = [ + sanitise_header(v) for v in msg.get_all(field) # type: ignore + ] + else: + value = sanitise_header(msg.get(field)) # type: ignore + if key == "keywords": + # Accept both comma-separated and space-separated + # forms, for better compatibility with old data. + if "," in value: + value = [v.strip() for v in value.split(",")] + else: + value = value.split() + result[key] = value + + payload = cast(str, msg.get_payload()) + if payload: + result["description"] = payload + + return result diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/base.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/base.py new file mode 100644 index 0000000..9eabcdb --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/base.py @@ -0,0 +1,688 @@ +import csv +import email.message +import functools +import json +import logging +import pathlib +import re +import zipfile +from typing import ( + IO, + Any, + Collection, + Container, + Dict, + Iterable, + Iterator, + List, + NamedTuple, + Optional, + Protocol, + Tuple, + Union, +) + +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import Version + +from pip._internal.exceptions import NoneMetadataError +from pip._internal.locations import site_packages, user_site +from pip._internal.models.direct_url import ( + DIRECT_URL_METADATA_NAME, + DirectUrl, + DirectUrlValidationError, +) +from pip._internal.utils.compat import stdlib_pkgs # TODO: Move definition here. +from pip._internal.utils.egg_link import egg_link_path_from_sys_path +from pip._internal.utils.misc import is_local, normalize_path +from pip._internal.utils.urls import url_to_path + +from ._json import msg_to_json + +InfoPath = Union[str, pathlib.PurePath] + +logger = logging.getLogger(__name__) + + +class BaseEntryPoint(Protocol): + @property + def name(self) -> str: + raise NotImplementedError() + + @property + def value(self) -> str: + raise NotImplementedError() + + @property + def group(self) -> str: + raise NotImplementedError() + + +def _convert_installed_files_path( + entry: Tuple[str, ...], + info: Tuple[str, ...], +) -> str: + """Convert a legacy installed-files.txt path into modern RECORD path. + + The legacy format stores paths relative to the info directory, while the + modern format stores paths relative to the package root, e.g. the + site-packages directory. + + :param entry: Path parts of the installed-files.txt entry. + :param info: Path parts of the egg-info directory relative to package root. + :returns: The converted entry. + + For best compatibility with symlinks, this does not use ``abspath()`` or + ``Path.resolve()``, but tries to work with path parts: + + 1. While ``entry`` starts with ``..``, remove the equal amounts of parts + from ``info``; if ``info`` is empty, start appending ``..`` instead. + 2. Join the two directly. + """ + while entry and entry[0] == "..": + if not info or info[-1] == "..": + info += ("..",) + else: + info = info[:-1] + entry = entry[1:] + return str(pathlib.Path(*info, *entry)) + + +class RequiresEntry(NamedTuple): + requirement: str + extra: str + marker: str + + +class BaseDistribution(Protocol): + @classmethod + def from_directory(cls, directory: str) -> "BaseDistribution": + """Load the distribution from a metadata directory. + + :param directory: Path to a metadata directory, e.g. ``.dist-info``. + """ + raise NotImplementedError() + + @classmethod + def from_metadata_file_contents( + cls, + metadata_contents: bytes, + filename: str, + project_name: str, + ) -> "BaseDistribution": + """Load the distribution from the contents of a METADATA file. + + This is used to implement PEP 658 by generating a "shallow" dist object that can + be used for resolution without downloading or building the actual dist yet. + + :param metadata_contents: The contents of a METADATA file. + :param filename: File name for the dist with this metadata. + :param project_name: Name of the project this dist represents. + """ + raise NotImplementedError() + + @classmethod + def from_wheel(cls, wheel: "Wheel", name: str) -> "BaseDistribution": + """Load the distribution from a given wheel. + + :param wheel: A concrete wheel definition. + :param name: File name of the wheel. + + :raises InvalidWheel: Whenever loading of the wheel causes a + :py:exc:`zipfile.BadZipFile` exception to be thrown. + :raises UnsupportedWheel: If the wheel is a valid zip, but malformed + internally. + """ + raise NotImplementedError() + + def __repr__(self) -> str: + return f"{self.raw_name} {self.raw_version} ({self.location})" + + def __str__(self) -> str: + return f"{self.raw_name} {self.raw_version}" + + @property + def location(self) -> Optional[str]: + """Where the distribution is loaded from. + + A string value is not necessarily a filesystem path, since distributions + can be loaded from other sources, e.g. arbitrary zip archives. ``None`` + means the distribution is created in-memory. + + Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If + this is a symbolic link, we want to preserve the relative path between + it and files in the distribution. + """ + raise NotImplementedError() + + @property + def editable_project_location(self) -> Optional[str]: + """The project location for editable distributions. + + This is the directory where pyproject.toml or setup.py is located. + None if the distribution is not installed in editable mode. + """ + # TODO: this property is relatively costly to compute, memoize it ? + direct_url = self.direct_url + if direct_url: + if direct_url.is_local_editable(): + return url_to_path(direct_url.url) + else: + # Search for an .egg-link file by walking sys.path, as it was + # done before by dist_is_editable(). + egg_link_path = egg_link_path_from_sys_path(self.raw_name) + if egg_link_path: + # TODO: get project location from second line of egg_link file + # (https://github.com/pypa/pip/issues/10243) + return self.location + return None + + @property + def installed_location(self) -> Optional[str]: + """The distribution's "installed" location. + + This should generally be a ``site-packages`` directory. This is + usually ``dist.location``, except for legacy develop-installed packages, + where ``dist.location`` is the source code location, and this is where + the ``.egg-link`` file is. + + The returned location is normalized (in particular, with symlinks removed). + """ + raise NotImplementedError() + + @property + def info_location(self) -> Optional[str]: + """Location of the .[egg|dist]-info directory or file. + + Similarly to ``location``, a string value is not necessarily a + filesystem path. ``None`` means the distribution is created in-memory. + + For a modern .dist-info installation on disk, this should be something + like ``{location}/{raw_name}-{version}.dist-info``. + + Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If + this is a symbolic link, we want to preserve the relative path between + it and other files in the distribution. + """ + raise NotImplementedError() + + @property + def installed_by_distutils(self) -> bool: + """Whether this distribution is installed with legacy distutils format. + + A distribution installed with "raw" distutils not patched by setuptools + uses one single file at ``info_location`` to store metadata. We need to + treat this specially on uninstallation. + """ + info_location = self.info_location + if not info_location: + return False + return pathlib.Path(info_location).is_file() + + @property + def installed_as_egg(self) -> bool: + """Whether this distribution is installed as an egg. + + This usually indicates the distribution was installed by (older versions + of) easy_install. + """ + location = self.location + if not location: + return False + return location.endswith(".egg") + + @property + def installed_with_setuptools_egg_info(self) -> bool: + """Whether this distribution is installed with the ``.egg-info`` format. + + This usually indicates the distribution was installed with setuptools + with an old pip version or with ``single-version-externally-managed``. + + Note that this ensure the metadata store is a directory. distutils can + also installs an ``.egg-info``, but as a file, not a directory. This + property is *False* for that case. Also see ``installed_by_distutils``. + """ + info_location = self.info_location + if not info_location: + return False + if not info_location.endswith(".egg-info"): + return False + return pathlib.Path(info_location).is_dir() + + @property + def installed_with_dist_info(self) -> bool: + """Whether this distribution is installed with the "modern format". + + This indicates a "modern" installation, e.g. storing metadata in the + ``.dist-info`` directory. This applies to installations made by + setuptools (but through pip, not directly), or anything using the + standardized build backend interface (PEP 517). + """ + info_location = self.info_location + if not info_location: + return False + if not info_location.endswith(".dist-info"): + return False + return pathlib.Path(info_location).is_dir() + + @property + def canonical_name(self) -> NormalizedName: + raise NotImplementedError() + + @property + def version(self) -> Version: + raise NotImplementedError() + + @property + def raw_version(self) -> str: + raise NotImplementedError() + + @property + def setuptools_filename(self) -> str: + """Convert a project name to its setuptools-compatible filename. + + This is a copy of ``pkg_resources.to_filename()`` for compatibility. + """ + return self.raw_name.replace("-", "_") + + @property + def direct_url(self) -> Optional[DirectUrl]: + """Obtain a DirectUrl from this distribution. + + Returns None if the distribution has no `direct_url.json` metadata, + or if `direct_url.json` is invalid. + """ + try: + content = self.read_text(DIRECT_URL_METADATA_NAME) + except FileNotFoundError: + return None + try: + return DirectUrl.from_json(content) + except ( + UnicodeDecodeError, + json.JSONDecodeError, + DirectUrlValidationError, + ) as e: + logger.warning( + "Error parsing %s for %s: %s", + DIRECT_URL_METADATA_NAME, + self.canonical_name, + e, + ) + return None + + @property + def installer(self) -> str: + try: + installer_text = self.read_text("INSTALLER") + except (OSError, ValueError, NoneMetadataError): + return "" # Fail silently if the installer file cannot be read. + for line in installer_text.splitlines(): + cleaned_line = line.strip() + if cleaned_line: + return cleaned_line + return "" + + @property + def requested(self) -> bool: + return self.is_file("REQUESTED") + + @property + def editable(self) -> bool: + return bool(self.editable_project_location) + + @property + def local(self) -> bool: + """If distribution is installed in the current virtual environment. + + Always True if we're not in a virtualenv. + """ + if self.installed_location is None: + return False + return is_local(self.installed_location) + + @property + def in_usersite(self) -> bool: + if self.installed_location is None or user_site is None: + return False + return self.installed_location.startswith(normalize_path(user_site)) + + @property + def in_site_packages(self) -> bool: + if self.installed_location is None or site_packages is None: + return False + return self.installed_location.startswith(normalize_path(site_packages)) + + def is_file(self, path: InfoPath) -> bool: + """Check whether an entry in the info directory is a file.""" + raise NotImplementedError() + + def iter_distutils_script_names(self) -> Iterator[str]: + """Find distutils 'scripts' entries metadata. + + If 'scripts' is supplied in ``setup.py``, distutils records those in the + installed distribution's ``scripts`` directory, a file for each script. + """ + raise NotImplementedError() + + def read_text(self, path: InfoPath) -> str: + """Read a file in the info directory. + + :raise FileNotFoundError: If ``path`` does not exist in the directory. + :raise NoneMetadataError: If ``path`` exists in the info directory, but + cannot be read. + """ + raise NotImplementedError() + + def iter_entry_points(self) -> Iterable[BaseEntryPoint]: + raise NotImplementedError() + + def _metadata_impl(self) -> email.message.Message: + raise NotImplementedError() + + @functools.cached_property + def metadata(self) -> email.message.Message: + """Metadata of distribution parsed from e.g. METADATA or PKG-INFO. + + This should return an empty message if the metadata file is unavailable. + + :raises NoneMetadataError: If the metadata file is available, but does + not contain valid metadata. + """ + metadata = self._metadata_impl() + self._add_egg_info_requires(metadata) + return metadata + + @property + def metadata_dict(self) -> Dict[str, Any]: + """PEP 566 compliant JSON-serializable representation of METADATA or PKG-INFO. + + This should return an empty dict if the metadata file is unavailable. + + :raises NoneMetadataError: If the metadata file is available, but does + not contain valid metadata. + """ + return msg_to_json(self.metadata) + + @property + def metadata_version(self) -> Optional[str]: + """Value of "Metadata-Version:" in distribution metadata, if available.""" + return self.metadata.get("Metadata-Version") + + @property + def raw_name(self) -> str: + """Value of "Name:" in distribution metadata.""" + # The metadata should NEVER be missing the Name: key, but if it somehow + # does, fall back to the known canonical name. + return self.metadata.get("Name", self.canonical_name) + + @property + def requires_python(self) -> SpecifierSet: + """Value of "Requires-Python:" in distribution metadata. + + If the key does not exist or contains an invalid value, an empty + SpecifierSet should be returned. + """ + value = self.metadata.get("Requires-Python") + if value is None: + return SpecifierSet() + try: + # Convert to str to satisfy the type checker; this can be a Header object. + spec = SpecifierSet(str(value)) + except InvalidSpecifier as e: + message = "Package %r has an invalid Requires-Python: %s" + logger.warning(message, self.raw_name, e) + return SpecifierSet() + return spec + + def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]: + """Dependencies of this distribution. + + For modern .dist-info distributions, this is the collection of + "Requires-Dist:" entries in distribution metadata. + """ + raise NotImplementedError() + + def iter_raw_dependencies(self) -> Iterable[str]: + """Raw Requires-Dist metadata.""" + return self.metadata.get_all("Requires-Dist", []) + + def iter_provided_extras(self) -> Iterable[NormalizedName]: + """Extras provided by this distribution. + + For modern .dist-info distributions, this is the collection of + "Provides-Extra:" entries in distribution metadata. + + The return value of this function is expected to be normalised names, + per PEP 685, with the returned value being handled appropriately by + `iter_dependencies`. + """ + raise NotImplementedError() + + def _iter_declared_entries_from_record(self) -> Optional[Iterator[str]]: + try: + text = self.read_text("RECORD") + except FileNotFoundError: + return None + # This extra Path-str cast normalizes entries. + return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines())) + + def _iter_declared_entries_from_legacy(self) -> Optional[Iterator[str]]: + try: + text = self.read_text("installed-files.txt") + except FileNotFoundError: + return None + paths = (p for p in text.splitlines(keepends=False) if p) + root = self.location + info = self.info_location + if root is None or info is None: + return paths + try: + info_rel = pathlib.Path(info).relative_to(root) + except ValueError: # info is not relative to root. + return paths + if not info_rel.parts: # info *is* root. + return paths + return ( + _convert_installed_files_path(pathlib.Path(p).parts, info_rel.parts) + for p in paths + ) + + def iter_declared_entries(self) -> Optional[Iterator[str]]: + """Iterate through file entries declared in this distribution. + + For modern .dist-info distributions, this is the files listed in the + ``RECORD`` metadata file. For legacy setuptools distributions, this + comes from ``installed-files.txt``, with entries normalized to be + compatible with the format used by ``RECORD``. + + :return: An iterator for listed entries, or None if the distribution + contains neither ``RECORD`` nor ``installed-files.txt``. + """ + return ( + self._iter_declared_entries_from_record() + or self._iter_declared_entries_from_legacy() + ) + + def _iter_requires_txt_entries(self) -> Iterator[RequiresEntry]: + """Parse a ``requires.txt`` in an egg-info directory. + + This is an INI-ish format where an egg-info stores dependencies. A + section name describes extra other environment markers, while each entry + is an arbitrary string (not a key-value pair) representing a dependency + as a requirement string (no markers). + + There is a construct in ``importlib.metadata`` called ``Sectioned`` that + does mostly the same, but the format is currently considered private. + """ + try: + content = self.read_text("requires.txt") + except FileNotFoundError: + return + extra = marker = "" # Section-less entries don't have markers. + for line in content.splitlines(): + line = line.strip() + if not line or line.startswith("#"): # Comment; ignored. + continue + if line.startswith("[") and line.endswith("]"): # A section header. + extra, _, marker = line.strip("[]").partition(":") + continue + yield RequiresEntry(requirement=line, extra=extra, marker=marker) + + def _iter_egg_info_extras(self) -> Iterable[str]: + """Get extras from the egg-info directory.""" + known_extras = {""} + for entry in self._iter_requires_txt_entries(): + extra = canonicalize_name(entry.extra) + if extra in known_extras: + continue + known_extras.add(extra) + yield extra + + def _iter_egg_info_dependencies(self) -> Iterable[str]: + """Get distribution dependencies from the egg-info directory. + + To ease parsing, this converts a legacy dependency entry into a PEP 508 + requirement string. Like ``_iter_requires_txt_entries()``, there is code + in ``importlib.metadata`` that does mostly the same, but not do exactly + what we need. + + Namely, ``importlib.metadata`` does not normalize the extra name before + putting it into the requirement string, which causes marker comparison + to fail because the dist-info format do normalize. This is consistent in + all currently available PEP 517 backends, although not standardized. + """ + for entry in self._iter_requires_txt_entries(): + extra = canonicalize_name(entry.extra) + if extra and entry.marker: + marker = f'({entry.marker}) and extra == "{extra}"' + elif extra: + marker = f'extra == "{extra}"' + elif entry.marker: + marker = entry.marker + else: + marker = "" + if marker: + yield f"{entry.requirement} ; {marker}" + else: + yield entry.requirement + + def _add_egg_info_requires(self, metadata: email.message.Message) -> None: + """Add egg-info requires.txt information to the metadata.""" + if not metadata.get_all("Requires-Dist"): + for dep in self._iter_egg_info_dependencies(): + metadata["Requires-Dist"] = dep + if not metadata.get_all("Provides-Extra"): + for extra in self._iter_egg_info_extras(): + metadata["Provides-Extra"] = extra + + +class BaseEnvironment: + """An environment containing distributions to introspect.""" + + @classmethod + def default(cls) -> "BaseEnvironment": + raise NotImplementedError() + + @classmethod + def from_paths(cls, paths: Optional[List[str]]) -> "BaseEnvironment": + raise NotImplementedError() + + def get_distribution(self, name: str) -> Optional["BaseDistribution"]: + """Given a requirement name, return the installed distributions. + + The name may not be normalized. The implementation must canonicalize + it for lookup. + """ + raise NotImplementedError() + + def _iter_distributions(self) -> Iterator["BaseDistribution"]: + """Iterate through installed distributions. + + This function should be implemented by subclass, but never called + directly. Use the public ``iter_distribution()`` instead, which + implements additional logic to make sure the distributions are valid. + """ + raise NotImplementedError() + + def iter_all_distributions(self) -> Iterator[BaseDistribution]: + """Iterate through all installed distributions without any filtering.""" + for dist in self._iter_distributions(): + # Make sure the distribution actually comes from a valid Python + # packaging distribution. Pip's AdjacentTempDirectory leaves folders + # e.g. ``~atplotlib.dist-info`` if cleanup was interrupted. The + # valid project name pattern is taken from PEP 508. + project_name_valid = re.match( + r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", + dist.canonical_name, + flags=re.IGNORECASE, + ) + if not project_name_valid: + logger.warning( + "Ignoring invalid distribution %s (%s)", + dist.canonical_name, + dist.location, + ) + continue + yield dist + + def iter_installed_distributions( + self, + local_only: bool = True, + skip: Container[str] = stdlib_pkgs, + include_editables: bool = True, + editables_only: bool = False, + user_only: bool = False, + ) -> Iterator[BaseDistribution]: + """Return a list of installed distributions. + + This is based on ``iter_all_distributions()`` with additional filtering + options. Note that ``iter_installed_distributions()`` without arguments + is *not* equal to ``iter_all_distributions()``, since some of the + configurations exclude packages by default. + + :param local_only: If True (default), only return installations + local to the current virtualenv, if in a virtualenv. + :param skip: An iterable of canonicalized project names to ignore; + defaults to ``stdlib_pkgs``. + :param include_editables: If False, don't report editables. + :param editables_only: If True, only report editables. + :param user_only: If True, only report installations in the user + site directory. + """ + it = self.iter_all_distributions() + if local_only: + it = (d for d in it if d.local) + if not include_editables: + it = (d for d in it if not d.editable) + if editables_only: + it = (d for d in it if d.editable) + if user_only: + it = (d for d in it if d.in_usersite) + return (d for d in it if d.canonical_name not in skip) + + +class Wheel(Protocol): + location: str + + def as_zipfile(self) -> zipfile.ZipFile: + raise NotImplementedError() + + +class FilesystemWheel(Wheel): + def __init__(self, location: str) -> None: + self.location = location + + def as_zipfile(self) -> zipfile.ZipFile: + return zipfile.ZipFile(self.location, allowZip64=True) + + +class MemoryWheel(Wheel): + def __init__(self, location: str, stream: IO[bytes]) -> None: + self.location = location + self.stream = stream + + def as_zipfile(self) -> zipfile.ZipFile: + return zipfile.ZipFile(self.stream, allowZip64=True) diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py new file mode 100644 index 0000000..a779138 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py @@ -0,0 +1,6 @@ +from ._dists import Distribution +from ._envs import Environment + +__all__ = ["NAME", "Distribution", "Environment"] + +NAME = "importlib" diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c50f4a94120154d2d2ef8874232210cf569d3a1 GIT binary patch literal 362 zcmX|6Jxc^J5KV4(@AS@X1X~eo+(H*y5kd4iy~1({gzP3P!F-X;tz4&-Kf(Sw8~=#^ zVBtWtvJ`WT>F zm)cn$lq@G%zw1*D+s(J%B~+NU`H2lEWlB-%6IgmgOF;DL&W?!lw)RYGX=-v~ZDq9< zz7kZL79O;IMoLy)3&RQMmR!h^G%|>N2UAvyhB)bRNC)8!Q@Iv_aTZwqe^ySxm4VU& qH|y4pwdGSKPJ9XntbW{V0enOl;|1DTpzYV;;qBmMuz45z5jbCG(r5?( literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24410805acaa44085e792736b1cd334bd3974ece GIT binary patch literal 4495 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9c5a4e4cb33378c967445e05557bb4595512eb2 GIT binary patch literal 11083 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 pd524IEgxSw_1b6h48TR7#gK7f`(JzyZyW#s literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py new file mode 100644 index 0000000..ec1e815 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py @@ -0,0 +1,85 @@ +import importlib.metadata +import os +from typing import Any, Optional, Protocol, Tuple, cast + +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name + + +class BadMetadata(ValueError): + def __init__(self, dist: importlib.metadata.Distribution, *, reason: str) -> None: + self.dist = dist + self.reason = reason + + def __str__(self) -> str: + return f"Bad metadata in {self.dist} ({self.reason})" + + +class BasePath(Protocol): + """A protocol that various path objects conform. + + This exists because importlib.metadata uses both ``pathlib.Path`` and + ``zipfile.Path``, and we need a common base for type hints (Union does not + work well since ``zipfile.Path`` is too new for our linter setup). + + This does not mean to be exhaustive, but only contains things that present + in both classes *that we need*. + """ + + @property + def name(self) -> str: + raise NotImplementedError() + + @property + def parent(self) -> "BasePath": + raise NotImplementedError() + + +def get_info_location(d: importlib.metadata.Distribution) -> Optional[BasePath]: + """Find the path to the distribution's metadata directory. + + HACK: This relies on importlib.metadata's private ``_path`` attribute. Not + all distributions exist on disk, so importlib.metadata is correct to not + expose the attribute as public. But pip's code base is old and not as clean, + so we do this to avoid having to rewrite too many things. Hopefully we can + eliminate this some day. + """ + return getattr(d, "_path", None) + + +def parse_name_and_version_from_info_directory( + dist: importlib.metadata.Distribution, +) -> Tuple[Optional[str], Optional[str]]: + """Get a name and version from the metadata directory name. + + This is much faster than reading distribution metadata. + """ + info_location = get_info_location(dist) + if info_location is None: + return None, None + + stem, suffix = os.path.splitext(info_location.name) + if suffix == ".dist-info": + name, sep, version = stem.partition("-") + if sep: + return name, version + + if suffix == ".egg-info": + name = stem.split("-", 1)[0] + return name, None + + return None, None + + +def get_dist_canonical_name(dist: importlib.metadata.Distribution) -> NormalizedName: + """Get the distribution's normalized name. + + The ``name`` attribute is only available in Python 3.10 or later. We are + targeting exactly that, but Mypy does not know this. + """ + if name := parse_name_and_version_from_info_directory(dist)[0]: + return canonicalize_name(name) + + name = cast(Any, dist).name + if not isinstance(name, str): + raise BadMetadata(dist, reason="invalid metadata entry 'name'") + return canonicalize_name(name) diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py new file mode 100644 index 0000000..d220b61 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py @@ -0,0 +1,228 @@ +import email.message +import importlib.metadata +import pathlib +import zipfile +from os import PathLike +from typing import ( + Collection, + Dict, + Iterable, + Iterator, + Mapping, + Optional, + Sequence, + Union, + cast, +) + +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.exceptions import InvalidWheel, UnsupportedWheel +from pip._internal.metadata.base import ( + BaseDistribution, + BaseEntryPoint, + InfoPath, + Wheel, +) +from pip._internal.utils.misc import normalize_path +from pip._internal.utils.packaging import get_requirement +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.wheel import parse_wheel, read_wheel_metadata_file + +from ._compat import ( + BasePath, + get_dist_canonical_name, + parse_name_and_version_from_info_directory, +) + + +class WheelDistribution(importlib.metadata.Distribution): + """An ``importlib.metadata.Distribution`` read from a wheel. + + Although ``importlib.metadata.PathDistribution`` accepts ``zipfile.Path``, + its implementation is too "lazy" for pip's needs (we can't keep the ZipFile + handle open for the entire lifetime of the distribution object). + + This implementation eagerly reads the entire metadata directory into the + memory instead, and operates from that. + """ + + def __init__( + self, + files: Mapping[pathlib.PurePosixPath, bytes], + info_location: pathlib.PurePosixPath, + ) -> None: + self._files = files + self.info_location = info_location + + @classmethod + def from_zipfile( + cls, + zf: zipfile.ZipFile, + name: str, + location: str, + ) -> "WheelDistribution": + info_dir, _ = parse_wheel(zf, name) + paths = ( + (name, pathlib.PurePosixPath(name.split("/", 1)[-1])) + for name in zf.namelist() + if name.startswith(f"{info_dir}/") + ) + files = { + relpath: read_wheel_metadata_file(zf, fullpath) + for fullpath, relpath in paths + } + info_location = pathlib.PurePosixPath(location, info_dir) + return cls(files, info_location) + + def iterdir(self, path: InfoPath) -> Iterator[pathlib.PurePosixPath]: + # Only allow iterating through the metadata directory. + if pathlib.PurePosixPath(str(path)) in self._files: + return iter(self._files) + raise FileNotFoundError(path) + + def read_text(self, filename: str) -> Optional[str]: + try: + data = self._files[pathlib.PurePosixPath(filename)] + except KeyError: + return None + try: + text = data.decode("utf-8") + except UnicodeDecodeError as e: + wheel = self.info_location.parent + error = f"Error decoding metadata for {wheel}: {e} in {filename} file" + raise UnsupportedWheel(error) + return text + + def locate_file(self, path: Union[str, "PathLike[str]"]) -> pathlib.Path: + # This method doesn't make sense for our in-memory wheel, but the API + # requires us to define it. + raise NotImplementedError + + +class Distribution(BaseDistribution): + def __init__( + self, + dist: importlib.metadata.Distribution, + info_location: Optional[BasePath], + installed_location: Optional[BasePath], + ) -> None: + self._dist = dist + self._info_location = info_location + self._installed_location = installed_location + + @classmethod + def from_directory(cls, directory: str) -> BaseDistribution: + info_location = pathlib.Path(directory) + dist = importlib.metadata.Distribution.at(info_location) + return cls(dist, info_location, info_location.parent) + + @classmethod + def from_metadata_file_contents( + cls, + metadata_contents: bytes, + filename: str, + project_name: str, + ) -> BaseDistribution: + # Generate temp dir to contain the metadata file, and write the file contents. + temp_dir = pathlib.Path( + TempDirectory(kind="metadata", globally_managed=True).path + ) + metadata_path = temp_dir / "METADATA" + metadata_path.write_bytes(metadata_contents) + # Construct dist pointing to the newly created directory. + dist = importlib.metadata.Distribution.at(metadata_path.parent) + return cls(dist, metadata_path.parent, None) + + @classmethod + def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution: + try: + with wheel.as_zipfile() as zf: + dist = WheelDistribution.from_zipfile(zf, name, wheel.location) + except zipfile.BadZipFile as e: + raise InvalidWheel(wheel.location, name) from e + return cls(dist, dist.info_location, pathlib.PurePosixPath(wheel.location)) + + @property + def location(self) -> Optional[str]: + if self._info_location is None: + return None + return str(self._info_location.parent) + + @property + def info_location(self) -> Optional[str]: + if self._info_location is None: + return None + return str(self._info_location) + + @property + def installed_location(self) -> Optional[str]: + if self._installed_location is None: + return None + return normalize_path(str(self._installed_location)) + + @property + def canonical_name(self) -> NormalizedName: + return get_dist_canonical_name(self._dist) + + @property + def version(self) -> Version: + if version := parse_name_and_version_from_info_directory(self._dist)[1]: + return parse_version(version) + return parse_version(self._dist.version) + + @property + def raw_version(self) -> str: + return self._dist.version + + def is_file(self, path: InfoPath) -> bool: + return self._dist.read_text(str(path)) is not None + + def iter_distutils_script_names(self) -> Iterator[str]: + # A distutils installation is always "flat" (not in e.g. egg form), so + # if this distribution's info location is NOT a pathlib.Path (but e.g. + # zipfile.Path), it can never contain any distutils scripts. + if not isinstance(self._info_location, pathlib.Path): + return + for child in self._info_location.joinpath("scripts").iterdir(): + yield child.name + + def read_text(self, path: InfoPath) -> str: + content = self._dist.read_text(str(path)) + if content is None: + raise FileNotFoundError(path) + return content + + def iter_entry_points(self) -> Iterable[BaseEntryPoint]: + # importlib.metadata's EntryPoint structure satisfies BaseEntryPoint. + return self._dist.entry_points + + def _metadata_impl(self) -> email.message.Message: + # From Python 3.10+, importlib.metadata declares PackageMetadata as the + # return type. This protocol is unfortunately a disaster now and misses + # a ton of fields that we need, including get() and get_payload(). We + # rely on the implementation that the object is actually a Message now, + # until upstream can improve the protocol. (python/cpython#94952) + return cast(email.message.Message, self._dist.metadata) + + def iter_provided_extras(self) -> Iterable[NormalizedName]: + return [ + canonicalize_name(extra) + for extra in self.metadata.get_all("Provides-Extra", []) + ] + + def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]: + contexts: Sequence[Dict[str, str]] = [{"extra": e} for e in extras] + for req_string in self.metadata.get_all("Requires-Dist", []): + # strip() because email.message.Message.get_all() may return a leading \n + # in case a long header was wrapped. + req = get_requirement(req_string.strip()) + if not req.marker: + yield req + elif not extras and req.marker.evaluate({"extra": ""}): + yield req + elif any(req.marker.evaluate(context) for context in contexts): + yield req diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py new file mode 100644 index 0000000..4d906fd --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py @@ -0,0 +1,189 @@ +import functools +import importlib.metadata +import logging +import os +import pathlib +import sys +import zipfile +import zipimport +from typing import Iterator, List, Optional, Sequence, Set, Tuple + +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name + +from pip._internal.metadata.base import BaseDistribution, BaseEnvironment +from pip._internal.models.wheel import Wheel +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.filetypes import WHEEL_EXTENSION + +from ._compat import BadMetadata, BasePath, get_dist_canonical_name, get_info_location +from ._dists import Distribution + +logger = logging.getLogger(__name__) + + +def _looks_like_wheel(location: str) -> bool: + if not location.endswith(WHEEL_EXTENSION): + return False + if not os.path.isfile(location): + return False + if not Wheel.wheel_file_re.match(os.path.basename(location)): + return False + return zipfile.is_zipfile(location) + + +class _DistributionFinder: + """Finder to locate distributions. + + The main purpose of this class is to memoize found distributions' names, so + only one distribution is returned for each package name. At lot of pip code + assumes this (because it is setuptools's behavior), and not doing the same + can potentially cause a distribution in lower precedence path to override a + higher precedence one if the caller is not careful. + + Eventually we probably want to make it possible to see lower precedence + installations as well. It's useful feature, after all. + """ + + FoundResult = Tuple[importlib.metadata.Distribution, Optional[BasePath]] + + def __init__(self) -> None: + self._found_names: Set[NormalizedName] = set() + + def _find_impl(self, location: str) -> Iterator[FoundResult]: + """Find distributions in a location.""" + # Skip looking inside a wheel. Since a package inside a wheel is not + # always valid (due to .data directories etc.), its .dist-info entry + # should not be considered an installed distribution. + if _looks_like_wheel(location): + return + # To know exactly where we find a distribution, we have to feed in the + # paths one by one, instead of dumping the list to importlib.metadata. + for dist in importlib.metadata.distributions(path=[location]): + info_location = get_info_location(dist) + try: + name = get_dist_canonical_name(dist) + except BadMetadata as e: + logger.warning("Skipping %s due to %s", info_location, e.reason) + continue + if name in self._found_names: + continue + self._found_names.add(name) + yield dist, info_location + + def find(self, location: str) -> Iterator[BaseDistribution]: + """Find distributions in a location. + + The path can be either a directory, or a ZIP archive. + """ + for dist, info_location in self._find_impl(location): + if info_location is None: + installed_location: Optional[BasePath] = None + else: + installed_location = info_location.parent + yield Distribution(dist, info_location, installed_location) + + def find_linked(self, location: str) -> Iterator[BaseDistribution]: + """Read location in egg-link files and return distributions in there. + + The path should be a directory; otherwise this returns nothing. This + follows how setuptools does this for compatibility. The first non-empty + line in the egg-link is read as a path (resolved against the egg-link's + containing directory if relative). Distributions found at that linked + location are returned. + """ + path = pathlib.Path(location) + if not path.is_dir(): + return + for child in path.iterdir(): + if child.suffix != ".egg-link": + continue + with child.open() as f: + lines = (line.strip() for line in f) + target_rel = next((line for line in lines if line), "") + if not target_rel: + continue + target_location = str(path.joinpath(target_rel)) + for dist, info_location in self._find_impl(target_location): + yield Distribution(dist, info_location, path) + + def _find_eggs_in_dir(self, location: str) -> Iterator[BaseDistribution]: + from pip._vendor.pkg_resources import find_distributions + + from pip._internal.metadata import pkg_resources as legacy + + with os.scandir(location) as it: + for entry in it: + if not entry.name.endswith(".egg"): + continue + for dist in find_distributions(entry.path): + yield legacy.Distribution(dist) + + def _find_eggs_in_zip(self, location: str) -> Iterator[BaseDistribution]: + from pip._vendor.pkg_resources import find_eggs_in_zip + + from pip._internal.metadata import pkg_resources as legacy + + try: + importer = zipimport.zipimporter(location) + except zipimport.ZipImportError: + return + for dist in find_eggs_in_zip(importer, location): + yield legacy.Distribution(dist) + + def find_eggs(self, location: str) -> Iterator[BaseDistribution]: + """Find eggs in a location. + + This actually uses the old *pkg_resources* backend. We likely want to + deprecate this so we can eventually remove the *pkg_resources* + dependency entirely. Before that, this should first emit a deprecation + warning for some versions when using the fallback since importing + *pkg_resources* is slow for those who don't need it. + """ + if os.path.isdir(location): + yield from self._find_eggs_in_dir(location) + if zipfile.is_zipfile(location): + yield from self._find_eggs_in_zip(location) + + +@functools.lru_cache(maxsize=None) # Warn a distribution exactly once. +def _emit_egg_deprecation(location: Optional[str]) -> None: + deprecated( + reason=f"Loading egg at {location} is deprecated.", + replacement="to use pip for package installation", + gone_in="25.1", + issue=12330, + ) + + +class Environment(BaseEnvironment): + def __init__(self, paths: Sequence[str]) -> None: + self._paths = paths + + @classmethod + def default(cls) -> BaseEnvironment: + return cls(sys.path) + + @classmethod + def from_paths(cls, paths: Optional[List[str]]) -> BaseEnvironment: + if paths is None: + return cls(sys.path) + return cls(paths) + + def _iter_distributions(self) -> Iterator[BaseDistribution]: + finder = _DistributionFinder() + for location in self._paths: + yield from finder.find(location) + for dist in finder.find_eggs(location): + _emit_egg_deprecation(dist.location) + yield dist + # This must go last because that's how pkg_resources tie-breaks. + yield from finder.find_linked(location) + + def get_distribution(self, name: str) -> Optional[BaseDistribution]: + canonical_name = canonicalize_name(name) + matches = ( + distribution + for distribution in self.iter_all_distributions() + if distribution.canonical_name == canonical_name + ) + return next(matches, None) diff --git a/backend/venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py b/backend/venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py new file mode 100644 index 0000000..4ea84f9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py @@ -0,0 +1,301 @@ +import email.message +import email.parser +import logging +import os +import zipfile +from typing import ( + Collection, + Iterable, + Iterator, + List, + Mapping, + NamedTuple, + Optional, +) + +from pip._vendor import pkg_resources +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.exceptions import InvalidWheel, NoneMetadataError, UnsupportedWheel +from pip._internal.utils.egg_link import egg_link_path_from_location +from pip._internal.utils.misc import display_path, normalize_path +from pip._internal.utils.wheel import parse_wheel, read_wheel_metadata_file + +from .base import ( + BaseDistribution, + BaseEntryPoint, + BaseEnvironment, + InfoPath, + Wheel, +) + +__all__ = ["NAME", "Distribution", "Environment"] + +logger = logging.getLogger(__name__) + +NAME = "pkg_resources" + + +class EntryPoint(NamedTuple): + name: str + value: str + group: str + + +class InMemoryMetadata: + """IMetadataProvider that reads metadata files from a dictionary. + + This also maps metadata decoding exceptions to our internal exception type. + """ + + def __init__(self, metadata: Mapping[str, bytes], wheel_name: str) -> None: + self._metadata = metadata + self._wheel_name = wheel_name + + def has_metadata(self, name: str) -> bool: + return name in self._metadata + + def get_metadata(self, name: str) -> str: + try: + return self._metadata[name].decode() + except UnicodeDecodeError as e: + # Augment the default error with the origin of the file. + raise UnsupportedWheel( + f"Error decoding metadata for {self._wheel_name}: {e} in {name} file" + ) + + def get_metadata_lines(self, name: str) -> Iterable[str]: + return pkg_resources.yield_lines(self.get_metadata(name)) + + def metadata_isdir(self, name: str) -> bool: + return False + + def metadata_listdir(self, name: str) -> List[str]: + return [] + + def run_script(self, script_name: str, namespace: str) -> None: + pass + + +class Distribution(BaseDistribution): + def __init__(self, dist: pkg_resources.Distribution) -> None: + self._dist = dist + # This is populated lazily, to avoid loading metadata for all possible + # distributions eagerly. + self.__extra_mapping: Optional[Mapping[NormalizedName, str]] = None + + @property + def _extra_mapping(self) -> Mapping[NormalizedName, str]: + if self.__extra_mapping is None: + self.__extra_mapping = { + canonicalize_name(extra): extra for extra in self._dist.extras + } + + return self.__extra_mapping + + @classmethod + def from_directory(cls, directory: str) -> BaseDistribution: + dist_dir = directory.rstrip(os.sep) + + # Build a PathMetadata object, from path to metadata. :wink: + base_dir, dist_dir_name = os.path.split(dist_dir) + metadata = pkg_resources.PathMetadata(base_dir, dist_dir) + + # Determine the correct Distribution object type. + if dist_dir.endswith(".egg-info"): + dist_cls = pkg_resources.Distribution + dist_name = os.path.splitext(dist_dir_name)[0] + else: + assert dist_dir.endswith(".dist-info") + dist_cls = pkg_resources.DistInfoDistribution + dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0] + + dist = dist_cls(base_dir, project_name=dist_name, metadata=metadata) + return cls(dist) + + @classmethod + def from_metadata_file_contents( + cls, + metadata_contents: bytes, + filename: str, + project_name: str, + ) -> BaseDistribution: + metadata_dict = { + "METADATA": metadata_contents, + } + dist = pkg_resources.DistInfoDistribution( + location=filename, + metadata=InMemoryMetadata(metadata_dict, filename), + project_name=project_name, + ) + return cls(dist) + + @classmethod + def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution: + try: + with wheel.as_zipfile() as zf: + info_dir, _ = parse_wheel(zf, name) + metadata_dict = { + path.split("/", 1)[-1]: read_wheel_metadata_file(zf, path) + for path in zf.namelist() + if path.startswith(f"{info_dir}/") + } + except zipfile.BadZipFile as e: + raise InvalidWheel(wheel.location, name) from e + except UnsupportedWheel as e: + raise UnsupportedWheel(f"{name} has an invalid wheel, {e}") + dist = pkg_resources.DistInfoDistribution( + location=wheel.location, + metadata=InMemoryMetadata(metadata_dict, wheel.location), + project_name=name, + ) + return cls(dist) + + @property + def location(self) -> Optional[str]: + return self._dist.location + + @property + def installed_location(self) -> Optional[str]: + egg_link = egg_link_path_from_location(self.raw_name) + if egg_link: + location = egg_link + elif self.location: + location = self.location + else: + return None + return normalize_path(location) + + @property + def info_location(self) -> Optional[str]: + return self._dist.egg_info + + @property + def installed_by_distutils(self) -> bool: + # A distutils-installed distribution is provided by FileMetadata. This + # provider has a "path" attribute not present anywhere else. Not the + # best introspection logic, but pip has been doing this for a long time. + try: + return bool(self._dist._provider.path) + except AttributeError: + return False + + @property + def canonical_name(self) -> NormalizedName: + return canonicalize_name(self._dist.project_name) + + @property + def version(self) -> Version: + return parse_version(self._dist.version) + + @property + def raw_version(self) -> str: + return self._dist.version + + def is_file(self, path: InfoPath) -> bool: + return self._dist.has_metadata(str(path)) + + def iter_distutils_script_names(self) -> Iterator[str]: + yield from self._dist.metadata_listdir("scripts") + + def read_text(self, path: InfoPath) -> str: + name = str(path) + if not self._dist.has_metadata(name): + raise FileNotFoundError(name) + content = self._dist.get_metadata(name) + if content is None: + raise NoneMetadataError(self, name) + return content + + def iter_entry_points(self) -> Iterable[BaseEntryPoint]: + for group, entries in self._dist.get_entry_map().items(): + for name, entry_point in entries.items(): + name, _, value = str(entry_point).partition("=") + yield EntryPoint(name=name.strip(), value=value.strip(), group=group) + + def _metadata_impl(self) -> email.message.Message: + """ + :raises NoneMetadataError: if the distribution reports `has_metadata()` + True but `get_metadata()` returns None. + """ + if isinstance(self._dist, pkg_resources.DistInfoDistribution): + metadata_name = "METADATA" + else: + metadata_name = "PKG-INFO" + try: + metadata = self.read_text(metadata_name) + except FileNotFoundError: + if self.location: + displaying_path = display_path(self.location) + else: + displaying_path = repr(self.location) + logger.warning("No metadata found in %s", displaying_path) + metadata = "" + feed_parser = email.parser.FeedParser() + feed_parser.feed(metadata) + return feed_parser.close() + + def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]: + if extras: + relevant_extras = set(self._extra_mapping) & set( + map(canonicalize_name, extras) + ) + extras = [self._extra_mapping[extra] for extra in relevant_extras] + return self._dist.requires(extras) + + def iter_provided_extras(self) -> Iterable[NormalizedName]: + return self._extra_mapping.keys() + + +class Environment(BaseEnvironment): + def __init__(self, ws: pkg_resources.WorkingSet) -> None: + self._ws = ws + + @classmethod + def default(cls) -> BaseEnvironment: + return cls(pkg_resources.working_set) + + @classmethod + def from_paths(cls, paths: Optional[List[str]]) -> BaseEnvironment: + return cls(pkg_resources.WorkingSet(paths)) + + def _iter_distributions(self) -> Iterator[BaseDistribution]: + for dist in self._ws: + yield Distribution(dist) + + def _search_distribution(self, name: str) -> Optional[BaseDistribution]: + """Find a distribution matching the ``name`` in the environment. + + This searches from *all* distributions available in the environment, to + match the behavior of ``pkg_resources.get_distribution()``. + """ + canonical_name = canonicalize_name(name) + for dist in self.iter_all_distributions(): + if dist.canonical_name == canonical_name: + return dist + return None + + def get_distribution(self, name: str) -> Optional[BaseDistribution]: + # Search the distribution by looking through the working set. + dist = self._search_distribution(name) + if dist: + return dist + + # If distribution could not be found, call working_set.require to + # update the working set, and try to find the distribution again. + # This might happen for e.g. when you install a package twice, once + # using setup.py develop and again using setup.py install. Now when + # running pip uninstall twice, the package gets removed from the + # working set in the first uninstall, so we have to populate the + # working set again so that pip knows about it and the packages gets + # picked up and is successfully uninstalled the second time too. + try: + # We didn't pass in any version specifiers, so this can never + # raise pkg_resources.VersionConflict. + self._ws.require(name) + except pkg_resources.DistributionNotFound: + return None + return self._search_distribution(name) diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/models/__init__.py new file mode 100644 index 0000000..7855226 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/__init__.py @@ -0,0 +1,2 @@ +"""A package that contains models that represent entities. +""" diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67b37a02e19de328ac61b6100aecbf19b2019a76 GIT binary patch literal 270 zcmXv}OG*Pl5bcgZLm+o($SMmnTM<#jtz_X+8k$abF&0jLsBR&V?M-gIREGGE_J5Vk_`c4t6x)cDFh$~ z2IGd86ZLw{{~&tJc%$!etqWE-Kd2}=V{Ul50!7<3dl`*k2CFg4+;1mWOulq*O{e^H TFjfZNKPOVk-;tDK8Z-O{bZN(`Ojj9calmM68x>Zh3%tbu$!q7_~!&xsP0i;el z(+jl4D5p`vP0wt_3826W&9nY6TE(&3S{7GluuD4jc z%)DkZh?eW0#IYYYo0R#~4Wcz5A!hCRlIP!`5vjv`t$sOJs`DVBZ?wSbEmK}^1+6KF zPAH4KaH<&-8uF=rT*-bwVc06e4pQ@Ft+f2Lg(40USe!J*Cb1p{VBF}=i0vBkurVPTdXQRHT_8t7C9`UG{I z$$u+N<~|9r{5+_2w0CU0XWg~#Ozxb%ur>YF%$GA;_O`OU_|5gNuWx_w?aiIBD?7#& zHV(m7Mbuv05$KJw>jF8ep}79Plf#6FlykW3gS9H0!_rem(_MNtgh1-BKf zOq76$YO)hTO@MlcvaPbyu#&I}B|bg}>QnTya_N^BUR$60sa(A^w^yw_QEGeTqqpAg zE3!JZakYY>{kuoD77qU&iVJ-Z=g{5@WuLSa;qkrImvhk8&ocO(&rbZRq@n z#LUi{6I$9Xh{!V+w~`$b(GywpuxstSYwhg$$c`uWVP}LAbdP48XXwmx^yV}4&U5tYzJ{dAopZbR#XqDmyny>i=z)x+llz$=Tk|hV*@Z^{ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd9d664886da9d5b1daf419dfc62608ee4ce1d27 GIT binary patch literal 10848 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 MpyR*Rny3W+KOuS5y8r+H literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83b1121e754e5d7298961a4541aabfece8337eac GIT binary patch literal 4227 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa91ac5796c1c1d471abf8b642e02e9d72e15755 GIT binary patch literal 2281 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 Uv)dx+F8Cc(@P;4KXNKzk8%8c9NdN!< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ab5712e2ae3cef0076f5e8a11b747fd77b3bc9b GIT binary patch literal 1027 zcmZWo&1(}u6rbIEHZg4lKYH*mSV01sfZj?`v{YNHMXVkSfn~Duk{#ULS!X6m(^J8E z_vYQ3RQv<{7rc6qJ&B&YH53s%`DXKh=!5;u@6En9``&NfeyY_f1a0-hV{zLhhRDRe_>Q1`AnPGm2)z=GYDZzR}(LvHzkdXiw2c^@J_LWGC zPV+Y531$|%N*+M$PbJBg+|-#04W#9u*zQx5yOo1{s{lnPad#cVGM1aO{G1i$tZ3P& zR4=E+y-dIZbB9hC4P?kQO_&KZ9R|V=C{sZD8s%r&szy6Z1LZ=2Z=@1F|2gYHBa2sgEJN8DQbh|T3uS~|tgP&LF^j_=jl)yjr%!mRJ!DOERLngCI)xkkyHEz`Q6!A zYbQ$f6pJDe_u4}#eHlfdeDFj(fEe2wwL4fb#Jr9EpuHnHZ7uN5r+w&lB9bOXXR{DC zu}%neb261ULaJ(8vQWcEUqyID#(B3;J}Hy4mkzhT)|OxHeEA0|wWDoyewMjgFQ_GS z(&~JoKr1^CYIzo;&RLeFT(F_#^@(D))C#)xuhTaWPI8XpjNO8h|G7w<%ik979#+Ri c;#OZ@`RrW$Bks!By4jh30OV~Yn*aa+ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae12b08db8c49859402b8ca5acef55e302cf40e5 GIT binary patch literal 4991 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 Kt(OQ)n)WXeMi1iv literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51e9bd3b795e9810c9340a03d4ecd1694ddfd4f6 GIT binary patch literal 4957 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 Z-^e3>CqMc#IsLC5TM&+YPO#*={SV__-8ldN literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35b5420a5a7545932e2777f6c680b2952b4bcb02 GIT binary patch literal 6556 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/candidate.py b/backend/venv/Lib/site-packages/pip/_internal/models/candidate.py new file mode 100644 index 0000000..f27f283 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/candidate.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass + +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.models.link import Link + + +@dataclass(frozen=True) +class InstallationCandidate: + """Represents a potential "candidate" for installation.""" + + __slots__ = ["name", "version", "link"] + + name: str + version: Version + link: Link + + def __init__(self, name: str, version: str, link: Link) -> None: + object.__setattr__(self, "name", name) + object.__setattr__(self, "version", parse_version(version)) + object.__setattr__(self, "link", link) + + def __str__(self) -> str: + return f"{self.name!r} candidate (version {self.version} at {self.link})" diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/direct_url.py b/backend/venv/Lib/site-packages/pip/_internal/models/direct_url.py new file mode 100644 index 0000000..fc5ec8d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/direct_url.py @@ -0,0 +1,224 @@ +""" PEP 610 """ + +import json +import re +import urllib.parse +from dataclasses import dataclass +from typing import Any, ClassVar, Dict, Iterable, Optional, Type, TypeVar, Union + +__all__ = [ + "DirectUrl", + "DirectUrlValidationError", + "DirInfo", + "ArchiveInfo", + "VcsInfo", +] + +T = TypeVar("T") + +DIRECT_URL_METADATA_NAME = "direct_url.json" +ENV_VAR_RE = re.compile(r"^\$\{[A-Za-z0-9-_]+\}(:\$\{[A-Za-z0-9-_]+\})?$") + + +class DirectUrlValidationError(Exception): + pass + + +def _get( + d: Dict[str, Any], expected_type: Type[T], key: str, default: Optional[T] = None +) -> Optional[T]: + """Get value from dictionary and verify expected type.""" + if key not in d: + return default + value = d[key] + if not isinstance(value, expected_type): + raise DirectUrlValidationError( + f"{value!r} has unexpected type for {key} (expected {expected_type})" + ) + return value + + +def _get_required( + d: Dict[str, Any], expected_type: Type[T], key: str, default: Optional[T] = None +) -> T: + value = _get(d, expected_type, key, default) + if value is None: + raise DirectUrlValidationError(f"{key} must have a value") + return value + + +def _exactly_one_of(infos: Iterable[Optional["InfoType"]]) -> "InfoType": + infos = [info for info in infos if info is not None] + if not infos: + raise DirectUrlValidationError( + "missing one of archive_info, dir_info, vcs_info" + ) + if len(infos) > 1: + raise DirectUrlValidationError( + "more than one of archive_info, dir_info, vcs_info" + ) + assert infos[0] is not None + return infos[0] + + +def _filter_none(**kwargs: Any) -> Dict[str, Any]: + """Make dict excluding None values.""" + return {k: v for k, v in kwargs.items() if v is not None} + + +@dataclass +class VcsInfo: + name: ClassVar = "vcs_info" + + vcs: str + commit_id: str + requested_revision: Optional[str] = None + + @classmethod + def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["VcsInfo"]: + if d is None: + return None + return cls( + vcs=_get_required(d, str, "vcs"), + commit_id=_get_required(d, str, "commit_id"), + requested_revision=_get(d, str, "requested_revision"), + ) + + def _to_dict(self) -> Dict[str, Any]: + return _filter_none( + vcs=self.vcs, + requested_revision=self.requested_revision, + commit_id=self.commit_id, + ) + + +class ArchiveInfo: + name = "archive_info" + + def __init__( + self, + hash: Optional[str] = None, + hashes: Optional[Dict[str, str]] = None, + ) -> None: + # set hashes before hash, since the hash setter will further populate hashes + self.hashes = hashes + self.hash = hash + + @property + def hash(self) -> Optional[str]: + return self._hash + + @hash.setter + def hash(self, value: Optional[str]) -> None: + if value is not None: + # Auto-populate the hashes key to upgrade to the new format automatically. + # We don't back-populate the legacy hash key from hashes. + try: + hash_name, hash_value = value.split("=", 1) + except ValueError: + raise DirectUrlValidationError( + f"invalid archive_info.hash format: {value!r}" + ) + if self.hashes is None: + self.hashes = {hash_name: hash_value} + elif hash_name not in self.hashes: + self.hashes = self.hashes.copy() + self.hashes[hash_name] = hash_value + self._hash = value + + @classmethod + def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["ArchiveInfo"]: + if d is None: + return None + return cls(hash=_get(d, str, "hash"), hashes=_get(d, dict, "hashes")) + + def _to_dict(self) -> Dict[str, Any]: + return _filter_none(hash=self.hash, hashes=self.hashes) + + +@dataclass +class DirInfo: + name: ClassVar = "dir_info" + + editable: bool = False + + @classmethod + def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["DirInfo"]: + if d is None: + return None + return cls(editable=_get_required(d, bool, "editable", default=False)) + + def _to_dict(self) -> Dict[str, Any]: + return _filter_none(editable=self.editable or None) + + +InfoType = Union[ArchiveInfo, DirInfo, VcsInfo] + + +@dataclass +class DirectUrl: + url: str + info: InfoType + subdirectory: Optional[str] = None + + def _remove_auth_from_netloc(self, netloc: str) -> str: + if "@" not in netloc: + return netloc + user_pass, netloc_no_user_pass = netloc.split("@", 1) + if ( + isinstance(self.info, VcsInfo) + and self.info.vcs == "git" + and user_pass == "git" + ): + return netloc + if ENV_VAR_RE.match(user_pass): + return netloc + return netloc_no_user_pass + + @property + def redacted_url(self) -> str: + """url with user:password part removed unless it is formed with + environment variables as specified in PEP 610, or it is ``git`` + in the case of a git URL. + """ + purl = urllib.parse.urlsplit(self.url) + netloc = self._remove_auth_from_netloc(purl.netloc) + surl = urllib.parse.urlunsplit( + (purl.scheme, netloc, purl.path, purl.query, purl.fragment) + ) + return surl + + def validate(self) -> None: + self.from_dict(self.to_dict()) + + @classmethod + def from_dict(cls, d: Dict[str, Any]) -> "DirectUrl": + return DirectUrl( + url=_get_required(d, str, "url"), + subdirectory=_get(d, str, "subdirectory"), + info=_exactly_one_of( + [ + ArchiveInfo._from_dict(_get(d, dict, "archive_info")), + DirInfo._from_dict(_get(d, dict, "dir_info")), + VcsInfo._from_dict(_get(d, dict, "vcs_info")), + ] + ), + ) + + def to_dict(self) -> Dict[str, Any]: + res = _filter_none( + url=self.redacted_url, + subdirectory=self.subdirectory, + ) + res[self.info.name] = self.info._to_dict() + return res + + @classmethod + def from_json(cls, s: str) -> "DirectUrl": + return cls.from_dict(json.loads(s)) + + def to_json(self) -> str: + return json.dumps(self.to_dict(), sort_keys=True) + + def is_local_editable(self) -> bool: + return isinstance(self.info, DirInfo) and self.info.editable diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/format_control.py b/backend/venv/Lib/site-packages/pip/_internal/models/format_control.py new file mode 100644 index 0000000..ccd1127 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/format_control.py @@ -0,0 +1,78 @@ +from typing import FrozenSet, Optional, Set + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import CommandError + + +class FormatControl: + """Helper for managing formats from which a package can be installed.""" + + __slots__ = ["no_binary", "only_binary"] + + def __init__( + self, + no_binary: Optional[Set[str]] = None, + only_binary: Optional[Set[str]] = None, + ) -> None: + if no_binary is None: + no_binary = set() + if only_binary is None: + only_binary = set() + + self.no_binary = no_binary + self.only_binary = only_binary + + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + return NotImplemented + + if self.__slots__ != other.__slots__: + return False + + return all(getattr(self, k) == getattr(other, k) for k in self.__slots__) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.no_binary}, {self.only_binary})" + + @staticmethod + def handle_mutual_excludes(value: str, target: Set[str], other: Set[str]) -> None: + if value.startswith("-"): + raise CommandError( + "--no-binary / --only-binary option requires 1 argument." + ) + new = value.split(",") + while ":all:" in new: + other.clear() + target.clear() + target.add(":all:") + del new[: new.index(":all:") + 1] + # Without a none, we want to discard everything as :all: covers it + if ":none:" not in new: + return + for name in new: + if name == ":none:": + target.clear() + continue + name = canonicalize_name(name) + other.discard(name) + target.add(name) + + def get_allowed_formats(self, canonical_name: str) -> FrozenSet[str]: + result = {"binary", "source"} + if canonical_name in self.only_binary: + result.discard("source") + elif canonical_name in self.no_binary: + result.discard("binary") + elif ":all:" in self.only_binary: + result.discard("source") + elif ":all:" in self.no_binary: + result.discard("binary") + return frozenset(result) + + def disallow_binaries(self) -> None: + self.handle_mutual_excludes( + ":all:", + self.no_binary, + self.only_binary, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/index.py b/backend/venv/Lib/site-packages/pip/_internal/models/index.py new file mode 100644 index 0000000..b94c325 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/index.py @@ -0,0 +1,28 @@ +import urllib.parse + + +class PackageIndex: + """Represents a Package Index and provides easier access to endpoints""" + + __slots__ = ["url", "netloc", "simple_url", "pypi_url", "file_storage_domain"] + + def __init__(self, url: str, file_storage_domain: str) -> None: + super().__init__() + self.url = url + self.netloc = urllib.parse.urlsplit(url).netloc + self.simple_url = self._url_for_path("simple") + self.pypi_url = self._url_for_path("pypi") + + # This is part of a temporary hack used to block installs of PyPI + # packages which depend on external urls only necessary until PyPI can + # block such packages themselves + self.file_storage_domain = file_storage_domain + + def _url_for_path(self, path: str) -> str: + return urllib.parse.urljoin(self.url, path) + + +PyPI = PackageIndex("https://pypi.org/", file_storage_domain="files.pythonhosted.org") +TestPyPI = PackageIndex( + "https://test.pypi.org/", file_storage_domain="test-files.pythonhosted.org" +) diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/installation_report.py b/backend/venv/Lib/site-packages/pip/_internal/models/installation_report.py new file mode 100644 index 0000000..b9c6330 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/installation_report.py @@ -0,0 +1,56 @@ +from typing import Any, Dict, Sequence + +from pip._vendor.packaging.markers import default_environment + +from pip import __version__ +from pip._internal.req.req_install import InstallRequirement + + +class InstallationReport: + def __init__(self, install_requirements: Sequence[InstallRequirement]): + self._install_requirements = install_requirements + + @classmethod + def _install_req_to_dict(cls, ireq: InstallRequirement) -> Dict[str, Any]: + assert ireq.download_info, f"No download_info for {ireq}" + res = { + # PEP 610 json for the download URL. download_info.archive_info.hashes may + # be absent when the requirement was installed from the wheel cache + # and the cache entry was populated by an older pip version that did not + # record origin.json. + "download_info": ireq.download_info.to_dict(), + # is_direct is true if the requirement was a direct URL reference (which + # includes editable requirements), and false if the requirement was + # downloaded from a PEP 503 index or --find-links. + "is_direct": ireq.is_direct, + # is_yanked is true if the requirement was yanked from the index, but + # was still selected by pip to conform to PEP 592. + "is_yanked": ireq.link.is_yanked if ireq.link else False, + # requested is true if the requirement was specified by the user (aka + # top level requirement), and false if it was installed as a dependency of a + # requirement. https://peps.python.org/pep-0376/#requested + "requested": ireq.user_supplied, + # PEP 566 json encoding for metadata + # https://www.python.org/dev/peps/pep-0566/#json-compatible-metadata + "metadata": ireq.get_dist().metadata_dict, + } + if ireq.user_supplied and ireq.extras: + # For top level requirements, the list of requested extras, if any. + res["requested_extras"] = sorted(ireq.extras) + return res + + def to_dict(self) -> Dict[str, Any]: + return { + "version": "1", + "pip_version": __version__, + "install": [ + self._install_req_to_dict(ireq) for ireq in self._install_requirements + ], + # https://peps.python.org/pep-0508/#environment-markers + # TODO: currently, the resolver uses the default environment to evaluate + # environment markers, so that is what we report here. In the future, it + # should also take into account options such as --python-version or + # --platform, perhaps under the form of an environment_override field? + # https://github.com/pypa/pip/issues/11198 + "environment": default_environment(), + } diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/link.py b/backend/venv/Lib/site-packages/pip/_internal/models/link.py new file mode 100644 index 0000000..27ad016 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/link.py @@ -0,0 +1,604 @@ +import functools +import itertools +import logging +import os +import posixpath +import re +import urllib.parse +from dataclasses import dataclass +from typing import ( + TYPE_CHECKING, + Any, + Dict, + List, + Mapping, + NamedTuple, + Optional, + Tuple, + Union, +) + +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.filetypes import WHEEL_EXTENSION +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.misc import ( + pairwise, + redact_auth_from_url, + split_auth_from_netloc, + splitext, +) +from pip._internal.utils.urls import path_to_url, url_to_path + +if TYPE_CHECKING: + from pip._internal.index.collector import IndexContent + +logger = logging.getLogger(__name__) + + +# Order matters, earlier hashes have a precedence over later hashes for what +# we will pick to use. +_SUPPORTED_HASHES = ("sha512", "sha384", "sha256", "sha224", "sha1", "md5") + + +@dataclass(frozen=True) +class LinkHash: + """Links to content may have embedded hash values. This class parses those. + + `name` must be any member of `_SUPPORTED_HASHES`. + + This class can be converted to and from `ArchiveInfo`. While ArchiveInfo intends to + be JSON-serializable to conform to PEP 610, this class contains the logic for + parsing a hash name and value for correctness, and then checking whether that hash + conforms to a schema with `.is_hash_allowed()`.""" + + name: str + value: str + + _hash_url_fragment_re = re.compile( + # NB: we do not validate that the second group (.*) is a valid hex + # digest. Instead, we simply keep that string in this class, and then check it + # against Hashes when hash-checking is needed. This is easier to debug than + # proactively discarding an invalid hex digest, as we handle incorrect hashes + # and malformed hashes in the same place. + r"[#&]({choices})=([^&]*)".format( + choices="|".join(re.escape(hash_name) for hash_name in _SUPPORTED_HASHES) + ), + ) + + def __post_init__(self) -> None: + assert self.name in _SUPPORTED_HASHES + + @classmethod + @functools.lru_cache(maxsize=None) + def find_hash_url_fragment(cls, url: str) -> Optional["LinkHash"]: + """Search a string for a checksum algorithm name and encoded output value.""" + match = cls._hash_url_fragment_re.search(url) + if match is None: + return None + name, value = match.groups() + return cls(name=name, value=value) + + def as_dict(self) -> Dict[str, str]: + return {self.name: self.value} + + def as_hashes(self) -> Hashes: + """Return a Hashes instance which checks only for the current hash.""" + return Hashes({self.name: [self.value]}) + + def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool: + """ + Return True if the current hash is allowed by `hashes`. + """ + if hashes is None: + return False + return hashes.is_hash_allowed(self.name, hex_digest=self.value) + + +@dataclass(frozen=True) +class MetadataFile: + """Information about a core metadata file associated with a distribution.""" + + hashes: Optional[Dict[str, str]] + + def __post_init__(self) -> None: + if self.hashes is not None: + assert all(name in _SUPPORTED_HASHES for name in self.hashes) + + +def supported_hashes(hashes: Optional[Dict[str, str]]) -> Optional[Dict[str, str]]: + # Remove any unsupported hash types from the mapping. If this leaves no + # supported hashes, return None + if hashes is None: + return None + hashes = {n: v for n, v in hashes.items() if n in _SUPPORTED_HASHES} + if not hashes: + return None + return hashes + + +def _clean_url_path_part(part: str) -> str: + """ + Clean a "part" of a URL path (i.e. after splitting on "@" characters). + """ + # We unquote prior to quoting to make sure nothing is double quoted. + return urllib.parse.quote(urllib.parse.unquote(part)) + + +def _clean_file_url_path(part: str) -> str: + """ + Clean the first part of a URL path that corresponds to a local + filesystem path (i.e. the first part after splitting on "@" characters). + """ + # We unquote prior to quoting to make sure nothing is double quoted. + # Also, on Windows the path part might contain a drive letter which + # should not be quoted. On Linux where drive letters do not + # exist, the colon should be quoted. We rely on urllib.request + # to do the right thing here. + return urllib.request.pathname2url(urllib.request.url2pathname(part)) + + +# percent-encoded: / +_reserved_chars_re = re.compile("(@|%2F)", re.IGNORECASE) + + +def _clean_url_path(path: str, is_local_path: bool) -> str: + """ + Clean the path portion of a URL. + """ + if is_local_path: + clean_func = _clean_file_url_path + else: + clean_func = _clean_url_path_part + + # Split on the reserved characters prior to cleaning so that + # revision strings in VCS URLs are properly preserved. + parts = _reserved_chars_re.split(path) + + cleaned_parts = [] + for to_clean, reserved in pairwise(itertools.chain(parts, [""])): + cleaned_parts.append(clean_func(to_clean)) + # Normalize %xx escapes (e.g. %2f -> %2F) + cleaned_parts.append(reserved.upper()) + + return "".join(cleaned_parts) + + +def _ensure_quoted_url(url: str) -> str: + """ + Make sure a link is fully quoted. + For example, if ' ' occurs in the URL, it will be replaced with "%20", + and without double-quoting other characters. + """ + # Split the URL into parts according to the general structure + # `scheme://netloc/path?query#fragment`. + result = urllib.parse.urlsplit(url) + # If the netloc is empty, then the URL refers to a local filesystem path. + is_local_path = not result.netloc + path = _clean_url_path(result.path, is_local_path=is_local_path) + return urllib.parse.urlunsplit(result._replace(path=path)) + + +def _absolute_link_url(base_url: str, url: str) -> str: + """ + A faster implementation of urllib.parse.urljoin with a shortcut + for absolute http/https URLs. + """ + if url.startswith(("https://", "http://")): + return url + else: + return urllib.parse.urljoin(base_url, url) + + +@functools.total_ordering +class Link: + """Represents a parsed link from a Package Index's simple URL""" + + __slots__ = [ + "_parsed_url", + "_url", + "_path", + "_hashes", + "comes_from", + "requires_python", + "yanked_reason", + "metadata_file_data", + "cache_link_parsing", + "egg_fragment", + ] + + def __init__( + self, + url: str, + comes_from: Optional[Union[str, "IndexContent"]] = None, + requires_python: Optional[str] = None, + yanked_reason: Optional[str] = None, + metadata_file_data: Optional[MetadataFile] = None, + cache_link_parsing: bool = True, + hashes: Optional[Mapping[str, str]] = None, + ) -> None: + """ + :param url: url of the resource pointed to (href of the link) + :param comes_from: instance of IndexContent where the link was found, + or string. + :param requires_python: String containing the `Requires-Python` + metadata field, specified in PEP 345. This may be specified by + a data-requires-python attribute in the HTML link tag, as + described in PEP 503. + :param yanked_reason: the reason the file has been yanked, if the + file has been yanked, or None if the file hasn't been yanked. + This is the value of the "data-yanked" attribute, if present, in + a simple repository HTML link. If the file has been yanked but + no reason was provided, this should be the empty string. See + PEP 592 for more information and the specification. + :param metadata_file_data: the metadata attached to the file, or None if + no such metadata is provided. This argument, if not None, indicates + that a separate metadata file exists, and also optionally supplies + hashes for that file. + :param cache_link_parsing: A flag that is used elsewhere to determine + whether resources retrieved from this link should be cached. PyPI + URLs should generally have this set to False, for example. + :param hashes: A mapping of hash names to digests to allow us to + determine the validity of a download. + """ + + # The comes_from, requires_python, and metadata_file_data arguments are + # only used by classmethods of this class, and are not used in client + # code directly. + + # url can be a UNC windows share + if url.startswith("\\\\"): + url = path_to_url(url) + + self._parsed_url = urllib.parse.urlsplit(url) + # Store the url as a private attribute to prevent accidentally + # trying to set a new value. + self._url = url + # The .path property is hot, so calculate its value ahead of time. + self._path = urllib.parse.unquote(self._parsed_url.path) + + link_hash = LinkHash.find_hash_url_fragment(url) + hashes_from_link = {} if link_hash is None else link_hash.as_dict() + if hashes is None: + self._hashes = hashes_from_link + else: + self._hashes = {**hashes, **hashes_from_link} + + self.comes_from = comes_from + self.requires_python = requires_python if requires_python else None + self.yanked_reason = yanked_reason + self.metadata_file_data = metadata_file_data + + self.cache_link_parsing = cache_link_parsing + self.egg_fragment = self._egg_fragment() + + @classmethod + def from_json( + cls, + file_data: Dict[str, Any], + page_url: str, + ) -> Optional["Link"]: + """ + Convert an pypi json document from a simple repository page into a Link. + """ + file_url = file_data.get("url") + if file_url is None: + return None + + url = _ensure_quoted_url(_absolute_link_url(page_url, file_url)) + pyrequire = file_data.get("requires-python") + yanked_reason = file_data.get("yanked") + hashes = file_data.get("hashes", {}) + + # PEP 714: Indexes must use the name core-metadata, but + # clients should support the old name as a fallback for compatibility. + metadata_info = file_data.get("core-metadata") + if metadata_info is None: + metadata_info = file_data.get("dist-info-metadata") + + # The metadata info value may be a boolean, or a dict of hashes. + if isinstance(metadata_info, dict): + # The file exists, and hashes have been supplied + metadata_file_data = MetadataFile(supported_hashes(metadata_info)) + elif metadata_info: + # The file exists, but there are no hashes + metadata_file_data = MetadataFile(None) + else: + # False or not present: the file does not exist + metadata_file_data = None + + # The Link.yanked_reason expects an empty string instead of a boolean. + if yanked_reason and not isinstance(yanked_reason, str): + yanked_reason = "" + # The Link.yanked_reason expects None instead of False. + elif not yanked_reason: + yanked_reason = None + + return cls( + url, + comes_from=page_url, + requires_python=pyrequire, + yanked_reason=yanked_reason, + hashes=hashes, + metadata_file_data=metadata_file_data, + ) + + @classmethod + def from_element( + cls, + anchor_attribs: Dict[str, Optional[str]], + page_url: str, + base_url: str, + ) -> Optional["Link"]: + """ + Convert an anchor element's attributes in a simple repository page to a Link. + """ + href = anchor_attribs.get("href") + if not href: + return None + + url = _ensure_quoted_url(_absolute_link_url(base_url, href)) + pyrequire = anchor_attribs.get("data-requires-python") + yanked_reason = anchor_attribs.get("data-yanked") + + # PEP 714: Indexes must use the name data-core-metadata, but + # clients should support the old name as a fallback for compatibility. + metadata_info = anchor_attribs.get("data-core-metadata") + if metadata_info is None: + metadata_info = anchor_attribs.get("data-dist-info-metadata") + # The metadata info value may be the string "true", or a string of + # the form "hashname=hashval" + if metadata_info == "true": + # The file exists, but there are no hashes + metadata_file_data = MetadataFile(None) + elif metadata_info is None: + # The file does not exist + metadata_file_data = None + else: + # The file exists, and hashes have been supplied + hashname, sep, hashval = metadata_info.partition("=") + if sep == "=": + metadata_file_data = MetadataFile(supported_hashes({hashname: hashval})) + else: + # Error - data is wrong. Treat as no hashes supplied. + logger.debug( + "Index returned invalid data-dist-info-metadata value: %s", + metadata_info, + ) + metadata_file_data = MetadataFile(None) + + return cls( + url, + comes_from=page_url, + requires_python=pyrequire, + yanked_reason=yanked_reason, + metadata_file_data=metadata_file_data, + ) + + def __str__(self) -> str: + if self.requires_python: + rp = f" (requires-python:{self.requires_python})" + else: + rp = "" + if self.comes_from: + return f"{redact_auth_from_url(self._url)} (from {self.comes_from}){rp}" + else: + return redact_auth_from_url(str(self._url)) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash(self.url) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Link): + return NotImplemented + return self.url == other.url + + def __lt__(self, other: Any) -> bool: + if not isinstance(other, Link): + return NotImplemented + return self.url < other.url + + @property + def url(self) -> str: + return self._url + + @property + def filename(self) -> str: + path = self.path.rstrip("/") + name = posixpath.basename(path) + if not name: + # Make sure we don't leak auth information if the netloc + # includes a username and password. + netloc, user_pass = split_auth_from_netloc(self.netloc) + return netloc + + name = urllib.parse.unquote(name) + assert name, f"URL {self._url!r} produced no filename" + return name + + @property + def file_path(self) -> str: + return url_to_path(self.url) + + @property + def scheme(self) -> str: + return self._parsed_url.scheme + + @property + def netloc(self) -> str: + """ + This can contain auth information. + """ + return self._parsed_url.netloc + + @property + def path(self) -> str: + return self._path + + def splitext(self) -> Tuple[str, str]: + return splitext(posixpath.basename(self.path.rstrip("/"))) + + @property + def ext(self) -> str: + return self.splitext()[1] + + @property + def url_without_fragment(self) -> str: + scheme, netloc, path, query, fragment = self._parsed_url + return urllib.parse.urlunsplit((scheme, netloc, path, query, "")) + + _egg_fragment_re = re.compile(r"[#&]egg=([^&]*)") + + # Per PEP 508. + _project_name_re = re.compile( + r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE + ) + + def _egg_fragment(self) -> Optional[str]: + match = self._egg_fragment_re.search(self._url) + if not match: + return None + + # An egg fragment looks like a PEP 508 project name, along with + # an optional extras specifier. Anything else is invalid. + project_name = match.group(1) + if not self._project_name_re.match(project_name): + deprecated( + reason=f"{self} contains an egg fragment with a non-PEP 508 name.", + replacement="to use the req @ url syntax, and remove the egg fragment", + gone_in="25.1", + issue=13157, + ) + + return project_name + + _subdirectory_fragment_re = re.compile(r"[#&]subdirectory=([^&]*)") + + @property + def subdirectory_fragment(self) -> Optional[str]: + match = self._subdirectory_fragment_re.search(self._url) + if not match: + return None + return match.group(1) + + def metadata_link(self) -> Optional["Link"]: + """Return a link to the associated core metadata file (if any).""" + if self.metadata_file_data is None: + return None + metadata_url = f"{self.url_without_fragment}.metadata" + if self.metadata_file_data.hashes is None: + return Link(metadata_url) + return Link(metadata_url, hashes=self.metadata_file_data.hashes) + + def as_hashes(self) -> Hashes: + return Hashes({k: [v] for k, v in self._hashes.items()}) + + @property + def hash(self) -> Optional[str]: + return next(iter(self._hashes.values()), None) + + @property + def hash_name(self) -> Optional[str]: + return next(iter(self._hashes), None) + + @property + def show_url(self) -> str: + return posixpath.basename(self._url.split("#", 1)[0].split("?", 1)[0]) + + @property + def is_file(self) -> bool: + return self.scheme == "file" + + def is_existing_dir(self) -> bool: + return self.is_file and os.path.isdir(self.file_path) + + @property + def is_wheel(self) -> bool: + return self.ext == WHEEL_EXTENSION + + @property + def is_vcs(self) -> bool: + from pip._internal.vcs import vcs + + return self.scheme in vcs.all_schemes + + @property + def is_yanked(self) -> bool: + return self.yanked_reason is not None + + @property + def has_hash(self) -> bool: + return bool(self._hashes) + + def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool: + """ + Return True if the link has a hash and it is allowed by `hashes`. + """ + if hashes is None: + return False + return any(hashes.is_hash_allowed(k, v) for k, v in self._hashes.items()) + + +class _CleanResult(NamedTuple): + """Convert link for equivalency check. + + This is used in the resolver to check whether two URL-specified requirements + likely point to the same distribution and can be considered equivalent. This + equivalency logic avoids comparing URLs literally, which can be too strict + (e.g. "a=1&b=2" vs "b=2&a=1") and produce conflicts unexpecting to users. + + Currently this does three things: + + 1. Drop the basic auth part. This is technically wrong since a server can + serve different content based on auth, but if it does that, it is even + impossible to guarantee two URLs without auth are equivalent, since + the user can input different auth information when prompted. So the + practical solution is to assume the auth doesn't affect the response. + 2. Parse the query to avoid the ordering issue. Note that ordering under the + same key in the query are NOT cleaned; i.e. "a=1&a=2" and "a=2&a=1" are + still considered different. + 3. Explicitly drop most of the fragment part, except ``subdirectory=`` and + hash values, since it should have no impact the downloaded content. Note + that this drops the "egg=" part historically used to denote the requested + project (and extras), which is wrong in the strictest sense, but too many + people are supplying it inconsistently to cause superfluous resolution + conflicts, so we choose to also ignore them. + """ + + parsed: urllib.parse.SplitResult + query: Dict[str, List[str]] + subdirectory: str + hashes: Dict[str, str] + + +def _clean_link(link: Link) -> _CleanResult: + parsed = link._parsed_url + netloc = parsed.netloc.rsplit("@", 1)[-1] + # According to RFC 8089, an empty host in file: means localhost. + if parsed.scheme == "file" and not netloc: + netloc = "localhost" + fragment = urllib.parse.parse_qs(parsed.fragment) + if "egg" in fragment: + logger.debug("Ignoring egg= fragment in %s", link) + try: + # If there are multiple subdirectory values, use the first one. + # This matches the behavior of Link.subdirectory_fragment. + subdirectory = fragment["subdirectory"][0] + except (IndexError, KeyError): + subdirectory = "" + # If there are multiple hash values under the same algorithm, use the + # first one. This matches the behavior of Link.hash_value. + hashes = {k: fragment[k][0] for k in _SUPPORTED_HASHES if k in fragment} + return _CleanResult( + parsed=parsed._replace(netloc=netloc, query="", fragment=""), + query=urllib.parse.parse_qs(parsed.query), + subdirectory=subdirectory, + hashes=hashes, + ) + + +@functools.lru_cache(maxsize=None) +def links_equivalent(link1: Link, link2: Link) -> bool: + return _clean_link(link1) == _clean_link(link2) diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/scheme.py b/backend/venv/Lib/site-packages/pip/_internal/models/scheme.py new file mode 100644 index 0000000..06a9a55 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/scheme.py @@ -0,0 +1,25 @@ +""" +For types associated with installation schemes. + +For a general overview of available schemes and their context, see +https://docs.python.org/3/install/index.html#alternate-installation. +""" + +from dataclasses import dataclass + +SCHEME_KEYS = ["platlib", "purelib", "headers", "scripts", "data"] + + +@dataclass(frozen=True) +class Scheme: + """A Scheme holds paths which are used as the base directories for + artifacts associated with a Python package. + """ + + __slots__ = SCHEME_KEYS + + platlib: str + purelib: str + headers: str + scripts: str + data: str diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/search_scope.py b/backend/venv/Lib/site-packages/pip/_internal/models/search_scope.py new file mode 100644 index 0000000..ee7bc86 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/search_scope.py @@ -0,0 +1,127 @@ +import itertools +import logging +import os +import posixpath +import urllib.parse +from dataclasses import dataclass +from typing import List + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.models.index import PyPI +from pip._internal.utils.compat import has_tls +from pip._internal.utils.misc import normalize_path, redact_auth_from_url + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class SearchScope: + """ + Encapsulates the locations that pip is configured to search. + """ + + __slots__ = ["find_links", "index_urls", "no_index"] + + find_links: List[str] + index_urls: List[str] + no_index: bool + + @classmethod + def create( + cls, + find_links: List[str], + index_urls: List[str], + no_index: bool, + ) -> "SearchScope": + """ + Create a SearchScope object after normalizing the `find_links`. + """ + # Build find_links. If an argument starts with ~, it may be + # a local file relative to a home directory. So try normalizing + # it and if it exists, use the normalized version. + # This is deliberately conservative - it might be fine just to + # blindly normalize anything starting with a ~... + built_find_links: List[str] = [] + for link in find_links: + if link.startswith("~"): + new_link = normalize_path(link) + if os.path.exists(new_link): + link = new_link + built_find_links.append(link) + + # If we don't have TLS enabled, then WARN if anyplace we're looking + # relies on TLS. + if not has_tls(): + for link in itertools.chain(index_urls, built_find_links): + parsed = urllib.parse.urlparse(link) + if parsed.scheme == "https": + logger.warning( + "pip is configured with locations that require " + "TLS/SSL, however the ssl module in Python is not " + "available." + ) + break + + return cls( + find_links=built_find_links, + index_urls=index_urls, + no_index=no_index, + ) + + def get_formatted_locations(self) -> str: + lines = [] + redacted_index_urls = [] + if self.index_urls and self.index_urls != [PyPI.simple_url]: + for url in self.index_urls: + redacted_index_url = redact_auth_from_url(url) + + # Parse the URL + purl = urllib.parse.urlsplit(redacted_index_url) + + # URL is generally invalid if scheme and netloc is missing + # there are issues with Python and URL parsing, so this test + # is a bit crude. See bpo-20271, bpo-23505. Python doesn't + # always parse invalid URLs correctly - it should raise + # exceptions for malformed URLs + if not purl.scheme and not purl.netloc: + logger.warning( + 'The index url "%s" seems invalid, please provide a scheme.', + redacted_index_url, + ) + + redacted_index_urls.append(redacted_index_url) + + lines.append( + "Looking in indexes: {}".format(", ".join(redacted_index_urls)) + ) + + if self.find_links: + lines.append( + "Looking in links: {}".format( + ", ".join(redact_auth_from_url(url) for url in self.find_links) + ) + ) + return "\n".join(lines) + + def get_index_urls_locations(self, project_name: str) -> List[str]: + """Returns the locations found via self.index_urls + + Checks the url_name on the main (first in the list) index and + use this url_name to produce all locations + """ + + def mkurl_pypi_url(url: str) -> str: + loc = posixpath.join( + url, urllib.parse.quote(canonicalize_name(project_name)) + ) + # For maximum compatibility with easy_install, ensure the path + # ends in a trailing slash. Although this isn't in the spec + # (and PyPI can handle it without the slash) some other index + # implementations might break if they relied on easy_install's + # behavior. + if not loc.endswith("/"): + loc = loc + "/" + return loc + + return [mkurl_pypi_url(url) for url in self.index_urls] diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/selection_prefs.py b/backend/venv/Lib/site-packages/pip/_internal/models/selection_prefs.py new file mode 100644 index 0000000..e9b50aa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/selection_prefs.py @@ -0,0 +1,53 @@ +from typing import Optional + +from pip._internal.models.format_control import FormatControl + + +# TODO: This needs Python 3.10's improved slots support for dataclasses +# to be converted into a dataclass. +class SelectionPreferences: + """ + Encapsulates the candidate selection preferences for downloading + and installing files. + """ + + __slots__ = [ + "allow_yanked", + "allow_all_prereleases", + "format_control", + "prefer_binary", + "ignore_requires_python", + ] + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + def __init__( + self, + allow_yanked: bool, + allow_all_prereleases: bool = False, + format_control: Optional[FormatControl] = None, + prefer_binary: bool = False, + ignore_requires_python: Optional[bool] = None, + ) -> None: + """Create a SelectionPreferences object. + + :param allow_yanked: Whether files marked as yanked (in the sense + of PEP 592) are permitted to be candidates for install. + :param format_control: A FormatControl object or None. Used to control + the selection of source packages / binary packages when consulting + the index and links. + :param prefer_binary: Whether to prefer an old, but valid, binary + dist over a new source dist. + :param ignore_requires_python: Whether to ignore incompatible + "Requires-Python" values in links. Defaults to False. + """ + if ignore_requires_python is None: + ignore_requires_python = False + + self.allow_yanked = allow_yanked + self.allow_all_prereleases = allow_all_prereleases + self.format_control = format_control + self.prefer_binary = prefer_binary + self.ignore_requires_python = ignore_requires_python diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/target_python.py b/backend/venv/Lib/site-packages/pip/_internal/models/target_python.py new file mode 100644 index 0000000..88925a9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/target_python.py @@ -0,0 +1,121 @@ +import sys +from typing import List, Optional, Set, Tuple + +from pip._vendor.packaging.tags import Tag + +from pip._internal.utils.compatibility_tags import get_supported, version_info_to_nodot +from pip._internal.utils.misc import normalize_version_info + + +class TargetPython: + """ + Encapsulates the properties of a Python interpreter one is targeting + for a package install, download, etc. + """ + + __slots__ = [ + "_given_py_version_info", + "abis", + "implementation", + "platforms", + "py_version", + "py_version_info", + "_valid_tags", + "_valid_tags_set", + ] + + def __init__( + self, + platforms: Optional[List[str]] = None, + py_version_info: Optional[Tuple[int, ...]] = None, + abis: Optional[List[str]] = None, + implementation: Optional[str] = None, + ) -> None: + """ + :param platforms: A list of strings or None. If None, searches for + packages that are supported by the current system. Otherwise, will + find packages that can be built on the platforms passed in. These + packages will only be downloaded for distribution: they will + not be built locally. + :param py_version_info: An optional tuple of ints representing the + Python version information to use (e.g. `sys.version_info[:3]`). + This can have length 1, 2, or 3 when provided. + :param abis: A list of strings or None. This is passed to + compatibility_tags.py's get_supported() function as is. + :param implementation: A string or None. This is passed to + compatibility_tags.py's get_supported() function as is. + """ + # Store the given py_version_info for when we call get_supported(). + self._given_py_version_info = py_version_info + + if py_version_info is None: + py_version_info = sys.version_info[:3] + else: + py_version_info = normalize_version_info(py_version_info) + + py_version = ".".join(map(str, py_version_info[:2])) + + self.abis = abis + self.implementation = implementation + self.platforms = platforms + self.py_version = py_version + self.py_version_info = py_version_info + + # This is used to cache the return value of get_(un)sorted_tags. + self._valid_tags: Optional[List[Tag]] = None + self._valid_tags_set: Optional[Set[Tag]] = None + + def format_given(self) -> str: + """ + Format the given, non-None attributes for display. + """ + display_version = None + if self._given_py_version_info is not None: + display_version = ".".join( + str(part) for part in self._given_py_version_info + ) + + key_values = [ + ("platforms", self.platforms), + ("version_info", display_version), + ("abis", self.abis), + ("implementation", self.implementation), + ] + return " ".join( + f"{key}={value!r}" for key, value in key_values if value is not None + ) + + def get_sorted_tags(self) -> List[Tag]: + """ + Return the supported PEP 425 tags to check wheel candidates against. + + The tags are returned in order of preference (most preferred first). + """ + if self._valid_tags is None: + # Pass versions=None if no py_version_info was given since + # versions=None uses special default logic. + py_version_info = self._given_py_version_info + if py_version_info is None: + version = None + else: + version = version_info_to_nodot(py_version_info) + + tags = get_supported( + version=version, + platforms=self.platforms, + abis=self.abis, + impl=self.implementation, + ) + self._valid_tags = tags + + return self._valid_tags + + def get_unsorted_tags(self) -> Set[Tag]: + """Exactly the same as get_sorted_tags, but returns a set. + + This is important for performance. + """ + if self._valid_tags_set is None: + self._valid_tags_set = set(self.get_sorted_tags()) + + return self._valid_tags_set diff --git a/backend/venv/Lib/site-packages/pip/_internal/models/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/models/wheel.py new file mode 100644 index 0000000..ea85600 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/models/wheel.py @@ -0,0 +1,118 @@ +"""Represents a wheel file and provides access to the various parts of the +name that have meaning. +""" + +import re +from typing import Dict, Iterable, List + +from pip._vendor.packaging.tags import Tag +from pip._vendor.packaging.utils import ( + InvalidWheelFilename as PackagingInvalidWheelName, +) +from pip._vendor.packaging.utils import parse_wheel_filename + +from pip._internal.exceptions import InvalidWheelFilename +from pip._internal.utils.deprecation import deprecated + + +class Wheel: + """A wheel file""" + + wheel_file_re = re.compile( + r"""^(?P(?P[^\s-]+?)-(?P[^\s-]*?)) + ((-(?P\d[^-]*?))?-(?P[^\s-]+?)-(?P[^\s-]+?)-(?P[^\s-]+?) + \.whl|\.dist-info)$""", + re.VERBOSE, + ) + + def __init__(self, filename: str) -> None: + """ + :raises InvalidWheelFilename: when the filename is invalid for a wheel + """ + wheel_info = self.wheel_file_re.match(filename) + if not wheel_info: + raise InvalidWheelFilename(f"{filename} is not a valid wheel filename.") + self.filename = filename + self.name = wheel_info.group("name").replace("_", "-") + _version = wheel_info.group("ver") + if "_" in _version: + try: + parse_wheel_filename(filename) + except PackagingInvalidWheelName as e: + deprecated( + reason=( + f"Wheel filename {filename!r} is not correctly normalised. " + "Future versions of pip will raise the following error:\n" + f"{e.args[0]}\n\n" + ), + replacement=( + "to rename the wheel to use a correctly normalised " + "name (this may require updating the version in " + "the project metadata)" + ), + gone_in="25.1", + issue=12938, + ) + + _version = _version.replace("_", "-") + + self.version = _version + self.build_tag = wheel_info.group("build") + self.pyversions = wheel_info.group("pyver").split(".") + self.abis = wheel_info.group("abi").split(".") + self.plats = wheel_info.group("plat").split(".") + + # All the tag combinations from this file + self.file_tags = { + Tag(x, y, z) for x in self.pyversions for y in self.abis for z in self.plats + } + + def get_formatted_file_tags(self) -> List[str]: + """Return the wheel's tags as a sorted list of strings.""" + return sorted(str(tag) for tag in self.file_tags) + + def support_index_min(self, tags: List[Tag]) -> int: + """Return the lowest index that one of the wheel's file_tag combinations + achieves in the given list of supported tags. + + For example, if there are 8 supported tags and one of the file tags + is first in the list, then return 0. + + :param tags: the PEP 425 tags to check the wheel against, in order + with most preferred first. + + :raises ValueError: If none of the wheel's file tags match one of + the supported tags. + """ + try: + return next(i for i, t in enumerate(tags) if t in self.file_tags) + except StopIteration: + raise ValueError() + + def find_most_preferred_tag( + self, tags: List[Tag], tag_to_priority: Dict[Tag, int] + ) -> int: + """Return the priority of the most preferred tag that one of the wheel's file + tag combinations achieves in the given list of supported tags using the given + tag_to_priority mapping, where lower priorities are more-preferred. + + This is used in place of support_index_min in some cases in order to avoid + an expensive linear scan of a large list of tags. + + :param tags: the PEP 425 tags to check the wheel against. + :param tag_to_priority: a mapping from tag to priority of that tag, where + lower is more preferred. + + :raises ValueError: If none of the wheel's file tags match one of + the supported tags. + """ + return min( + tag_to_priority[tag] for tag in self.file_tags if tag in tag_to_priority + ) + + def supported(self, tags: Iterable[Tag]) -> bool: + """Return whether the wheel is compatible with one of the given tags. + + :param tags: the PEP 425 tags to check the wheel against. + """ + return not self.file_tags.isdisjoint(tags) diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/network/__init__.py new file mode 100644 index 0000000..b51bde9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/__init__.py @@ -0,0 +1,2 @@ +"""Contains purely network-related utilities. +""" diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3684062650f12d1144d4a9b340875bf2896f526 GIT binary patch literal 258 zcmXw!O-chn5QV#A&=ANS23!S623(4`$yQvrl!m4=T?|F0yPE2rgz+Mt!HpO32HAQ6 zF*{e*Kzy5e-=nCX&&6V{MAskBcq{d5gn#L?InBhpDX(7CpqG=^n+?U{Fy<=t4Bb#g zCn#S?j5>_FbLEiNCP9Gl{8X7XrrC9EchU0k{E+aSyQ& z4`%C{9Yk-0_vR6|CS!qBlGL@3O~O=5cL9#BtIrqIRw69cuG4Uw-3Ri02M>HHTgPYe Q`0MwD*7|3n^^~WAe^A#>4*&oF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ba45f4fa9f3577fe31087ed90ed2fd19bf8e669 GIT binary patch literal 22103 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b1a7b18480092aabba7b55a99a9d0ef4992ddba GIT binary patch literal 7050 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 V6W8_yf$XbicXNlnB#<$a_+Nq3i**11 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf10061766e12c37ba321ae08b2f138fd42c5cee GIT binary patch literal 11611 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..658af4dd1ce9d73fffe9a99bab51f84c77754903 GIT binary patch literal 18910 zcmc(HdvF~0ec$dq_uhv$h!+n4LE?xPA0kCjBt;SgNsu5w6QC@es5u>P7vzEWKz0uV z0Ucs0!^U7sM`Xt}AxjyW>Irc2)M`Q6|9_kAz^#O1Pcc$)w9g~(tp$Nd#$^v9Y@tTq@q?ml;s z6S)8<@}eQi2MjDW28=8=1xze92h1$C1S~AJ2COU=0s@O|0UL|$0XvHw0SAkn0Vj)H z0T+wi0S}A40WV@>v?NvoTnB32owj8z4yV%34_*p|SSSWTcNRvW10 zX?&(=U93J(A8QCSu)I0CHRcO6va}`I6l)GN$F>EwvAh-emcVwF7NR?1t%25OM9aG zW6uVjWod8pKr@f#j-3dcV0D$zp4iF2NuD!sl6B{LwKp)!hj(l5#E)K;isq10&y9TX{=dN(#mhbU_eyLLGqc^1ivE~qBu{LmC ztdqVnY!K^jnF1Hko^j+~7Pq9O#fFDl^-%#HBN2VKOz-9Z149Px6el*`;>0Ft+q*b> z^aL)l(q@!y(?=3`k(ITeY`gTLwEbOE4z`7r??8Dg${X|LK348W`A(@N-||;kX&Xx0 zC11YuC05#j(oU&<1Q-8;y*1D5Fw1G8_rp<5F@wAz$;!(l3okN|IoQBUi@cP*QL1vUD|c zJ(7?+?LVeL^!x3qYv|?kJ;CnNJ>6$}`%kIHWAO>qbRrT?s#lwsf>9IWJ42 zAz2bHXj4^%3z9OLh%1uTi6ZqP9akdB$aRS(gJL(jjZ0w~`1wR4ijqnK3XjQBu9dHb zWLj9%ID*0Jl1#f03?f@~MM?%mX*e_%O$Md-^@yB^$D}y5ij|39LtK6ib&(T^7&Zq( zkA#nnC9k5~H5eL}PDY{h-sS3^oL8C8%Juqt8d2uo0Lc`OnYgIKEIu$+hmv6sRY6$b$%6T#6CYu!FL*hi}=-Jr2JXkO<+@z51XRxOb$@q|q4A%sIo=}JPL z@LT*w)qFLX992|)r@R9vz;9%cYC~tC=+%UhEH0jO?B4Ti=Pvr!bzohE_29wXUAy<_ zg{o;7Q)CeR=)y0@yTOxcFo4(B0#!(JK3Aze0RBF z?4_X`MR1nmF`N|lY9+@_@hLuuGVK}34@xiLxa-`v`1?H1-KjQl6WkAsjG0JxCQcdwtOj4)~pYLa4_rXh}a^i{{ip6kNFO4S>;Y2JZ$zdrNiC@Q|#71Ab z9135P;^HObuV3nmT)u>xAa#tQ6lX)Zgc)`L8kY}uxGRS?x)crXbdFA_wnJBN_iv2K zM<%tE3DU|0!;#KI?4T$|I`a_MFfgSK!QXJ7-{jKnQ<=__v*L8}oAUk1dy|WvM&y60 z(60STT?3Cf8ACuZ)!n_pp8gkmFAVgb>**f~zIg0H@3G^3J%bOpRe*Bx0R*axZHwNy zd<118ehQYDyUDG&Ij1M%KJ`K8$p!bR1;?qh>6CmJRX?Up!pXPBLN}Diq_pn*5Uaw@ z&+mgZxsOv**eKEPjv+~P>=~gkZ+P@GB^rz1EE|B3)!`ywB;GMj;aG@fB61=llA`5W zE2dam)W#R|m4DYtZjn^U}K7acV? zxT15!^Yd^i{si}?A#Aw9g$=K|aKH`85*;dK&~Mm1!yS(a5L5Y*{8+WIpUvmBvAg~s z)}duXTW;1?%|B#Ki`H(Ft2$Dq&$JMW9(~U8o1#}NiP~e1DI?FNj3czo8y@{Mptg2H z6|zOO^}o1w*f?cMZq@6Pje1Hf1=efUb6~2f*nZ-&vp(!(RX6#NC<^BO{TdlV&KU1`u+x77jVtr(y zmlj>F7q|R<;OVyKM_IV_xS1Oty&ri;QTty2m*Pg+HnxGgRukd$H583(Z3?}%|2+Jr zy?z1Qm*};2L$5?aH$3@XtBU6O1#nowI@aoLy`g*yWw;sk=$0vK$~y9lUR#LqW<7iJ zS-nhubL2U_q!5b@`l*-_Qoei4Kf`()tckpqQH5)MT}vCCrU$YdQ&IH*myz_8_N@8OMA z0l`gfrg7%jx3@8t34#EvhBg^PMEr6ClIf_h(a0B&DjJPEg!~r|td>ADm}9|>%X5eFBe zNrvR4G9F1@RUNohop>)UCSDotYFreFf3o9 z9PMLH;+9|4tFK0&kRTpOH3hNhs%PMQPd`N9;EO#M273qkWx6J+mr3h%tst6F5kw|pChw!ZjOYtbscj>Se5zeA1_5XlxY;YaOEm$JJbWOrU4oKwR9 zY@HSPWoiTRGbUGbdIR5=1b#esk@VD8cIfW2`0*JuLF;5dq4S-<2v-%_Uz`c8NvUF z)&BL=8>uC0L&n-LGrnlu@v*S|NqzHoUU}=4w_lw*`NRGP{R{1f9u5CN;`b5@M+VaM z18JdVc}Lr_v-Cr6!?L&Rad}6&>)3+#_^R3Ha<3ZAt@df>nv?UE=RxjXoas%MZ+|Gf zYhUp0)#1FD<5MT+^k$oPO!v)HW}Lnc9aY(S|MZEw)wlcCkL<>xwe{gkOC5(Z9fub> zUU-jx+;KeHJ{PEq&9b>6dQ1Ke2kg{>$14rhc8KrLCTGS;d^>z3uc&oAxm&g|`8*o$p0hKyu{ zUF#q#8?aMUnqup!B2wOj?>{zJmTBIZfTv{y5v8a@gH4i!N}6C#*EPPiPc5Bare}MwJvRKT`@Uq z=lJE?mZjP~nc6+slIoeZw0HZ%$)&ENnXaSnH?J8Db?)gt9CL5ol4pCyvwe1A(X)F+ z;QafRS`TJg4?cQkq4nr{C7IUlrPec<)-wyOeRoZFgO9x}*rJ*p?`*wSJ}2HhF_wD!W_ucp0>8;N#cn{v}&04)_YhAXk1=D;bBW!u%IJx9FmvNlSx=NN^C2t09 z2WCujHII^ut`jR}&e_keaz>|Rg)^EhKmGJ&1LxZH`I^jg-YuVUyshLzr+3AO_-6`X z>p!e69k2_3>S!JCaDV2p4b&R{tcFJzMqU2#=2ENw9Etm!#07X5R17xoecC_KAsQs3 zXp~H%Nis_o$tnr>Sv5s{L0vCWok_B3C8CAF+5l_Q%ZgyFsI?br2+fLuLot(ohy)WmwK@y7s946oW zrfoX(W@?p`HQ%2tN!%KHM%;R;5Ra4;(s~L^f2p1>#G>J$QD=sy?8yqfW`vYp8=gY{ zqKP);2Csm57R^(RBxTu?a-g401f-N*w7g@~$B$X(M_o`6q^zP<9}6J#!^fqB5nrzP zqG+V4D3eR#t^CYW!XUBq+jJOO5k+k;LBrn;sAdV42yi^a z_b94e<50jLN~)kFgE3-oRa*>U5<>vM6tx{5~}t1L{d_E2UH8pL>MG6gh`R2 z!!l$4XV4eJ2l88#BD10VHuW!%g+t>PAT7~r5j-ddPz=a zg;=cdL+CCpPL{1lOPy5s0bWpQu(r@8mvZG>XU4zt`dhCrl(kI@pLnYN+2ph-TiY;g zS`@0YWi|JozxVvK>5i~sDz~*Rmsj3Db??;7>4ox^>7F$&S6zSq^?R=`Rdr;lI_9Jw z#vjDr8%kGoEL5GDKD}JKZK<{^Q`ts4-J}=y7e|d(P>;<=W0C+jeEQxBX`9 zyRmFb$5X4Rq;%D20TDZKr;nPgn>jrzE>yK4e>%IR{yWugRez`9tp;SzJn@uGJ3e3Y zbKa^?IkW8q53b19Jbhx(S+`u%Fr&QfU#e-()U*Tk>~hr>(#FpY{pKs*eP#CCeCd4m z{JwP4b4yJ}GfhVqnvO42bx)so^YrxTl?HGs(~keO;-@Ax%Jh2`-HqIj8f`r;b*-8Z?c z;M9au^U409ewarXdFc1M<$2Vr_FxdlVJu2V&KV5;(pV^}9YC3+XVr8WQlL!uTPD;D z;XIlEm+qi~aSBKXX17TGeM-@gG+CBx2<+_0-=Y)+i})#X2ySuUCaUYRFLZ-V%kDpz z?b`d)(_$`vQsP@NBgQ6_RIFGjC2*xRGcB{`*|E8c^F4EyGCK~YeFrl&&u2;wt=I^{ z&XrW&6=%BdMlxRCii3)roTuvU*v#N;%bam;a8CGcSGs<8rfN^dy?4b$0B&k^$87Vg zGTWM|Y0H$fuTcMB)$OILB}lFH^Ss%`7LE;l9sfYHr)Tvw1Ya-WAVeN+7zWY!4lEYn z9W-kNxB}5C8ip;?+%PW+x7-2n6G(wi5bgLmB%A1DFs@-cgK^(-1(3SI2OO}sdDN<4 z!9st9-*yas_VB1$kEhLS!^3>qicSgA1}dmqYRG$hp84hTq^ zWJW{<=9ci~1#PWa^qt5V(J^bxQAx74FzKA}PE%F&gOWIk7DfIe?3+x4R<&Hiq^{&x zCaflVD5lFp`@Fgb!N1_4LE=+f5NYix=yh)!Q`|Rj3q(G`r3}Bp{~FKZ-uj_sA_Wt4 zVNMdW_5A=29s_wGJP!wiBrM}5cCED`{W0E9ZNXqT8Ui5+GJ_v><)(Iz{sU?!eZSx= zbm|QX7`;OB{pUD(TNmCa&a5i%0d__J=otrPiHhB$N z2<&Mvw>HhF2oplmA7U-p+DszB)`lC=>x$wx>QbhWJfm2s00X%xyv`)?T!HPp4I9We zfO$kC*58oA?Rv+UGSMpIW|;cfvO(?kCup5bK>kxov6VN;|DMucqk#Ac)yr0#W|ljw zev7vD8{Ym;^u~Wgz*JXsE%Y7uGZap?{-Pb&*nA1?1S$7uCtzmvE;;Hlj=Hp?HS4Te zayDh0O|ysRw=M1I&g|)4be>rDl;0lDcy_FCX0JV4-JC72&6ZX@wIT;J=&5;XqZFu= zT|?+jhQZ~3OT+yG1gbR{6cgcKP{Y@>V=|o?*-Mp1*sA6CC`+?YUAa>hmZH&M@Byz) zm`?st?X>-fKq=s88cD>T-{PJc%w}Pwoa@^Asnu$32A-~Ln2Ba8+E!Rr;L0jjY*b-~ zZs8{mO4V>xtxs)kv;9d$^@%T7OjerTg5AfVn;sh8&7liIg%6DVCxPWuz;5W}fkC^N4iaBUR|;A7LGDg&0>1g3{Lg52 za_c4&>nv)ujW(Ig#<+^`c(Az%8P?90&+VNbd+(XFQ2T*!n(fU4$HsG0N#ka$4lzL5 z4PyKdVL+LBmmgEGfPgV)x%=}W6;iO1`WBJE{aGY6pzE{r_^nYW02C#7Awj6QJ>;|2XGNUZxfQn1a7R z@N>wU9h4nkFu>viv!8D46Kady*uSLI#vT5I3MqhdDJTDzJTMilTYX)4Uxi*_-Svhe zFE~bAV#X;-7STYIOC(oba^vMi^Ega25WPAqt1*cs&^I}4usw^V;6uyu?Uzd~1|f(Q&`h~Sx8#w?{g>C= zQ{g09i8o8&j9Q91*RV;fM!rnkf>vtqqY<<*Bq&0%tNR9%d=VaJq@~ci zo`O=({m@f@zf%SGLf-G49ARPy@q-7+dKmMqJC_H2n&+zGizk?XCB@(q3GsqFAesCG zfkuk6+A#%X`PQgKqR4}qxI)?fN&7|EpF56`!5yMMoo2r|vWDXs`JWVgMuC8{81W#u zqK!TM0y(E96EMB2-keekavOL&vVFNpC`t?u2Zuu>43ba;-@ah(vVn_cm***((%5Q4 zp#W@EzI;+(-meF{x+blZVhM6xMS^s8Uh=nwzDWs26IZTap8hgM<{2-lmchOm)YmN` zM*sj5EESUWdV(3-K&MNGfBhPWUE%>TO~icbr^)F8MXZ_ES-fa65!TF~Bw*BtGnO|NMI-!1Ix#!Xior^*j#$a=41@FWc zSkYgVH%_0(LOOCbW}J<)+a8stosAzjk32PU6*)Q89hb%-FY8!8oJYY}W=a#}#pH>1)5g2umX_;tgSDP?%W zmV(rgGC;>~`gP+Z$Q4{C(T4VHCf37Y662w#Sb$IQdg&$fGi8ROqxq&gnJ051+-9jy z9qLy=Hd2;hI2DdSsj~68&dc?i*Niwe!jcmuwWPPq2uhyp7NC>F0I(;;ix!a0-02bp zQg5I)THy_k4)bN&)cgOE?OBvT^!fK0r|lnkoL{QF2?M^hu}?m>>o_iVj|c}I^z|l5 zZI`$fVoE|__Uoka3;C!PHwa2Te8J%ZmB5EIV+wSFmnCWaJp!hd#KHy2wXPlJgT7<& zg62;v%lWOflb#ap_Kffly(P^e^n}!LeyB8L@@%0Gf?#a%(Z?c%t|lu;1B$vFm16G# zAxv6*tpw>)dH-bF5NR8sm1Hxzc%jc1Lmn6-933mn6kGxpLp2eZBx{xeZWcBpzDvG_ z1Le1=78)tkfhKYgl6@#t?JtI+V-m9o$*WXg!3RUIv&f$#BX6bPGX#FChD7L+%cP=V zH(WKwlq=BQ(FZRYyPVI^Cr}DqyWECpTArVxV6wId$!w&MZxfEGM{tvSTFQBS*>eBf zwz=wb>7MECtfwOFY0P@dW~yc@XN5UFU9~gg-FeptCyh7H-ab2Hgc;?N=B|0uLi4_i z;G1^beI@ItOgkEuOY72G&%FQ4`>pBv!G+SHv~vhLv6zpsklsz*qF6}>`*?)df_{xW#8nplBncHWUy)Coi{QgDn!AFA`@6oKce924m z0HJfafmq>_0I0>P_PL>jsy*|AnW_Viwk;hT${ZZ}zsyBVhF>+Cv3ToM}7LSwe3VX0=%V$Gi0XW($NEn8MOW11bBz4TUi zKAA2(wBS4hs$RQy#mL#3ex?wY^egtg{2hL`=^HJ3>0>UqJrGG zeHrqzwHLiXnyn2FM628(o^rrF*#UaX-#HCBYGZv0DO;|0W6Jghf9E3fdlnOytkatr zA^f!A5v?f`cmvu&Ja|KZ{{s2yum}DN_?9 zJShN<*6xXh_v!0Wz+9GyTxj14ik-gRVUQdY7d4Aq=sJ7}LYJeG?|LMpiF>|r>YIIf zhK42*W6T1^BtcLTke86y?n{7t!G{;7F#?EzqAHNJ@U^JcNlw0GAG$KD8-0j}kHf|R zNIa--M@L7FkaaLx)uQa^Jn8qswSs+7s+t+GPz7XJO4D_ka12y|ULb3*?53z|!Imp#yv zaqgQQn0aNcE$eBR?RxClJ)d~L?D77-thai_vbb7vp7AAYoFq3Xz8 z({fGoQcY*3rgQG~g_`H@T49nYubvstlx@$J*OA`2ZszsJ-ksUMS>~t&!PDjGoC|f;SghOz*d~}S8X(nuz4_BNCq9Mo?tK(2fkz! z9Oi48R!~DHL`r31J~e~n-%;v43W)!dNfcF`gX|U$Ff71uj9f#N_zMs@2NRm|=C+pq zN;MQ51+a1i!RP;k%hosEJT?8&-SF*K7fg+~Ox0VmTbr{x{MntI+0H$mdIos&3r{?y zD`rZ7UnHv}OTsK!J!8B*wPIsgyy=@Y-kVx+u&k4-sGk{{ZGP+JO!sU6TEePI$r4(|l9ypU?VLBw5B`=7W?XaUBXN}?K!1gQk$-C3YJQQ=mRGH4iAMii z^LOiWncj0+;)%_*Y9_dqW*S76rdbfr3DFY6PfLqdFCMT@`d~ zscL~Y9Ehq+mtH$ZbmiGe(asSm2Q)i3J6k0EGY=(sf>Ioy?p7b0_`f z1g1k&tAq465;n0`srAJ#<}R1gsr$tC^V z0^MSQ_!xyuNa~gim2Bvp`1;}+yP0au`uZGE?PMBTro7dbAm6$Uz;=OYZ#Oo%&qti=Bd+8l&i)Yx7|&-02XFX{%Lg?azw={m=r6d_A9KBb!5#aUd*Ng5 z@W<$q4xQYxqUyeaD3OtTqgtE^_NEP$EJqAHa!oVYOkHHTC&w-Y&A0n z7Hr#YTAp~y?+(s1&)k?Z&xPmr&Ru=r$!tB4t~ikKJa^LxZiKJCDJ*eS8LnzZNVgsP zfII%F#lGEe(~VCIE@iw;tDK!TthCzd3~8=nqxeEG~* z7Wu6!hRZx}x!e6INAaqWGx)TkwKGOP@4EZS8onQNefAQ+m509xg0&M^H(R>YpKg18 zjYD!xpnT2l^xm_%yukPJGi_@e#cP!mrknQZ*|SFe@ZIXAlEzF)<4-usF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..165ad7c041547fc77d6193237a7d880e72eb410b GIT binary patch literal 2259 zcmb7FO-vg{6rR~1du@zO0Gq!AHeh}n3Q3eEA|#503`r^wkrG919JiM74zOVFy0dG* zmXT1DgOla}mpW2^gwzXd(kjQEszf>T&|=K^RglIYG;sexo+YeVY%t)6RhBFPNhMV{rX)Og9{th(c&oS7`tn!d0RrRYfBp z`-X`=tYcfI{ zGB^sG88%Av6jg>}*bKWjc;GC2+Xk%WAs@3?f1}T$38rMY&vmXOKiJdKBMx-1?S#E# zyU!)&!Cr(}MsXeNH_J#IXi7J>?~G#13^Q4e5alI)65`Wl1#V7hI@tOvB-yeIP&?>d zZ*8+Deuci_XR&fd;t%$JE1F?}{)su0`n%dRVbNX!8NqHWwLf!$A z@rc2=4Db;xaP^8Ar#PxoF-7COqWlSD8Z536Iz?#7!i1@bEDNTB0o%%orbm?+F|iia zRK?&&(mK%$n?wMj#HhTk$fnS5O|3vi8Mx>vEn*q45RTg5?*lA#05ja6Yr6P zHb%|7X(nJrQG7iT>k!@+_QRcD#*N!J0kL#CR zLt89z)W8nT@_BB(LR_g3*Bot&r=B_5-s4y>9k&D|_+GgEi=X{0t+|8CLJ*b(-|kKm zs%U3g<@_iigXbx+DX9#HdKg=P9D;npo=3ABcd! zDQLW+K2Ag_sz*gDBU<-Gs1J7$_yBGIn4%8{ID@6pX~U-JP$3D!-KXnR9!cq>SPamq zqY_}>Of9ViV(`V?_8?Dv=9;Heb&;Zyim-YPK1~JkC)%Au1)+tn-Si&GhZn-@-i{S- z$A-&S=thT+7EU5x;BQptbLIvLAEK(-F9x?x!)$lw406@KLN@SoS8h}v&JQgNtyj0M zRJSfptX7}Q4Lq-^eO}?+sI0j=Sa2XuRe=ZFf3#MJc?wsQEe>wU$MxLc7U~ z`RKtTs9BAIn!VCsA)kgP5{W8`3hl(yMj}R4|CNu2hpzPXM}n8H4-ZDJeH0q7%GY3F zJ6d5LLIm$ra8+@Kl^!pvPd%e5o`Y2vh>bzoX`5)cg{ic!|yxj-kU{OB2iW zXXos>>RfF8RBrrE<0?A4=@XYxRl!z=`|7&-6`tk(^WT(3QL(NOuK~}7_QMYQC!Qds~EO`CJUkK6?Y^pv&&^> zm--=Ag%KDi4J1e%Adq^h3j|0C7e$Xfw&}4K5jHAf;~*}I9D1WG2Q|`5-|TY9RP_Ly zd2i;;Mm zg?Rb*&kn?zvS}^O|UC7 zetsUi>o$37)~?ramF~Gnh)rN6e${AP$BqM2pk;|>I9Oe_iRyswrUO1@bsVxP56W5Iv)?aNdFJn?2egZ)m9>bi@ zVqWL4p!2%0EVa=xMEh1s5rcI}mmzALp3sweirQdFPmhDQ<+z@?#Vc|fZ7@pwIw~LX zbMO&w1YsJ4sCDfsvDXY87q#MzXN2&^ffyFo42_x&!*L^Cgk~?*AYhe1_GP24;|;Y* zOkZ@up!vxr1Weal>>3vK1%llssn1urZ$yJ8l>YWVfbK(P8@YqU+q{R~10Z{B1R4gp zgS|CjU^ozJ@<1F29uw`};ykVvP-d_g2p&=gzPuP{K&G&5qB1jImVDl6HZbueRW<5{ ztE#>Lp9!e*`3B@1`x2<3BskSo0G}_aeL+(D!6*wp=U{W0q`)^x(=G#@p9tdy+g%6n zq*hJMaa7fzN1{P4-u${cdw#J&>=mL}mQi0>T(|A2ZCL;-3bn-8Ja`}G#rFNn_c6@KF+!-skxp$M@ z!m&2@UTPn9BcEFZ&Jc-;;;L5HO$cq0;J2IDan&VT-y}3izPN_TlI`GfjL@`Js!>e? z1<~jPu=x|z697%WssLCRH%1L;yVsYT*pJXVjE8Ci@PzBM_ZTmxLw(fIvarRw10dAs z`3|&N;=lx`9zTGW0NjKcYcN|P{8z;CZ)~a2gdb?0;IW>lv%ll+^-s4YxrZVnPl~)V z$m0N-1AxOnj7C<&(UWTVp%zJzkL&0JatqOH36Yn#WKXWq#2#p2#N5efx^^s*hNI3u zdvC2cw2357h$=UO-ho(e$v>CZnRT?mzKPbEvM}FDLiu$8$){*BZAmWPa49$!%B;^p z1e-E7)~`A}|4^FK#$S9cp#GihUM# z5&G@qFzsmU{5a6ISr3RyX!Z2D21O>NKRHhIbg-rp3^z+1c+L`SolqG1(qK+7?UfZ; z9IC`{jjCq)iST+*tG15IaYDmOX#7Z#cF)l+@J@>daGr%zkZC%53Ob*~8&!uAARvFx zktw<$_9@bucm_%PYt*mPg$^j1M%js-(nsurOlemt?Pf~dL!;Z1cP4k-yFdLz|HEs4 zEbV4rZu1Y*hu=4En|tZ$PI~$-zMp=v&GuqBIoBPVzT4W(f2Vz^J9cDy>&{k4=WceS zJNg_D8fJSkDtv1n@r87I?nx4*rgq+VkeulrIo^Kl-7DRZvAvO*&dAK&jgP(Gc=t!n z?k3MZeVCd47ZSnyNPhdm2N!me$9{R?VKVpr>$hL;X3v20?c|;0UiM@sdlHl;CUd36+hIx5djv7a72KU-k`Qs6-@Ge0aRXqm2S7KSn%S5?c_ znvp zL68+fX&!VGQ4YPlp58)_V=-QWV_#62&vSnG+qk^zRht}L@Nfdg`9i4rg1gy(9fa1^AOwB^E{)3I(x?D3af3dP zoR9=l|GV73Q!4!nFO2GuXWKMg!*oKX(Lx(kc)0!G1lU={dUylKz~(CfyU2H`5q%K) zLjTnA;5ie7|F Optional[AuthInfo]: ... + + @abstractmethod + def save_auth_info(self, url: str, username: str, password: str) -> None: ... + + +class KeyRingNullProvider(KeyRingBaseProvider): + """Keyring null provider""" + + has_keyring = False + + def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]: + return None + + def save_auth_info(self, url: str, username: str, password: str) -> None: + return None + + +class KeyRingPythonProvider(KeyRingBaseProvider): + """Keyring interface which uses locally imported `keyring`""" + + has_keyring = True + + def __init__(self) -> None: + import keyring + + self.keyring = keyring + + def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]: + # Support keyring's get_credential interface which supports getting + # credentials without a username. This is only available for + # keyring>=15.2.0. + if hasattr(self.keyring, "get_credential"): + logger.debug("Getting credentials from keyring for %s", url) + cred = self.keyring.get_credential(url, username) + if cred is not None: + return cred.username, cred.password + return None + + if username is not None: + logger.debug("Getting password from keyring for %s", url) + password = self.keyring.get_password(url, username) + if password: + return username, password + return None + + def save_auth_info(self, url: str, username: str, password: str) -> None: + self.keyring.set_password(url, username, password) + + +class KeyRingCliProvider(KeyRingBaseProvider): + """Provider which uses `keyring` cli + + Instead of calling the keyring package installed alongside pip + we call keyring on the command line which will enable pip to + use which ever installation of keyring is available first in + PATH. + """ + + has_keyring = True + + def __init__(self, cmd: str) -> None: + self.keyring = cmd + + def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]: + # This is the default implementation of keyring.get_credential + # https://github.com/jaraco/keyring/blob/97689324abcf01bd1793d49063e7ca01e03d7d07/keyring/backend.py#L134-L139 + if username is not None: + password = self._get_password(url, username) + if password is not None: + return username, password + return None + + def save_auth_info(self, url: str, username: str, password: str) -> None: + return self._set_password(url, username, password) + + def _get_password(self, service_name: str, username: str) -> Optional[str]: + """Mirror the implementation of keyring.get_password using cli""" + if self.keyring is None: + return None + + cmd = [self.keyring, "get", service_name, username] + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" + res = subprocess.run( + cmd, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + env=env, + ) + if res.returncode: + return None + return res.stdout.decode("utf-8").strip(os.linesep) + + def _set_password(self, service_name: str, username: str, password: str) -> None: + """Mirror the implementation of keyring.set_password using cli""" + if self.keyring is None: + return None + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" + subprocess.run( + [self.keyring, "set", service_name, username], + input=f"{password}{os.linesep}".encode(), + env=env, + check=True, + ) + return None + + +@lru_cache(maxsize=None) +def get_keyring_provider(provider: str) -> KeyRingBaseProvider: + logger.verbose("Keyring provider requested: %s", provider) + + # keyring has previously failed and been disabled + if KEYRING_DISABLED: + provider = "disabled" + if provider in ["import", "auto"]: + try: + impl = KeyRingPythonProvider() + logger.verbose("Keyring provider set: import") + return impl + except ImportError: + pass + except Exception as exc: + # In the event of an unexpected exception + # we should warn the user + msg = "Installed copy of keyring fails with exception %s" + if provider == "auto": + msg = msg + ", trying to find a keyring executable as a fallback" + logger.warning(msg, exc, exc_info=logger.isEnabledFor(logging.DEBUG)) + if provider in ["subprocess", "auto"]: + cli = shutil.which("keyring") + if cli and cli.startswith(sysconfig.get_path("scripts")): + # all code within this function is stolen from shutil.which implementation + @typing.no_type_check + def PATH_as_shutil_which_determines_it() -> str: + path = os.environ.get("PATH", None) + if path is None: + try: + path = os.confstr("CS_PATH") + except (AttributeError, ValueError): + # os.confstr() or CS_PATH is not available + path = os.defpath + # bpo-35755: Don't use os.defpath if the PATH environment variable is + # set to an empty string + + return path + + scripts = Path(sysconfig.get_path("scripts")) + + paths = [] + for path in PATH_as_shutil_which_determines_it().split(os.pathsep): + p = Path(path) + try: + if not p.samefile(scripts): + paths.append(path) + except FileNotFoundError: + pass + + path = os.pathsep.join(paths) + + cli = shutil.which("keyring", path=path) + + if cli: + logger.verbose("Keyring provider set: subprocess with executable %s", cli) + return KeyRingCliProvider(cli) + + logger.verbose("Keyring provider set: disabled") + return KeyRingNullProvider() + + +class MultiDomainBasicAuth(AuthBase): + def __init__( + self, + prompting: bool = True, + index_urls: Optional[List[str]] = None, + keyring_provider: str = "auto", + ) -> None: + self.prompting = prompting + self.index_urls = index_urls + self.keyring_provider = keyring_provider # type: ignore[assignment] + self.passwords: Dict[str, AuthInfo] = {} + # When the user is prompted to enter credentials and keyring is + # available, we will offer to save them. If the user accepts, + # this value is set to the credentials they entered. After the + # request authenticates, the caller should call + # ``save_credentials`` to save these. + self._credentials_to_save: Optional[Credentials] = None + + @property + def keyring_provider(self) -> KeyRingBaseProvider: + return get_keyring_provider(self._keyring_provider) + + @keyring_provider.setter + def keyring_provider(self, provider: str) -> None: + # The free function get_keyring_provider has been decorated with + # functools.cache. If an exception occurs in get_keyring_auth that + # cache will be cleared and keyring disabled, take that into account + # if you want to remove this indirection. + self._keyring_provider = provider + + @property + def use_keyring(self) -> bool: + # We won't use keyring when --no-input is passed unless + # a specific provider is requested because it might require + # user interaction + return self.prompting or self._keyring_provider not in ["auto", "disabled"] + + def _get_keyring_auth( + self, + url: Optional[str], + username: Optional[str], + ) -> Optional[AuthInfo]: + """Return the tuple auth for a given url from keyring.""" + # Do nothing if no url was provided + if not url: + return None + + try: + return self.keyring_provider.get_auth_info(url, username) + except Exception as exc: + # Log the full exception (with stacktrace) at debug, so it'll only + # show up when running in verbose mode. + logger.debug("Keyring is skipped due to an exception", exc_info=True) + # Always log a shortened version of the exception. + logger.warning( + "Keyring is skipped due to an exception: %s", + str(exc), + ) + global KEYRING_DISABLED + KEYRING_DISABLED = True + get_keyring_provider.cache_clear() + return None + + def _get_index_url(self, url: str) -> Optional[str]: + """Return the original index URL matching the requested URL. + + Cached or dynamically generated credentials may work against + the original index URL rather than just the netloc. + + The provided url should have had its username and password + removed already. If the original index url had credentials then + they will be included in the return value. + + Returns None if no matching index was found, or if --no-index + was specified by the user. + """ + if not url or not self.index_urls: + return None + + url = remove_auth_from_url(url).rstrip("/") + "/" + parsed_url = urllib.parse.urlsplit(url) + + candidates = [] + + for index in self.index_urls: + index = index.rstrip("/") + "/" + parsed_index = urllib.parse.urlsplit(remove_auth_from_url(index)) + if parsed_url == parsed_index: + return index + + if parsed_url.netloc != parsed_index.netloc: + continue + + candidate = urllib.parse.urlsplit(index) + candidates.append(candidate) + + if not candidates: + return None + + candidates.sort( + reverse=True, + key=lambda candidate: commonprefix( + [ + parsed_url.path, + candidate.path, + ] + ).rfind("/"), + ) + + return urllib.parse.urlunsplit(candidates[0]) + + def _get_new_credentials( + self, + original_url: str, + *, + allow_netrc: bool = True, + allow_keyring: bool = False, + ) -> AuthInfo: + """Find and return credentials for the specified URL.""" + # Split the credentials and netloc from the url. + url, netloc, url_user_password = split_auth_netloc_from_url( + original_url, + ) + + # Start with the credentials embedded in the url + username, password = url_user_password + if username is not None and password is not None: + logger.debug("Found credentials in url for %s", netloc) + return url_user_password + + # Find a matching index url for this request + index_url = self._get_index_url(url) + if index_url: + # Split the credentials from the url. + index_info = split_auth_netloc_from_url(index_url) + if index_info: + index_url, _, index_url_user_password = index_info + logger.debug("Found index url %s", index_url) + + # If an index URL was found, try its embedded credentials + if index_url and index_url_user_password[0] is not None: + username, password = index_url_user_password + if username is not None and password is not None: + logger.debug("Found credentials in index url for %s", netloc) + return index_url_user_password + + # Get creds from netrc if we still don't have them + if allow_netrc: + netrc_auth = get_netrc_auth(original_url) + if netrc_auth: + logger.debug("Found credentials in netrc for %s", netloc) + return netrc_auth + + # If we don't have a password and keyring is available, use it. + if allow_keyring: + # The index url is more specific than the netloc, so try it first + # fmt: off + kr_auth = ( + self._get_keyring_auth(index_url, username) or + self._get_keyring_auth(netloc, username) + ) + # fmt: on + if kr_auth: + logger.debug("Found credentials in keyring for %s", netloc) + return kr_auth + + return username, password + + def _get_url_and_credentials( + self, original_url: str + ) -> Tuple[str, Optional[str], Optional[str]]: + """Return the credentials to use for the provided URL. + + If allowed, netrc and keyring may be used to obtain the + correct credentials. + + Returns (url_without_credentials, username, password). Note + that even if the original URL contains credentials, this + function may return a different username and password. + """ + url, netloc, _ = split_auth_netloc_from_url(original_url) + + # Try to get credentials from original url + username, password = self._get_new_credentials(original_url) + + # If credentials not found, use any stored credentials for this netloc. + # Do this if either the username or the password is missing. + # This accounts for the situation in which the user has specified + # the username in the index url, but the password comes from keyring. + if (username is None or password is None) and netloc in self.passwords: + un, pw = self.passwords[netloc] + # It is possible that the cached credentials are for a different username, + # in which case the cache should be ignored. + if username is None or username == un: + username, password = un, pw + + if username is not None or password is not None: + # Convert the username and password if they're None, so that + # this netloc will show up as "cached" in the conditional above. + # Further, HTTPBasicAuth doesn't accept None, so it makes sense to + # cache the value that is going to be used. + username = username or "" + password = password or "" + + # Store any acquired credentials. + self.passwords[netloc] = (username, password) + + assert ( + # Credentials were found + (username is not None and password is not None) + # Credentials were not found + or (username is None and password is None) + ), f"Could not load credentials from url: {original_url}" + + return url, username, password + + def __call__(self, req: Request) -> Request: + # Get credentials for this request + url, username, password = self._get_url_and_credentials(req.url) + + # Set the url of the request to the url without any credentials + req.url = url + + if username is not None and password is not None: + # Send the basic auth with this request + req = HTTPBasicAuth(username, password)(req) + + # Attach a hook to handle 401 responses + req.register_hook("response", self.handle_401) + + return req + + # Factored out to allow for easy patching in tests + def _prompt_for_password( + self, netloc: str + ) -> Tuple[Optional[str], Optional[str], bool]: + username = ask_input(f"User for {netloc}: ") if self.prompting else None + if not username: + return None, None, False + if self.use_keyring: + auth = self._get_keyring_auth(netloc, username) + if auth and auth[0] is not None and auth[1] is not None: + return auth[0], auth[1], False + password = ask_password("Password: ") + return username, password, True + + # Factored out to allow for easy patching in tests + def _should_save_password_to_keyring(self) -> bool: + if ( + not self.prompting + or not self.use_keyring + or not self.keyring_provider.has_keyring + ): + return False + return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y" + + def handle_401(self, resp: Response, **kwargs: Any) -> Response: + # We only care about 401 responses, anything else we want to just + # pass through the actual response + if resp.status_code != 401: + return resp + + username, password = None, None + + # Query the keyring for credentials: + if self.use_keyring: + username, password = self._get_new_credentials( + resp.url, + allow_netrc=False, + allow_keyring=True, + ) + + # We are not able to prompt the user so simply return the response + if not self.prompting and not username and not password: + return resp + + parsed = urllib.parse.urlparse(resp.url) + + # Prompt the user for a new username and password + save = False + if not username and not password: + username, password, save = self._prompt_for_password(parsed.netloc) + + # Store the new username and password to use for future requests + self._credentials_to_save = None + if username is not None and password is not None: + self.passwords[parsed.netloc] = (username, password) + + # Prompt to save the password to keyring + if save and self._should_save_password_to_keyring(): + self._credentials_to_save = Credentials( + url=parsed.netloc, + username=username, + password=password, + ) + + # Consume content and release the original connection to allow our new + # request to reuse the same one. + # The result of the assignment isn't used, it's just needed to consume + # the content. + _ = resp.content + resp.raw.release_conn() + + # Add our new username and password to the request + req = HTTPBasicAuth(username or "", password or "")(resp.request) + req.register_hook("response", self.warn_on_401) + + # On successful request, save the credentials that were used to + # keyring. (Note that if the user responded "no" above, this member + # is not set and nothing will be saved.) + if self._credentials_to_save: + req.register_hook("response", self.save_credentials) + + # Send our new request + new_resp = resp.connection.send(req, **kwargs) + new_resp.history.append(resp) + + return new_resp + + def warn_on_401(self, resp: Response, **kwargs: Any) -> None: + """Response callback to warn about incorrect credentials.""" + if resp.status_code == 401: + logger.warning( + "401 Error, Credentials not correct for %s", + resp.request.url, + ) + + def save_credentials(self, resp: Response, **kwargs: Any) -> None: + """Response callback to save credentials on success.""" + assert ( + self.keyring_provider.has_keyring + ), "should never reach here without keyring" + + creds = self._credentials_to_save + self._credentials_to_save = None + if creds and resp.status_code < 400: + try: + logger.info("Saving credentials to keyring") + self.keyring_provider.save_auth_info( + creds.url, creds.username, creds.password + ) + except Exception: + logger.exception("Failed to save credentials") diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/cache.py b/backend/venv/Lib/site-packages/pip/_internal/network/cache.py new file mode 100644 index 0000000..fca04e6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/cache.py @@ -0,0 +1,118 @@ +"""HTTP cache implementation. +""" + +import os +from contextlib import contextmanager +from datetime import datetime +from typing import BinaryIO, Generator, Optional, Union + +from pip._vendor.cachecontrol.cache import SeparateBodyBaseCache +from pip._vendor.cachecontrol.caches import SeparateBodyFileCache +from pip._vendor.requests.models import Response + +from pip._internal.utils.filesystem import adjacent_tmp_file, replace +from pip._internal.utils.misc import ensure_dir + + +def is_from_cache(response: Response) -> bool: + return getattr(response, "from_cache", False) + + +@contextmanager +def suppressed_cache_errors() -> Generator[None, None, None]: + """If we can't access the cache then we can just skip caching and process + requests as if caching wasn't enabled. + """ + try: + yield + except OSError: + pass + + +class SafeFileCache(SeparateBodyBaseCache): + """ + A file based cache which is safe to use even when the target directory may + not be accessible or writable. + + There is a race condition when two processes try to write and/or read the + same entry at the same time, since each entry consists of two separate + files (https://github.com/psf/cachecontrol/issues/324). We therefore have + additional logic that makes sure that both files to be present before + returning an entry; this fixes the read side of the race condition. + + For the write side, we assume that the server will only ever return the + same data for the same URL, which ought to be the case for files pip is + downloading. PyPI does not have a mechanism to swap out a wheel for + another wheel, for example. If this assumption is not true, the + CacheControl issue will need to be fixed. + """ + + def __init__(self, directory: str) -> None: + assert directory is not None, "Cache directory must not be None." + super().__init__() + self.directory = directory + + def _get_cache_path(self, name: str) -> str: + # From cachecontrol.caches.file_cache.FileCache._fn, brought into our + # class for backwards-compatibility and to avoid using a non-public + # method. + hashed = SeparateBodyFileCache.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key: str) -> Optional[bytes]: + # The cache entry is only valid if both metadata and body exist. + metadata_path = self._get_cache_path(key) + body_path = metadata_path + ".body" + if not (os.path.exists(metadata_path) and os.path.exists(body_path)): + return None + with suppressed_cache_errors(): + with open(metadata_path, "rb") as f: + return f.read() + + def _write(self, path: str, data: bytes) -> None: + with suppressed_cache_errors(): + ensure_dir(os.path.dirname(path)) + + with adjacent_tmp_file(path) as f: + f.write(data) + # Inherit the read/write permissions of the cache directory + # to enable multi-user cache use-cases. + mode = ( + os.stat(self.directory).st_mode + & 0o666 # select read/write permissions of cache directory + | 0o600 # set owner read/write permissions + ) + # Change permissions only if there is no risk of following a symlink. + if os.chmod in os.supports_fd: + os.chmod(f.fileno(), mode) + elif os.chmod in os.supports_follow_symlinks: + os.chmod(f.name, mode, follow_symlinks=False) + + replace(f.name, path) + + def set( + self, key: str, value: bytes, expires: Union[int, datetime, None] = None + ) -> None: + path = self._get_cache_path(key) + self._write(path, value) + + def delete(self, key: str) -> None: + path = self._get_cache_path(key) + with suppressed_cache_errors(): + os.remove(path) + with suppressed_cache_errors(): + os.remove(path + ".body") + + def get_body(self, key: str) -> Optional[BinaryIO]: + # The cache entry is only valid if both metadata and body exist. + metadata_path = self._get_cache_path(key) + body_path = metadata_path + ".body" + if not (os.path.exists(metadata_path) and os.path.exists(body_path)): + return None + with suppressed_cache_errors(): + return open(body_path, "rb") + + def set_body(self, key: str, body: bytes) -> None: + path = self._get_cache_path(key) + ".body" + self._write(path, body) diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/download.py b/backend/venv/Lib/site-packages/pip/_internal/network/download.py new file mode 100644 index 0000000..5c3bce3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/download.py @@ -0,0 +1,187 @@ +"""Download files with progress indicators. +""" + +import email.message +import logging +import mimetypes +import os +from typing import Iterable, Optional, Tuple + +from pip._vendor.requests.models import Response + +from pip._internal.cli.progress_bars import get_download_progress_renderer +from pip._internal.exceptions import NetworkConnectionError +from pip._internal.models.index import PyPI +from pip._internal.models.link import Link +from pip._internal.network.cache import is_from_cache +from pip._internal.network.session import PipSession +from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks +from pip._internal.utils.misc import format_size, redact_auth_from_url, splitext + +logger = logging.getLogger(__name__) + + +def _get_http_response_size(resp: Response) -> Optional[int]: + try: + return int(resp.headers["content-length"]) + except (ValueError, KeyError, TypeError): + return None + + +def _prepare_download( + resp: Response, + link: Link, + progress_bar: str, +) -> Iterable[bytes]: + total_length = _get_http_response_size(resp) + + if link.netloc == PyPI.file_storage_domain: + url = link.show_url + else: + url = link.url_without_fragment + + logged_url = redact_auth_from_url(url) + + if total_length: + logged_url = f"{logged_url} ({format_size(total_length)})" + + if is_from_cache(resp): + logger.info("Using cached %s", logged_url) + else: + logger.info("Downloading %s", logged_url) + + if logger.getEffectiveLevel() > logging.INFO: + show_progress = False + elif is_from_cache(resp): + show_progress = False + elif not total_length: + show_progress = True + elif total_length > (512 * 1024): + show_progress = True + else: + show_progress = False + + chunks = response_chunks(resp) + + if not show_progress: + return chunks + + renderer = get_download_progress_renderer(bar_type=progress_bar, size=total_length) + return renderer(chunks) + + +def sanitize_content_filename(filename: str) -> str: + """ + Sanitize the "filename" value from a Content-Disposition header. + """ + return os.path.basename(filename) + + +def parse_content_disposition(content_disposition: str, default_filename: str) -> str: + """ + Parse the "filename" value from a Content-Disposition header, and + return the default filename if the result is empty. + """ + m = email.message.Message() + m["content-type"] = content_disposition + filename = m.get_param("filename") + if filename: + # We need to sanitize the filename to prevent directory traversal + # in case the filename contains ".." path parts. + filename = sanitize_content_filename(str(filename)) + return filename or default_filename + + +def _get_http_response_filename(resp: Response, link: Link) -> str: + """Get an ideal filename from the given HTTP response, falling back to + the link filename if not provided. + """ + filename = link.filename # fallback + # Have a look at the Content-Disposition header for a better guess + content_disposition = resp.headers.get("content-disposition") + if content_disposition: + filename = parse_content_disposition(content_disposition, filename) + ext: Optional[str] = splitext(filename)[1] + if not ext: + ext = mimetypes.guess_extension(resp.headers.get("content-type", "")) + if ext: + filename += ext + if not ext and link.url != resp.url: + ext = os.path.splitext(resp.url)[1] + if ext: + filename += ext + return filename + + +def _http_get_download(session: PipSession, link: Link) -> Response: + target_url = link.url.split("#", 1)[0] + resp = session.get(target_url, headers=HEADERS, stream=True) + raise_for_status(resp) + return resp + + +class Downloader: + def __init__( + self, + session: PipSession, + progress_bar: str, + ) -> None: + self._session = session + self._progress_bar = progress_bar + + def __call__(self, link: Link, location: str) -> Tuple[str, str]: + """Download the file given by link into location.""" + try: + resp = _http_get_download(self._session, link) + except NetworkConnectionError as e: + assert e.response is not None + logger.critical( + "HTTP error %s while getting %s", e.response.status_code, link + ) + raise + + filename = _get_http_response_filename(resp, link) + filepath = os.path.join(location, filename) + + chunks = _prepare_download(resp, link, self._progress_bar) + with open(filepath, "wb") as content_file: + for chunk in chunks: + content_file.write(chunk) + content_type = resp.headers.get("Content-Type", "") + return filepath, content_type + + +class BatchDownloader: + def __init__( + self, + session: PipSession, + progress_bar: str, + ) -> None: + self._session = session + self._progress_bar = progress_bar + + def __call__( + self, links: Iterable[Link], location: str + ) -> Iterable[Tuple[Link, Tuple[str, str]]]: + """Download the files given by links into location.""" + for link in links: + try: + resp = _http_get_download(self._session, link) + except NetworkConnectionError as e: + assert e.response is not None + logger.critical( + "HTTP error %s while getting %s", + e.response.status_code, + link, + ) + raise + + filename = _get_http_response_filename(resp, link) + filepath = os.path.join(location, filename) + + chunks = _prepare_download(resp, link, self._progress_bar) + with open(filepath, "wb") as content_file: + for chunk in chunks: + content_file.write(chunk) + content_type = resp.headers.get("Content-Type", "") + yield link, (filepath, content_type) diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py b/backend/venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py new file mode 100644 index 0000000..03f883c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py @@ -0,0 +1,210 @@ +"""Lazy ZIP over HTTP""" + +__all__ = ["HTTPRangeRequestUnsupported", "dist_from_wheel_url"] + +from bisect import bisect_left, bisect_right +from contextlib import contextmanager +from tempfile import NamedTemporaryFile +from typing import Any, Dict, Generator, List, Optional, Tuple +from zipfile import BadZipFile, ZipFile + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response + +from pip._internal.metadata import BaseDistribution, MemoryWheel, get_wheel_distribution +from pip._internal.network.session import PipSession +from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks + + +class HTTPRangeRequestUnsupported(Exception): + pass + + +def dist_from_wheel_url(name: str, url: str, session: PipSession) -> BaseDistribution: + """Return a distribution object from the given wheel URL. + + This uses HTTP range requests to only fetch the portion of the wheel + containing metadata, just enough for the object to be constructed. + If such requests are not supported, HTTPRangeRequestUnsupported + is raised. + """ + with LazyZipOverHTTP(url, session) as zf: + # For read-only ZIP files, ZipFile only needs methods read, + # seek, seekable and tell, not the whole IO protocol. + wheel = MemoryWheel(zf.name, zf) # type: ignore + # After context manager exit, wheel.name + # is an invalid file by intention. + return get_wheel_distribution(wheel, canonicalize_name(name)) + + +class LazyZipOverHTTP: + """File-like object mapped to a ZIP file over HTTP. + + This uses HTTP range requests to lazily fetch the file's content, + which is supposed to be fed to ZipFile. If such requests are not + supported by the server, raise HTTPRangeRequestUnsupported + during initialization. + """ + + def __init__( + self, url: str, session: PipSession, chunk_size: int = CONTENT_CHUNK_SIZE + ) -> None: + head = session.head(url, headers=HEADERS) + raise_for_status(head) + assert head.status_code == 200 + self._session, self._url, self._chunk_size = session, url, chunk_size + self._length = int(head.headers["Content-Length"]) + self._file = NamedTemporaryFile() + self.truncate(self._length) + self._left: List[int] = [] + self._right: List[int] = [] + if "bytes" not in head.headers.get("Accept-Ranges", "none"): + raise HTTPRangeRequestUnsupported("range request is not supported") + self._check_zip() + + @property + def mode(self) -> str: + """Opening mode, which is always rb.""" + return "rb" + + @property + def name(self) -> str: + """Path to the underlying file.""" + return self._file.name + + def seekable(self) -> bool: + """Return whether random access is supported, which is True.""" + return True + + def close(self) -> None: + """Close the file.""" + self._file.close() + + @property + def closed(self) -> bool: + """Whether the file is closed.""" + return self._file.closed + + def read(self, size: int = -1) -> bytes: + """Read up to size bytes from the object and return them. + + As a convenience, if size is unspecified or -1, + all bytes until EOF are returned. Fewer than + size bytes may be returned if EOF is reached. + """ + download_size = max(size, self._chunk_size) + start, length = self.tell(), self._length + stop = length if size < 0 else min(start + download_size, length) + start = max(0, stop - download_size) + self._download(start, stop - 1) + return self._file.read(size) + + def readable(self) -> bool: + """Return whether the file is readable, which is True.""" + return True + + def seek(self, offset: int, whence: int = 0) -> int: + """Change stream position and return the new absolute position. + + Seek to offset relative position indicated by whence: + * 0: Start of stream (the default). pos should be >= 0; + * 1: Current position - pos may be negative; + * 2: End of stream - pos usually negative. + """ + return self._file.seek(offset, whence) + + def tell(self) -> int: + """Return the current position.""" + return self._file.tell() + + def truncate(self, size: Optional[int] = None) -> int: + """Resize the stream to the given size in bytes. + + If size is unspecified resize to the current position. + The current stream position isn't changed. + + Return the new file size. + """ + return self._file.truncate(size) + + def writable(self) -> bool: + """Return False.""" + return False + + def __enter__(self) -> "LazyZipOverHTTP": + self._file.__enter__() + return self + + def __exit__(self, *exc: Any) -> None: + self._file.__exit__(*exc) + + @contextmanager + def _stay(self) -> Generator[None, None, None]: + """Return a context manager keeping the position. + + At the end of the block, seek back to original position. + """ + pos = self.tell() + try: + yield + finally: + self.seek(pos) + + def _check_zip(self) -> None: + """Check and download until the file is a valid ZIP.""" + end = self._length - 1 + for start in reversed(range(0, end, self._chunk_size)): + self._download(start, end) + with self._stay(): + try: + # For read-only ZIP files, ZipFile only needs + # methods read, seek, seekable and tell. + ZipFile(self) + except BadZipFile: + pass + else: + break + + def _stream_response( + self, start: int, end: int, base_headers: Dict[str, str] = HEADERS + ) -> Response: + """Return HTTP response to a range request from start to end.""" + headers = base_headers.copy() + headers["Range"] = f"bytes={start}-{end}" + # TODO: Get range requests to be correctly cached + headers["Cache-Control"] = "no-cache" + return self._session.get(self._url, headers=headers, stream=True) + + def _merge( + self, start: int, end: int, left: int, right: int + ) -> Generator[Tuple[int, int], None, None]: + """Return a generator of intervals to be fetched. + + Args: + start (int): Start of needed interval + end (int): End of needed interval + left (int): Index of first overlapping downloaded data + right (int): Index after last overlapping downloaded data + """ + lslice, rslice = self._left[left:right], self._right[left:right] + i = start = min([start] + lslice[:1]) + end = max([end] + rslice[-1:]) + for j, k in zip(lslice, rslice): + if j > i: + yield i, j - 1 + i = k + 1 + if i <= end: + yield i, end + self._left[left:right], self._right[left:right] = [start], [end] + + def _download(self, start: int, end: int) -> None: + """Download bytes from start to end inclusively.""" + with self._stay(): + left = bisect_left(self._right, start) + right = bisect_right(self._left, end) + for start, end in self._merge(start, end, left, right): + response = self._stream_response(start, end) + response.raise_for_status() + self.seek(start) + for chunk in response_chunks(response, self._chunk_size): + self._file.write(chunk) diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/session.py b/backend/venv/Lib/site-packages/pip/_internal/network/session.py new file mode 100644 index 0000000..5e10f8f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/session.py @@ -0,0 +1,523 @@ +"""PipSession and supporting code, containing all pip-specific +network request configuration and behavior. +""" + +import email.utils +import functools +import io +import ipaddress +import json +import logging +import mimetypes +import os +import platform +import shutil +import subprocess +import sys +import urllib.parse +import warnings +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Generator, + List, + Mapping, + Optional, + Sequence, + Tuple, + Union, +) + +from pip._vendor import requests, urllib3 +from pip._vendor.cachecontrol import CacheControlAdapter as _BaseCacheControlAdapter +from pip._vendor.requests.adapters import DEFAULT_POOLBLOCK, BaseAdapter +from pip._vendor.requests.adapters import HTTPAdapter as _BaseHTTPAdapter +from pip._vendor.requests.models import PreparedRequest, Response +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.urllib3.connectionpool import ConnectionPool +from pip._vendor.urllib3.exceptions import InsecureRequestWarning + +from pip import __version__ +from pip._internal.metadata import get_default_environment +from pip._internal.models.link import Link +from pip._internal.network.auth import MultiDomainBasicAuth +from pip._internal.network.cache import SafeFileCache + +# Import ssl from compat so the initial import occurs in only one place. +from pip._internal.utils.compat import has_tls +from pip._internal.utils.glibc import libc_ver +from pip._internal.utils.misc import build_url_from_netloc, parse_netloc +from pip._internal.utils.urls import url_to_path + +if TYPE_CHECKING: + from ssl import SSLContext + + from pip._vendor.urllib3.poolmanager import PoolManager + + +logger = logging.getLogger(__name__) + +SecureOrigin = Tuple[str, str, Optional[Union[int, str]]] + + +# Ignore warning raised when using --trusted-host. +warnings.filterwarnings("ignore", category=InsecureRequestWarning) + + +SECURE_ORIGINS: List[SecureOrigin] = [ + # protocol, hostname, port + # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) + ("https", "*", "*"), + ("*", "localhost", "*"), + ("*", "127.0.0.0/8", "*"), + ("*", "::1/128", "*"), + ("file", "*", None), + # ssh is always secure. + ("ssh", "*", "*"), +] + + +# These are environment variables present when running under various +# CI systems. For each variable, some CI systems that use the variable +# are indicated. The collection was chosen so that for each of a number +# of popular systems, at least one of the environment variables is used. +# This list is used to provide some indication of and lower bound for +# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive. +# For more background, see: https://github.com/pypa/pip/issues/5499 +CI_ENVIRONMENT_VARIABLES = ( + # Azure Pipelines + "BUILD_BUILDID", + # Jenkins + "BUILD_ID", + # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI + "CI", + # Explicit environment variable. + "PIP_IS_CI", +) + + +def looks_like_ci() -> bool: + """ + Return whether it looks like pip is running under CI. + """ + # We don't use the method of checking for a tty (e.g. using isatty()) + # because some CI systems mimic a tty (e.g. Travis CI). Thus that + # method doesn't provide definitive information in either direction. + return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES) + + +@functools.lru_cache(maxsize=1) +def user_agent() -> str: + """ + Return a string representing the user agent. + """ + data: Dict[str, Any] = { + "installer": {"name": "pip", "version": __version__}, + "python": platform.python_version(), + "implementation": { + "name": platform.python_implementation(), + }, + } + + if data["implementation"]["name"] == "CPython": + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == "PyPy": + pypy_version_info = sys.pypy_version_info # type: ignore + if pypy_version_info.releaselevel == "final": + pypy_version_info = pypy_version_info[:3] + data["implementation"]["version"] = ".".join( + [str(x) for x in pypy_version_info] + ) + elif data["implementation"]["name"] == "Jython": + # Complete Guess + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == "IronPython": + # Complete Guess + data["implementation"]["version"] = platform.python_version() + + if sys.platform.startswith("linux"): + from pip._vendor import distro + + linux_distribution = distro.name(), distro.version(), distro.codename() + distro_infos: Dict[str, Any] = dict( + filter( + lambda x: x[1], + zip(["name", "version", "id"], linux_distribution), + ) + ) + libc = dict( + filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + ) + ) + if libc: + distro_infos["libc"] = libc + if distro_infos: + data["distro"] = distro_infos + + if sys.platform.startswith("darwin") and platform.mac_ver()[0]: + data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} + + if platform.system(): + data.setdefault("system", {})["name"] = platform.system() + + if platform.release(): + data.setdefault("system", {})["release"] = platform.release() + + if platform.machine(): + data["cpu"] = platform.machine() + + if has_tls(): + import _ssl as ssl + + data["openssl_version"] = ssl.OPENSSL_VERSION + + setuptools_dist = get_default_environment().get_distribution("setuptools") + if setuptools_dist is not None: + data["setuptools_version"] = str(setuptools_dist.version) + + if shutil.which("rustc") is not None: + # If for any reason `rustc --version` fails, silently ignore it + try: + rustc_output = subprocess.check_output( + ["rustc", "--version"], stderr=subprocess.STDOUT, timeout=0.5 + ) + except Exception: + pass + else: + if rustc_output.startswith(b"rustc "): + # The format of `rustc --version` is: + # `b'rustc 1.52.1 (9bc8c42bb 2021-05-09)\n'` + # We extract just the middle (1.52.1) part + data["rustc_version"] = rustc_output.split(b" ")[1].decode() + + # Use None rather than False so as not to give the impression that + # pip knows it is not being run under CI. Rather, it is a null or + # inconclusive result. Also, we include some value rather than no + # value to make it easier to know that the check has been run. + data["ci"] = True if looks_like_ci() else None + + user_data = os.environ.get("PIP_USER_AGENT_USER_DATA") + if user_data is not None: + data["user_data"] = user_data + + return "{data[installer][name]}/{data[installer][version]} {json}".format( + data=data, + json=json.dumps(data, separators=(",", ":"), sort_keys=True), + ) + + +class LocalFSAdapter(BaseAdapter): + def send( + self, + request: PreparedRequest, + stream: bool = False, + timeout: Optional[Union[float, Tuple[float, float]]] = None, + verify: Union[bool, str] = True, + cert: Optional[Union[str, Tuple[str, str]]] = None, + proxies: Optional[Mapping[str, str]] = None, + ) -> Response: + pathname = url_to_path(request.url) + + resp = Response() + resp.status_code = 200 + resp.url = request.url + + try: + stats = os.stat(pathname) + except OSError as exc: + # format the exception raised as a io.BytesIO object, + # to return a better error message: + resp.status_code = 404 + resp.reason = type(exc).__name__ + resp.raw = io.BytesIO(f"{resp.reason}: {exc}".encode()) + else: + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + content_type = mimetypes.guess_type(pathname)[0] or "text/plain" + resp.headers = CaseInsensitiveDict( + { + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + } + ) + + resp.raw = open(pathname, "rb") + resp.close = resp.raw.close + + return resp + + def close(self) -> None: + pass + + +class _SSLContextAdapterMixin: + """Mixin to add the ``ssl_context`` constructor argument to HTTP adapters. + + The additional argument is forwarded directly to the pool manager. This allows us + to dynamically decide what SSL store to use at runtime, which is used to implement + the optional ``truststore`` backend. + """ + + def __init__( + self, + *, + ssl_context: Optional["SSLContext"] = None, + **kwargs: Any, + ) -> None: + self._ssl_context = ssl_context + super().__init__(**kwargs) + + def init_poolmanager( + self, + connections: int, + maxsize: int, + block: bool = DEFAULT_POOLBLOCK, + **pool_kwargs: Any, + ) -> "PoolManager": + if self._ssl_context is not None: + pool_kwargs.setdefault("ssl_context", self._ssl_context) + return super().init_poolmanager( # type: ignore[misc] + connections=connections, + maxsize=maxsize, + block=block, + **pool_kwargs, + ) + + +class HTTPAdapter(_SSLContextAdapterMixin, _BaseHTTPAdapter): + pass + + +class CacheControlAdapter(_SSLContextAdapterMixin, _BaseCacheControlAdapter): + pass + + +class InsecureHTTPAdapter(HTTPAdapter): + def cert_verify( + self, + conn: ConnectionPool, + url: str, + verify: Union[bool, str], + cert: Optional[Union[str, Tuple[str, str]]], + ) -> None: + super().cert_verify(conn=conn, url=url, verify=False, cert=cert) + + +class InsecureCacheControlAdapter(CacheControlAdapter): + def cert_verify( + self, + conn: ConnectionPool, + url: str, + verify: Union[bool, str], + cert: Optional[Union[str, Tuple[str, str]]], + ) -> None: + super().cert_verify(conn=conn, url=url, verify=False, cert=cert) + + +class PipSession(requests.Session): + timeout: Optional[int] = None + + def __init__( + self, + *args: Any, + retries: int = 0, + cache: Optional[str] = None, + trusted_hosts: Sequence[str] = (), + index_urls: Optional[List[str]] = None, + ssl_context: Optional["SSLContext"] = None, + **kwargs: Any, + ) -> None: + """ + :param trusted_hosts: Domains not to emit warnings for when not using + HTTPS. + """ + super().__init__(*args, **kwargs) + + # Namespace the attribute with "pip_" just in case to prevent + # possible conflicts with the base class. + self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = [] + self.pip_proxy = None + + # Attach our User Agent to the request + self.headers["User-Agent"] = user_agent() + + # Attach our Authentication handler to the session + self.auth = MultiDomainBasicAuth(index_urls=index_urls) + + # Create our urllib3.Retry instance which will allow us to customize + # how we handle retries. + retries = urllib3.Retry( + # Set the total number of retries that a particular request can + # have. + total=retries, + # A 503 error from PyPI typically means that the Fastly -> Origin + # connection got interrupted in some way. A 503 error in general + # is typically considered a transient error so we'll go ahead and + # retry it. + # A 500 may indicate transient error in Amazon S3 + # A 502 may be a transient error from a CDN like CloudFlare or CloudFront + # A 520 or 527 - may indicate transient error in CloudFlare + status_forcelist=[500, 502, 503, 520, 527], + # Add a small amount of back off between failed requests in + # order to prevent hammering the service. + backoff_factor=0.25, + ) # type: ignore + + # Our Insecure HTTPAdapter disables HTTPS validation. It does not + # support caching so we'll use it for all http:// URLs. + # If caching is disabled, we will also use it for + # https:// hosts that we've marked as ignoring + # TLS errors for (trusted-hosts). + insecure_adapter = InsecureHTTPAdapter(max_retries=retries) + + # We want to _only_ cache responses on securely fetched origins or when + # the host is specified as trusted. We do this because + # we can't validate the response of an insecurely/untrusted fetched + # origin, and we don't want someone to be able to poison the cache and + # require manual eviction from the cache to fix it. + if cache: + secure_adapter = CacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ssl_context=ssl_context, + ) + self._trusted_host_adapter = InsecureCacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ) + else: + secure_adapter = HTTPAdapter(max_retries=retries, ssl_context=ssl_context) + self._trusted_host_adapter = insecure_adapter + + self.mount("https://", secure_adapter) + self.mount("http://", insecure_adapter) + + # Enable file:// urls + self.mount("file://", LocalFSAdapter()) + + for host in trusted_hosts: + self.add_trusted_host(host, suppress_logging=True) + + def update_index_urls(self, new_index_urls: List[str]) -> None: + """ + :param new_index_urls: New index urls to update the authentication + handler with. + """ + self.auth.index_urls = new_index_urls + + def add_trusted_host( + self, host: str, source: Optional[str] = None, suppress_logging: bool = False + ) -> None: + """ + :param host: It is okay to provide a host that has previously been + added. + :param source: An optional source string, for logging where the host + string came from. + """ + if not suppress_logging: + msg = f"adding trusted host: {host!r}" + if source is not None: + msg += f" (from {source})" + logger.info(msg) + + parsed_host, parsed_port = parse_netloc(host) + if parsed_host is None: + raise ValueError(f"Trusted host URL must include a host part: {host!r}") + if (parsed_host, parsed_port) not in self.pip_trusted_origins: + self.pip_trusted_origins.append((parsed_host, parsed_port)) + + self.mount( + build_url_from_netloc(host, scheme="http") + "/", self._trusted_host_adapter + ) + self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter) + if not parsed_port: + self.mount( + build_url_from_netloc(host, scheme="http") + ":", + self._trusted_host_adapter, + ) + # Mount wildcard ports for the same host. + self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter) + + def iter_secure_origins(self) -> Generator[SecureOrigin, None, None]: + yield from SECURE_ORIGINS + for host, port in self.pip_trusted_origins: + yield ("*", host, "*" if port is None else port) + + def is_secure_origin(self, location: Link) -> bool: + # Determine if this url used a secure transport mechanism + parsed = urllib.parse.urlparse(str(location)) + origin_protocol, origin_host, origin_port = ( + parsed.scheme, + parsed.hostname, + parsed.port, + ) + + # The protocol to use to see if the protocol matches. + # Don't count the repository type as part of the protocol: in + # cases such as "git+ssh", only use "ssh". (I.e., Only verify against + # the last scheme.) + origin_protocol = origin_protocol.rsplit("+", 1)[-1] + + # Determine if our origin is a secure origin by looking through our + # hardcoded list of secure origins, as well as any additional ones + # configured on this PackageFinder instance. + for secure_origin in self.iter_secure_origins(): + secure_protocol, secure_host, secure_port = secure_origin + if origin_protocol != secure_protocol and secure_protocol != "*": + continue + + try: + addr = ipaddress.ip_address(origin_host or "") + network = ipaddress.ip_network(secure_host) + except ValueError: + # We don't have both a valid address or a valid network, so + # we'll check this origin against hostnames. + if ( + origin_host + and origin_host.lower() != secure_host.lower() + and secure_host != "*" + ): + continue + else: + # We have a valid address and network, so see if the address + # is contained within the network. + if addr not in network: + continue + + # Check to see if the port matches. + if ( + origin_port != secure_port + and secure_port != "*" + and secure_port is not None + ): + continue + + # If we've gotten here, then this origin matches the current + # secure origin and we should return True + return True + + # If we've gotten to this point, then the origin isn't secure and we + # will not accept it as a valid location to search. We will however + # log a warning that we are ignoring it. + logger.warning( + "The repository located at %s is not a trusted or secure host and " + "is being ignored. If this repository is available via HTTPS we " + "recommend you use HTTPS instead, otherwise you may silence " + "this warning and allow it anyway with '--trusted-host %s'.", + origin_host, + origin_host, + ) + + return False + + def request(self, method: str, url: str, *args: Any, **kwargs: Any) -> Response: + # Allow setting a default timeout on a session + kwargs.setdefault("timeout", self.timeout) + # Allow setting a default proxies on a session + kwargs.setdefault("proxies", self.proxies) + + # Dispatch the actual request + return super().request(method, url, *args, **kwargs) diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/utils.py b/backend/venv/Lib/site-packages/pip/_internal/network/utils.py new file mode 100644 index 0000000..bba4c26 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/utils.py @@ -0,0 +1,98 @@ +from typing import Dict, Generator + +from pip._vendor.requests.models import Response + +from pip._internal.exceptions import NetworkConnectionError + +# The following comments and HTTP headers were originally added by +# Donald Stufft in git commit 22c562429a61bb77172039e480873fb239dd8c03. +# +# We use Accept-Encoding: identity here because requests defaults to +# accepting compressed responses. This breaks in a variety of ways +# depending on how the server is configured. +# - Some servers will notice that the file isn't a compressible file +# and will leave the file alone and with an empty Content-Encoding +# - Some servers will notice that the file is already compressed and +# will leave the file alone, adding a Content-Encoding: gzip header +# - Some servers won't notice anything at all and will take a file +# that's already been compressed and compress it again, and set +# the Content-Encoding: gzip header +# By setting this to request only the identity encoding we're hoping +# to eliminate the third case. Hopefully there does not exist a server +# which when given a file will notice it is already compressed and that +# you're not asking for a compressed file and will then decompress it +# before sending because if that's the case I don't think it'll ever be +# possible to make this work. +HEADERS: Dict[str, str] = {"Accept-Encoding": "identity"} + +DOWNLOAD_CHUNK_SIZE = 256 * 1024 + + +def raise_for_status(resp: Response) -> None: + http_error_msg = "" + if isinstance(resp.reason, bytes): + # We attempt to decode utf-8 first because some servers + # choose to localize their reason strings. If the string + # isn't utf-8, we fall back to iso-8859-1 for all other + # encodings. + try: + reason = resp.reason.decode("utf-8") + except UnicodeDecodeError: + reason = resp.reason.decode("iso-8859-1") + else: + reason = resp.reason + + if 400 <= resp.status_code < 500: + http_error_msg = ( + f"{resp.status_code} Client Error: {reason} for url: {resp.url}" + ) + + elif 500 <= resp.status_code < 600: + http_error_msg = ( + f"{resp.status_code} Server Error: {reason} for url: {resp.url}" + ) + + if http_error_msg: + raise NetworkConnectionError(http_error_msg, response=resp) + + +def response_chunks( + response: Response, chunk_size: int = DOWNLOAD_CHUNK_SIZE +) -> Generator[bytes, None, None]: + """Given a requests Response, provide the data chunks.""" + try: + # Special case for urllib3. + for chunk in response.raw.stream( + chunk_size, + # We use decode_content=False here because we don't + # want urllib3 to mess with the raw bytes we get + # from the server. If we decompress inside of + # urllib3 then we cannot verify the checksum + # because the checksum will be of the compressed + # file. This breakage will only occur if the + # server adds a Content-Encoding header, which + # depends on how the server was configured: + # - Some servers will notice that the file isn't a + # compressible file and will leave the file alone + # and with an empty Content-Encoding + # - Some servers will notice that the file is + # already compressed and will leave the file + # alone and will add a Content-Encoding: gzip + # header + # - Some servers won't notice anything at all and + # will take a file that's already been compressed + # and compress it again and set the + # Content-Encoding: gzip header + # + # By setting this not to decode automatically we + # hope to eliminate problems with the second case. + decode_content=False, + ): + yield chunk + except AttributeError: + # Standard file-like object. + while True: + chunk = response.raw.read(chunk_size) + if not chunk: + break + yield chunk diff --git a/backend/venv/Lib/site-packages/pip/_internal/network/xmlrpc.py b/backend/venv/Lib/site-packages/pip/_internal/network/xmlrpc.py new file mode 100644 index 0000000..22ec8d2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/network/xmlrpc.py @@ -0,0 +1,62 @@ +"""xmlrpclib.Transport implementation +""" + +import logging +import urllib.parse +import xmlrpc.client +from typing import TYPE_CHECKING, Tuple + +from pip._internal.exceptions import NetworkConnectionError +from pip._internal.network.session import PipSession +from pip._internal.network.utils import raise_for_status + +if TYPE_CHECKING: + from xmlrpc.client import _HostType, _Marshallable + + from _typeshed import SizedBuffer + +logger = logging.getLogger(__name__) + + +class PipXmlrpcTransport(xmlrpc.client.Transport): + """Provide a `xmlrpclib.Transport` implementation via a `PipSession` + object. + """ + + def __init__( + self, index_url: str, session: PipSession, use_datetime: bool = False + ) -> None: + super().__init__(use_datetime) + index_parts = urllib.parse.urlparse(index_url) + self._scheme = index_parts.scheme + self._session = session + + def request( + self, + host: "_HostType", + handler: str, + request_body: "SizedBuffer", + verbose: bool = False, + ) -> Tuple["_Marshallable", ...]: + assert isinstance(host, str) + parts = (self._scheme, host, handler, None, None, None) + url = urllib.parse.urlunparse(parts) + try: + headers = {"Content-Type": "text/xml"} + response = self._session.post( + url, + data=request_body, + headers=headers, + stream=True, + ) + raise_for_status(response) + self.verbose = verbose + return self.parse_response(response.raw) + except NetworkConnectionError as exc: + assert exc.response + logger.critical( + "HTTP error %s while getting %s", + exc.response.status_code, + url, + ) + raise diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/operations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ab4283377dae0166e8e67518f4f90414bf8416e GIT binary patch literal 201 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

        sbq}sYTzRl4Wq)hUBncXs-A}#pZ)0KlH-dlc)Lj qfyKVEuViW4wg9pEm{;hov~}K|F0~!1nz3?Xf`1LRhZZ36^ZkDlDe%Dn literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7be81fd671ccc6946e7a56b2efdc4179c8f7d415 GIT binary patch literal 10252 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47119859753b32710ea6c35bd2fa5ae7f3978c75 GIT binary patch literal 7671 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 OV>!Ji!#;floc#-Yas*)j literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21b9ce42b75178e46aa6d49de65f1e3d08ad64a1 GIT binary patch literal 1915 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 O8pWmU47BJZEb4#4)+V_C literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52975063665513d0c5cdd6acb3725233f35627ee GIT binary patch literal 1681 zcmZux-ESL35Z}EIf7{Jxi<7Ec$p>{w9jYoMM4=KXt)QyXD)17^)#>8fIOp6KyXUx$ zTnGrEL;~fpkq}Z}Q48uHz)Skdi=!4LTtTV?ec;U^kt&rJX3w!*5PQ0vnVs34*_q$$ zPswBq!5I2s-nbwk^g9vXnFlqUCm)xgHWslx zrOXVwsCdgnxpDc1GI4%VS>z~CTu?&a7>tZ5&4M#!4!mcBljhda?-Ax1w#IR%v@tTRjIg!dAXFYu)4`HM zm9=i=j9Z0pN&u#;=U8SYgJ}frzIO78W|%~8M*QzxBPU2YQC_TEn$CmUBGoJlBF$GEr{Gu?p#`EE_9|2Y`XqnULwS%_^Vf{U zJTp9U&V|l`Mq_!`aL2*gBNQ5T+;IsFlE}t`3ycSzvu@SzdFeu`OI)ZbeFb7kz|X#i zX&p8CP~ucQo~cV2m>WV;?)x>8+DdFD>ius%7verrL)hwL03;^|2~YNME_q%c**~T2Om9-O#gDMw;{vw3w8z~ z{_?F^3H{jj?v%LG6#;f&XG1|ol|*-e-lBF6X$NsgJ&tfT0eUkf>4LHna%_Up#kar^U+M%)R%Vd+zzU z=R0SAOeW(9#^6_{j71TlUl|dOM0>M(0XA2Vj&#mM`C#Sp9MHVUTS8vo7*8-GmY5eU zDKGhS#Ee?8e2hap!f38DRJyU^_zfxuE#%)_o*i99uIpyth49HB3FHmCj;Yf6Z~uPHCoziI-sew+u=Ry9`%)N!7M7 zDb@^kwn!_6Pgs~zt&F{hty$QMP6tZ7P7Ax5uDM!KHwZ4d4yk*hi>-?8Nd&u9VwWO; z=l&dpS%7c#dx+->YVzm#H_!!6M((=M96R4MbiOIv-~%RyTzLIp=t2`+Lwe+MA$*^O zNRyjmRyK`hB$RjoaY#lWC2tY|vMDtAFU8Q(f+#~C*)QaP?XBUhr{!s`D?Hs;o5F|d z8s9;K$n{ag&W8}mEJ#m8p4_+L?>eyI)-KH+U z=@fpy3P`Z9?W$Dd7M~)v>Yt>NEqOS|Lse;FOKWRT!sym{7H%xwES4sI^&) zP1TrDX|=?}W~!!H_iwsc^#o`mHG|?2HGmgYkAwBBujzQB`&CR`!`2w&)pbNpsKc}o zfS);pb;H%BO{~s1L~V4a&s6H*(Hx*R>pGU1$#8^Wqj79Xvu($1JH38un5xsbq*W>Q zLkmJ`*Mq7%n5yj3tTrEC49qQlyO_QoOI=bHmF2GeUk~4jjsMm$vXUCQ{_gdo%li&5 zE0e1N-xPXlLJ}UQn@|%>L6-K=SdUWSd;;LrT{}#6RKs*f)_ov6p_{vaKZo z`!RhRg8gJHcNl%k0p%c5AT}l7k=pDV9unxC<7d%lxzb7p5)e{*_R1xHeN3zEL((R>JEW)vhBpe6cXE*{W-pG`j)W0K;+_yT<}($BI70ibcX&jVDl-_&NOotpW}0h;d_+ zmZMiq{4yB=lKu11GcdITj^pm3)IB8sf_nczZ~l&sK9GAZ?zk)W+>(2)j^CDt&O>H* ubI-2ClPv+(2g$*f2rHz!yRQ{xyBJcov}Cr6BPn&U^wF8M1W;rUEc^>`$qW7f literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86ccc37b323856c880b8b4c465da574ad33fcecf GIT binary patch literal 3850 zcmb_fOKcm*8J^{Gm%GcSNKr2*&f1h@v9js+OEp|ru^qHgWi&<)Q56srcSTWNa*3Ix zX%SSRwmC>>0Lv!}2n@(TfvT`k_}CtkYk@+l1bDl35fx2<=C+6hxbUg}%<>@%NlqPV zXa0ZYpZEWL|L8B_u!10^{`f)hs~|%Erb;VCo5IU)KzN8Wq;UqC@=9*X2fEMTOa3W; zNthBiTF)C|DKHgavfq$O@|4VE!B9%UsbDEI72=Q&>1ckSHA$z`BTqO_n~G|p?$=}e zplSg`7Cz#8&mZ)RH>oo$Cl;Ilhn zv`^6^PiN~&i}hnS*&(UTgHVfQ@6_NXRFG7|EEJ06LZ+U0*E>cPj=NgY%N7|^9Zsot zx9Ytk98)LFvR*%Su=W>KqN^uP+|}`n36f>1WX`O8RF54nRMH}*yLUu7vyPpvf^OZI zoz?SJ@vc6h-_;E#&|H)wT)#2?^YcJi-va6^G-uAH5Ed{k9a^j16x|!^?g*hC;EW_xGYm zi9MH(Y{^Hq<<##Azb`#5{Y^g03@>jYJGAub#^m$Zc941?B5MWm)?H~>p_lC&XsiHNS0ozWVIr8{Inv!-;b%x5Rw6G zd5@&7ij#h9H=J5O)#K$>r{`@Z@H*8skytlQe_ZIqVkS3h8!qgr#i zTFF^+6dP1#?gMya3O#)j=kS8cd`pFk07QU~X6geI%)^=u=4`Vg1#dl}=CPi$bWJUr z>TJ=_Nk*Ccnlf1Za=WQyVgTe^uB-xbnN>!)3AXIw)sg(1X%fH)v|wVT$5afwhA_RZ zwB(4y#4tYdVjO`wCs51bGT1vj4B_}p;`r&d9RIvoECagxXm5H7m`166faOc1Kqv=N zgsLh|g6JFq_-8!~W!cu7q)&&$gVY#4@)$CJP8@|3tLK0F)1@1K560}+4>rzijBK8{ zxfywHnYX3jPIPd6`q|a(==hd2zRbUnBKIRJkyWxI9kQc|F9XW*`QOx6ul@R$yOEKN z?hVOB-04w!^wh?&XK|P3!slHc$st#Q?0bg#G8n#papmIuD=Sylr1hZ83V4W7fqmEuw6Js@ElS^yI}Ju``7VcKv=4bAL>FH}dMdW( zldUdT9ZU1^meeUb7+zE?detm7lm=k6AvWZv%9AF?ECw6Fyib$quQU5?ltLX04kCPp zLk(%3`sRV8wRgy&ef#?sglZBnNRx*+^dUMp=Ym{A_xKM{jZ2}^h;TI@wc_BnAba)c zVEvPE%Ki*X)iRA0fWBtPP^%0`6x~NXpFY}zZS&2NQ55R>9wU%89W<$6RwdOuecH@c z4Z~vsE2G|m;c%@;^y8}cdLb+XXV^$-9v_3_z$1`3QHX?AvCM)Lb+~$hEtO*1n}Kmg zP#s||3Lz_9@4w#Z(jlEOb%@jtRTiu{cqO!q)qQU=m^MLY~;`&=R zbHFZ|xAQkAA0m@!;X4^39mLf6G4%_NYXnW7sTME|5srN0US4O&am3kTxk%=4h8n80 zF<`)Z5w^@IBOUUnXNWcr)2w|)I8Ch;FLcv~r4yp7&q4?!5cBZ~+AMlc9k$MvEd?{7 zfq>p$D|r+a-_Kj#wd0Fm`9t`~4rIVweJFm$mXdbwklmBA``+G@g}Au%6E}i-(m+Mx z#+}W?*wVxcIk{@=$f@-jC9lv*Xft{0+0c%3$@MF8-;3m+9UHLU9<#d-+kNlA7(J2Y zn|nQ|EAdcypsbzWjvZMRUL;T1@m@PQV0R_${*-;_$X-zFQI-{$EH?1!BvJ;q2nE8^p_fb|`Uwa%FPu;!Y^_A{4(ru`;pQfALSAh8hCnpoJxQf(md3_x)^kFhSlEkygLIAbYX5*3*?addT`8Gb)zGivYtRHl zjmUo>gNVX$|3DG=`vM*L3Z4BY`q>xg)~-CT-1}S}*pdg?zYI`mq>npp2cxU}%4L@ac{kGK3Q&ScFyaQNB%wqv8$zaXJe0eM9#?=82I=Z{15}bwvVSe{;K!~^HF&D_t?>^o XyFseKJ2UErsT64rxfcbEoy7kDb|BjI literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py new file mode 100644 index 0000000..0ed8dd2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py @@ -0,0 +1,138 @@ +import contextlib +import hashlib +import logging +import os +from types import TracebackType +from typing import Dict, Generator, Optional, Type, Union + +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +@contextlib.contextmanager +def update_env_context_manager(**changes: str) -> Generator[None, None, None]: + target = os.environ + + # Save values from the target and change them. + non_existent_marker = object() + saved_values: Dict[str, Union[object, str]] = {} + for name, new_value in changes.items(): + try: + saved_values[name] = target[name] + except KeyError: + saved_values[name] = non_existent_marker + target[name] = new_value + + try: + yield + finally: + # Restore original values in the target. + for name, original_value in saved_values.items(): + if original_value is non_existent_marker: + del target[name] + else: + assert isinstance(original_value, str) # for mypy + target[name] = original_value + + +@contextlib.contextmanager +def get_build_tracker() -> Generator["BuildTracker", None, None]: + root = os.environ.get("PIP_BUILD_TRACKER") + with contextlib.ExitStack() as ctx: + if root is None: + root = ctx.enter_context(TempDirectory(kind="build-tracker")).path + ctx.enter_context(update_env_context_manager(PIP_BUILD_TRACKER=root)) + logger.debug("Initialized build tracking at %s", root) + + with BuildTracker(root) as tracker: + yield tracker + + +class TrackerId(str): + """Uniquely identifying string provided to the build tracker.""" + + +class BuildTracker: + """Ensure that an sdist cannot request itself as a setup requirement. + + When an sdist is prepared, it identifies its setup requirements in the + context of ``BuildTracker.track()``. If a requirement shows up recursively, this + raises an exception. + + This stops fork bombs embedded in malicious packages.""" + + def __init__(self, root: str) -> None: + self._root = root + self._entries: Dict[TrackerId, InstallRequirement] = {} + logger.debug("Created build tracker: %s", self._root) + + def __enter__(self) -> "BuildTracker": + logger.debug("Entered build tracker: %s", self._root) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.cleanup() + + def _entry_path(self, key: TrackerId) -> str: + hashed = hashlib.sha224(key.encode()).hexdigest() + return os.path.join(self._root, hashed) + + def add(self, req: InstallRequirement, key: TrackerId) -> None: + """Add an InstallRequirement to build tracking.""" + + # Get the file to write information about this requirement. + entry_path = self._entry_path(key) + + # Try reading from the file. If it exists and can be read from, a build + # is already in progress, so a LookupError is raised. + try: + with open(entry_path) as fp: + contents = fp.read() + except FileNotFoundError: + pass + else: + message = f"{req.link} is already being built: {contents}" + raise LookupError(message) + + # If we're here, req should really not be building already. + assert key not in self._entries + + # Start tracking this requirement. + with open(entry_path, "w", encoding="utf-8") as fp: + fp.write(str(req)) + self._entries[key] = req + + logger.debug("Added %s to build tracker %r", req, self._root) + + def remove(self, req: InstallRequirement, key: TrackerId) -> None: + """Remove an InstallRequirement from build tracking.""" + + # Delete the created file and the corresponding entry. + os.unlink(self._entry_path(key)) + del self._entries[key] + + logger.debug("Removed %s from build tracker %r", req, self._root) + + def cleanup(self) -> None: + for key, req in list(self._entries.items()): + self.remove(req, key) + + logger.debug("Removed build tracker: %r", self._root) + + @contextlib.contextmanager + def track(self, req: InstallRequirement, key: str) -> Generator[None, None, None]: + """Ensure that `key` cannot install itself as a setup requirement. + + :raises LookupError: If `key` was already provided in a parent invocation of + the context introduced by this method.""" + tracker_id = TrackerId(key) + self.add(req, tracker_id) + yield + self.remove(req, tracker_id) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata.py new file mode 100644 index 0000000..c66ac35 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata.py @@ -0,0 +1,39 @@ +"""Metadata generation logic for source distributions. +""" + +import os + +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip._internal.build_env import BuildEnvironment +from pip._internal.exceptions import ( + InstallationSubprocessError, + MetadataGenerationFailed, +) +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory + + +def generate_metadata( + build_env: BuildEnvironment, backend: BuildBackendHookCaller, details: str +) -> str: + """Generate metadata using mechanisms described in PEP 517. + + Returns the generated metadata directory. + """ + metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True) + + metadata_dir = metadata_tmpdir.path + + with build_env: + # Note that BuildBackendHookCaller implements a fallback for + # prepare_metadata_for_build_wheel, so we don't have to + # consider the possibility that this hook doesn't exist. + runner = runner_with_spinner_message("Preparing metadata (pyproject.toml)") + with backend.subprocess_runner(runner): + try: + distinfo_dir = backend.prepare_metadata_for_build_wheel(metadata_dir) + except InstallationSubprocessError as error: + raise MetadataGenerationFailed(package_details=details) from error + + return os.path.join(metadata_dir, distinfo_dir) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py new file mode 100644 index 0000000..3397ccf --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py @@ -0,0 +1,42 @@ +"""Metadata generation logic for source distributions. +""" + +import os + +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip._internal.build_env import BuildEnvironment +from pip._internal.exceptions import ( + InstallationSubprocessError, + MetadataGenerationFailed, +) +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory + + +def generate_editable_metadata( + build_env: BuildEnvironment, backend: BuildBackendHookCaller, details: str +) -> str: + """Generate metadata using mechanisms described in PEP 660. + + Returns the generated metadata directory. + """ + metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True) + + metadata_dir = metadata_tmpdir.path + + with build_env: + # Note that BuildBackendHookCaller implements a fallback for + # prepare_metadata_for_build_wheel/editable, so we don't have to + # consider the possibility that this hook doesn't exist. + runner = runner_with_spinner_message( + "Preparing editable metadata (pyproject.toml)" + ) + with backend.subprocess_runner(runner): + try: + distinfo_dir = backend.prepare_metadata_for_build_editable(metadata_dir) + except InstallationSubprocessError as error: + raise MetadataGenerationFailed(package_details=details) from error + + assert distinfo_dir is not None + return os.path.join(metadata_dir, distinfo_dir) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py new file mode 100644 index 0000000..c01dd1c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py @@ -0,0 +1,74 @@ +"""Metadata generation logic for legacy source distributions. +""" + +import logging +import os + +from pip._internal.build_env import BuildEnvironment +from pip._internal.cli.spinners import open_spinner +from pip._internal.exceptions import ( + InstallationError, + InstallationSubprocessError, + MetadataGenerationFailed, +) +from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +def _find_egg_info(directory: str) -> str: + """Find an .egg-info subdirectory in `directory`.""" + filenames = [f for f in os.listdir(directory) if f.endswith(".egg-info")] + + if not filenames: + raise InstallationError(f"No .egg-info directory found in {directory}") + + if len(filenames) > 1: + raise InstallationError( + f"More than one .egg-info directory found in {directory}" + ) + + return os.path.join(directory, filenames[0]) + + +def generate_metadata( + build_env: BuildEnvironment, + setup_py_path: str, + source_dir: str, + isolated: bool, + details: str, +) -> str: + """Generate metadata using setup.py-based defacto mechanisms. + + Returns the generated metadata directory. + """ + logger.debug( + "Running setup.py (path:%s) egg_info for package %s", + setup_py_path, + details, + ) + + egg_info_dir = TempDirectory(kind="pip-egg-info", globally_managed=True).path + + args = make_setuptools_egg_info_args( + setup_py_path, + egg_info_dir=egg_info_dir, + no_user_config=isolated, + ) + + with build_env: + with open_spinner("Preparing metadata (setup.py)") as spinner: + try: + call_subprocess( + args, + cwd=source_dir, + command_desc="python setup.py egg_info", + spinner=spinner, + ) + except InstallationSubprocessError as error: + raise MetadataGenerationFailed(package_details=details) from error + + # Return the .egg-info directory. + return _find_egg_info(egg_info_dir) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel.py new file mode 100644 index 0000000..064811a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel.py @@ -0,0 +1,37 @@ +import logging +import os +from typing import Optional + +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip._internal.utils.subprocess import runner_with_spinner_message + +logger = logging.getLogger(__name__) + + +def build_wheel_pep517( + name: str, + backend: BuildBackendHookCaller, + metadata_directory: str, + tempd: str, +) -> Optional[str]: + """Build one InstallRequirement using the PEP 517 build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + assert metadata_directory is not None + try: + logger.debug("Destination directory: %s", tempd) + + runner = runner_with_spinner_message( + f"Building wheel for {name} (pyproject.toml)" + ) + with backend.subprocess_runner(runner): + wheel_name = backend.build_wheel( + tempd, + metadata_directory=metadata_directory, + ) + except Exception: + logger.error("Failed building wheel for %s", name) + return None + return os.path.join(tempd, wheel_name) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py new file mode 100644 index 0000000..719d69d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py @@ -0,0 +1,46 @@ +import logging +import os +from typing import Optional + +from pip._vendor.pyproject_hooks import BuildBackendHookCaller, HookMissing + +from pip._internal.utils.subprocess import runner_with_spinner_message + +logger = logging.getLogger(__name__) + + +def build_wheel_editable( + name: str, + backend: BuildBackendHookCaller, + metadata_directory: str, + tempd: str, +) -> Optional[str]: + """Build one InstallRequirement using the PEP 660 build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + assert metadata_directory is not None + try: + logger.debug("Destination directory: %s", tempd) + + runner = runner_with_spinner_message( + f"Building editable for {name} (pyproject.toml)" + ) + with backend.subprocess_runner(runner): + try: + wheel_name = backend.build_editable( + tempd, + metadata_directory=metadata_directory, + ) + except HookMissing as e: + logger.error( + "Cannot build editable %s because the build " + "backend does not have the %s hook", + name, + e, + ) + return None + except Exception: + logger.error("Failed building editable for %s", name) + return None + return os.path.join(tempd, wheel_name) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py new file mode 100644 index 0000000..3ee2a70 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py @@ -0,0 +1,102 @@ +import logging +import os.path +from typing import List, Optional + +from pip._internal.cli.spinners import open_spinner +from pip._internal.utils.setuptools_build import make_setuptools_bdist_wheel_args +from pip._internal.utils.subprocess import call_subprocess, format_command_args + +logger = logging.getLogger(__name__) + + +def format_command_result( + command_args: List[str], + command_output: str, +) -> str: + """Format command information for logging.""" + command_desc = format_command_args(command_args) + text = f"Command arguments: {command_desc}\n" + + if not command_output: + text += "Command output: None" + elif logger.getEffectiveLevel() > logging.DEBUG: + text += "Command output: [use --verbose to show]" + else: + if not command_output.endswith("\n"): + command_output += "\n" + text += f"Command output:\n{command_output}" + + return text + + +def get_legacy_build_wheel_path( + names: List[str], + temp_dir: str, + name: str, + command_args: List[str], + command_output: str, +) -> Optional[str]: + """Return the path to the wheel in the temporary build directory.""" + # Sort for determinism. + names = sorted(names) + if not names: + msg = f"Legacy build of wheel for {name!r} created no files.\n" + msg += format_command_result(command_args, command_output) + logger.warning(msg) + return None + + if len(names) > 1: + msg = ( + f"Legacy build of wheel for {name!r} created more than one file.\n" + f"Filenames (choosing first): {names}\n" + ) + msg += format_command_result(command_args, command_output) + logger.warning(msg) + + return os.path.join(temp_dir, names[0]) + + +def build_wheel_legacy( + name: str, + setup_py_path: str, + source_dir: str, + global_options: List[str], + build_options: List[str], + tempd: str, +) -> Optional[str]: + """Build one unpacked package using the "legacy" build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + wheel_args = make_setuptools_bdist_wheel_args( + setup_py_path, + global_options=global_options, + build_options=build_options, + destination_dir=tempd, + ) + + spin_message = f"Building wheel for {name} (setup.py)" + with open_spinner(spin_message) as spinner: + logger.debug("Destination directory: %s", tempd) + + try: + output = call_subprocess( + wheel_args, + command_desc="python setup.py bdist_wheel", + cwd=source_dir, + spinner=spinner, + ) + except Exception: + spinner.finish("error") + logger.error("Failed building wheel for %s", name) + return None + + names = os.listdir(tempd) + wheel_path = get_legacy_build_wheel_path( + names=names, + temp_dir=tempd, + name=name, + command_args=wheel_args, + command_output=output, + ) + return wheel_path diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/check.py b/backend/venv/Lib/site-packages/pip/_internal/operations/check.py new file mode 100644 index 0000000..4b6fbc4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/check.py @@ -0,0 +1,181 @@ +"""Validation of dependencies of packages +""" + +import logging +from contextlib import suppress +from email.parser import Parser +from functools import reduce +from typing import ( + Callable, + Dict, + FrozenSet, + Generator, + Iterable, + List, + NamedTuple, + Optional, + Set, + Tuple, +) + +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.tags import Tag, parse_tag +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import Version + +from pip._internal.distributions import make_distribution_for_install_requirement +from pip._internal.metadata import get_default_environment +from pip._internal.metadata.base import BaseDistribution +from pip._internal.req.req_install import InstallRequirement + +logger = logging.getLogger(__name__) + + +class PackageDetails(NamedTuple): + version: Version + dependencies: List[Requirement] + + +# Shorthands +PackageSet = Dict[NormalizedName, PackageDetails] +Missing = Tuple[NormalizedName, Requirement] +Conflicting = Tuple[NormalizedName, Version, Requirement] + +MissingDict = Dict[NormalizedName, List[Missing]] +ConflictingDict = Dict[NormalizedName, List[Conflicting]] +CheckResult = Tuple[MissingDict, ConflictingDict] +ConflictDetails = Tuple[PackageSet, CheckResult] + + +def create_package_set_from_installed() -> Tuple[PackageSet, bool]: + """Converts a list of distributions into a PackageSet.""" + package_set = {} + problems = False + env = get_default_environment() + for dist in env.iter_installed_distributions(local_only=False, skip=()): + name = dist.canonical_name + try: + dependencies = list(dist.iter_dependencies()) + package_set[name] = PackageDetails(dist.version, dependencies) + except (OSError, ValueError) as e: + # Don't crash on unreadable or broken metadata. + logger.warning("Error parsing dependencies of %s: %s", name, e) + problems = True + return package_set, problems + + +def check_package_set( + package_set: PackageSet, should_ignore: Optional[Callable[[str], bool]] = None +) -> CheckResult: + """Check if a package set is consistent + + If should_ignore is passed, it should be a callable that takes a + package name and returns a boolean. + """ + + missing = {} + conflicting = {} + + for package_name, package_detail in package_set.items(): + # Info about dependencies of package_name + missing_deps: Set[Missing] = set() + conflicting_deps: Set[Conflicting] = set() + + if should_ignore and should_ignore(package_name): + continue + + for req in package_detail.dependencies: + name = canonicalize_name(req.name) + + # Check if it's missing + if name not in package_set: + missed = True + if req.marker is not None: + missed = req.marker.evaluate({"extra": ""}) + if missed: + missing_deps.add((name, req)) + continue + + # Check if there's a conflict + version = package_set[name].version + if not req.specifier.contains(version, prereleases=True): + conflicting_deps.add((name, version, req)) + + if missing_deps: + missing[package_name] = sorted(missing_deps, key=str) + if conflicting_deps: + conflicting[package_name] = sorted(conflicting_deps, key=str) + + return missing, conflicting + + +def check_install_conflicts(to_install: List[InstallRequirement]) -> ConflictDetails: + """For checking if the dependency graph would be consistent after \ + installing given requirements + """ + # Start from the current state + package_set, _ = create_package_set_from_installed() + # Install packages + would_be_installed = _simulate_installation_of(to_install, package_set) + + # Only warn about directly-dependent packages; create a whitelist of them + whitelist = _create_whitelist(would_be_installed, package_set) + + return ( + package_set, + check_package_set( + package_set, should_ignore=lambda name: name not in whitelist + ), + ) + + +def check_unsupported( + packages: Iterable[BaseDistribution], + supported_tags: Iterable[Tag], +) -> Generator[BaseDistribution, None, None]: + for p in packages: + with suppress(FileNotFoundError): + wheel_file = p.read_text("WHEEL") + wheel_tags: FrozenSet[Tag] = reduce( + frozenset.union, + map(parse_tag, Parser().parsestr(wheel_file).get_all("Tag", [])), + frozenset(), + ) + if wheel_tags.isdisjoint(supported_tags): + yield p + + +def _simulate_installation_of( + to_install: List[InstallRequirement], package_set: PackageSet +) -> Set[NormalizedName]: + """Computes the version of packages after installing to_install.""" + # Keep track of packages that were installed + installed = set() + + # Modify it as installing requirement_set would (assuming no errors) + for inst_req in to_install: + abstract_dist = make_distribution_for_install_requirement(inst_req) + dist = abstract_dist.get_metadata_distribution() + name = dist.canonical_name + package_set[name] = PackageDetails(dist.version, list(dist.iter_dependencies())) + + installed.add(name) + + return installed + + +def _create_whitelist( + would_be_installed: Set[NormalizedName], package_set: PackageSet +) -> Set[NormalizedName]: + packages_affected = set(would_be_installed) + + for package_name in package_set: + if package_name in packages_affected: + continue + + for req in package_set[package_name].dependencies: + if canonicalize_name(req.name) in packages_affected: + packages_affected.add(package_name) + break + + return packages_affected diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/freeze.py b/backend/venv/Lib/site-packages/pip/_internal/operations/freeze.py new file mode 100644 index 0000000..ae5dd37 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/freeze.py @@ -0,0 +1,256 @@ +import collections +import logging +import os +from dataclasses import dataclass, field +from typing import Container, Dict, Generator, Iterable, List, NamedTuple, Optional, Set + +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import InvalidVersion + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.metadata import BaseDistribution, get_environment +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, +) +from pip._internal.req.req_file import COMMENT_RE +from pip._internal.utils.direct_url_helpers import direct_url_as_pep440_direct_reference + +logger = logging.getLogger(__name__) + + +class _EditableInfo(NamedTuple): + requirement: str + comments: List[str] + + +def freeze( + requirement: Optional[List[str]] = None, + local_only: bool = False, + user_only: bool = False, + paths: Optional[List[str]] = None, + isolated: bool = False, + exclude_editable: bool = False, + skip: Container[str] = (), +) -> Generator[str, None, None]: + installations: Dict[str, FrozenRequirement] = {} + + dists = get_environment(paths).iter_installed_distributions( + local_only=local_only, + skip=(), + user_only=user_only, + ) + for dist in dists: + req = FrozenRequirement.from_dist(dist) + if exclude_editable and req.editable: + continue + installations[req.canonical_name] = req + + if requirement: + # the options that don't get turned into an InstallRequirement + # should only be emitted once, even if the same option is in multiple + # requirements files, so we need to keep track of what has been emitted + # so that we don't emit it again if it's seen again + emitted_options: Set[str] = set() + # keep track of which files a requirement is in so that we can + # give an accurate warning if a requirement appears multiple times. + req_files: Dict[str, List[str]] = collections.defaultdict(list) + for req_file_path in requirement: + with open(req_file_path) as req_file: + for line in req_file: + if ( + not line.strip() + or line.strip().startswith("#") + or line.startswith( + ( + "-r", + "--requirement", + "-f", + "--find-links", + "-i", + "--index-url", + "--pre", + "--trusted-host", + "--process-dependency-links", + "--extra-index-url", + "--use-feature", + ) + ) + ): + line = line.rstrip() + if line not in emitted_options: + emitted_options.add(line) + yield line + continue + + if line.startswith("-e") or line.startswith("--editable"): + if line.startswith("-e"): + line = line[2:].strip() + else: + line = line[len("--editable") :].strip().lstrip("=") + line_req = install_req_from_editable( + line, + isolated=isolated, + ) + else: + line_req = install_req_from_line( + COMMENT_RE.sub("", line).strip(), + isolated=isolated, + ) + + if not line_req.name: + logger.info( + "Skipping line in requirement file [%s] because " + "it's not clear what it would install: %s", + req_file_path, + line.strip(), + ) + logger.info( + " (add #egg=PackageName to the URL to avoid" + " this warning)" + ) + else: + line_req_canonical_name = canonicalize_name(line_req.name) + if line_req_canonical_name not in installations: + # either it's not installed, or it is installed + # but has been processed already + if not req_files[line_req.name]: + logger.warning( + "Requirement file [%s] contains %s, but " + "package %r is not installed", + req_file_path, + COMMENT_RE.sub("", line).strip(), + line_req.name, + ) + else: + req_files[line_req.name].append(req_file_path) + else: + yield str(installations[line_req_canonical_name]).rstrip() + del installations[line_req_canonical_name] + req_files[line_req.name].append(req_file_path) + + # Warn about requirements that were included multiple times (in a + # single requirements file or in different requirements files). + for name, files in req_files.items(): + if len(files) > 1: + logger.warning( + "Requirement %s included multiple times [%s]", + name, + ", ".join(sorted(set(files))), + ) + + yield ("## The following requirements were added by pip freeze:") + for installation in sorted(installations.values(), key=lambda x: x.name.lower()): + if installation.canonical_name not in skip: + yield str(installation).rstrip() + + +def _format_as_name_version(dist: BaseDistribution) -> str: + try: + dist_version = dist.version + except InvalidVersion: + # legacy version + return f"{dist.raw_name}==={dist.raw_version}" + else: + return f"{dist.raw_name}=={dist_version}" + + +def _get_editable_info(dist: BaseDistribution) -> _EditableInfo: + """ + Compute and return values (req, comments) for use in + FrozenRequirement.from_dist(). + """ + editable_project_location = dist.editable_project_location + assert editable_project_location + location = os.path.normcase(os.path.abspath(editable_project_location)) + + from pip._internal.vcs import RemoteNotFoundError, RemoteNotValidError, vcs + + vcs_backend = vcs.get_backend_for_dir(location) + + if vcs_backend is None: + display = _format_as_name_version(dist) + logger.debug( + 'No VCS found for editable requirement "%s" in: %r', + display, + location, + ) + return _EditableInfo( + requirement=location, + comments=[f"# Editable install with no version control ({display})"], + ) + + vcs_name = type(vcs_backend).__name__ + + try: + req = vcs_backend.get_src_requirement(location, dist.raw_name) + except RemoteNotFoundError: + display = _format_as_name_version(dist) + return _EditableInfo( + requirement=location, + comments=[f"# Editable {vcs_name} install with no remote ({display})"], + ) + except RemoteNotValidError as ex: + display = _format_as_name_version(dist) + return _EditableInfo( + requirement=location, + comments=[ + f"# Editable {vcs_name} install ({display}) with either a deleted " + f"local remote or invalid URI:", + f"# '{ex.url}'", + ], + ) + except BadCommand: + logger.warning( + "cannot determine version of editable source in %s " + "(%s command not found in path)", + location, + vcs_backend.name, + ) + return _EditableInfo(requirement=location, comments=[]) + except InstallationError as exc: + logger.warning("Error when trying to get requirement for VCS system %s", exc) + else: + return _EditableInfo(requirement=req, comments=[]) + + logger.warning("Could not determine repository location of %s", location) + + return _EditableInfo( + requirement=location, + comments=["## !! Could not determine repository location"], + ) + + +@dataclass(frozen=True) +class FrozenRequirement: + name: str + req: str + editable: bool + comments: Iterable[str] = field(default_factory=tuple) + + @property + def canonical_name(self) -> NormalizedName: + return canonicalize_name(self.name) + + @classmethod + def from_dist(cls, dist: BaseDistribution) -> "FrozenRequirement": + editable = dist.editable + if editable: + req, comments = _get_editable_info(dist) + else: + comments = [] + direct_url = dist.direct_url + if direct_url: + # if PEP 610 metadata is present, use it + req = direct_url_as_pep440_direct_reference(direct_url, dist.raw_name) + else: + # name==version requirement + req = _format_as_name_version(dist) + + return cls(dist.raw_name, req, editable, comments=comments) + + def __str__(self) -> str: + req = self.req + if self.editable: + req = f"-e {req}" + return "\n".join(list(self.comments) + [str(req)]) + "\n" diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/install/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/operations/install/__init__.py new file mode 100644 index 0000000..24d6a5d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/install/__init__.py @@ -0,0 +1,2 @@ +"""For modules related to installing packages. +""" diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0d8cb46813d7e6efaaccd304c8aa79c62109f5c GIT binary patch literal 270 zcmXv}K}th06inKprO-PBTotr`(OoHS1Xtq1r36Cy^Y{dlyzmk$--~z#H(taWbn6Ag z?p*mkwzGLNykVI6oX=;1aq;osSA4$)ae_RO!<5OJaN<$)axr?nyhTzG-E)AV2!gHP zR7K@esWt?kI+bnvWIHI!+5JN9&y8`|8uKm=L*#G1S?f&Lk&Thv`USDY7=cB^w&dK(=~Jr8(AU41aw!W|{l_bo1Z$n$Ebu TFsux_zsFL_pOKUkny~x>3-eMy literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5f9e142150a1a8cd9cf2a357eed91f58e69ba92 GIT binary patch literal 1802 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 M?p`)R>=5Mt1=0*v6#xJL literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py b/backend/venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py new file mode 100644 index 0000000..9aaa699 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py @@ -0,0 +1,47 @@ +"""Legacy editable installation process, i.e. `setup.py develop`. +""" + +import logging +from typing import Optional, Sequence + +from pip._internal.build_env import BuildEnvironment +from pip._internal.utils.logging import indent_log +from pip._internal.utils.setuptools_build import make_setuptools_develop_args +from pip._internal.utils.subprocess import call_subprocess + +logger = logging.getLogger(__name__) + + +def install_editable( + *, + global_options: Sequence[str], + prefix: Optional[str], + home: Optional[str], + use_user_site: bool, + name: str, + setup_py_path: str, + isolated: bool, + build_env: BuildEnvironment, + unpacked_source_directory: str, +) -> None: + """Install a package in editable mode. Most arguments are pass-through + to setuptools. + """ + logger.info("Running setup.py develop for %s", name) + + args = make_setuptools_develop_args( + setup_py_path, + global_options=global_options, + no_user_config=isolated, + prefix=prefix, + home=home, + use_user_site=use_user_site, + ) + + with indent_log(): + with build_env: + call_subprocess( + args, + command_desc="python setup.py develop", + cwd=unpacked_source_directory, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/install/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/operations/install/wheel.py new file mode 100644 index 0000000..aef42aa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/install/wheel.py @@ -0,0 +1,741 @@ +"""Support for installing and building the "wheel" binary package format. +""" + +import collections +import compileall +import contextlib +import csv +import importlib +import logging +import os.path +import re +import shutil +import sys +import warnings +from base64 import urlsafe_b64encode +from email.message import Message +from itertools import chain, filterfalse, starmap +from typing import ( + IO, + TYPE_CHECKING, + Any, + BinaryIO, + Callable, + Dict, + Generator, + Iterable, + Iterator, + List, + NewType, + Optional, + Protocol, + Sequence, + Set, + Tuple, + Union, + cast, +) +from zipfile import ZipFile, ZipInfo + +from pip._vendor.distlib.scripts import ScriptMaker +from pip._vendor.distlib.util import get_export_entry +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import InstallationError +from pip._internal.locations import get_major_minor_version +from pip._internal.metadata import ( + BaseDistribution, + FilesystemWheel, + get_wheel_distribution, +) +from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl +from pip._internal.models.scheme import SCHEME_KEYS, Scheme +from pip._internal.utils.filesystem import adjacent_tmp_file, replace +from pip._internal.utils.misc import StreamWrapper, ensure_dir, hash_file, partition +from pip._internal.utils.unpacking import ( + current_umask, + is_within_directory, + set_extracted_file_to_default_mode_plus_executable, + zip_item_is_executable, +) +from pip._internal.utils.wheel import parse_wheel + +if TYPE_CHECKING: + + class File(Protocol): + src_record_path: "RecordPath" + dest_path: str + changed: bool + + def save(self) -> None: + pass + + +logger = logging.getLogger(__name__) + +RecordPath = NewType("RecordPath", str) +InstalledCSVRow = Tuple[RecordPath, str, Union[int, str]] + + +def rehash(path: str, blocksize: int = 1 << 20) -> Tuple[str, str]: + """Return (encoded_digest, length) for path using hashlib.sha256()""" + h, length = hash_file(path, blocksize) + digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=") + return (digest, str(length)) + + +def csv_io_kwargs(mode: str) -> Dict[str, Any]: + """Return keyword arguments to properly open a CSV file + in the given mode. + """ + return {"mode": mode, "newline": "", "encoding": "utf-8"} + + +def fix_script(path: str) -> bool: + """Replace #!python with #!/path/to/python + Return True if file was changed. + """ + # XXX RECORD hashes will need to be updated + assert os.path.isfile(path) + + with open(path, "rb") as script: + firstline = script.readline() + if not firstline.startswith(b"#!python"): + return False + exename = sys.executable.encode(sys.getfilesystemencoding()) + firstline = b"#!" + exename + os.linesep.encode("ascii") + rest = script.read() + with open(path, "wb") as script: + script.write(firstline) + script.write(rest) + return True + + +def wheel_root_is_purelib(metadata: Message) -> bool: + return metadata.get("Root-Is-Purelib", "").lower() == "true" + + +def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, str]]: + console_scripts = {} + gui_scripts = {} + for entry_point in dist.iter_entry_points(): + if entry_point.group == "console_scripts": + console_scripts[entry_point.name] = entry_point.value + elif entry_point.group == "gui_scripts": + gui_scripts[entry_point.name] = entry_point.value + return console_scripts, gui_scripts + + +def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]: + """Determine if any scripts are not on PATH and format a warning. + Returns a warning message if one or more scripts are not on PATH, + otherwise None. + """ + if not scripts: + return None + + # Group scripts by the path they were installed in + grouped_by_dir: Dict[str, Set[str]] = collections.defaultdict(set) + for destfile in scripts: + parent_dir = os.path.dirname(destfile) + script_name = os.path.basename(destfile) + grouped_by_dir[parent_dir].add(script_name) + + # We don't want to warn for directories that are on PATH. + not_warn_dirs = [ + os.path.normcase(os.path.normpath(i)).rstrip(os.sep) + for i in os.environ.get("PATH", "").split(os.pathsep) + ] + # If an executable sits with sys.executable, we don't warn for it. + # This covers the case of venv invocations without activating the venv. + not_warn_dirs.append( + os.path.normcase(os.path.normpath(os.path.dirname(sys.executable))) + ) + warn_for: Dict[str, Set[str]] = { + parent_dir: scripts + for parent_dir, scripts in grouped_by_dir.items() + if os.path.normcase(os.path.normpath(parent_dir)) not in not_warn_dirs + } + if not warn_for: + return None + + # Format a message + msg_lines = [] + for parent_dir, dir_scripts in warn_for.items(): + sorted_scripts: List[str] = sorted(dir_scripts) + if len(sorted_scripts) == 1: + start_text = f"script {sorted_scripts[0]} is" + else: + start_text = "scripts {} are".format( + ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1] + ) + + msg_lines.append( + f"The {start_text} installed in '{parent_dir}' which is not on PATH." + ) + + last_line_fmt = ( + "Consider adding {} to PATH or, if you prefer " + "to suppress this warning, use --no-warn-script-location." + ) + if len(msg_lines) == 1: + msg_lines.append(last_line_fmt.format("this directory")) + else: + msg_lines.append(last_line_fmt.format("these directories")) + + # Add a note if any directory starts with ~ + warn_for_tilde = any( + i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i + ) + if warn_for_tilde: + tilde_warning_msg = ( + "NOTE: The current PATH contains path(s) starting with `~`, " + "which may not be expanded by all applications." + ) + msg_lines.append(tilde_warning_msg) + + # Returns the formatted multiline message + return "\n".join(msg_lines) + + +def _normalized_outrows( + outrows: Iterable[InstalledCSVRow], +) -> List[Tuple[str, str, str]]: + """Normalize the given rows of a RECORD file. + + Items in each row are converted into str. Rows are then sorted to make + the value more predictable for tests. + + Each row is a 3-tuple (path, hash, size) and corresponds to a record of + a RECORD file (see PEP 376 and PEP 427 for details). For the rows + passed to this function, the size can be an integer as an int or string, + or the empty string. + """ + # Normally, there should only be one row per path, in which case the + # second and third elements don't come into play when sorting. + # However, in cases in the wild where a path might happen to occur twice, + # we don't want the sort operation to trigger an error (but still want + # determinism). Since the third element can be an int or string, we + # coerce each element to a string to avoid a TypeError in this case. + # For additional background, see-- + # https://github.com/pypa/pip/issues/5868 + return sorted( + (record_path, hash_, str(size)) for record_path, hash_, size in outrows + ) + + +def _record_to_fs_path(record_path: RecordPath, lib_dir: str) -> str: + return os.path.join(lib_dir, record_path) + + +def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath: + # On Windows, do not handle relative paths if they belong to different + # logical disks + if os.path.splitdrive(path)[0].lower() == os.path.splitdrive(lib_dir)[0].lower(): + path = os.path.relpath(path, lib_dir) + + path = path.replace(os.path.sep, "/") + return cast("RecordPath", path) + + +def get_csv_rows_for_installed( + old_csv_rows: List[List[str]], + installed: Dict[RecordPath, RecordPath], + changed: Set[RecordPath], + generated: List[str], + lib_dir: str, +) -> List[InstalledCSVRow]: + """ + :param installed: A map from archive RECORD path to installation RECORD + path. + """ + installed_rows: List[InstalledCSVRow] = [] + for row in old_csv_rows: + if len(row) > 3: + logger.warning("RECORD line has more than three elements: %s", row) + old_record_path = cast("RecordPath", row[0]) + new_record_path = installed.pop(old_record_path, old_record_path) + if new_record_path in changed: + digest, length = rehash(_record_to_fs_path(new_record_path, lib_dir)) + else: + digest = row[1] if len(row) > 1 else "" + length = row[2] if len(row) > 2 else "" + installed_rows.append((new_record_path, digest, length)) + for f in generated: + path = _fs_to_record_path(f, lib_dir) + digest, length = rehash(f) + installed_rows.append((path, digest, length)) + return installed_rows + [ + (installed_record_path, "", "") for installed_record_path in installed.values() + ] + + +def get_console_script_specs(console: Dict[str, str]) -> List[str]: + """ + Given the mapping from entrypoint name to callable, return the relevant + console script specs. + """ + # Don't mutate caller's version + console = console.copy() + + scripts_to_generate = [] + + # Special case pip and setuptools to generate versioned wrappers + # + # The issue is that some projects (specifically, pip and setuptools) use + # code in setup.py to create "versioned" entry points - pip2.7 on Python + # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into + # the wheel metadata at build time, and so if the wheel is installed with + # a *different* version of Python the entry points will be wrong. The + # correct fix for this is to enhance the metadata to be able to describe + # such versioned entry points. + # Currently, projects using versioned entry points will either have + # incorrect versioned entry points, or they will not be able to distribute + # "universal" wheels (i.e., they will need a wheel per Python version). + # + # Because setuptools and pip are bundled with _ensurepip and virtualenv, + # we need to use universal wheels. As a workaround, we + # override the versioned entry points in the wheel and generate the + # correct ones. + # + # To add the level of hack in this section of code, in order to support + # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment + # variable which will control which version scripts get installed. + # + # ENSUREPIP_OPTIONS=altinstall + # - Only pipX.Y and easy_install-X.Y will be generated and installed + # ENSUREPIP_OPTIONS=install + # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note + # that this option is technically if ENSUREPIP_OPTIONS is set and is + # not altinstall + # DEFAULT + # - The default behavior is to install pip, pipX, pipX.Y, easy_install + # and easy_install-X.Y. + pip_script = console.pop("pip", None) + if pip_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + scripts_to_generate.append("pip = " + pip_script) + + if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": + scripts_to_generate.append(f"pip{sys.version_info[0]} = {pip_script}") + + scripts_to_generate.append(f"pip{get_major_minor_version()} = {pip_script}") + # Delete any other versioned pip entry points + pip_ep = [k for k in console if re.match(r"pip(\d+(\.\d+)?)?$", k)] + for k in pip_ep: + del console[k] + easy_install_script = console.pop("easy_install", None) + if easy_install_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + scripts_to_generate.append("easy_install = " + easy_install_script) + + scripts_to_generate.append( + f"easy_install-{get_major_minor_version()} = {easy_install_script}" + ) + # Delete any other versioned easy_install entry points + easy_install_ep = [ + k for k in console if re.match(r"easy_install(-\d+\.\d+)?$", k) + ] + for k in easy_install_ep: + del console[k] + + # Generate the console entry points specified in the wheel + scripts_to_generate.extend(starmap("{} = {}".format, console.items())) + + return scripts_to_generate + + +class ZipBackedFile: + def __init__( + self, src_record_path: RecordPath, dest_path: str, zip_file: ZipFile + ) -> None: + self.src_record_path = src_record_path + self.dest_path = dest_path + self._zip_file = zip_file + self.changed = False + + def _getinfo(self) -> ZipInfo: + return self._zip_file.getinfo(self.src_record_path) + + def save(self) -> None: + # When we open the output file below, any existing file is truncated + # before we start writing the new contents. This is fine in most + # cases, but can cause a segfault if pip has loaded a shared + # object (e.g. from pyopenssl through its vendored urllib3) + # Since the shared object is mmap'd an attempt to call a + # symbol in it will then cause a segfault. Unlinking the file + # allows writing of new contents while allowing the process to + # continue to use the old copy. + if os.path.exists(self.dest_path): + os.unlink(self.dest_path) + + zipinfo = self._getinfo() + + # optimization: the file is created by open(), + # skip the decompression when there is 0 bytes to decompress. + with open(self.dest_path, "wb") as dest: + if zipinfo.file_size > 0: + with self._zip_file.open(zipinfo) as f: + blocksize = min(zipinfo.file_size, 1024 * 1024) + shutil.copyfileobj(f, dest, blocksize) + + if zip_item_is_executable(zipinfo): + set_extracted_file_to_default_mode_plus_executable(self.dest_path) + + +class ScriptFile: + def __init__(self, file: "File") -> None: + self._file = file + self.src_record_path = self._file.src_record_path + self.dest_path = self._file.dest_path + self.changed = False + + def save(self) -> None: + self._file.save() + self.changed = fix_script(self.dest_path) + + +class MissingCallableSuffix(InstallationError): + def __init__(self, entry_point: str) -> None: + super().__init__( + f"Invalid script entry point: {entry_point} - A callable " + "suffix is required. Cf https://packaging.python.org/" + "specifications/entry-points/#use-for-scripts for more " + "information." + ) + + +def _raise_for_invalid_entrypoint(specification: str) -> None: + entry = get_export_entry(specification) + if entry is not None and entry.suffix is None: + raise MissingCallableSuffix(str(entry)) + + +class PipScriptMaker(ScriptMaker): + def make( + self, specification: str, options: Optional[Dict[str, Any]] = None + ) -> List[str]: + _raise_for_invalid_entrypoint(specification) + return super().make(specification, options) + + +def _install_wheel( # noqa: C901, PLR0915 function is too long + name: str, + wheel_zip: ZipFile, + wheel_path: str, + scheme: Scheme, + pycompile: bool = True, + warn_script_location: bool = True, + direct_url: Optional[DirectUrl] = None, + requested: bool = False, +) -> None: + """Install a wheel. + + :param name: Name of the project to install + :param wheel_zip: open ZipFile for wheel being installed + :param scheme: Distutils scheme dictating the install directories + :param req_description: String used in place of the requirement, for + logging + :param pycompile: Whether to byte-compile installed Python files + :param warn_script_location: Whether to check that scripts are installed + into a directory on PATH + :raises UnsupportedWheel: + * when the directory holds an unpacked wheel with incompatible + Wheel-Version + * when the .dist-info dir does not match the wheel + """ + info_dir, metadata = parse_wheel(wheel_zip, name) + + if wheel_root_is_purelib(metadata): + lib_dir = scheme.purelib + else: + lib_dir = scheme.platlib + + # Record details of the files moved + # installed = files copied from the wheel to the destination + # changed = files changed while installing (scripts #! line typically) + # generated = files newly generated during the install (script wrappers) + installed: Dict[RecordPath, RecordPath] = {} + changed: Set[RecordPath] = set() + generated: List[str] = [] + + def record_installed( + srcfile: RecordPath, destfile: str, modified: bool = False + ) -> None: + """Map archive RECORD paths to installation RECORD paths.""" + newpath = _fs_to_record_path(destfile, lib_dir) + installed[srcfile] = newpath + if modified: + changed.add(newpath) + + def is_dir_path(path: RecordPath) -> bool: + return path.endswith("/") + + def assert_no_path_traversal(dest_dir_path: str, target_path: str) -> None: + if not is_within_directory(dest_dir_path, target_path): + message = ( + "The wheel {!r} has a file {!r} trying to install" + " outside the target directory {!r}" + ) + raise InstallationError( + message.format(wheel_path, target_path, dest_dir_path) + ) + + def root_scheme_file_maker( + zip_file: ZipFile, dest: str + ) -> Callable[[RecordPath], "File"]: + def make_root_scheme_file(record_path: RecordPath) -> "File": + normed_path = os.path.normpath(record_path) + dest_path = os.path.join(dest, normed_path) + assert_no_path_traversal(dest, dest_path) + return ZipBackedFile(record_path, dest_path, zip_file) + + return make_root_scheme_file + + def data_scheme_file_maker( + zip_file: ZipFile, scheme: Scheme + ) -> Callable[[RecordPath], "File"]: + scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS} + + def make_data_scheme_file(record_path: RecordPath) -> "File": + normed_path = os.path.normpath(record_path) + try: + _, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2) + except ValueError: + message = ( + f"Unexpected file in {wheel_path}: {record_path!r}. .data directory" + " contents should be named like: '/'." + ) + raise InstallationError(message) + + try: + scheme_path = scheme_paths[scheme_key] + except KeyError: + valid_scheme_keys = ", ".join(sorted(scheme_paths)) + message = ( + f"Unknown scheme key used in {wheel_path}: {scheme_key} " + f"(for file {record_path!r}). .data directory contents " + f"should be in subdirectories named with a valid scheme " + f"key ({valid_scheme_keys})" + ) + raise InstallationError(message) + + dest_path = os.path.join(scheme_path, dest_subpath) + assert_no_path_traversal(scheme_path, dest_path) + return ZipBackedFile(record_path, dest_path, zip_file) + + return make_data_scheme_file + + def is_data_scheme_path(path: RecordPath) -> bool: + return path.split("/", 1)[0].endswith(".data") + + paths = cast(List[RecordPath], wheel_zip.namelist()) + file_paths = filterfalse(is_dir_path, paths) + root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths) + + make_root_scheme_file = root_scheme_file_maker(wheel_zip, lib_dir) + files: Iterator[File] = map(make_root_scheme_file, root_scheme_paths) + + def is_script_scheme_path(path: RecordPath) -> bool: + parts = path.split("/", 2) + return len(parts) > 2 and parts[0].endswith(".data") and parts[1] == "scripts" + + other_scheme_paths, script_scheme_paths = partition( + is_script_scheme_path, data_scheme_paths + ) + + make_data_scheme_file = data_scheme_file_maker(wheel_zip, scheme) + other_scheme_files = map(make_data_scheme_file, other_scheme_paths) + files = chain(files, other_scheme_files) + + # Get the defined entry points + distribution = get_wheel_distribution( + FilesystemWheel(wheel_path), + canonicalize_name(name), + ) + console, gui = get_entrypoints(distribution) + + def is_entrypoint_wrapper(file: "File") -> bool: + # EP, EP.exe and EP-script.py are scripts generated for + # entry point EP by setuptools + path = file.dest_path + name = os.path.basename(path) + if name.lower().endswith(".exe"): + matchname = name[:-4] + elif name.lower().endswith("-script.py"): + matchname = name[:-10] + elif name.lower().endswith(".pya"): + matchname = name[:-4] + else: + matchname = name + # Ignore setuptools-generated scripts + return matchname in console or matchname in gui + + script_scheme_files: Iterator[File] = map( + make_data_scheme_file, script_scheme_paths + ) + script_scheme_files = filterfalse(is_entrypoint_wrapper, script_scheme_files) + script_scheme_files = map(ScriptFile, script_scheme_files) + files = chain(files, script_scheme_files) + + existing_parents = set() + for file in files: + # directory creation is lazy and after file filtering + # to ensure we don't install empty dirs; empty dirs can't be + # uninstalled. + parent_dir = os.path.dirname(file.dest_path) + if parent_dir not in existing_parents: + ensure_dir(parent_dir) + existing_parents.add(parent_dir) + file.save() + record_installed(file.src_record_path, file.dest_path, file.changed) + + def pyc_source_file_paths() -> Generator[str, None, None]: + # We de-duplicate installation paths, since there can be overlap (e.g. + # file in .data maps to same location as file in wheel root). + # Sorting installation paths makes it easier to reproduce and debug + # issues related to permissions on existing files. + for installed_path in sorted(set(installed.values())): + full_installed_path = os.path.join(lib_dir, installed_path) + if not os.path.isfile(full_installed_path): + continue + if not full_installed_path.endswith(".py"): + continue + yield full_installed_path + + def pyc_output_path(path: str) -> str: + """Return the path the pyc file would have been written to.""" + return importlib.util.cache_from_source(path) + + # Compile all of the pyc files for the installed files + if pycompile: + with contextlib.redirect_stdout( + StreamWrapper.from_stream(sys.stdout) + ) as stdout: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + for path in pyc_source_file_paths(): + success = compileall.compile_file(path, force=True, quiet=True) + if success: + pyc_path = pyc_output_path(path) + assert os.path.exists(pyc_path) + pyc_record_path = cast( + "RecordPath", pyc_path.replace(os.path.sep, "/") + ) + record_installed(pyc_record_path, pyc_path) + logger.debug(stdout.getvalue()) + + maker = PipScriptMaker(None, scheme.scripts) + + # Ensure old scripts are overwritten. + # See https://github.com/pypa/pip/issues/1800 + maker.clobber = True + + # Ensure we don't generate any variants for scripts because this is almost + # never what somebody wants. + # See https://bitbucket.org/pypa/distlib/issue/35/ + maker.variants = {""} + + # This is required because otherwise distlib creates scripts that are not + # executable. + # See https://bitbucket.org/pypa/distlib/issue/32/ + maker.set_mode = True + + # Generate the console and GUI entry points specified in the wheel + scripts_to_generate = get_console_script_specs(console) + + gui_scripts_to_generate = list(starmap("{} = {}".format, gui.items())) + + generated_console_scripts = maker.make_multiple(scripts_to_generate) + generated.extend(generated_console_scripts) + + generated.extend(maker.make_multiple(gui_scripts_to_generate, {"gui": True})) + + if warn_script_location: + msg = message_about_scripts_not_on_PATH(generated_console_scripts) + if msg is not None: + logger.warning(msg) + + generated_file_mode = 0o666 & ~current_umask() + + @contextlib.contextmanager + def _generate_file(path: str, **kwargs: Any) -> Generator[BinaryIO, None, None]: + with adjacent_tmp_file(path, **kwargs) as f: + yield f + os.chmod(f.name, generated_file_mode) + replace(f.name, path) + + dest_info_dir = os.path.join(lib_dir, info_dir) + + # Record pip as the installer + installer_path = os.path.join(dest_info_dir, "INSTALLER") + with _generate_file(installer_path) as installer_file: + installer_file.write(b"pip\n") + generated.append(installer_path) + + # Record the PEP 610 direct URL reference + if direct_url is not None: + direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME) + with _generate_file(direct_url_path) as direct_url_file: + direct_url_file.write(direct_url.to_json().encode("utf-8")) + generated.append(direct_url_path) + + # Record the REQUESTED file + if requested: + requested_path = os.path.join(dest_info_dir, "REQUESTED") + with open(requested_path, "wb"): + pass + generated.append(requested_path) + + record_text = distribution.read_text("RECORD") + record_rows = list(csv.reader(record_text.splitlines())) + + rows = get_csv_rows_for_installed( + record_rows, + installed=installed, + changed=changed, + generated=generated, + lib_dir=lib_dir, + ) + + # Record details of all files installed + record_path = os.path.join(dest_info_dir, "RECORD") + + with _generate_file(record_path, **csv_io_kwargs("w")) as record_file: + # Explicitly cast to typing.IO[str] as a workaround for the mypy error: + # "writer" has incompatible type "BinaryIO"; expected "_Writer" + writer = csv.writer(cast("IO[str]", record_file)) + writer.writerows(_normalized_outrows(rows)) + + +@contextlib.contextmanager +def req_error_context(req_description: str) -> Generator[None, None, None]: + try: + yield + except InstallationError as e: + message = f"For req: {req_description}. {e.args[0]}" + raise InstallationError(message) from e + + +def install_wheel( + name: str, + wheel_path: str, + scheme: Scheme, + req_description: str, + pycompile: bool = True, + warn_script_location: bool = True, + direct_url: Optional[DirectUrl] = None, + requested: bool = False, +) -> None: + with ZipFile(wheel_path, allowZip64=True) as z: + with req_error_context(req_description): + _install_wheel( + name=name, + wheel_zip=z, + wheel_path=wheel_path, + scheme=scheme, + pycompile=pycompile, + warn_script_location=warn_script_location, + direct_url=direct_url, + requested=requested, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/operations/prepare.py b/backend/venv/Lib/site-packages/pip/_internal/operations/prepare.py new file mode 100644 index 0000000..e6aa344 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/operations/prepare.py @@ -0,0 +1,732 @@ +"""Prepares a distribution for installation +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import mimetypes +import os +import shutil +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, Iterable, List, Optional + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.distributions import make_distribution_for_install_requirement +from pip._internal.distributions.installed import InstalledDistribution +from pip._internal.exceptions import ( + DirectoryUrlHashUnsupported, + HashMismatch, + HashUnpinned, + InstallationError, + MetadataInconsistent, + NetworkConnectionError, + VcsHashUnsupported, +) +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import BaseDistribution, get_metadata_distribution +from pip._internal.models.direct_url import ArchiveInfo +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.network.download import BatchDownloader, Downloader +from pip._internal.network.lazy_wheel import ( + HTTPRangeRequestUnsupported, + dist_from_wheel_url, +) +from pip._internal.network.session import PipSession +from pip._internal.operations.build.build_tracker import BuildTracker +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils._log import getLogger +from pip._internal.utils.direct_url_helpers import ( + direct_url_for_editable, + direct_url_from_link, +) +from pip._internal.utils.hashes import Hashes, MissingHashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + display_path, + hash_file, + hide_url, + redact_auth_from_requirement, +) +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.unpacking import unpack_file +from pip._internal.vcs import vcs + +logger = getLogger(__name__) + + +def _get_prepared_distribution( + req: InstallRequirement, + build_tracker: BuildTracker, + finder: PackageFinder, + build_isolation: bool, + check_build_deps: bool, +) -> BaseDistribution: + """Prepare a distribution for installation.""" + abstract_dist = make_distribution_for_install_requirement(req) + tracker_id = abstract_dist.build_tracker_id + if tracker_id is not None: + with build_tracker.track(req, tracker_id): + abstract_dist.prepare_distribution_metadata( + finder, build_isolation, check_build_deps + ) + return abstract_dist.get_metadata_distribution() + + +def unpack_vcs_link(link: Link, location: str, verbosity: int) -> None: + vcs_backend = vcs.get_backend_for_scheme(link.scheme) + assert vcs_backend is not None + vcs_backend.unpack(location, url=hide_url(link.url), verbosity=verbosity) + + +@dataclass +class File: + path: str + content_type: Optional[str] = None + + def __post_init__(self) -> None: + if self.content_type is None: + self.content_type = mimetypes.guess_type(self.path)[0] + + +def get_http_url( + link: Link, + download: Downloader, + download_dir: Optional[str] = None, + hashes: Optional[Hashes] = None, +) -> File: + temp_dir = TempDirectory(kind="unpack", globally_managed=True) + # If a download dir is specified, is the file already downloaded there? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, download_dir, hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + content_type = None + else: + # let's download to a tmp dir + from_path, content_type = download(link, temp_dir.path) + if hashes: + hashes.check_against_path(from_path) + + return File(from_path, content_type) + + +def get_file_url( + link: Link, download_dir: Optional[str] = None, hashes: Optional[Hashes] = None +) -> File: + """Get file and optionally check its hash.""" + # If a download dir is specified, is the file already there and valid? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, download_dir, hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + else: + from_path = link.file_path + + # If --require-hashes is off, `hashes` is either empty, the + # link's embedded hash, or MissingHashes; it is required to + # match. If --require-hashes is on, we are satisfied by any + # hash in `hashes` matching: a URL-based or an option-based + # one; no internet-sourced hash will be in `hashes`. + if hashes: + hashes.check_against_path(from_path) + return File(from_path, None) + + +def unpack_url( + link: Link, + location: str, + download: Downloader, + verbosity: int, + download_dir: Optional[str] = None, + hashes: Optional[Hashes] = None, +) -> Optional[File]: + """Unpack link into location, downloading if required. + + :param hashes: A Hashes object, one of whose embedded hashes must match, + or HashMismatch will be raised. If the Hashes is empty, no matches are + required, and unhashable types of requirements (like VCS ones, which + would ordinarily raise HashUnsupported) are allowed. + """ + # non-editable vcs urls + if link.is_vcs: + unpack_vcs_link(link, location, verbosity=verbosity) + return None + + assert not link.is_existing_dir() + + # file urls + if link.is_file: + file = get_file_url(link, download_dir, hashes=hashes) + + # http urls + else: + file = get_http_url( + link, + download, + download_dir, + hashes=hashes, + ) + + # unpack the archive to the build dir location. even when only downloading + # archives, they have to be unpacked to parse dependencies, except wheels + if not link.is_wheel: + unpack_file(file.path, location, file.content_type) + + return file + + +def _check_download_dir( + link: Link, + download_dir: str, + hashes: Optional[Hashes], + warn_on_hash_mismatch: bool = True, +) -> Optional[str]: + """Check download_dir for previously downloaded file with correct hash + If a correct file is found return its path else None + """ + download_path = os.path.join(download_dir, link.filename) + + if not os.path.exists(download_path): + return None + + # If already downloaded, does its hash match? + logger.info("File was already downloaded %s", download_path) + if hashes: + try: + hashes.check_against_path(download_path) + except HashMismatch: + if warn_on_hash_mismatch: + logger.warning( + "Previously-downloaded file %s has bad hash. Re-downloading.", + download_path, + ) + os.unlink(download_path) + return None + return download_path + + +class RequirementPreparer: + """Prepares a Requirement""" + + def __init__( + self, + build_dir: str, + download_dir: Optional[str], + src_dir: str, + build_isolation: bool, + check_build_deps: bool, + build_tracker: BuildTracker, + session: PipSession, + progress_bar: str, + finder: PackageFinder, + require_hashes: bool, + use_user_site: bool, + lazy_wheel: bool, + verbosity: int, + legacy_resolver: bool, + ) -> None: + super().__init__() + + self.src_dir = src_dir + self.build_dir = build_dir + self.build_tracker = build_tracker + self._session = session + self._download = Downloader(session, progress_bar) + self._batch_download = BatchDownloader(session, progress_bar) + self.finder = finder + + # Where still-packed archives should be written to. If None, they are + # not saved, and are deleted immediately after unpacking. + self.download_dir = download_dir + + # Is build isolation allowed? + self.build_isolation = build_isolation + + # Should check build dependencies? + self.check_build_deps = check_build_deps + + # Should hash-checking be required? + self.require_hashes = require_hashes + + # Should install in user site-packages? + self.use_user_site = use_user_site + + # Should wheels be downloaded lazily? + self.use_lazy_wheel = lazy_wheel + + # How verbose should underlying tooling be? + self.verbosity = verbosity + + # Are we using the legacy resolver? + self.legacy_resolver = legacy_resolver + + # Memoized downloaded files, as mapping of url: path. + self._downloaded: Dict[str, str] = {} + + # Previous "header" printed for a link-based InstallRequirement + self._previous_requirement_header = ("", "") + + def _log_preparing_link(self, req: InstallRequirement) -> None: + """Provide context for the requirement being prepared.""" + if req.link.is_file and not req.is_wheel_from_cache: + message = "Processing %s" + information = str(display_path(req.link.file_path)) + else: + message = "Collecting %s" + information = redact_auth_from_requirement(req.req) if req.req else str(req) + + # If we used req.req, inject requirement source if available (this + # would already be included if we used req directly) + if req.req and req.comes_from: + if isinstance(req.comes_from, str): + comes_from: Optional[str] = req.comes_from + else: + comes_from = req.comes_from.from_path() + if comes_from: + information += f" (from {comes_from})" + + if (message, information) != self._previous_requirement_header: + self._previous_requirement_header = (message, information) + logger.info(message, information) + + if req.is_wheel_from_cache: + with indent_log(): + logger.info("Using cached %s", req.link.filename) + + def _ensure_link_req_src_dir( + self, req: InstallRequirement, parallel_builds: bool + ) -> None: + """Ensure source_dir of a linked InstallRequirement.""" + # Since source_dir is only set for editable requirements. + if req.link.is_wheel: + # We don't need to unpack wheels, so no need for a source + # directory. + return + assert req.source_dir is None + if req.link.is_existing_dir(): + # build local directories in-tree + req.source_dir = req.link.file_path + return + + # We always delete unpacked sdists after pip runs. + req.ensure_has_source_dir( + self.build_dir, + autodelete=True, + parallel_builds=parallel_builds, + ) + req.ensure_pristine_source_checkout() + + def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes: + # By the time this is called, the requirement's link should have + # been checked so we can tell what kind of requirements req is + # and raise some more informative errors than otherwise. + # (For example, we can raise VcsHashUnsupported for a VCS URL + # rather than HashMissing.) + if not self.require_hashes: + return req.hashes(trust_internet=True) + + # We could check these first 2 conditions inside unpack_url + # and save repetition of conditions, but then we would + # report less-useful error messages for unhashable + # requirements, complaining that there's no hash provided. + if req.link.is_vcs: + raise VcsHashUnsupported() + if req.link.is_existing_dir(): + raise DirectoryUrlHashUnsupported() + + # Unpinned packages are asking for trouble when a new version + # is uploaded. This isn't a security check, but it saves users + # a surprising hash mismatch in the future. + # file:/// URLs aren't pinnable, so don't complain about them + # not being pinned. + if not req.is_direct and not req.is_pinned: + raise HashUnpinned() + + # If known-good hashes are missing for this requirement, + # shim it with a facade object that will provoke hash + # computation and then raise a HashMissing exception + # showing the user what the hash should be. + return req.hashes(trust_internet=False) or MissingHashes() + + def _fetch_metadata_only( + self, + req: InstallRequirement, + ) -> Optional[BaseDistribution]: + if self.legacy_resolver: + logger.debug( + "Metadata-only fetching is not used in the legacy resolver", + ) + return None + if self.require_hashes: + logger.debug( + "Metadata-only fetching is not used as hash checking is required", + ) + return None + # Try PEP 658 metadata first, then fall back to lazy wheel if unavailable. + return self._fetch_metadata_using_link_data_attr( + req + ) or self._fetch_metadata_using_lazy_wheel(req.link) + + def _fetch_metadata_using_link_data_attr( + self, + req: InstallRequirement, + ) -> Optional[BaseDistribution]: + """Fetch metadata from the data-dist-info-metadata attribute, if possible.""" + # (1) Get the link to the metadata file, if provided by the backend. + metadata_link = req.link.metadata_link() + if metadata_link is None: + return None + assert req.req is not None + logger.verbose( + "Obtaining dependency information for %s from %s", + req.req, + metadata_link, + ) + # (2) Download the contents of the METADATA file, separate from the dist itself. + metadata_file = get_http_url( + metadata_link, + self._download, + hashes=metadata_link.as_hashes(), + ) + with open(metadata_file.path, "rb") as f: + metadata_contents = f.read() + # (3) Generate a dist just from those file contents. + metadata_dist = get_metadata_distribution( + metadata_contents, + req.link.filename, + req.req.name, + ) + # (4) Ensure the Name: field from the METADATA file matches the name from the + # install requirement. + # + # NB: raw_name will fall back to the name from the install requirement if + # the Name: field is not present, but it's noted in the raw_name docstring + # that that should NEVER happen anyway. + if canonicalize_name(metadata_dist.raw_name) != canonicalize_name(req.req.name): + raise MetadataInconsistent( + req, "Name", req.req.name, metadata_dist.raw_name + ) + return metadata_dist + + def _fetch_metadata_using_lazy_wheel( + self, + link: Link, + ) -> Optional[BaseDistribution]: + """Fetch metadata using lazy wheel, if possible.""" + # --use-feature=fast-deps must be provided. + if not self.use_lazy_wheel: + return None + if link.is_file or not link.is_wheel: + logger.debug( + "Lazy wheel is not used as %r does not point to a remote wheel", + link, + ) + return None + + wheel = Wheel(link.filename) + name = canonicalize_name(wheel.name) + logger.info( + "Obtaining dependency information from %s %s", + name, + wheel.version, + ) + url = link.url.split("#", 1)[0] + try: + return dist_from_wheel_url(name, url, self._session) + except HTTPRangeRequestUnsupported: + logger.debug("%s does not support range requests", url) + return None + + def _complete_partial_requirements( + self, + partially_downloaded_reqs: Iterable[InstallRequirement], + parallel_builds: bool = False, + ) -> None: + """Download any requirements which were only fetched by metadata.""" + # Download to a temporary directory. These will be copied over as + # needed for downstream 'download', 'wheel', and 'install' commands. + temp_dir = TempDirectory(kind="unpack", globally_managed=True).path + + # Map each link to the requirement that owns it. This allows us to set + # `req.local_file_path` on the appropriate requirement after passing + # all the links at once into BatchDownloader. + links_to_fully_download: Dict[Link, InstallRequirement] = {} + for req in partially_downloaded_reqs: + assert req.link + links_to_fully_download[req.link] = req + + batch_download = self._batch_download( + links_to_fully_download.keys(), + temp_dir, + ) + for link, (filepath, _) in batch_download: + logger.debug("Downloading link %s to %s", link, filepath) + req = links_to_fully_download[link] + # Record the downloaded file path so wheel reqs can extract a Distribution + # in .get_dist(). + req.local_file_path = filepath + # Record that the file is downloaded so we don't do it again in + # _prepare_linked_requirement(). + self._downloaded[req.link.url] = filepath + + # If this is an sdist, we need to unpack it after downloading, but the + # .source_dir won't be set up until we are in _prepare_linked_requirement(). + # Add the downloaded archive to the install requirement to unpack after + # preparing the source dir. + if not req.is_wheel: + req.needs_unpacked_archive(Path(filepath)) + + # This step is necessary to ensure all lazy wheels are processed + # successfully by the 'download', 'wheel', and 'install' commands. + for req in partially_downloaded_reqs: + self._prepare_linked_requirement(req, parallel_builds) + + def prepare_linked_requirement( + self, req: InstallRequirement, parallel_builds: bool = False + ) -> BaseDistribution: + """Prepare a requirement to be obtained from req.link.""" + assert req.link + self._log_preparing_link(req) + with indent_log(): + # Check if the relevant file is already available + # in the download directory + file_path = None + if self.download_dir is not None and req.link.is_wheel: + hashes = self._get_linked_req_hashes(req) + file_path = _check_download_dir( + req.link, + self.download_dir, + hashes, + # When a locally built wheel has been found in cache, we don't warn + # about re-downloading when the already downloaded wheel hash does + # not match. This is because the hash must be checked against the + # original link, not the cached link. It that case the already + # downloaded file will be removed and re-fetched from cache (which + # implies a hash check against the cache entry's origin.json). + warn_on_hash_mismatch=not req.is_wheel_from_cache, + ) + + if file_path is not None: + # The file is already available, so mark it as downloaded + self._downloaded[req.link.url] = file_path + else: + # The file is not available, attempt to fetch only metadata + metadata_dist = self._fetch_metadata_only(req) + if metadata_dist is not None: + req.needs_more_preparation = True + return metadata_dist + + # None of the optimizations worked, fully prepare the requirement + return self._prepare_linked_requirement(req, parallel_builds) + + def prepare_linked_requirements_more( + self, reqs: Iterable[InstallRequirement], parallel_builds: bool = False + ) -> None: + """Prepare linked requirements more, if needed.""" + reqs = [req for req in reqs if req.needs_more_preparation] + for req in reqs: + # Determine if any of these requirements were already downloaded. + if self.download_dir is not None and req.link.is_wheel: + hashes = self._get_linked_req_hashes(req) + file_path = _check_download_dir(req.link, self.download_dir, hashes) + if file_path is not None: + self._downloaded[req.link.url] = file_path + req.needs_more_preparation = False + + # Prepare requirements we found were already downloaded for some + # reason. The other downloads will be completed separately. + partially_downloaded_reqs: List[InstallRequirement] = [] + for req in reqs: + if req.needs_more_preparation: + partially_downloaded_reqs.append(req) + else: + self._prepare_linked_requirement(req, parallel_builds) + + # TODO: separate this part out from RequirementPreparer when the v1 + # resolver can be removed! + self._complete_partial_requirements( + partially_downloaded_reqs, + parallel_builds=parallel_builds, + ) + + def _prepare_linked_requirement( + self, req: InstallRequirement, parallel_builds: bool + ) -> BaseDistribution: + assert req.link + link = req.link + + hashes = self._get_linked_req_hashes(req) + + if hashes and req.is_wheel_from_cache: + assert req.download_info is not None + assert link.is_wheel + assert link.is_file + # We need to verify hashes, and we have found the requirement in the cache + # of locally built wheels. + if ( + isinstance(req.download_info.info, ArchiveInfo) + and req.download_info.info.hashes + and hashes.has_one_of(req.download_info.info.hashes) + ): + # At this point we know the requirement was built from a hashable source + # artifact, and we verified that the cache entry's hash of the original + # artifact matches one of the hashes we expect. We don't verify hashes + # against the cached wheel, because the wheel is not the original. + hashes = None + else: + logger.warning( + "The hashes of the source archive found in cache entry " + "don't match, ignoring cached built wheel " + "and re-downloading source." + ) + req.link = req.cached_wheel_source_link + link = req.link + + self._ensure_link_req_src_dir(req, parallel_builds) + + if link.is_existing_dir(): + local_file = None + elif link.url not in self._downloaded: + try: + local_file = unpack_url( + link, + req.source_dir, + self._download, + self.verbosity, + self.download_dir, + hashes, + ) + except NetworkConnectionError as exc: + raise InstallationError( + f"Could not install requirement {req} because of HTTP " + f"error {exc} for URL {link}" + ) + else: + file_path = self._downloaded[link.url] + if hashes: + hashes.check_against_path(file_path) + local_file = File(file_path, content_type=None) + + # If download_info is set, we got it from the wheel cache. + if req.download_info is None: + # Editables don't go through this function (see + # prepare_editable_requirement). + assert not req.editable + req.download_info = direct_url_from_link(link, req.source_dir) + # Make sure we have a hash in download_info. If we got it as part of the + # URL, it will have been verified and we can rely on it. Otherwise we + # compute it from the downloaded file. + # FIXME: https://github.com/pypa/pip/issues/11943 + if ( + isinstance(req.download_info.info, ArchiveInfo) + and not req.download_info.info.hashes + and local_file + ): + hash = hash_file(local_file.path)[0].hexdigest() + # We populate info.hash for backward compatibility. + # This will automatically populate info.hashes. + req.download_info.info.hash = f"sha256={hash}" + + # For use in later processing, + # preserve the file path on the requirement. + if local_file: + req.local_file_path = local_file.path + + dist = _get_prepared_distribution( + req, + self.build_tracker, + self.finder, + self.build_isolation, + self.check_build_deps, + ) + return dist + + def save_linked_requirement(self, req: InstallRequirement) -> None: + assert self.download_dir is not None + assert req.link is not None + link = req.link + if link.is_vcs or (link.is_existing_dir() and req.editable): + # Make a .zip of the source_dir we already created. + req.archive(self.download_dir) + return + + if link.is_existing_dir(): + logger.debug( + "Not copying link to destination directory " + "since it is a directory: %s", + link, + ) + return + if req.local_file_path is None: + # No distribution was downloaded for this requirement. + return + + download_location = os.path.join(self.download_dir, link.filename) + if not os.path.exists(download_location): + shutil.copy(req.local_file_path, download_location) + download_path = display_path(download_location) + logger.info("Saved %s", download_path) + + def prepare_editable_requirement( + self, + req: InstallRequirement, + ) -> BaseDistribution: + """Prepare an editable requirement.""" + assert req.editable, "cannot prepare a non-editable req as editable" + + logger.info("Obtaining %s", req) + + with indent_log(): + if self.require_hashes: + raise InstallationError( + f"The editable requirement {req} cannot be installed when " + "requiring hashes, because there is no single file to " + "hash." + ) + req.ensure_has_source_dir(self.src_dir) + req.update_editable() + assert req.source_dir + req.download_info = direct_url_for_editable(req.unpacked_source_directory) + + dist = _get_prepared_distribution( + req, + self.build_tracker, + self.finder, + self.build_isolation, + self.check_build_deps, + ) + + req.check_if_exists(self.use_user_site) + + return dist + + def prepare_installed_requirement( + self, + req: InstallRequirement, + skip_reason: str, + ) -> BaseDistribution: + """Prepare an already-installed requirement.""" + assert req.satisfied_by, "req should have been satisfied but isn't" + assert skip_reason is not None, ( + "did not get skip reason skipped but req.satisfied_by " + f"is set to {req.satisfied_by}" + ) + logger.info( + "Requirement %s: %s (%s)", skip_reason, req, req.satisfied_by.version + ) + with indent_log(): + if self.require_hashes: + logger.debug( + "Since it is already installed, we are trusting this " + "package without checking its hash. To ensure a " + "completely repeatable environment, install into an " + "empty virtualenv." + ) + return InstalledDistribution(req).get_metadata_distribution() diff --git a/backend/venv/Lib/site-packages/pip/_internal/pyproject.py b/backend/venv/Lib/site-packages/pip/_internal/pyproject.py new file mode 100644 index 0000000..0e8452f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/pyproject.py @@ -0,0 +1,185 @@ +import importlib.util +import os +import sys +from collections import namedtuple +from typing import Any, List, Optional + +if sys.version_info >= (3, 11): + import tomllib +else: + from pip._vendor import tomli as tomllib + +from pip._vendor.packaging.requirements import InvalidRequirement + +from pip._internal.exceptions import ( + InstallationError, + InvalidPyProjectBuildRequires, + MissingPyProjectBuildRequires, +) +from pip._internal.utils.packaging import get_requirement + + +def _is_list_of_str(obj: Any) -> bool: + return isinstance(obj, list) and all(isinstance(item, str) for item in obj) + + +def make_pyproject_path(unpacked_source_directory: str) -> str: + return os.path.join(unpacked_source_directory, "pyproject.toml") + + +BuildSystemDetails = namedtuple( + "BuildSystemDetails", ["requires", "backend", "check", "backend_path"] +) + + +def load_pyproject_toml( + use_pep517: Optional[bool], pyproject_toml: str, setup_py: str, req_name: str +) -> Optional[BuildSystemDetails]: + """Load the pyproject.toml file. + + Parameters: + use_pep517 - Has the user requested PEP 517 processing? None + means the user hasn't explicitly specified. + pyproject_toml - Location of the project's pyproject.toml file + setup_py - Location of the project's setup.py file + req_name - The name of the requirement we're processing (for + error reporting) + + Returns: + None if we should use the legacy code path, otherwise a tuple + ( + requirements from pyproject.toml, + name of PEP 517 backend, + requirements we should check are installed after setting + up the build environment + directory paths to import the backend from (backend-path), + relative to the project root. + ) + """ + has_pyproject = os.path.isfile(pyproject_toml) + has_setup = os.path.isfile(setup_py) + + if not has_pyproject and not has_setup: + raise InstallationError( + f"{req_name} does not appear to be a Python project: " + f"neither 'setup.py' nor 'pyproject.toml' found." + ) + + if has_pyproject: + with open(pyproject_toml, encoding="utf-8") as f: + pp_toml = tomllib.loads(f.read()) + build_system = pp_toml.get("build-system") + else: + build_system = None + + # The following cases must use PEP 517 + # We check for use_pep517 being non-None and falsy because that means + # the user explicitly requested --no-use-pep517. The value 0 as + # opposed to False can occur when the value is provided via an + # environment variable or config file option (due to the quirk of + # strtobool() returning an integer in pip's configuration code). + if has_pyproject and not has_setup: + if use_pep517 is not None and not use_pep517: + raise InstallationError( + "Disabling PEP 517 processing is invalid: " + "project does not have a setup.py" + ) + use_pep517 = True + elif build_system and "build-backend" in build_system: + if use_pep517 is not None and not use_pep517: + raise InstallationError( + "Disabling PEP 517 processing is invalid: " + "project specifies a build backend of {} " + "in pyproject.toml".format(build_system["build-backend"]) + ) + use_pep517 = True + + # If we haven't worked out whether to use PEP 517 yet, + # and the user hasn't explicitly stated a preference, + # we do so if the project has a pyproject.toml file + # or if we cannot import setuptools or wheels. + + # We fallback to PEP 517 when without setuptools or without the wheel package, + # so setuptools can be installed as a default build backend. + # For more info see: + # https://discuss.python.org/t/pip-without-setuptools-could-the-experience-be-improved/11810/9 + # https://github.com/pypa/pip/issues/8559 + elif use_pep517 is None: + use_pep517 = ( + has_pyproject + or not importlib.util.find_spec("setuptools") + or not importlib.util.find_spec("wheel") + ) + + # At this point, we know whether we're going to use PEP 517. + assert use_pep517 is not None + + # If we're using the legacy code path, there is nothing further + # for us to do here. + if not use_pep517: + return None + + if build_system is None: + # Either the user has a pyproject.toml with no build-system + # section, or the user has no pyproject.toml, but has opted in + # explicitly via --use-pep517. + # In the absence of any explicit backend specification, we + # assume the setuptools backend that most closely emulates the + # traditional direct setup.py execution, and require wheel and + # a version of setuptools that supports that backend. + + build_system = { + "requires": ["setuptools>=40.8.0"], + "build-backend": "setuptools.build_meta:__legacy__", + } + + # If we're using PEP 517, we have build system information (either + # from pyproject.toml, or defaulted by the code above). + # Note that at this point, we do not know if the user has actually + # specified a backend, though. + assert build_system is not None + + # Ensure that the build-system section in pyproject.toml conforms + # to PEP 518. + + # Specifying the build-system table but not the requires key is invalid + if "requires" not in build_system: + raise MissingPyProjectBuildRequires(package=req_name) + + # Error out if requires is not a list of strings + requires = build_system["requires"] + if not _is_list_of_str(requires): + raise InvalidPyProjectBuildRequires( + package=req_name, + reason="It is not a list of strings.", + ) + + # Each requirement must be valid as per PEP 508 + for requirement in requires: + try: + get_requirement(requirement) + except InvalidRequirement as error: + raise InvalidPyProjectBuildRequires( + package=req_name, + reason=f"It contains an invalid requirement: {requirement!r}", + ) from error + + backend = build_system.get("build-backend") + backend_path = build_system.get("backend-path", []) + check: List[str] = [] + if backend is None: + # If the user didn't specify a backend, we assume they want to use + # the setuptools backend. But we can't be sure they have included + # a version of setuptools which supplies the backend. So we + # make a note to check that this requirement is present once + # we have set up the environment. + # This is quite a lot of work to check for a very specific case. But + # the problem is, that case is potentially quite common - projects that + # adopted PEP 518 early for the ability to specify requirements to + # execute setup.py, but never considered needing to mention the build + # tools themselves. The original PEP 518 code had a similar check (but + # implemented in a different way). + backend = "setuptools.build_meta:__legacy__" + check = ["setuptools>=40.8.0"] + + return BuildSystemDetails(requires, backend, check, backend_path) diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/req/__init__.py new file mode 100644 index 0000000..422d851 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/req/__init__.py @@ -0,0 +1,90 @@ +import collections +import logging +from dataclasses import dataclass +from typing import Generator, List, Optional, Sequence, Tuple + +from pip._internal.utils.logging import indent_log + +from .req_file import parse_requirements +from .req_install import InstallRequirement +from .req_set import RequirementSet + +__all__ = [ + "RequirementSet", + "InstallRequirement", + "parse_requirements", + "install_given_reqs", +] + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class InstallationResult: + name: str + + +def _validate_requirements( + requirements: List[InstallRequirement], +) -> Generator[Tuple[str, InstallRequirement], None, None]: + for req in requirements: + assert req.name, f"invalid to-be-installed requirement: {req}" + yield req.name, req + + +def install_given_reqs( + requirements: List[InstallRequirement], + global_options: Sequence[str], + root: Optional[str], + home: Optional[str], + prefix: Optional[str], + warn_script_location: bool, + use_user_site: bool, + pycompile: bool, +) -> List[InstallationResult]: + """ + Install everything in the given list. + + (to be called after having downloaded and unpacked the packages) + """ + to_install = collections.OrderedDict(_validate_requirements(requirements)) + + if to_install: + logger.info( + "Installing collected packages: %s", + ", ".join(to_install.keys()), + ) + + installed = [] + + with indent_log(): + for req_name, requirement in to_install.items(): + if requirement.should_reinstall: + logger.info("Attempting uninstall: %s", req_name) + with indent_log(): + uninstalled_pathset = requirement.uninstall(auto_confirm=True) + else: + uninstalled_pathset = None + + try: + requirement.install( + global_options, + root=root, + home=home, + prefix=prefix, + warn_script_location=warn_script_location, + use_user_site=use_user_site, + pycompile=pycompile, + ) + except Exception: + # if install did not succeed, rollback previous uninstall + if uninstalled_pathset and not requirement.install_succeeded: + uninstalled_pathset.rollback() + raise + else: + if uninstalled_pathset and requirement.install_succeeded: + uninstalled_pathset.commit() + + installed.append(InstallationResult(req_name)) + + return installed diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dcd82d82f0f628bec193c54c8167ee596f956543 GIT binary patch literal 3449 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f69c7a1b4833e07341ec4701666538f7c631a70b GIT binary patch literal 21259 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

        MtZ18c76!{|bcxqW+2&-~=2<)1zIkBoz{2q) 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 Iy<3F;3rw-{TL1t6 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46d366eecf9672e3cc1e4060091fae2be943a66b GIT binary patch literal 38474 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�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 Oo>w`}_n08H*ZdFaGtZ>} literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04ecdf03ef0b2a43c4426d94390e05806054e6b6 GIT binary patch literal 32098 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 Tuple[str, Optional[str]]: + m = re.match(r"^(.+)(\[[^\]]+\])$", path) + extras = None + if m: + path_no_extras = m.group(1) + extras = m.group(2) + else: + path_no_extras = path + + return path_no_extras, extras + + +def convert_extras(extras: Optional[str]) -> Set[str]: + if not extras: + return set() + return get_requirement("placeholder" + extras.lower()).extras + + +def _set_requirement_extras(req: Requirement, new_extras: Set[str]) -> Requirement: + """ + Returns a new requirement based on the given one, with the supplied extras. If the + given requirement already has extras those are replaced (or dropped if no new extras + are given). + """ + match: Optional[re.Match[str]] = re.fullmatch( + # see https://peps.python.org/pep-0508/#complete-grammar + r"([\w\t .-]+)(\[[^\]]*\])?(.*)", + str(req), + flags=re.ASCII, + ) + # ireq.req is a valid requirement so the regex should always match + assert ( + match is not None + ), f"regex match on requirement {req} failed, this should never happen" + pre: Optional[str] = match.group(1) + post: Optional[str] = match.group(3) + assert ( + pre is not None and post is not None + ), f"regex group selection for requirement {req} failed, this should never happen" + extras: str = "[{}]".format(",".join(sorted(new_extras)) if new_extras else "") + return get_requirement(f"{pre}{extras}{post}") + + +def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]: + """Parses an editable requirement into: + - a requirement name + - an URL + - extras + - editable options + Accepted requirements: + svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir + .[some_extra] + """ + + url = editable_req + + # If a file path is specified with extras, strip off the extras. + url_no_extras, extras = _strip_extras(url) + + if os.path.isdir(url_no_extras): + # Treating it as code that has already been checked out + url_no_extras = path_to_url(url_no_extras) + + if url_no_extras.lower().startswith("file:"): + package_name = Link(url_no_extras).egg_fragment + if extras: + return ( + package_name, + url_no_extras, + get_requirement("placeholder" + extras.lower()).extras, + ) + else: + return package_name, url_no_extras, set() + + for version_control in vcs: + if url.lower().startswith(f"{version_control}:"): + url = f"{version_control}+{url}" + break + + link = Link(url) + + if not link.is_vcs: + backends = ", ".join(vcs.all_schemes) + raise InstallationError( + f"{editable_req} is not a valid editable requirement. " + f"It should either be a path to a local project or a VCS URL " + f"(beginning with {backends})." + ) + + package_name = link.egg_fragment + if not package_name: + raise InstallationError( + f"Could not detect requirement name for '{editable_req}', " + "please specify one with #egg=your_package_name" + ) + return package_name, url, set() + + +def check_first_requirement_in_file(filename: str) -> None: + """Check if file is parsable as a requirements file. + + This is heavily based on ``pkg_resources.parse_requirements``, but + simplified to just check the first meaningful line. + + :raises InvalidRequirement: If the first meaningful line cannot be parsed + as an requirement. + """ + with open(filename, encoding="utf-8", errors="ignore") as f: + # Create a steppable iterator, so we can handle \-continuations. + lines = ( + line + for line in (line.strip() for line in f) + if line and not line.startswith("#") # Skip blank lines/comments. + ) + + for line in lines: + # Drop comments -- a hash without a space may be in a URL. + if " #" in line: + line = line[: line.find(" #")] + # If there is a line continuation, drop it, and append the next line. + if line.endswith("\\"): + line = line[:-2].strip() + next(lines, "") + get_requirement(line) + return + + +def deduce_helpful_msg(req: str) -> str: + """Returns helpful msg in case requirements file does not exist, + or cannot be parsed. + + :params req: Requirements file path + """ + if not os.path.exists(req): + return f" File '{req}' does not exist." + msg = " The path does exist. " + # Try to parse and check if it is a requirements file. + try: + check_first_requirement_in_file(req) + except InvalidRequirement: + logger.debug("Cannot parse '%s' as requirements file", req) + else: + msg += ( + f"The argument you provided " + f"({req}) appears to be a" + f" requirements file. If that is the" + f" case, use the '-r' flag to install" + f" the packages specified within it." + ) + return msg + + +@dataclass(frozen=True) +class RequirementParts: + requirement: Optional[Requirement] + link: Optional[Link] + markers: Optional[Marker] + extras: Set[str] + + +def parse_req_from_editable(editable_req: str) -> RequirementParts: + name, url, extras_override = parse_editable(editable_req) + + if name is not None: + try: + req: Optional[Requirement] = get_requirement(name) + except InvalidRequirement as exc: + raise InstallationError(f"Invalid requirement: {name!r}: {exc}") + else: + req = None + + link = Link(url) + + return RequirementParts(req, link, None, extras_override) + + +# ---- The actual constructors follow ---- + + +def install_req_from_editable( + editable_req: str, + comes_from: Optional[Union[InstallRequirement, str]] = None, + *, + use_pep517: Optional[bool] = None, + isolated: bool = False, + global_options: Optional[List[str]] = None, + hash_options: Optional[Dict[str, List[str]]] = None, + constraint: bool = False, + user_supplied: bool = False, + permit_editable_wheels: bool = False, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, +) -> InstallRequirement: + parts = parse_req_from_editable(editable_req) + + return InstallRequirement( + parts.requirement, + comes_from=comes_from, + user_supplied=user_supplied, + editable=True, + permit_editable_wheels=permit_editable_wheels, + link=parts.link, + constraint=constraint, + use_pep517=use_pep517, + isolated=isolated, + global_options=global_options, + hash_options=hash_options, + config_settings=config_settings, + extras=parts.extras, + ) + + +def _looks_like_path(name: str) -> bool: + """Checks whether the string "looks like" a path on the filesystem. + + This does not check whether the target actually exists, only judge from the + appearance. + + Returns true if any of the following conditions is true: + * a path separator is found (either os.path.sep or os.path.altsep); + * a dot is found (which represents the current directory). + """ + if os.path.sep in name: + return True + if os.path.altsep is not None and os.path.altsep in name: + return True + if name.startswith("."): + return True + return False + + +def _get_url_from_path(path: str, name: str) -> Optional[str]: + """ + First, it checks whether a provided path is an installable directory. If it + is, returns the path. + + If false, check if the path is an archive file (such as a .whl). + The function checks if the path is a file. If false, if the path has + an @, it will treat it as a PEP 440 URL requirement and return the path. + """ + if _looks_like_path(name) and os.path.isdir(path): + if is_installable_dir(path): + return path_to_url(path) + # TODO: The is_installable_dir test here might not be necessary + # now that it is done in load_pyproject_toml too. + raise InstallationError( + f"Directory {name!r} is not installable. Neither 'setup.py' " + "nor 'pyproject.toml' found." + ) + if not is_archive_file(path): + return None + if os.path.isfile(path): + return path_to_url(path) + urlreq_parts = name.split("@", 1) + if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]): + # If the path contains '@' and the part before it does not look + # like a path, try to treat it as a PEP 440 URL req instead. + return None + logger.warning( + "Requirement %r looks like a filename, but the file does not exist", + name, + ) + return path_to_url(path) + + +def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementParts: + if is_url(name): + marker_sep = "; " + else: + marker_sep = ";" + if marker_sep in name: + name, markers_as_string = name.split(marker_sep, 1) + markers_as_string = markers_as_string.strip() + if not markers_as_string: + markers = None + else: + markers = Marker(markers_as_string) + else: + markers = None + name = name.strip() + req_as_string = None + path = os.path.normpath(os.path.abspath(name)) + link = None + extras_as_string = None + + if is_url(name): + link = Link(name) + else: + p, extras_as_string = _strip_extras(path) + url = _get_url_from_path(p, name) + if url is not None: + link = Link(url) + + # it's a local file, dir, or url + if link: + # Handle relative file URLs + if link.scheme == "file" and re.search(r"\.\./", link.url): + link = Link(path_to_url(os.path.normpath(os.path.abspath(link.path)))) + # wheel file + if link.is_wheel: + wheel = Wheel(link.filename) # can raise InvalidWheelFilename + req_as_string = f"{wheel.name}=={wheel.version}" + else: + # set the req to the egg fragment. when it's not there, this + # will become an 'unnamed' requirement + req_as_string = link.egg_fragment + + # a requirement specifier + else: + req_as_string = name + + extras = convert_extras(extras_as_string) + + def with_source(text: str) -> str: + if not line_source: + return text + return f"{text} (from {line_source})" + + def _parse_req_string(req_as_string: str) -> Requirement: + try: + return get_requirement(req_as_string) + except InvalidRequirement as exc: + if os.path.sep in req_as_string: + add_msg = "It looks like a path." + add_msg += deduce_helpful_msg(req_as_string) + elif "=" in req_as_string and not any( + op in req_as_string for op in operators + ): + add_msg = "= is not a valid operator. Did you mean == ?" + else: + add_msg = "" + msg = with_source(f"Invalid requirement: {req_as_string!r}: {exc}") + if add_msg: + msg += f"\nHint: {add_msg}" + raise InstallationError(msg) + + if req_as_string is not None: + req: Optional[Requirement] = _parse_req_string(req_as_string) + else: + req = None + + return RequirementParts(req, link, markers, extras) + + +def install_req_from_line( + name: str, + comes_from: Optional[Union[str, InstallRequirement]] = None, + *, + use_pep517: Optional[bool] = None, + isolated: bool = False, + global_options: Optional[List[str]] = None, + hash_options: Optional[Dict[str, List[str]]] = None, + constraint: bool = False, + line_source: Optional[str] = None, + user_supplied: bool = False, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, +) -> InstallRequirement: + """Creates an InstallRequirement from a name, which might be a + requirement, directory containing 'setup.py', filename, or URL. + + :param line_source: An optional string describing where the line is from, + for logging purposes in case of an error. + """ + parts = parse_req_from_line(name, line_source) + + return InstallRequirement( + parts.requirement, + comes_from, + link=parts.link, + markers=parts.markers, + use_pep517=use_pep517, + isolated=isolated, + global_options=global_options, + hash_options=hash_options, + config_settings=config_settings, + constraint=constraint, + extras=parts.extras, + user_supplied=user_supplied, + ) + + +def install_req_from_req_string( + req_string: str, + comes_from: Optional[InstallRequirement] = None, + isolated: bool = False, + use_pep517: Optional[bool] = None, + user_supplied: bool = False, +) -> InstallRequirement: + try: + req = get_requirement(req_string) + except InvalidRequirement as exc: + raise InstallationError(f"Invalid requirement: {req_string!r}: {exc}") + + domains_not_allowed = [ + PyPI.file_storage_domain, + TestPyPI.file_storage_domain, + ] + if ( + req.url + and comes_from + and comes_from.link + and comes_from.link.netloc in domains_not_allowed + ): + # Explicitly disallow pypi packages that depend on external urls + raise InstallationError( + "Packages installed from PyPI cannot depend on packages " + "which are not also hosted on PyPI.\n" + f"{comes_from.name} depends on {req} " + ) + + return InstallRequirement( + req, + comes_from, + isolated=isolated, + use_pep517=use_pep517, + user_supplied=user_supplied, + ) + + +def install_req_from_parsed_requirement( + parsed_req: ParsedRequirement, + isolated: bool = False, + use_pep517: Optional[bool] = None, + user_supplied: bool = False, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, +) -> InstallRequirement: + if parsed_req.is_editable: + req = install_req_from_editable( + parsed_req.requirement, + comes_from=parsed_req.comes_from, + use_pep517=use_pep517, + constraint=parsed_req.constraint, + isolated=isolated, + user_supplied=user_supplied, + config_settings=config_settings, + ) + + else: + req = install_req_from_line( + parsed_req.requirement, + comes_from=parsed_req.comes_from, + use_pep517=use_pep517, + isolated=isolated, + global_options=( + parsed_req.options.get("global_options", []) + if parsed_req.options + else [] + ), + hash_options=( + parsed_req.options.get("hashes", {}) if parsed_req.options else {} + ), + constraint=parsed_req.constraint, + line_source=parsed_req.line_source, + user_supplied=user_supplied, + config_settings=config_settings, + ) + return req + + +def install_req_from_link_and_ireq( + link: Link, ireq: InstallRequirement +) -> InstallRequirement: + return InstallRequirement( + req=ireq.req, + comes_from=ireq.comes_from, + editable=ireq.editable, + link=link, + markers=ireq.markers, + use_pep517=ireq.use_pep517, + isolated=ireq.isolated, + global_options=ireq.global_options, + hash_options=ireq.hash_options, + config_settings=ireq.config_settings, + user_supplied=ireq.user_supplied, + ) + + +def install_req_drop_extras(ireq: InstallRequirement) -> InstallRequirement: + """ + Creates a new InstallationRequirement using the given template but without + any extras. Sets the original requirement as the new one's parent + (comes_from). + """ + return InstallRequirement( + req=( + _set_requirement_extras(ireq.req, set()) if ireq.req is not None else None + ), + comes_from=ireq, + editable=ireq.editable, + link=ireq.link, + markers=ireq.markers, + use_pep517=ireq.use_pep517, + isolated=ireq.isolated, + global_options=ireq.global_options, + hash_options=ireq.hash_options, + constraint=ireq.constraint, + extras=[], + config_settings=ireq.config_settings, + user_supplied=ireq.user_supplied, + permit_editable_wheels=ireq.permit_editable_wheels, + ) + + +def install_req_extend_extras( + ireq: InstallRequirement, + extras: Collection[str], +) -> InstallRequirement: + """ + Returns a copy of an installation requirement with some additional extras. + Makes a shallow copy of the ireq object. + """ + result = copy.copy(ireq) + result.extras = {*ireq.extras, *extras} + result.req = ( + _set_requirement_extras(ireq.req, result.extras) + if ireq.req is not None + else None + ) + return result diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/req_file.py b/backend/venv/Lib/site-packages/pip/_internal/req/req_file.py new file mode 100644 index 0000000..f6ba70f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/req/req_file.py @@ -0,0 +1,623 @@ +""" +Requirements file parsing +""" + +import codecs +import locale +import logging +import optparse +import os +import re +import shlex +import sys +import urllib.parse +from dataclasses import dataclass +from optparse import Values +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generator, + Iterable, + List, + NoReturn, + Optional, + Tuple, +) + +from pip._internal.cli import cmdoptions +from pip._internal.exceptions import InstallationError, RequirementsFileParseError +from pip._internal.models.search_scope import SearchScope + +if TYPE_CHECKING: + from pip._internal.index.package_finder import PackageFinder + from pip._internal.network.session import PipSession + +__all__ = ["parse_requirements"] + +ReqFileLines = Iterable[Tuple[int, str]] + +LineParser = Callable[[str], Tuple[str, Values]] + +SCHEME_RE = re.compile(r"^(http|https|file):", re.I) +COMMENT_RE = re.compile(r"(^|\s+)#.*$") + +# Matches environment variable-style values in '${MY_VARIABLE_1}' with the +# variable name consisting of only uppercase letters, digits or the '_' +# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, +# 2013 Edition. +ENV_VAR_RE = re.compile(r"(?P\$\{(?P[A-Z0-9_]+)\})") + +SUPPORTED_OPTIONS: List[Callable[..., optparse.Option]] = [ + cmdoptions.index_url, + cmdoptions.extra_index_url, + cmdoptions.no_index, + cmdoptions.constraints, + cmdoptions.requirements, + cmdoptions.editable, + cmdoptions.find_links, + cmdoptions.no_binary, + cmdoptions.only_binary, + cmdoptions.prefer_binary, + cmdoptions.require_hashes, + cmdoptions.pre, + cmdoptions.trusted_host, + cmdoptions.use_new_feature, +] + +# options to be passed to requirements +SUPPORTED_OPTIONS_REQ: List[Callable[..., optparse.Option]] = [ + cmdoptions.global_options, + cmdoptions.hash, + cmdoptions.config_settings, +] + +SUPPORTED_OPTIONS_EDITABLE_REQ: List[Callable[..., optparse.Option]] = [ + cmdoptions.config_settings, +] + + +# the 'dest' string values +SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ] +SUPPORTED_OPTIONS_EDITABLE_REQ_DEST = [ + str(o().dest) for o in SUPPORTED_OPTIONS_EDITABLE_REQ +] + +# order of BOMS is important: codecs.BOM_UTF16_LE is a prefix of codecs.BOM_UTF32_LE +# so data.startswith(BOM_UTF16_LE) would be true for UTF32_LE data +BOMS: List[Tuple[bytes, str]] = [ + (codecs.BOM_UTF8, "utf-8"), + (codecs.BOM_UTF32, "utf-32"), + (codecs.BOM_UTF32_BE, "utf-32-be"), + (codecs.BOM_UTF32_LE, "utf-32-le"), + (codecs.BOM_UTF16, "utf-16"), + (codecs.BOM_UTF16_BE, "utf-16-be"), + (codecs.BOM_UTF16_LE, "utf-16-le"), +] + +PEP263_ENCODING_RE = re.compile(rb"coding[:=]\s*([-\w.]+)") +DEFAULT_ENCODING = "utf-8" + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class ParsedRequirement: + # TODO: replace this with slots=True when dropping Python 3.9 support. + __slots__ = ( + "requirement", + "is_editable", + "comes_from", + "constraint", + "options", + "line_source", + ) + + requirement: str + is_editable: bool + comes_from: str + constraint: bool + options: Optional[Dict[str, Any]] + line_source: Optional[str] + + +@dataclass(frozen=True) +class ParsedLine: + __slots__ = ("filename", "lineno", "args", "opts", "constraint") + + filename: str + lineno: int + args: str + opts: Values + constraint: bool + + @property + def is_editable(self) -> bool: + return bool(self.opts.editables) + + @property + def requirement(self) -> Optional[str]: + if self.args: + return self.args + elif self.is_editable: + # We don't support multiple -e on one line + return self.opts.editables[0] + return None + + +def parse_requirements( + filename: str, + session: "PipSession", + finder: Optional["PackageFinder"] = None, + options: Optional[optparse.Values] = None, + constraint: bool = False, +) -> Generator[ParsedRequirement, None, None]: + """Parse a requirements file and yield ParsedRequirement instances. + + :param filename: Path or url of requirements file. + :param session: PipSession instance. + :param finder: Instance of pip.index.PackageFinder. + :param options: cli options. + :param constraint: If true, parsing a constraint file rather than + requirements file. + """ + line_parser = get_line_parser(finder) + parser = RequirementsFileParser(session, line_parser) + + for parsed_line in parser.parse(filename, constraint): + parsed_req = handle_line( + parsed_line, options=options, finder=finder, session=session + ) + if parsed_req is not None: + yield parsed_req + + +def preprocess(content: str) -> ReqFileLines: + """Split, filter, and join lines, and return a line iterator + + :param content: the content of the requirements file + """ + lines_enum: ReqFileLines = enumerate(content.splitlines(), start=1) + lines_enum = join_lines(lines_enum) + lines_enum = ignore_comments(lines_enum) + lines_enum = expand_env_variables(lines_enum) + return lines_enum + + +def handle_requirement_line( + line: ParsedLine, + options: Optional[optparse.Values] = None, +) -> ParsedRequirement: + # preserve for the nested code path + line_comes_from = "{} {} (line {})".format( + "-c" if line.constraint else "-r", + line.filename, + line.lineno, + ) + + assert line.requirement is not None + + # get the options that apply to requirements + if line.is_editable: + supported_dest = SUPPORTED_OPTIONS_EDITABLE_REQ_DEST + else: + supported_dest = SUPPORTED_OPTIONS_REQ_DEST + req_options = {} + for dest in supported_dest: + if dest in line.opts.__dict__ and line.opts.__dict__[dest]: + req_options[dest] = line.opts.__dict__[dest] + + line_source = f"line {line.lineno} of {line.filename}" + return ParsedRequirement( + requirement=line.requirement, + is_editable=line.is_editable, + comes_from=line_comes_from, + constraint=line.constraint, + options=req_options, + line_source=line_source, + ) + + +def handle_option_line( + opts: Values, + filename: str, + lineno: int, + finder: Optional["PackageFinder"] = None, + options: Optional[optparse.Values] = None, + session: Optional["PipSession"] = None, +) -> None: + if opts.hashes: + logger.warning( + "%s line %s has --hash but no requirement, and will be ignored.", + filename, + lineno, + ) + + if options: + # percolate options upward + if opts.require_hashes: + options.require_hashes = opts.require_hashes + if opts.features_enabled: + options.features_enabled.extend( + f for f in opts.features_enabled if f not in options.features_enabled + ) + + # set finder options + if finder: + find_links = finder.find_links + index_urls = finder.index_urls + no_index = finder.search_scope.no_index + if opts.no_index is True: + no_index = True + index_urls = [] + if opts.index_url and not no_index: + index_urls = [opts.index_url] + if opts.extra_index_urls and not no_index: + index_urls.extend(opts.extra_index_urls) + if opts.find_links: + # FIXME: it would be nice to keep track of the source + # of the find_links: support a find-links local path + # relative to a requirements file. + value = opts.find_links[0] + req_dir = os.path.dirname(os.path.abspath(filename)) + relative_to_reqs_file = os.path.join(req_dir, value) + if os.path.exists(relative_to_reqs_file): + value = relative_to_reqs_file + find_links.append(value) + + if session: + # We need to update the auth urls in session + session.update_index_urls(index_urls) + + search_scope = SearchScope( + find_links=find_links, + index_urls=index_urls, + no_index=no_index, + ) + finder.search_scope = search_scope + + if opts.pre: + finder.set_allow_all_prereleases() + + if opts.prefer_binary: + finder.set_prefer_binary() + + if session: + for host in opts.trusted_hosts or []: + source = f"line {lineno} of {filename}" + session.add_trusted_host(host, source=source) + + +def handle_line( + line: ParsedLine, + options: Optional[optparse.Values] = None, + finder: Optional["PackageFinder"] = None, + session: Optional["PipSession"] = None, +) -> Optional[ParsedRequirement]: + """Handle a single parsed requirements line; This can result in + creating/yielding requirements, or updating the finder. + + :param line: The parsed line to be processed. + :param options: CLI options. + :param finder: The finder - updated by non-requirement lines. + :param session: The session - updated by non-requirement lines. + + Returns a ParsedRequirement object if the line is a requirement line, + otherwise returns None. + + For lines that contain requirements, the only options that have an effect + are from SUPPORTED_OPTIONS_REQ, and they are scoped to the + requirement. Other options from SUPPORTED_OPTIONS may be present, but are + ignored. + + For lines that do not contain requirements, the only options that have an + effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may + be present, but are ignored. These lines may contain multiple options + (although our docs imply only one is supported), and all our parsed and + affect the finder. + """ + + if line.requirement is not None: + parsed_req = handle_requirement_line(line, options) + return parsed_req + else: + handle_option_line( + line.opts, + line.filename, + line.lineno, + finder, + options, + session, + ) + return None + + +class RequirementsFileParser: + def __init__( + self, + session: "PipSession", + line_parser: LineParser, + ) -> None: + self._session = session + self._line_parser = line_parser + + def parse( + self, filename: str, constraint: bool + ) -> Generator[ParsedLine, None, None]: + """Parse a given file, yielding parsed lines.""" + yield from self._parse_and_recurse( + filename, constraint, [{os.path.abspath(filename): None}] + ) + + def _parse_and_recurse( + self, + filename: str, + constraint: bool, + parsed_files_stack: List[Dict[str, Optional[str]]], + ) -> Generator[ParsedLine, None, None]: + for line in self._parse_file(filename, constraint): + if line.requirement is None and ( + line.opts.requirements or line.opts.constraints + ): + # parse a nested requirements file + if line.opts.requirements: + req_path = line.opts.requirements[0] + nested_constraint = False + else: + req_path = line.opts.constraints[0] + nested_constraint = True + + # original file is over http + if SCHEME_RE.search(filename): + # do a url join so relative paths work + req_path = urllib.parse.urljoin(filename, req_path) + # original file and nested file are paths + elif not SCHEME_RE.search(req_path): + # do a join so relative paths work + # and then abspath so that we can identify recursive references + req_path = os.path.abspath( + os.path.join( + os.path.dirname(filename), + req_path, + ) + ) + parsed_files = parsed_files_stack[0] + if req_path in parsed_files: + initial_file = parsed_files[req_path] + tail = ( + f" and again in {initial_file}" + if initial_file is not None + else "" + ) + raise RequirementsFileParseError( + f"{req_path} recursively references itself in {filename}{tail}" + ) + # Keeping a track where was each file first included in + new_parsed_files = parsed_files.copy() + new_parsed_files[req_path] = filename + yield from self._parse_and_recurse( + req_path, nested_constraint, [new_parsed_files, *parsed_files_stack] + ) + else: + yield line + + def _parse_file( + self, filename: str, constraint: bool + ) -> Generator[ParsedLine, None, None]: + _, content = get_file_content(filename, self._session) + + lines_enum = preprocess(content) + + for line_number, line in lines_enum: + try: + args_str, opts = self._line_parser(line) + except OptionParsingError as e: + # add offending line + msg = f"Invalid requirement: {line}\n{e.msg}" + raise RequirementsFileParseError(msg) + + yield ParsedLine( + filename, + line_number, + args_str, + opts, + constraint, + ) + + +def get_line_parser(finder: Optional["PackageFinder"]) -> LineParser: + def parse_line(line: str) -> Tuple[str, Values]: + # Build new parser for each line since it accumulates appendable + # options. + parser = build_parser() + defaults = parser.get_default_values() + defaults.index_url = None + if finder: + defaults.format_control = finder.format_control + + args_str, options_str = break_args_options(line) + + try: + options = shlex.split(options_str) + except ValueError as e: + raise OptionParsingError(f"Could not split options: {options_str}") from e + + opts, _ = parser.parse_args(options, defaults) + + return args_str, opts + + return parse_line + + +def break_args_options(line: str) -> Tuple[str, str]: + """Break up the line into an args and options string. We only want to shlex + (and then optparse) the options, not the args. args can contain markers + which are corrupted by shlex. + """ + tokens = line.split(" ") + args = [] + options = tokens[:] + for token in tokens: + if token.startswith("-") or token.startswith("--"): + break + else: + args.append(token) + options.pop(0) + return " ".join(args), " ".join(options) + + +class OptionParsingError(Exception): + def __init__(self, msg: str) -> None: + self.msg = msg + + +def build_parser() -> optparse.OptionParser: + """ + Return a parser for parsing requirement lines + """ + parser = optparse.OptionParser(add_help_option=False) + + option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ + for option_factory in option_factories: + option = option_factory() + parser.add_option(option) + + # By default optparse sys.exits on parsing errors. We want to wrap + # that in our own exception. + def parser_exit(self: Any, msg: str) -> "NoReturn": + raise OptionParsingError(msg) + + # NOTE: mypy disallows assigning to a method + # https://github.com/python/mypy/issues/2427 + parser.exit = parser_exit # type: ignore + + return parser + + +def join_lines(lines_enum: ReqFileLines) -> ReqFileLines: + """Joins a line ending in '\' with the previous line (except when following + comments). The joined line takes on the index of the first line. + """ + primary_line_number = None + new_line: List[str] = [] + for line_number, line in lines_enum: + if not line.endswith("\\") or COMMENT_RE.match(line): + if COMMENT_RE.match(line): + # this ensures comments are always matched later + line = " " + line + if new_line: + new_line.append(line) + assert primary_line_number is not None + yield primary_line_number, "".join(new_line) + new_line = [] + else: + yield line_number, line + else: + if not new_line: + primary_line_number = line_number + new_line.append(line.strip("\\")) + + # last line contains \ + if new_line: + assert primary_line_number is not None + yield primary_line_number, "".join(new_line) + + # TODO: handle space after '\'. + + +def ignore_comments(lines_enum: ReqFileLines) -> ReqFileLines: + """ + Strips comments and filter empty lines. + """ + for line_number, line in lines_enum: + line = COMMENT_RE.sub("", line) + line = line.strip() + if line: + yield line_number, line + + +def expand_env_variables(lines_enum: ReqFileLines) -> ReqFileLines: + """Replace all environment variables that can be retrieved via `os.getenv`. + + The only allowed format for environment variables defined in the + requirement file is `${MY_VARIABLE_1}` to ensure two things: + + 1. Strings that contain a `$` aren't accidentally (partially) expanded. + 2. Ensure consistency across platforms for requirement files. + + These points are the result of a discussion on the `github pull + request #3514 `_. + + Valid characters in variable names follow the `POSIX standard + `_ and are limited + to uppercase letter, digits and the `_` (underscore). + """ + for line_number, line in lines_enum: + for env_var, var_name in ENV_VAR_RE.findall(line): + value = os.getenv(var_name) + if not value: + continue + + line = line.replace(env_var, value) + + yield line_number, line + + +def get_file_content(url: str, session: "PipSession") -> Tuple[str, str]: + """Gets the content of a file; it may be a filename, file: URL, or + http: URL. Returns (location, content). Content is unicode. + Respects # -*- coding: declarations on the retrieved files. + + :param url: File path or url. + :param session: PipSession instance. + """ + scheme = urllib.parse.urlsplit(url).scheme + # Pip has special support for file:// URLs (LocalFSAdapter). + if scheme in ["http", "https", "file"]: + # Delay importing heavy network modules until absolutely necessary. + from pip._internal.network.utils import raise_for_status + + resp = session.get(url) + raise_for_status(resp) + return resp.url, resp.text + + # Assume this is a bare path. + try: + with open(url, "rb") as f: + raw_content = f.read() + except OSError as exc: + raise InstallationError(f"Could not open requirements file: {exc}") + + content = _decode_req_file(raw_content, url) + + return url, content + + +def _decode_req_file(data: bytes, url: str) -> str: + for bom, encoding in BOMS: + if data.startswith(bom): + return data[len(bom) :].decode(encoding) + + for line in data.split(b"\n")[:2]: + if line[0:1] == b"#": + result = PEP263_ENCODING_RE.search(line) + if result is not None: + encoding = result.groups()[0].decode("ascii") + return data.decode(encoding) + + try: + return data.decode(DEFAULT_ENCODING) + except UnicodeDecodeError: + locale_encoding = locale.getpreferredencoding(False) or sys.getdefaultencoding() + logging.warning( + "unable to decode data from %s with default encoding %s, " + "falling back to encoding from locale: %s. " + "If this is intentional you should specify the encoding with a " + "PEP-263 style comment, e.g. '# -*- coding: %s -*-'", + url, + DEFAULT_ENCODING, + locale_encoding, + locale_encoding, + ) + return data.decode(locale_encoding) diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/req_install.py b/backend/venv/Lib/site-packages/pip/_internal/req/req_install.py new file mode 100644 index 0000000..3262d82 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/req/req_install.py @@ -0,0 +1,934 @@ +import functools +import logging +import os +import shutil +import sys +import uuid +import zipfile +from optparse import Values +from pathlib import Path +from typing import Any, Collection, Dict, Iterable, List, Optional, Sequence, Union + +from pip._vendor.packaging.markers import Marker +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip._internal.build_env import BuildEnvironment, NoOpBuildEnvironment +from pip._internal.exceptions import InstallationError, PreviousBuildDirError +from pip._internal.locations import get_scheme +from pip._internal.metadata import ( + BaseDistribution, + get_default_environment, + get_directory_distribution, + get_wheel_distribution, +) +from pip._internal.metadata.base import FilesystemWheel +from pip._internal.models.direct_url import DirectUrl +from pip._internal.models.link import Link +from pip._internal.operations.build.metadata import generate_metadata +from pip._internal.operations.build.metadata_editable import generate_editable_metadata +from pip._internal.operations.build.metadata_legacy import ( + generate_metadata as generate_metadata_legacy, +) +from pip._internal.operations.install.editable_legacy import ( + install_editable as install_editable_legacy, +) +from pip._internal.operations.install.wheel import install_wheel +from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path +from pip._internal.req.req_uninstall import UninstallPathSet +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.misc import ( + ConfiguredBuildBackendHookCaller, + ask_path_exists, + backup_dir, + display_path, + hide_url, + is_installable_dir, + redact_auth_from_requirement, + redact_auth_from_url, +) +from pip._internal.utils.packaging import get_requirement +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds +from pip._internal.utils.unpacking import unpack_file +from pip._internal.utils.virtualenv import running_under_virtualenv +from pip._internal.vcs import vcs + +logger = logging.getLogger(__name__) + + +class InstallRequirement: + """ + Represents something that may be installed later on, may have information + about where to fetch the relevant requirement and also contains logic for + installing the said requirement. + """ + + def __init__( + self, + req: Optional[Requirement], + comes_from: Optional[Union[str, "InstallRequirement"]], + editable: bool = False, + link: Optional[Link] = None, + markers: Optional[Marker] = None, + use_pep517: Optional[bool] = None, + isolated: bool = False, + *, + global_options: Optional[List[str]] = None, + hash_options: Optional[Dict[str, List[str]]] = None, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + constraint: bool = False, + extras: Collection[str] = (), + user_supplied: bool = False, + permit_editable_wheels: bool = False, + ) -> None: + assert req is None or isinstance(req, Requirement), req + self.req = req + self.comes_from = comes_from + self.constraint = constraint + self.editable = editable + self.permit_editable_wheels = permit_editable_wheels + + # source_dir is the local directory where the linked requirement is + # located, or unpacked. In case unpacking is needed, creating and + # populating source_dir is done by the RequirementPreparer. Note this + # is not necessarily the directory where pyproject.toml or setup.py is + # located - that one is obtained via unpacked_source_directory. + self.source_dir: Optional[str] = None + if self.editable: + assert link + if link.is_file: + self.source_dir = os.path.normpath(os.path.abspath(link.file_path)) + + # original_link is the direct URL that was provided by the user for the + # requirement, either directly or via a constraints file. + if link is None and req and req.url: + # PEP 508 URL requirement + link = Link(req.url) + self.link = self.original_link = link + + # When this InstallRequirement is a wheel obtained from the cache of locally + # built wheels, this is the source link corresponding to the cache entry, which + # was used to download and build the cached wheel. + self.cached_wheel_source_link: Optional[Link] = None + + # Information about the location of the artifact that was downloaded . This + # property is guaranteed to be set in resolver results. + self.download_info: Optional[DirectUrl] = None + + # Path to any downloaded or already-existing package. + self.local_file_path: Optional[str] = None + if self.link and self.link.is_file: + self.local_file_path = self.link.file_path + + if extras: + self.extras = extras + elif req: + self.extras = req.extras + else: + self.extras = set() + if markers is None and req: + markers = req.marker + self.markers = markers + + # This holds the Distribution object if this requirement is already installed. + self.satisfied_by: Optional[BaseDistribution] = None + # Whether the installation process should try to uninstall an existing + # distribution before installing this requirement. + self.should_reinstall = False + # Temporary build location + self._temp_build_dir: Optional[TempDirectory] = None + # Set to True after successful installation + self.install_succeeded: Optional[bool] = None + # Supplied options + self.global_options = global_options if global_options else [] + self.hash_options = hash_options if hash_options else {} + self.config_settings = config_settings + # Set to True after successful preparation of this requirement + self.prepared = False + # User supplied requirement are explicitly requested for installation + # by the user via CLI arguments or requirements files, as opposed to, + # e.g. dependencies, extras or constraints. + self.user_supplied = user_supplied + + self.isolated = isolated + self.build_env: BuildEnvironment = NoOpBuildEnvironment() + + # For PEP 517, the directory where we request the project metadata + # gets stored. We need this to pass to build_wheel, so the backend + # can ensure that the wheel matches the metadata (see the PEP for + # details). + self.metadata_directory: Optional[str] = None + + # The static build requirements (from pyproject.toml) + self.pyproject_requires: Optional[List[str]] = None + + # Build requirements that we will check are available + self.requirements_to_check: List[str] = [] + + # The PEP 517 backend we should use to build the project + self.pep517_backend: Optional[BuildBackendHookCaller] = None + + # Are we using PEP 517 for this requirement? + # After pyproject.toml has been loaded, the only valid values are True + # and False. Before loading, None is valid (meaning "use the default"). + # Setting an explicit value before loading pyproject.toml is supported, + # but after loading this flag should be treated as read only. + self.use_pep517 = use_pep517 + + # If config settings are provided, enforce PEP 517. + if self.config_settings: + if self.use_pep517 is False: + logger.warning( + "--no-use-pep517 ignored for %s " + "because --config-settings are specified.", + self, + ) + self.use_pep517 = True + + # This requirement needs more preparation before it can be built + self.needs_more_preparation = False + + # This requirement needs to be unpacked before it can be installed. + self._archive_source: Optional[Path] = None + + def __str__(self) -> str: + if self.req: + s = redact_auth_from_requirement(self.req) + if self.link: + s += f" from {redact_auth_from_url(self.link.url)}" + elif self.link: + s = redact_auth_from_url(self.link.url) + else: + s = "" + if self.satisfied_by is not None: + if self.satisfied_by.location is not None: + location = display_path(self.satisfied_by.location) + else: + location = "" + s += f" in {location}" + if self.comes_from: + if isinstance(self.comes_from, str): + comes_from: Optional[str] = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += f" (from {comes_from})" + return s + + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} object: " + f"{str(self)} editable={self.editable!r}>" + ) + + def format_debug(self) -> str: + """An un-tested helper for getting state, for debugging.""" + attributes = vars(self) + names = sorted(attributes) + + state = (f"{attr}={attributes[attr]!r}" for attr in sorted(names)) + return "<{name} object: {{{state}}}>".format( + name=self.__class__.__name__, + state=", ".join(state), + ) + + # Things that are valid for all kinds of requirements? + @property + def name(self) -> Optional[str]: + if self.req is None: + return None + return self.req.name + + @functools.cached_property + def supports_pyproject_editable(self) -> bool: + if not self.use_pep517: + return False + assert self.pep517_backend + with self.build_env: + runner = runner_with_spinner_message( + "Checking if build backend supports build_editable" + ) + with self.pep517_backend.subprocess_runner(runner): + return "build_editable" in self.pep517_backend._supported_features() + + @property + def specifier(self) -> SpecifierSet: + assert self.req is not None + return self.req.specifier + + @property + def is_direct(self) -> bool: + """Whether this requirement was specified as a direct URL.""" + return self.original_link is not None + + @property + def is_pinned(self) -> bool: + """Return whether I am pinned to an exact version. + + For example, some-package==1.2 is pinned; some-package>1.2 is not. + """ + assert self.req is not None + specifiers = self.req.specifier + return len(specifiers) == 1 and next(iter(specifiers)).operator in {"==", "==="} + + def match_markers(self, extras_requested: Optional[Iterable[str]] = None) -> bool: + if not extras_requested: + # Provide an extra to safely evaluate the markers + # without matching any extra + extras_requested = ("",) + if self.markers is not None: + return any( + self.markers.evaluate({"extra": extra}) for extra in extras_requested + ) + else: + return True + + @property + def has_hash_options(self) -> bool: + """Return whether any known-good hashes are specified as options. + + These activate --require-hashes mode; hashes specified as part of a + URL do not. + + """ + return bool(self.hash_options) + + def hashes(self, trust_internet: bool = True) -> Hashes: + """Return a hash-comparer that considers my option- and URL-based + hashes to be known-good. + + Hashes in URLs--ones embedded in the requirements file, not ones + downloaded from an index server--are almost peers with ones from + flags. They satisfy --require-hashes (whether it was implicitly or + explicitly activated) but do not activate it. md5 and sha224 are not + allowed in flags, which should nudge people toward good algos. We + always OR all hashes together, even ones from URLs. + + :param trust_internet: Whether to trust URL-based (#md5=...) hashes + downloaded from the internet, as by populate_link() + + """ + good_hashes = self.hash_options.copy() + if trust_internet: + link = self.link + elif self.is_direct and self.user_supplied: + link = self.original_link + else: + link = None + if link and link.hash: + assert link.hash_name is not None + good_hashes.setdefault(link.hash_name, []).append(link.hash) + return Hashes(good_hashes) + + def from_path(self) -> Optional[str]: + """Format a nice indicator to show where this "comes from" """ + if self.req is None: + return None + s = str(self.req) + if self.comes_from: + comes_from: Optional[str] + if isinstance(self.comes_from, str): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += "->" + comes_from + return s + + def ensure_build_location( + self, build_dir: str, autodelete: bool, parallel_builds: bool + ) -> str: + assert build_dir is not None + if self._temp_build_dir is not None: + assert self._temp_build_dir.path + return self._temp_build_dir.path + if self.req is None: + # Some systems have /tmp as a symlink which confuses custom + # builds (such as numpy). Thus, we ensure that the real path + # is returned. + self._temp_build_dir = TempDirectory( + kind=tempdir_kinds.REQ_BUILD, globally_managed=True + ) + + return self._temp_build_dir.path + + # This is the only remaining place where we manually determine the path + # for the temporary directory. It is only needed for editables where + # it is the value of the --src option. + + # When parallel builds are enabled, add a UUID to the build directory + # name so multiple builds do not interfere with each other. + dir_name: str = canonicalize_name(self.req.name) + if parallel_builds: + dir_name = f"{dir_name}_{uuid.uuid4().hex}" + + # FIXME: Is there a better place to create the build_dir? (hg and bzr + # need this) + if not os.path.exists(build_dir): + logger.debug("Creating directory %s", build_dir) + os.makedirs(build_dir) + actual_build_dir = os.path.join(build_dir, dir_name) + # `None` indicates that we respect the globally-configured deletion + # settings, which is what we actually want when auto-deleting. + delete_arg = None if autodelete else False + return TempDirectory( + path=actual_build_dir, + delete=delete_arg, + kind=tempdir_kinds.REQ_BUILD, + globally_managed=True, + ).path + + def _set_requirement(self) -> None: + """Set requirement after generating metadata.""" + assert self.req is None + assert self.metadata is not None + assert self.source_dir is not None + + # Construct a Requirement object from the generated metadata + if isinstance(parse_version(self.metadata["Version"]), Version): + op = "==" + else: + op = "===" + + self.req = get_requirement( + "".join( + [ + self.metadata["Name"], + op, + self.metadata["Version"], + ] + ) + ) + + def warn_on_mismatching_name(self) -> None: + assert self.req is not None + metadata_name = canonicalize_name(self.metadata["Name"]) + if canonicalize_name(self.req.name) == metadata_name: + # Everything is fine. + return + + # If we're here, there's a mismatch. Log a warning about it. + logger.warning( + "Generating metadata for package %s " + "produced metadata for project name %s. Fix your " + "#egg=%s fragments.", + self.name, + metadata_name, + self.name, + ) + self.req = get_requirement(metadata_name) + + def check_if_exists(self, use_user_site: bool) -> None: + """Find an installed distribution that satisfies or conflicts + with this requirement, and set self.satisfied_by or + self.should_reinstall appropriately. + """ + if self.req is None: + return + existing_dist = get_default_environment().get_distribution(self.req.name) + if not existing_dist: + return + + version_compatible = self.req.specifier.contains( + existing_dist.version, + prereleases=True, + ) + if not version_compatible: + self.satisfied_by = None + if use_user_site: + if existing_dist.in_usersite: + self.should_reinstall = True + elif running_under_virtualenv() and existing_dist.in_site_packages: + raise InstallationError( + f"Will not install to the user site because it will " + f"lack sys.path precedence to {existing_dist.raw_name} " + f"in {existing_dist.location}" + ) + else: + self.should_reinstall = True + else: + if self.editable: + self.should_reinstall = True + # when installing editables, nothing pre-existing should ever + # satisfy + self.satisfied_by = None + else: + self.satisfied_by = existing_dist + + # Things valid for wheels + @property + def is_wheel(self) -> bool: + if not self.link: + return False + return self.link.is_wheel + + @property + def is_wheel_from_cache(self) -> bool: + # When True, it means that this InstallRequirement is a local wheel file in the + # cache of locally built wheels. + return self.cached_wheel_source_link is not None + + # Things valid for sdists + @property + def unpacked_source_directory(self) -> str: + assert self.source_dir, f"No source dir for {self}" + return os.path.join( + self.source_dir, self.link and self.link.subdirectory_fragment or "" + ) + + @property + def setup_py_path(self) -> str: + assert self.source_dir, f"No source dir for {self}" + setup_py = os.path.join(self.unpacked_source_directory, "setup.py") + + return setup_py + + @property + def setup_cfg_path(self) -> str: + assert self.source_dir, f"No source dir for {self}" + setup_cfg = os.path.join(self.unpacked_source_directory, "setup.cfg") + + return setup_cfg + + @property + def pyproject_toml_path(self) -> str: + assert self.source_dir, f"No source dir for {self}" + return make_pyproject_path(self.unpacked_source_directory) + + def load_pyproject_toml(self) -> None: + """Load the pyproject.toml file. + + After calling this routine, all of the attributes related to PEP 517 + processing for this requirement have been set. In particular, the + use_pep517 attribute can be used to determine whether we should + follow the PEP 517 or legacy (setup.py) code path. + """ + pyproject_toml_data = load_pyproject_toml( + self.use_pep517, self.pyproject_toml_path, self.setup_py_path, str(self) + ) + + if pyproject_toml_data is None: + assert not self.config_settings + self.use_pep517 = False + return + + self.use_pep517 = True + requires, backend, check, backend_path = pyproject_toml_data + self.requirements_to_check = check + self.pyproject_requires = requires + self.pep517_backend = ConfiguredBuildBackendHookCaller( + self, + self.unpacked_source_directory, + backend, + backend_path=backend_path, + ) + + def isolated_editable_sanity_check(self) -> None: + """Check that an editable requirement if valid for use with PEP 517/518. + + This verifies that an editable that has a pyproject.toml either supports PEP 660 + or as a setup.py or a setup.cfg + """ + if ( + self.editable + and self.use_pep517 + and not self.supports_pyproject_editable + and not os.path.isfile(self.setup_py_path) + and not os.path.isfile(self.setup_cfg_path) + ): + raise InstallationError( + f"Project {self} has a 'pyproject.toml' and its build " + f"backend is missing the 'build_editable' hook. Since it does not " + f"have a 'setup.py' nor a 'setup.cfg', " + f"it cannot be installed in editable mode. " + f"Consider using a build backend that supports PEP 660." + ) + + def prepare_metadata(self) -> None: + """Ensure that project metadata is available. + + Under PEP 517 and PEP 660, call the backend hook to prepare the metadata. + Under legacy processing, call setup.py egg-info. + """ + assert self.source_dir, f"No source dir for {self}" + details = self.name or f"from {self.link}" + + if self.use_pep517: + assert self.pep517_backend is not None + if ( + self.editable + and self.permit_editable_wheels + and self.supports_pyproject_editable + ): + self.metadata_directory = generate_editable_metadata( + build_env=self.build_env, + backend=self.pep517_backend, + details=details, + ) + else: + self.metadata_directory = generate_metadata( + build_env=self.build_env, + backend=self.pep517_backend, + details=details, + ) + else: + self.metadata_directory = generate_metadata_legacy( + build_env=self.build_env, + setup_py_path=self.setup_py_path, + source_dir=self.unpacked_source_directory, + isolated=self.isolated, + details=details, + ) + + # Act on the newly generated metadata, based on the name and version. + if not self.name: + self._set_requirement() + else: + self.warn_on_mismatching_name() + + self.assert_source_matches_version() + + @property + def metadata(self) -> Any: + if not hasattr(self, "_metadata"): + self._metadata = self.get_dist().metadata + + return self._metadata + + def get_dist(self) -> BaseDistribution: + if self.metadata_directory: + return get_directory_distribution(self.metadata_directory) + elif self.local_file_path and self.is_wheel: + assert self.req is not None + return get_wheel_distribution( + FilesystemWheel(self.local_file_path), + canonicalize_name(self.req.name), + ) + raise AssertionError( + f"InstallRequirement {self} has no metadata directory and no wheel: " + f"can't make a distribution." + ) + + def assert_source_matches_version(self) -> None: + assert self.source_dir, f"No source dir for {self}" + version = self.metadata["version"] + if self.req and self.req.specifier and version not in self.req.specifier: + logger.warning( + "Requested %s, but installing version %s", + self, + version, + ) + else: + logger.debug( + "Source in %s has version %s, which satisfies requirement %s", + display_path(self.source_dir), + version, + self, + ) + + # For both source distributions and editables + def ensure_has_source_dir( + self, + parent_dir: str, + autodelete: bool = False, + parallel_builds: bool = False, + ) -> None: + """Ensure that a source_dir is set. + + This will create a temporary build dir if the name of the requirement + isn't known yet. + + :param parent_dir: The ideal pip parent_dir for the source_dir. + Generally src_dir for editables and build_dir for sdists. + :return: self.source_dir + """ + if self.source_dir is None: + self.source_dir = self.ensure_build_location( + parent_dir, + autodelete=autodelete, + parallel_builds=parallel_builds, + ) + + def needs_unpacked_archive(self, archive_source: Path) -> None: + assert self._archive_source is None + self._archive_source = archive_source + + def ensure_pristine_source_checkout(self) -> None: + """Ensure the source directory has not yet been built in.""" + assert self.source_dir is not None + if self._archive_source is not None: + unpack_file(str(self._archive_source), self.source_dir) + elif is_installable_dir(self.source_dir): + # If a checkout exists, it's unwise to keep going. + # version inconsistencies are logged later, but do not fail + # the installation. + raise PreviousBuildDirError( + f"pip can't proceed with requirements '{self}' due to a " + f"pre-existing build directory ({self.source_dir}). This is likely " + "due to a previous installation that failed . pip is " + "being responsible and not assuming it can delete this. " + "Please delete it and try again." + ) + + # For editable installations + def update_editable(self) -> None: + if not self.link: + logger.debug( + "Cannot update repository at %s; repository location is unknown", + self.source_dir, + ) + return + assert self.editable + assert self.source_dir + if self.link.scheme == "file": + # Static paths don't get updated + return + vcs_backend = vcs.get_backend_for_scheme(self.link.scheme) + # Editable requirements are validated in Requirement constructors. + # So here, if it's neither a path nor a valid VCS URL, it's a bug. + assert vcs_backend, f"Unsupported VCS URL {self.link.url}" + hidden_url = hide_url(self.link.url) + vcs_backend.obtain(self.source_dir, url=hidden_url, verbosity=0) + + # Top-level Actions + def uninstall( + self, auto_confirm: bool = False, verbose: bool = False + ) -> Optional[UninstallPathSet]: + """ + Uninstall the distribution currently satisfying this requirement. + + Prompts before removing or modifying files unless + ``auto_confirm`` is True. + + Refuses to delete or modify files outside of ``sys.prefix`` - + thus uninstallation within a virtual environment can only + modify that virtual environment, even if the virtualenv is + linked to global site-packages. + + """ + assert self.req + dist = get_default_environment().get_distribution(self.req.name) + if not dist: + logger.warning("Skipping %s as it is not installed.", self.name) + return None + logger.info("Found existing installation: %s", dist) + + uninstalled_pathset = UninstallPathSet.from_dist(dist) + uninstalled_pathset.remove(auto_confirm, verbose) + return uninstalled_pathset + + def _get_archive_name(self, path: str, parentdir: str, rootdir: str) -> str: + def _clean_zip_name(name: str, prefix: str) -> str: + assert name.startswith( + prefix + os.path.sep + ), f"name {name!r} doesn't start with prefix {prefix!r}" + name = name[len(prefix) + 1 :] + name = name.replace(os.path.sep, "/") + return name + + assert self.req is not None + path = os.path.join(parentdir, path) + name = _clean_zip_name(path, rootdir) + return self.req.name + "/" + name + + def archive(self, build_dir: Optional[str]) -> None: + """Saves archive to provided build_dir. + + Used for saving downloaded VCS requirements as part of `pip download`. + """ + assert self.source_dir + if build_dir is None: + return + + create_archive = True + archive_name = "{}-{}.zip".format(self.name, self.metadata["version"]) + archive_path = os.path.join(build_dir, archive_name) + + if os.path.exists(archive_path): + response = ask_path_exists( + f"The file {display_path(archive_path)} exists. (i)gnore, (w)ipe, " + "(b)ackup, (a)bort ", + ("i", "w", "b", "a"), + ) + if response == "i": + create_archive = False + elif response == "w": + logger.warning("Deleting %s", display_path(archive_path)) + os.remove(archive_path) + elif response == "b": + dest_file = backup_dir(archive_path) + logger.warning( + "Backing up %s to %s", + display_path(archive_path), + display_path(dest_file), + ) + shutil.move(archive_path, dest_file) + elif response == "a": + sys.exit(-1) + + if not create_archive: + return + + zip_output = zipfile.ZipFile( + archive_path, + "w", + zipfile.ZIP_DEFLATED, + allowZip64=True, + ) + with zip_output: + dir = os.path.normcase(os.path.abspath(self.unpacked_source_directory)) + for dirpath, dirnames, filenames in os.walk(dir): + for dirname in dirnames: + dir_arcname = self._get_archive_name( + dirname, + parentdir=dirpath, + rootdir=dir, + ) + zipdir = zipfile.ZipInfo(dir_arcname + "/") + zipdir.external_attr = 0x1ED << 16 # 0o755 + zip_output.writestr(zipdir, "") + for filename in filenames: + file_arcname = self._get_archive_name( + filename, + parentdir=dirpath, + rootdir=dir, + ) + filename = os.path.join(dirpath, filename) + zip_output.write(filename, file_arcname) + + logger.info("Saved %s", display_path(archive_path)) + + def install( + self, + global_options: Optional[Sequence[str]] = None, + root: Optional[str] = None, + home: Optional[str] = None, + prefix: Optional[str] = None, + warn_script_location: bool = True, + use_user_site: bool = False, + pycompile: bool = True, + ) -> None: + assert self.req is not None + scheme = get_scheme( + self.req.name, + user=use_user_site, + home=home, + root=root, + isolated=self.isolated, + prefix=prefix, + ) + + if self.editable and not self.is_wheel: + deprecated( + reason=( + f"Legacy editable install of {self} (setup.py develop) " + "is deprecated." + ), + replacement=( + "to add a pyproject.toml or enable --use-pep517, " + "and use setuptools >= 64. " + "If the resulting installation is not behaving as expected, " + "try using --config-settings editable_mode=compat. " + "Please consult the setuptools documentation for more information" + ), + gone_in="25.1", + issue=11457, + ) + if self.config_settings: + logger.warning( + "--config-settings ignored for legacy editable install of %s. " + "Consider upgrading to a version of setuptools " + "that supports PEP 660 (>= 64).", + self, + ) + install_editable_legacy( + global_options=global_options if global_options is not None else [], + prefix=prefix, + home=home, + use_user_site=use_user_site, + name=self.req.name, + setup_py_path=self.setup_py_path, + isolated=self.isolated, + build_env=self.build_env, + unpacked_source_directory=self.unpacked_source_directory, + ) + self.install_succeeded = True + return + + assert self.is_wheel + assert self.local_file_path + + install_wheel( + self.req.name, + self.local_file_path, + scheme=scheme, + req_description=str(self.req), + pycompile=pycompile, + warn_script_location=warn_script_location, + direct_url=self.download_info if self.is_direct else None, + requested=self.user_supplied, + ) + self.install_succeeded = True + + +def check_invalid_constraint_type(req: InstallRequirement) -> str: + # Check for unsupported forms + problem = "" + if not req.name: + problem = "Unnamed requirements are not allowed as constraints" + elif req.editable: + problem = "Editable requirements are not allowed as constraints" + elif req.extras: + problem = "Constraints cannot have extras" + + if problem: + deprecated( + reason=( + "Constraints are only allowed to take the form of a package " + "name and a version specifier. Other forms were originally " + "permitted as an accident of the implementation, but were " + "undocumented. The new implementation of the resolver no " + "longer supports these forms." + ), + replacement="replacing the constraint with a requirement", + # No plan yet for when the new resolver becomes default + gone_in=None, + issue=8210, + ) + + return problem + + +def _has_option(options: Values, reqs: List[InstallRequirement], option: str) -> bool: + if getattr(options, option, None): + return True + for req in reqs: + if getattr(req, option, None): + return True + return False + + +def check_legacy_setup_py_options( + options: Values, + reqs: List[InstallRequirement], +) -> None: + has_build_options = _has_option(options, reqs, "build_options") + has_global_options = _has_option(options, reqs, "global_options") + if has_build_options or has_global_options: + deprecated( + reason="--build-option and --global-option are deprecated.", + issue=11859, + replacement="to use --config-settings", + gone_in=None, + ) + logger.warning( + "Implying --no-binary=:all: due to the presence of " + "--build-option / --global-option. " + ) + options.format_control.disallow_binaries() diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/req_set.py b/backend/venv/Lib/site-packages/pip/_internal/req/req_set.py new file mode 100644 index 0000000..ec7a6e0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/req/req_set.py @@ -0,0 +1,82 @@ +import logging +from collections import OrderedDict +from typing import Dict, List + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.req.req_install import InstallRequirement + +logger = logging.getLogger(__name__) + + +class RequirementSet: + def __init__(self, check_supported_wheels: bool = True) -> None: + """Create a RequirementSet.""" + + self.requirements: Dict[str, InstallRequirement] = OrderedDict() + self.check_supported_wheels = check_supported_wheels + + self.unnamed_requirements: List[InstallRequirement] = [] + + def __str__(self) -> str: + requirements = sorted( + (req for req in self.requirements.values() if not req.comes_from), + key=lambda req: canonicalize_name(req.name or ""), + ) + return " ".join(str(req.req) for req in requirements) + + def __repr__(self) -> str: + requirements = sorted( + self.requirements.values(), + key=lambda req: canonicalize_name(req.name or ""), + ) + + format_string = "<{classname} object; {count} requirement(s): {reqs}>" + return format_string.format( + classname=self.__class__.__name__, + count=len(requirements), + reqs=", ".join(str(req.req) for req in requirements), + ) + + def add_unnamed_requirement(self, install_req: InstallRequirement) -> None: + assert not install_req.name + self.unnamed_requirements.append(install_req) + + def add_named_requirement(self, install_req: InstallRequirement) -> None: + assert install_req.name + + project_name = canonicalize_name(install_req.name) + self.requirements[project_name] = install_req + + def has_requirement(self, name: str) -> bool: + project_name = canonicalize_name(name) + + return ( + project_name in self.requirements + and not self.requirements[project_name].constraint + ) + + def get_requirement(self, name: str) -> InstallRequirement: + project_name = canonicalize_name(name) + + if project_name in self.requirements: + return self.requirements[project_name] + + raise KeyError(f"No project with the name {name!r}") + + @property + def all_requirements(self) -> List[InstallRequirement]: + return self.unnamed_requirements + list(self.requirements.values()) + + @property + def requirements_to_install(self) -> List[InstallRequirement]: + """Return the list of requirements that need to be installed. + + TODO remove this property together with the legacy resolver, since the new + resolver only returns requirements that need to be installed. + """ + return [ + install_req + for install_req in self.all_requirements + if not install_req.constraint and not install_req.satisfied_by + ] diff --git a/backend/venv/Lib/site-packages/pip/_internal/req/req_uninstall.py b/backend/venv/Lib/site-packages/pip/_internal/req/req_uninstall.py new file mode 100644 index 0000000..26df208 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/req/req_uninstall.py @@ -0,0 +1,633 @@ +import functools +import os +import sys +import sysconfig +from importlib.util import cache_from_source +from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Set, Tuple + +from pip._internal.exceptions import LegacyDistutilsInstall, UninstallMissingRecord +from pip._internal.locations import get_bin_prefix, get_bin_user +from pip._internal.metadata import BaseDistribution +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.egg_link import egg_link_path_from_location +from pip._internal.utils.logging import getLogger, indent_log +from pip._internal.utils.misc import ask, normalize_path, renames, rmtree +from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory +from pip._internal.utils.virtualenv import running_under_virtualenv + +logger = getLogger(__name__) + + +def _script_names( + bin_dir: str, script_name: str, is_gui: bool +) -> Generator[str, None, None]: + """Create the fully qualified name of the files created by + {console,gui}_scripts for the given ``dist``. + Returns the list of file names + """ + exe_name = os.path.join(bin_dir, script_name) + yield exe_name + if not WINDOWS: + return + yield f"{exe_name}.exe" + yield f"{exe_name}.exe.manifest" + if is_gui: + yield f"{exe_name}-script.pyw" + else: + yield f"{exe_name}-script.py" + + +def _unique( + fn: Callable[..., Generator[Any, None, None]] +) -> Callable[..., Generator[Any, None, None]]: + @functools.wraps(fn) + def unique(*args: Any, **kw: Any) -> Generator[Any, None, None]: + seen: Set[Any] = set() + for item in fn(*args, **kw): + if item not in seen: + seen.add(item) + yield item + + return unique + + +@_unique +def uninstallation_paths(dist: BaseDistribution) -> Generator[str, None, None]: + """ + Yield all the uninstallation paths for dist based on RECORD-without-.py[co] + + Yield paths to all the files in RECORD. For each .py file in RECORD, add + the .pyc and .pyo in the same directory. + + UninstallPathSet.add() takes care of the __pycache__ .py[co]. + + If RECORD is not found, raises an error, + with possible information from the INSTALLER file. + + https://packaging.python.org/specifications/recording-installed-packages/ + """ + location = dist.location + assert location is not None, "not installed" + + entries = dist.iter_declared_entries() + if entries is None: + raise UninstallMissingRecord(distribution=dist) + + for entry in entries: + path = os.path.join(location, entry) + yield path + if path.endswith(".py"): + dn, fn = os.path.split(path) + base = fn[:-3] + path = os.path.join(dn, base + ".pyc") + yield path + path = os.path.join(dn, base + ".pyo") + yield path + + +def compact(paths: Iterable[str]) -> Set[str]: + """Compact a path set to contain the minimal number of paths + necessary to contain all paths in the set. If /a/path/ and + /a/path/to/a/file.txt are both in the set, leave only the + shorter path.""" + + sep = os.path.sep + short_paths: Set[str] = set() + for path in sorted(paths, key=len): + should_skip = any( + path.startswith(shortpath.rstrip("*")) + and path[len(shortpath.rstrip("*").rstrip(sep))] == sep + for shortpath in short_paths + ) + if not should_skip: + short_paths.add(path) + return short_paths + + +def compress_for_rename(paths: Iterable[str]) -> Set[str]: + """Returns a set containing the paths that need to be renamed. + + This set may include directories when the original sequence of paths + included every file on disk. + """ + case_map = {os.path.normcase(p): p for p in paths} + remaining = set(case_map) + unchecked = sorted({os.path.split(p)[0] for p in case_map.values()}, key=len) + wildcards: Set[str] = set() + + def norm_join(*a: str) -> str: + return os.path.normcase(os.path.join(*a)) + + for root in unchecked: + if any(os.path.normcase(root).startswith(w) for w in wildcards): + # This directory has already been handled. + continue + + all_files: Set[str] = set() + all_subdirs: Set[str] = set() + for dirname, subdirs, files in os.walk(root): + all_subdirs.update(norm_join(root, dirname, d) for d in subdirs) + all_files.update(norm_join(root, dirname, f) for f in files) + # If all the files we found are in our remaining set of files to + # remove, then remove them from the latter set and add a wildcard + # for the directory. + if not (all_files - remaining): + remaining.difference_update(all_files) + wildcards.add(root + os.sep) + + return set(map(case_map.__getitem__, remaining)) | wildcards + + +def compress_for_output_listing(paths: Iterable[str]) -> Tuple[Set[str], Set[str]]: + """Returns a tuple of 2 sets of which paths to display to user + + The first set contains paths that would be deleted. Files of a package + are not added and the top-level directory of the package has a '*' added + at the end - to signify that all it's contents are removed. + + The second set contains files that would have been skipped in the above + folders. + """ + + will_remove = set(paths) + will_skip = set() + + # Determine folders and files + folders = set() + files = set() + for path in will_remove: + if path.endswith(".pyc"): + continue + if path.endswith("__init__.py") or ".dist-info" in path: + folders.add(os.path.dirname(path)) + files.add(path) + + _normcased_files = set(map(os.path.normcase, files)) + + folders = compact(folders) + + # This walks the tree using os.walk to not miss extra folders + # that might get added. + for folder in folders: + for dirpath, _, dirfiles in os.walk(folder): + for fname in dirfiles: + if fname.endswith(".pyc"): + continue + + file_ = os.path.join(dirpath, fname) + if ( + os.path.isfile(file_) + and os.path.normcase(file_) not in _normcased_files + ): + # We are skipping this file. Add it to the set. + will_skip.add(file_) + + will_remove = files | {os.path.join(folder, "*") for folder in folders} + + return will_remove, will_skip + + +class StashedUninstallPathSet: + """A set of file rename operations to stash files while + tentatively uninstalling them.""" + + def __init__(self) -> None: + # Mapping from source file root to [Adjacent]TempDirectory + # for files under that directory. + self._save_dirs: Dict[str, TempDirectory] = {} + # (old path, new path) tuples for each move that may need + # to be undone. + self._moves: List[Tuple[str, str]] = [] + + def _get_directory_stash(self, path: str) -> str: + """Stashes a directory. + + Directories are stashed adjacent to their original location if + possible, or else moved/copied into the user's temp dir.""" + + try: + save_dir: TempDirectory = AdjacentTempDirectory(path) + except OSError: + save_dir = TempDirectory(kind="uninstall") + self._save_dirs[os.path.normcase(path)] = save_dir + + return save_dir.path + + def _get_file_stash(self, path: str) -> str: + """Stashes a file. + + If no root has been provided, one will be created for the directory + in the user's temp directory.""" + path = os.path.normcase(path) + head, old_head = os.path.dirname(path), None + save_dir = None + + while head != old_head: + try: + save_dir = self._save_dirs[head] + break + except KeyError: + pass + head, old_head = os.path.dirname(head), head + else: + # Did not find any suitable root + head = os.path.dirname(path) + save_dir = TempDirectory(kind="uninstall") + self._save_dirs[head] = save_dir + + relpath = os.path.relpath(path, head) + if relpath and relpath != os.path.curdir: + return os.path.join(save_dir.path, relpath) + return save_dir.path + + def stash(self, path: str) -> str: + """Stashes the directory or file and returns its new location. + Handle symlinks as files to avoid modifying the symlink targets. + """ + path_is_dir = os.path.isdir(path) and not os.path.islink(path) + if path_is_dir: + new_path = self._get_directory_stash(path) + else: + new_path = self._get_file_stash(path) + + self._moves.append((path, new_path)) + if path_is_dir and os.path.isdir(new_path): + # If we're moving a directory, we need to + # remove the destination first or else it will be + # moved to inside the existing directory. + # We just created new_path ourselves, so it will + # be removable. + os.rmdir(new_path) + renames(path, new_path) + return new_path + + def commit(self) -> None: + """Commits the uninstall by removing stashed files.""" + for save_dir in self._save_dirs.values(): + save_dir.cleanup() + self._moves = [] + self._save_dirs = {} + + def rollback(self) -> None: + """Undoes the uninstall by moving stashed files back.""" + for p in self._moves: + logger.info("Moving to %s\n from %s", *p) + + for new_path, path in self._moves: + try: + logger.debug("Replacing %s from %s", new_path, path) + if os.path.isfile(new_path) or os.path.islink(new_path): + os.unlink(new_path) + elif os.path.isdir(new_path): + rmtree(new_path) + renames(path, new_path) + except OSError as ex: + logger.error("Failed to restore %s", new_path) + logger.debug("Exception: %s", ex) + + self.commit() + + @property + def can_rollback(self) -> bool: + return bool(self._moves) + + +class UninstallPathSet: + """A set of file paths to be removed in the uninstallation of a + requirement.""" + + def __init__(self, dist: BaseDistribution) -> None: + self._paths: Set[str] = set() + self._refuse: Set[str] = set() + self._pth: Dict[str, UninstallPthEntries] = {} + self._dist = dist + self._moved_paths = StashedUninstallPathSet() + # Create local cache of normalize_path results. Creating an UninstallPathSet + # can result in hundreds/thousands of redundant calls to normalize_path with + # the same args, which hurts performance. + self._normalize_path_cached = functools.lru_cache(normalize_path) + + def _permitted(self, path: str) -> bool: + """ + Return True if the given path is one we are permitted to + remove/modify, False otherwise. + + """ + # aka is_local, but caching normalized sys.prefix + if not running_under_virtualenv(): + return True + return path.startswith(self._normalize_path_cached(sys.prefix)) + + def add(self, path: str) -> None: + head, tail = os.path.split(path) + + # we normalize the head to resolve parent directory symlinks, but not + # the tail, since we only want to uninstall symlinks, not their targets + path = os.path.join(self._normalize_path_cached(head), os.path.normcase(tail)) + + if not os.path.exists(path): + return + if self._permitted(path): + self._paths.add(path) + else: + self._refuse.add(path) + + # __pycache__ files can show up after 'installed-files.txt' is created, + # due to imports + if os.path.splitext(path)[1] == ".py": + self.add(cache_from_source(path)) + + def add_pth(self, pth_file: str, entry: str) -> None: + pth_file = self._normalize_path_cached(pth_file) + if self._permitted(pth_file): + if pth_file not in self._pth: + self._pth[pth_file] = UninstallPthEntries(pth_file) + self._pth[pth_file].add(entry) + else: + self._refuse.add(pth_file) + + def remove(self, auto_confirm: bool = False, verbose: bool = False) -> None: + """Remove paths in ``self._paths`` with confirmation (unless + ``auto_confirm`` is True).""" + + if not self._paths: + logger.info( + "Can't uninstall '%s'. No files were found to uninstall.", + self._dist.raw_name, + ) + return + + dist_name_version = f"{self._dist.raw_name}-{self._dist.raw_version}" + logger.info("Uninstalling %s:", dist_name_version) + + with indent_log(): + if auto_confirm or self._allowed_to_proceed(verbose): + moved = self._moved_paths + + for_rename = compress_for_rename(self._paths) + + for path in sorted(compact(for_rename)): + moved.stash(path) + logger.verbose("Removing file or directory %s", path) + + for pth in self._pth.values(): + pth.remove() + + logger.info("Successfully uninstalled %s", dist_name_version) + + def _allowed_to_proceed(self, verbose: bool) -> bool: + """Display which files would be deleted and prompt for confirmation""" + + def _display(msg: str, paths: Iterable[str]) -> None: + if not paths: + return + + logger.info(msg) + with indent_log(): + for path in sorted(compact(paths)): + logger.info(path) + + if not verbose: + will_remove, will_skip = compress_for_output_listing(self._paths) + else: + # In verbose mode, display all the files that are going to be + # deleted. + will_remove = set(self._paths) + will_skip = set() + + _display("Would remove:", will_remove) + _display("Would not remove (might be manually added):", will_skip) + _display("Would not remove (outside of prefix):", self._refuse) + if verbose: + _display("Will actually move:", compress_for_rename(self._paths)) + + return ask("Proceed (Y/n)? ", ("y", "n", "")) != "n" + + def rollback(self) -> None: + """Rollback the changes previously made by remove().""" + if not self._moved_paths.can_rollback: + logger.error( + "Can't roll back %s; was not uninstalled", + self._dist.raw_name, + ) + return + logger.info("Rolling back uninstall of %s", self._dist.raw_name) + self._moved_paths.rollback() + for pth in self._pth.values(): + pth.rollback() + + def commit(self) -> None: + """Remove temporary save dir: rollback will no longer be possible.""" + self._moved_paths.commit() + + @classmethod + def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet": + dist_location = dist.location + info_location = dist.info_location + if dist_location is None: + logger.info( + "Not uninstalling %s since it is not installed", + dist.canonical_name, + ) + return cls(dist) + + normalized_dist_location = normalize_path(dist_location) + if not dist.local: + logger.info( + "Not uninstalling %s at %s, outside environment %s", + dist.canonical_name, + normalized_dist_location, + sys.prefix, + ) + return cls(dist) + + if normalized_dist_location in { + p + for p in {sysconfig.get_path("stdlib"), sysconfig.get_path("platstdlib")} + if p + }: + logger.info( + "Not uninstalling %s at %s, as it is in the standard library.", + dist.canonical_name, + normalized_dist_location, + ) + return cls(dist) + + paths_to_remove = cls(dist) + develop_egg_link = egg_link_path_from_location(dist.raw_name) + + # Distribution is installed with metadata in a "flat" .egg-info + # directory. This means it is not a modern .dist-info installation, an + # egg, or legacy editable. + setuptools_flat_installation = ( + dist.installed_with_setuptools_egg_info + and info_location is not None + and os.path.exists(info_location) + # If dist is editable and the location points to a ``.egg-info``, + # we are in fact in the legacy editable case. + and not info_location.endswith(f"{dist.setuptools_filename}.egg-info") + ) + + # Uninstall cases order do matter as in the case of 2 installs of the + # same package, pip needs to uninstall the currently detected version + if setuptools_flat_installation: + if info_location is not None: + paths_to_remove.add(info_location) + installed_files = dist.iter_declared_entries() + if installed_files is not None: + for installed_file in installed_files: + paths_to_remove.add(os.path.join(dist_location, installed_file)) + # FIXME: need a test for this elif block + # occurs with --single-version-externally-managed/--record outside + # of pip + elif dist.is_file("top_level.txt"): + try: + namespace_packages = dist.read_text("namespace_packages.txt") + except FileNotFoundError: + namespaces = [] + else: + namespaces = namespace_packages.splitlines(keepends=False) + for top_level_pkg in [ + p + for p in dist.read_text("top_level.txt").splitlines() + if p and p not in namespaces + ]: + path = os.path.join(dist_location, top_level_pkg) + paths_to_remove.add(path) + paths_to_remove.add(f"{path}.py") + paths_to_remove.add(f"{path}.pyc") + paths_to_remove.add(f"{path}.pyo") + + elif dist.installed_by_distutils: + raise LegacyDistutilsInstall(distribution=dist) + + elif dist.installed_as_egg: + # package installed by easy_install + # We cannot match on dist.egg_name because it can slightly vary + # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg + paths_to_remove.add(dist_location) + easy_install_egg = os.path.split(dist_location)[1] + easy_install_pth = os.path.join( + os.path.dirname(dist_location), + "easy-install.pth", + ) + paths_to_remove.add_pth(easy_install_pth, "./" + easy_install_egg) + + elif dist.installed_with_dist_info: + for path in uninstallation_paths(dist): + paths_to_remove.add(path) + + elif develop_egg_link: + # PEP 660 modern editable is handled in the ``.dist-info`` case + # above, so this only covers the setuptools-style editable. + with open(develop_egg_link) as fh: + link_pointer = os.path.normcase(fh.readline().strip()) + normalized_link_pointer = paths_to_remove._normalize_path_cached( + link_pointer + ) + assert os.path.samefile( + normalized_link_pointer, normalized_dist_location + ), ( + f"Egg-link {develop_egg_link} (to {link_pointer}) does not match " + f"installed location of {dist.raw_name} (at {dist_location})" + ) + paths_to_remove.add(develop_egg_link) + easy_install_pth = os.path.join( + os.path.dirname(develop_egg_link), "easy-install.pth" + ) + paths_to_remove.add_pth(easy_install_pth, dist_location) + + else: + logger.debug( + "Not sure how to uninstall: %s - Check: %s", + dist, + dist_location, + ) + + if dist.in_usersite: + bin_dir = get_bin_user() + else: + bin_dir = get_bin_prefix() + + # find distutils scripts= scripts + try: + for script in dist.iter_distutils_script_names(): + paths_to_remove.add(os.path.join(bin_dir, script)) + if WINDOWS: + paths_to_remove.add(os.path.join(bin_dir, f"{script}.bat")) + except (FileNotFoundError, NotADirectoryError): + pass + + # find console_scripts and gui_scripts + def iter_scripts_to_remove( + dist: BaseDistribution, + bin_dir: str, + ) -> Generator[str, None, None]: + for entry_point in dist.iter_entry_points(): + if entry_point.group == "console_scripts": + yield from _script_names(bin_dir, entry_point.name, False) + elif entry_point.group == "gui_scripts": + yield from _script_names(bin_dir, entry_point.name, True) + + for s in iter_scripts_to_remove(dist, bin_dir): + paths_to_remove.add(s) + + return paths_to_remove + + +class UninstallPthEntries: + def __init__(self, pth_file: str) -> None: + self.file = pth_file + self.entries: Set[str] = set() + self._saved_lines: Optional[List[bytes]] = None + + def add(self, entry: str) -> None: + entry = os.path.normcase(entry) + # On Windows, os.path.normcase converts the entry to use + # backslashes. This is correct for entries that describe absolute + # paths outside of site-packages, but all the others use forward + # slashes. + # os.path.splitdrive is used instead of os.path.isabs because isabs + # treats non-absolute paths with drive letter markings like c:foo\bar + # as absolute paths. It also does not recognize UNC paths if they don't + # have more than "\\sever\share". Valid examples: "\\server\share\" or + # "\\server\share\folder". + if WINDOWS and not os.path.splitdrive(entry)[0]: + entry = entry.replace("\\", "/") + self.entries.add(entry) + + def remove(self) -> None: + logger.verbose("Removing pth entries from %s:", self.file) + + # If the file doesn't exist, log a warning and return + if not os.path.isfile(self.file): + logger.warning("Cannot remove entries from nonexistent file %s", self.file) + return + with open(self.file, "rb") as fh: + # windows uses '\r\n' with py3k, but uses '\n' with py2.x + lines = fh.readlines() + self._saved_lines = lines + if any(b"\r\n" in line for line in lines): + endline = "\r\n" + else: + endline = "\n" + # handle missing trailing newline + if lines and not lines[-1].endswith(endline.encode("utf-8")): + lines[-1] = lines[-1] + endline.encode("utf-8") + for entry in self.entries: + try: + logger.verbose("Removing entry: %s", entry) + lines.remove((entry + endline).encode("utf-8")) + except ValueError: + pass + with open(self.file, "wb") as fh: + fh.writelines(lines) + + def rollback(self) -> bool: + if self._saved_lines is None: + logger.error("Cannot roll back changes to %s, none were made", self.file) + return False + logger.debug("Rolling %s back to previous state", self.file) + with open(self.file, "wb") as fh: + fh.writelines(self._saved_lines) + return True diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..915e8bbd40721c5da671b53b47aa07d54aec5028 GIT binary patch literal 201 zcmX@j%ge<81j_4zGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!%5b)dDJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`nFabl)g`G#d5JmtMXAO4Ii)3;`FZ;BK+(*S_;|g7%3B;Zx%nxjIjMF+TT?&zE_Ei@w2F|$|?ttjW@I0Ftg=wQy`n+*-jx<-+c z*VqR0jhDl7L`~Orp|fD@1qc&mNl4qWS<}zh z;7UDH-k(Ny$Wo3=X0M0q3x346j<}lK66t0Xhgp~4Kax^Nl*dRQtV^1hynrsDTE$}V zr@wx$5=+sLUK9n*MrB`!nusEhHE@Gw2bB`CTd8`rJ!twB%sZ7QLA8o&azTvrubHxhn3q`3}8Bwa0KRD}p-j`B%zm(d*! zie=ssalAUV0xo|Q&*PFk6JbUL2~glcZ*%lv5^pdJdu^cEeOW?`Zg+AI-Koww|G<`x+0tjW_MYASIJbCW+OKZ* iCKrzj*L%i|UU{`=tbWzCd9BB;{3zu4!Z(I4tNja~`ZgB; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/base.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/base.py new file mode 100644 index 0000000..42dade1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/base.py @@ -0,0 +1,20 @@ +from typing import Callable, List, Optional + +from pip._internal.req.req_install import InstallRequirement +from pip._internal.req.req_set import RequirementSet + +InstallRequirementProvider = Callable[ + [str, Optional[InstallRequirement]], InstallRequirement +] + + +class BaseResolver: + def resolve( + self, root_reqs: List[InstallRequirement], check_supported_wheels: bool + ) -> RequirementSet: + raise NotImplementedError() + + def get_installation_order( + self, req_set: RequirementSet + ) -> List[InstallRequirement]: + raise NotImplementedError() diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2589256450c8269c1888c4760867662f6e37452f GIT binary patch literal 208 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py new file mode 100644 index 0000000..1dd0d70 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py @@ -0,0 +1,597 @@ +"""Dependency Resolution + +The dependency resolution in pip is performed as follows: + +for top-level requirements: + a. only one spec allowed per project, regardless of conflicts or not. + otherwise a "double requirement" exception is raised + b. they override sub-dependency requirements. +for sub-dependencies + a. "first found, wins" (where the order is breadth first) +""" + +import logging +import sys +from collections import defaultdict +from itertools import chain +from typing import DefaultDict, Iterable, List, Optional, Set, Tuple + +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.requirements import Requirement + +from pip._internal.cache import WheelCache +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, + DistributionNotFound, + HashError, + HashErrors, + InstallationError, + NoneMetadataError, + UnsupportedPythonVersion, +) +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import BaseDistribution +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.req_install import ( + InstallRequirement, + check_invalid_constraint_type, +) +from pip._internal.req.req_set import RequirementSet +from pip._internal.resolution.base import BaseResolver, InstallRequirementProvider +from pip._internal.utils import compatibility_tags +from pip._internal.utils.compatibility_tags import get_supported +from pip._internal.utils.direct_url_helpers import direct_url_from_link +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import normalize_version_info +from pip._internal.utils.packaging import check_requires_python + +logger = logging.getLogger(__name__) + +DiscoveredDependencies = DefaultDict[Optional[str], List[InstallRequirement]] + + +def _check_dist_requires_python( + dist: BaseDistribution, + version_info: Tuple[int, int, int], + ignore_requires_python: bool = False, +) -> None: + """ + Check whether the given Python version is compatible with a distribution's + "Requires-Python" value. + + :param version_info: A 3-tuple of ints representing the Python + major-minor-micro version to check. + :param ignore_requires_python: Whether to ignore the "Requires-Python" + value if the given Python version isn't compatible. + + :raises UnsupportedPythonVersion: When the given Python version isn't + compatible. + """ + # This idiosyncratically converts the SpecifierSet to str and let + # check_requires_python then parse it again into SpecifierSet. But this + # is the legacy resolver so I'm just not going to bother refactoring. + try: + requires_python = str(dist.requires_python) + except FileNotFoundError as e: + raise NoneMetadataError(dist, str(e)) + try: + is_compatible = check_requires_python( + requires_python, + version_info=version_info, + ) + except specifiers.InvalidSpecifier as exc: + logger.warning( + "Package %r has an invalid Requires-Python: %s", dist.raw_name, exc + ) + return + + if is_compatible: + return + + version = ".".join(map(str, version_info)) + if ignore_requires_python: + logger.debug( + "Ignoring failed Requires-Python check for package %r: %s not in %r", + dist.raw_name, + version, + requires_python, + ) + return + + raise UnsupportedPythonVersion( + f"Package {dist.raw_name!r} requires a different Python: " + f"{version} not in {requires_python!r}" + ) + + +class Resolver(BaseResolver): + """Resolves which packages need to be installed/uninstalled to perform \ + the requested operation without breaking the requirements of any package. + """ + + _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} + + def __init__( + self, + preparer: RequirementPreparer, + finder: PackageFinder, + wheel_cache: Optional[WheelCache], + make_install_req: InstallRequirementProvider, + use_user_site: bool, + ignore_dependencies: bool, + ignore_installed: bool, + ignore_requires_python: bool, + force_reinstall: bool, + upgrade_strategy: str, + py_version_info: Optional[Tuple[int, ...]] = None, + ) -> None: + super().__init__() + assert upgrade_strategy in self._allowed_strategies + + if py_version_info is None: + py_version_info = sys.version_info[:3] + else: + py_version_info = normalize_version_info(py_version_info) + + self._py_version_info = py_version_info + + self.preparer = preparer + self.finder = finder + self.wheel_cache = wheel_cache + + self.upgrade_strategy = upgrade_strategy + self.force_reinstall = force_reinstall + self.ignore_dependencies = ignore_dependencies + self.ignore_installed = ignore_installed + self.ignore_requires_python = ignore_requires_python + self.use_user_site = use_user_site + self._make_install_req = make_install_req + + self._discovered_dependencies: DiscoveredDependencies = defaultdict(list) + + def resolve( + self, root_reqs: List[InstallRequirement], check_supported_wheels: bool + ) -> RequirementSet: + """Resolve what operations need to be done + + As a side-effect of this method, the packages (and their dependencies) + are downloaded, unpacked and prepared for installation. This + preparation is done by ``pip.operations.prepare``. + + Once PyPI has static dependency metadata available, it would be + possible to move the preparation to become a step separated from + dependency resolution. + """ + requirement_set = RequirementSet(check_supported_wheels=check_supported_wheels) + for req in root_reqs: + if req.constraint: + check_invalid_constraint_type(req) + self._add_requirement_to_set(requirement_set, req) + + # Actually prepare the files, and collect any exceptions. Most hash + # exceptions cannot be checked ahead of time, because + # _populate_link() needs to be called before we can make decisions + # based on link type. + discovered_reqs: List[InstallRequirement] = [] + hash_errors = HashErrors() + for req in chain(requirement_set.all_requirements, discovered_reqs): + try: + discovered_reqs.extend(self._resolve_one(requirement_set, req)) + except HashError as exc: + exc.req = req + hash_errors.append(exc) + + if hash_errors: + raise hash_errors + + return requirement_set + + def _add_requirement_to_set( + self, + requirement_set: RequirementSet, + install_req: InstallRequirement, + parent_req_name: Optional[str] = None, + extras_requested: Optional[Iterable[str]] = None, + ) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]]: + """Add install_req as a requirement to install. + + :param parent_req_name: The name of the requirement that needed this + added. The name is used because when multiple unnamed requirements + resolve to the same name, we could otherwise end up with dependency + links that point outside the Requirements set. parent_req must + already be added. Note that None implies that this is a user + supplied requirement, vs an inferred one. + :param extras_requested: an iterable of extras used to evaluate the + environment markers. + :return: Additional requirements to scan. That is either [] if + the requirement is not applicable, or [install_req] if the + requirement is applicable and has just been added. + """ + # If the markers do not match, ignore this requirement. + if not install_req.match_markers(extras_requested): + logger.info( + "Ignoring %s: markers '%s' don't match your environment", + install_req.name, + install_req.markers, + ) + return [], None + + # If the wheel is not supported, raise an error. + # Should check this after filtering out based on environment markers to + # allow specifying different wheels based on the environment/OS, in a + # single requirements file. + if install_req.link and install_req.link.is_wheel: + wheel = Wheel(install_req.link.filename) + tags = compatibility_tags.get_supported() + if requirement_set.check_supported_wheels and not wheel.supported(tags): + raise InstallationError( + f"{wheel.filename} is not a supported wheel on this platform." + ) + + # This next bit is really a sanity check. + assert ( + not install_req.user_supplied or parent_req_name is None + ), "a user supplied req shouldn't have a parent" + + # Unnamed requirements are scanned again and the requirement won't be + # added as a dependency until after scanning. + if not install_req.name: + requirement_set.add_unnamed_requirement(install_req) + return [install_req], None + + try: + existing_req: Optional[InstallRequirement] = ( + requirement_set.get_requirement(install_req.name) + ) + except KeyError: + existing_req = None + + has_conflicting_requirement = ( + parent_req_name is None + and existing_req + and not existing_req.constraint + and existing_req.extras == install_req.extras + and existing_req.req + and install_req.req + and existing_req.req.specifier != install_req.req.specifier + ) + if has_conflicting_requirement: + raise InstallationError( + f"Double requirement given: {install_req} " + f"(already in {existing_req}, name={install_req.name!r})" + ) + + # When no existing requirement exists, add the requirement as a + # dependency and it will be scanned again after. + if not existing_req: + requirement_set.add_named_requirement(install_req) + # We'd want to rescan this requirement later + return [install_req], install_req + + # Assume there's no need to scan, and that we've already + # encountered this for scanning. + if install_req.constraint or not existing_req.constraint: + return [], existing_req + + does_not_satisfy_constraint = install_req.link and not ( + existing_req.link and install_req.link.path == existing_req.link.path + ) + if does_not_satisfy_constraint: + raise InstallationError( + f"Could not satisfy constraints for '{install_req.name}': " + "installation from path or url cannot be " + "constrained to a version" + ) + # If we're now installing a constraint, mark the existing + # object for real installation. + existing_req.constraint = False + # If we're now installing a user supplied requirement, + # mark the existing object as such. + if install_req.user_supplied: + existing_req.user_supplied = True + existing_req.extras = tuple( + sorted(set(existing_req.extras) | set(install_req.extras)) + ) + logger.debug( + "Setting %s extras to: %s", + existing_req, + existing_req.extras, + ) + # Return the existing requirement for addition to the parent and + # scanning again. + return [existing_req], existing_req + + def _is_upgrade_allowed(self, req: InstallRequirement) -> bool: + if self.upgrade_strategy == "to-satisfy-only": + return False + elif self.upgrade_strategy == "eager": + return True + else: + assert self.upgrade_strategy == "only-if-needed" + return req.user_supplied or req.constraint + + def _set_req_to_reinstall(self, req: InstallRequirement) -> None: + """ + Set a requirement to be installed. + """ + # Don't uninstall the conflict if doing a user install and the + # conflict is not a user install. + assert req.satisfied_by is not None + if not self.use_user_site or req.satisfied_by.in_usersite: + req.should_reinstall = True + req.satisfied_by = None + + def _check_skip_installed( + self, req_to_install: InstallRequirement + ) -> Optional[str]: + """Check if req_to_install should be skipped. + + This will check if the req is installed, and whether we should upgrade + or reinstall it, taking into account all the relevant user options. + + After calling this req_to_install will only have satisfied_by set to + None if the req_to_install is to be upgraded/reinstalled etc. Any + other value will be a dist recording the current thing installed that + satisfies the requirement. + + Note that for vcs urls and the like we can't assess skipping in this + routine - we simply identify that we need to pull the thing down, + then later on it is pulled down and introspected to assess upgrade/ + reinstalls etc. + + :return: A text reason for why it was skipped, or None. + """ + if self.ignore_installed: + return None + + req_to_install.check_if_exists(self.use_user_site) + if not req_to_install.satisfied_by: + return None + + if self.force_reinstall: + self._set_req_to_reinstall(req_to_install) + return None + + if not self._is_upgrade_allowed(req_to_install): + if self.upgrade_strategy == "only-if-needed": + return "already satisfied, skipping upgrade" + return "already satisfied" + + # Check for the possibility of an upgrade. For link-based + # requirements we have to pull the tree down and inspect to assess + # the version #, so it's handled way down. + if not req_to_install.link: + try: + self.finder.find_requirement(req_to_install, upgrade=True) + except BestVersionAlreadyInstalled: + # Then the best version is installed. + return "already up-to-date" + except DistributionNotFound: + # No distribution found, so we squash the error. It will + # be raised later when we re-try later to do the install. + # Why don't we just raise here? + pass + + self._set_req_to_reinstall(req_to_install) + return None + + def _find_requirement_link(self, req: InstallRequirement) -> Optional[Link]: + upgrade = self._is_upgrade_allowed(req) + best_candidate = self.finder.find_requirement(req, upgrade) + if not best_candidate: + return None + + # Log a warning per PEP 592 if necessary before returning. + link = best_candidate.link + if link.is_yanked: + reason = link.yanked_reason or "" + msg = ( + # Mark this as a unicode string to prevent + # "UnicodeEncodeError: 'ascii' codec can't encode character" + # in Python 2 when the reason contains non-ascii characters. + "The candidate selected for download or install is a " + f"yanked version: {best_candidate}\n" + f"Reason for being yanked: {reason}" + ) + logger.warning(msg) + + return link + + def _populate_link(self, req: InstallRequirement) -> None: + """Ensure that if a link can be found for this, that it is found. + + Note that req.link may still be None - if the requirement is already + installed and not needed to be upgraded based on the return value of + _is_upgrade_allowed(). + + If preparer.require_hashes is True, don't use the wheel cache, because + cached wheels, always built locally, have different hashes than the + files downloaded from the index server and thus throw false hash + mismatches. Furthermore, cached wheels at present have undeterministic + contents due to file modification times. + """ + if req.link is None: + req.link = self._find_requirement_link(req) + + if self.wheel_cache is None or self.preparer.require_hashes: + return + + assert req.link is not None, "_find_requirement_link unexpectedly returned None" + cache_entry = self.wheel_cache.get_cache_entry( + link=req.link, + package_name=req.name, + supported_tags=get_supported(), + ) + if cache_entry is not None: + logger.debug("Using cached wheel link: %s", cache_entry.link) + if req.link is req.original_link and cache_entry.persistent: + req.cached_wheel_source_link = req.link + if cache_entry.origin is not None: + req.download_info = cache_entry.origin + else: + # Legacy cache entry that does not have origin.json. + # download_info may miss the archive_info.hashes field. + req.download_info = direct_url_from_link( + req.link, link_is_in_wheel_cache=cache_entry.persistent + ) + req.link = cache_entry.link + + def _get_dist_for(self, req: InstallRequirement) -> BaseDistribution: + """Takes a InstallRequirement and returns a single AbstractDist \ + representing a prepared variant of the same. + """ + if req.editable: + return self.preparer.prepare_editable_requirement(req) + + # satisfied_by is only evaluated by calling _check_skip_installed, + # so it must be None here. + assert req.satisfied_by is None + skip_reason = self._check_skip_installed(req) + + if req.satisfied_by: + return self.preparer.prepare_installed_requirement(req, skip_reason) + + # We eagerly populate the link, since that's our "legacy" behavior. + self._populate_link(req) + dist = self.preparer.prepare_linked_requirement(req) + + # NOTE + # The following portion is for determining if a certain package is + # going to be re-installed/upgraded or not and reporting to the user. + # This should probably get cleaned up in a future refactor. + + # req.req is only avail after unpack for URL + # pkgs repeat check_if_exists to uninstall-on-upgrade + # (#14) + if not self.ignore_installed: + req.check_if_exists(self.use_user_site) + + if req.satisfied_by: + should_modify = ( + self.upgrade_strategy != "to-satisfy-only" + or self.force_reinstall + or self.ignore_installed + or req.link.scheme == "file" + ) + if should_modify: + self._set_req_to_reinstall(req) + else: + logger.info( + "Requirement already satisfied (use --upgrade to upgrade): %s", + req, + ) + return dist + + def _resolve_one( + self, + requirement_set: RequirementSet, + req_to_install: InstallRequirement, + ) -> List[InstallRequirement]: + """Prepare a single requirements file. + + :return: A list of additional InstallRequirements to also install. + """ + # Tell user what we are doing for this requirement: + # obtain (editable), skipping, processing (local url), collecting + # (remote url or package name) + if req_to_install.constraint or req_to_install.prepared: + return [] + + req_to_install.prepared = True + + # Parse and return dependencies + dist = self._get_dist_for(req_to_install) + # This will raise UnsupportedPythonVersion if the given Python + # version isn't compatible with the distribution's Requires-Python. + _check_dist_requires_python( + dist, + version_info=self._py_version_info, + ignore_requires_python=self.ignore_requires_python, + ) + + more_reqs: List[InstallRequirement] = [] + + def add_req(subreq: Requirement, extras_requested: Iterable[str]) -> None: + # This idiosyncratically converts the Requirement to str and let + # make_install_req then parse it again into Requirement. But this is + # the legacy resolver so I'm just not going to bother refactoring. + sub_install_req = self._make_install_req(str(subreq), req_to_install) + parent_req_name = req_to_install.name + to_scan_again, add_to_parent = self._add_requirement_to_set( + requirement_set, + sub_install_req, + parent_req_name=parent_req_name, + extras_requested=extras_requested, + ) + if parent_req_name and add_to_parent: + self._discovered_dependencies[parent_req_name].append(add_to_parent) + more_reqs.extend(to_scan_again) + + with indent_log(): + # We add req_to_install before its dependencies, so that we + # can refer to it when adding dependencies. + assert req_to_install.name is not None + if not requirement_set.has_requirement(req_to_install.name): + # 'unnamed' requirements will get added here + # 'unnamed' requirements can only come from being directly + # provided by the user. + assert req_to_install.user_supplied + self._add_requirement_to_set( + requirement_set, req_to_install, parent_req_name=None + ) + + if not self.ignore_dependencies: + if req_to_install.extras: + logger.debug( + "Installing extra requirements: %r", + ",".join(req_to_install.extras), + ) + missing_requested = sorted( + set(req_to_install.extras) - set(dist.iter_provided_extras()) + ) + for missing in missing_requested: + logger.warning( + "%s %s does not provide the extra '%s'", + dist.raw_name, + dist.version, + missing, + ) + + available_requested = sorted( + set(dist.iter_provided_extras()) & set(req_to_install.extras) + ) + for subreq in dist.iter_dependencies(available_requested): + add_req(subreq, extras_requested=available_requested) + + return more_reqs + + def get_installation_order( + self, req_set: RequirementSet + ) -> List[InstallRequirement]: + """Create the installation order. + + The installation order is topological - requirements are installed + before the requiring thing. We break cycles at an arbitrary point, + and make no other guarantees. + """ + # The current implementation, which we may change at any point + # installs the user specified things in the order given, except when + # dependencies must come earlier to achieve topological order. + order = [] + ordered_reqs: Set[InstallRequirement] = set() + + def schedule(req: InstallRequirement) -> None: + if req.satisfied_by or req in ordered_reqs: + return + if req.constraint: + return + ordered_reqs.add(req) + for dep in self._discovered_dependencies[req.name]: + schedule(dep) + order.append(req) + + for install_req in req_set.requirements.values(): + schedule(install_req) + return order diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36241108697b3cd20870dd720cf3122b73e83a75 GIT binary patch literal 212 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..903193a7c41fb07d56260f06e0f9429e35a6eceb GIT binary patch literal 29412 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℘ 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 Nn2-EKz>Q(6{{tBC5;On+ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95bde07369473a8371bfcca1156c33f9eed983c0 GIT binary patch literal 32490 zcmc(|33MA*njTtMiH!tEfF!^b+zGCdNNvTNl)^Z+%dYw?1r$7=y-$DQJqAgXTy{uq0v$S|ZkjDJ^L;RH$)nPjm&Qe`y)-krbu(JnSEQsEs@q>YosmM7HJQ* zM>>KXkp%aAY(%%EG+iBax%Qqmg65 zW0A*#k446UW0A*$k4KINk4K&eKEcxX!cRs{1W!ax22Zl@n($MRr-M&No(Vn^`AYCB zk!OR?MuNehjuVWcUC$lj_}bSvzD_86-=K_p@T+=G(4W1fqC@^IJpaBfm*#hnrh>26 zzQ+Z#uu&MF()*Ag_yU950Jx2ULxVfPLj4GBdLNiYPw>=?F3|i}xdYQ3)3frSjI9M6GRrJ_+n8pV>}j;VwsZ1 zCeED;O`p!##wH>HfAah}h^d7c!cX!tx;ax`)-DoG(U8(D0_6O(6z zgVQl_CS!Z%j39(rK%gY!Ie^xRp;Ii+STr^gJwMH7%15WA81))KIw*?hmg-!oxfp>z zJ~8>?#AzYpc}$2+@Ds6#(do(Pv;=TyTgI6WW$n&*pPH7=pF0;7W5_xaI}@E&>+dRv zVRb`8N^{UhLesn;q6Mz~6OvF^*G%@OUK;1c=(%y>QcRqXG7W_hQ(`nS9tOnmiD`ZugZC2ZgYjfN zQ~)?rk3OD!aXh4q^f>hfpoOMm<1t_Z>QnP@Cg9P95H%5PrUq$!gaGs53F(X=!RMqX z6kLEhUh(|&G!S$g<0XjWXnyScL>T?>S2Vc-hKzL>)eT`_1Ps4cm5jZh#u$I!zOX1v z@H4rZ34A_RDRp`Nv-}_*iqTxj2RRS2?#c(0Qpe{%t8-;Z%7Eu1$|t1pQ-D4`sn!u) z>SVa5C6cI*dEt^4FgiUI4VW_SgO|>QLzAIcK|?aWwIvlsd9*oJ7}}(TJ`(~mo{uR_ zDNI5biwPi2g{aj9F_T1S)F(&oxYcHaT;~LimbRe&DNZm5MqalQp@IoMJ^5w~0b`~V zqcMdR#D*u%OG3sj=EpT-Ce)mcjRnjZ%Q&0x}#@J+)5ITU+_qbKK+^@yqq36zt(bM8YBm!)C?qU>FD-sdJNr4a*WktoA z=T2cR3)B2__`dMmvCygKq)<%gJ*UiY>A7>EbNxsSS_#_MFKRSK@m>(Zp;P@+6O#n0 z@7#=d5Ct>mad@OMIDeB%SN0_>eQB3(#o`kmQxjx#!^Jyu1S!^cCanpADc7ZDp+vAK z>jc7B=VI+B5v*F6fpxeM7~>m`hQq=n2+xzzXd&828An0qOBs89%1W6s435YqodA-? zj|FVvVXF5iIY-E`lCzndqvR07lQCe*i-XLE4ik@21Z(aX`JPanAUskR9P~^@)xyhi zMN87yk}j`Ym|PrMh|1;dNn?B3<6U$wPA+<{jjb4)6)*&0O_x<6fSy$|Ffrd{R*v7t z>jeW(SZG8SnW%fH3wg6(;n8`#1^=!1Z$pe#u<>@K>sT5GubcAlrLUQScEQ0rsH^$1 z*NpG8qOjnW@=l?Qr&LDX^_ns0(0;0c~73t#z~IatY8 z2~`DYss%UTS0mO7I9>)f4}oHRfZ}6NYT&EM!7~fhvBP z@%2J|u4WBF1K5j3-jAMW68wTK2fs;!-;5m1e2dT|w6M5*?HodDE|r;YMXENw4eU(2 z(9SEZQe!QA2Vy%|Y^TsERH(3&9_IrrOij(09|nc$)FlLj7NPpIUPX8GmRh$mz8i46 z_#X69FG7`Gr&_U^PMP^W#CP-k0#fAK)r%3^fY3gEqfiZ4{rKL5?+w71{d@!JpC7ei zFfIH5uwo-pHXye-SCWw*1dL5=6llEEnwW(F*6(J1GvWtxWtxR57HZ_TAapaoRjB8; zXr+n&27xMPiAt7-0d=lw#hGv$;=1Fyowx60H=4 zT!xG*bb2}}Y5)X2QA>LJjy*r7&*RgfFue zXU11PzXe|wH7>;Ai)b5r*q2sc_GMoa=UDSqs(!`lRi8>U0M)66&6Y?zVomCon⪻ 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

        Z*m(=mKM6gVz@mZyAd!o3I3p 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b70517539f510177b68c7051272c22e9cd525a75 GIT binary patch literal 10527 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

        b= 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59a70a2d1f70ac7922b3dcdbc1a7d8ab02bcf458 GIT binary patch literal 5044 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 E0z6d5;Q#;t literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc808f1e2baff967f96ce09c29b0a045759fd217 GIT binary patch literal 15360 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98274d707f30941ad5c08253c1ed1bd3c2b59838 GIT binary patch literal 12318 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 a4OSh str: + if not extras: + return project + extras_expr = ",".join(sorted(extras)) + return f"{project}[{extras_expr}]" + + +@dataclass(frozen=True) +class Constraint: + specifier: SpecifierSet + hashes: Hashes + links: FrozenSet[Link] + + @classmethod + def empty(cls) -> "Constraint": + return Constraint(SpecifierSet(), Hashes(), frozenset()) + + @classmethod + def from_ireq(cls, ireq: InstallRequirement) -> "Constraint": + links = frozenset([ireq.link]) if ireq.link else frozenset() + return Constraint(ireq.specifier, ireq.hashes(trust_internet=False), links) + + def __bool__(self) -> bool: + return bool(self.specifier) or bool(self.hashes) or bool(self.links) + + def __and__(self, other: InstallRequirement) -> "Constraint": + if not isinstance(other, InstallRequirement): + return NotImplemented + specifier = self.specifier & other.specifier + hashes = self.hashes & other.hashes(trust_internet=False) + links = self.links + if other.link: + links = links.union([other.link]) + return Constraint(specifier, hashes, links) + + def is_satisfied_by(self, candidate: "Candidate") -> bool: + # Reject if there are any mismatched URL constraints on this package. + if self.links and not all(_match_link(link, candidate) for link in self.links): + return False + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + return self.specifier.contains(candidate.version, prereleases=True) + + +class Requirement: + @property + def project_name(self) -> NormalizedName: + """The "project name" of a requirement. + + This is different from ``name`` if this requirement contains extras, + in which case ``name`` would contain the ``[...]`` part, while this + refers to the name of the project. + """ + raise NotImplementedError("Subclass should override") + + @property + def name(self) -> str: + """The name identifying this requirement in the resolver. + + This is different from ``project_name`` if this requirement contains + extras, where ``project_name`` would not contain the ``[...]`` part. + """ + raise NotImplementedError("Subclass should override") + + def is_satisfied_by(self, candidate: "Candidate") -> bool: + return False + + def get_candidate_lookup(self) -> CandidateLookup: + raise NotImplementedError("Subclass should override") + + def format_for_error(self) -> str: + raise NotImplementedError("Subclass should override") + + +def _match_link(link: Link, candidate: "Candidate") -> bool: + if candidate.source_link: + return links_equivalent(link, candidate.source_link) + return False + + +class Candidate: + @property + def project_name(self) -> NormalizedName: + """The "project name" of the candidate. + + This is different from ``name`` if this candidate contains extras, + in which case ``name`` would contain the ``[...]`` part, while this + refers to the name of the project. + """ + raise NotImplementedError("Override in subclass") + + @property + def name(self) -> str: + """The name identifying this candidate in the resolver. + + This is different from ``project_name`` if this candidate contains + extras, where ``project_name`` would not contain the ``[...]`` part. + """ + raise NotImplementedError("Override in subclass") + + @property + def version(self) -> Version: + raise NotImplementedError("Override in subclass") + + @property + def is_installed(self) -> bool: + raise NotImplementedError("Override in subclass") + + @property + def is_editable(self) -> bool: + raise NotImplementedError("Override in subclass") + + @property + def source_link(self) -> Optional[Link]: + raise NotImplementedError("Override in subclass") + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + raise NotImplementedError("Override in subclass") + + def get_install_requirement(self) -> Optional[InstallRequirement]: + raise NotImplementedError("Override in subclass") + + def format_for_error(self) -> str: + raise NotImplementedError("Subclass should override") diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py new file mode 100644 index 0000000..6617644 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py @@ -0,0 +1,574 @@ +import logging +import sys +from typing import TYPE_CHECKING, Any, FrozenSet, Iterable, Optional, Tuple, Union, cast + +from pip._vendor.packaging.requirements import InvalidRequirement +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import Version + +from pip._internal.exceptions import ( + HashError, + InstallationSubprocessError, + InvalidInstalledPackage, + MetadataInconsistent, + MetadataInvalid, +) +from pip._internal.metadata import BaseDistribution +from pip._internal.models.link import Link, links_equivalent +from pip._internal.models.wheel import Wheel +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, +) +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.direct_url_helpers import direct_url_from_link +from pip._internal.utils.misc import normalize_version_info + +from .base import Candidate, Requirement, format_name + +if TYPE_CHECKING: + from .factory import Factory + +logger = logging.getLogger(__name__) + +BaseCandidate = Union[ + "AlreadyInstalledCandidate", + "EditableCandidate", + "LinkCandidate", +] + +# Avoid conflicting with the PyPI package "Python". +REQUIRES_PYTHON_IDENTIFIER = cast(NormalizedName, "") + + +def as_base_candidate(candidate: Candidate) -> Optional[BaseCandidate]: + """The runtime version of BaseCandidate.""" + base_candidate_classes = ( + AlreadyInstalledCandidate, + EditableCandidate, + LinkCandidate, + ) + if isinstance(candidate, base_candidate_classes): + return candidate + return None + + +def make_install_req_from_link( + link: Link, template: InstallRequirement +) -> InstallRequirement: + assert not template.editable, "template is editable" + if template.req: + line = str(template.req) + else: + line = link.url + ireq = install_req_from_line( + line, + user_supplied=template.user_supplied, + comes_from=template.comes_from, + use_pep517=template.use_pep517, + isolated=template.isolated, + constraint=template.constraint, + global_options=template.global_options, + hash_options=template.hash_options, + config_settings=template.config_settings, + ) + ireq.original_link = template.original_link + ireq.link = link + ireq.extras = template.extras + return ireq + + +def make_install_req_from_editable( + link: Link, template: InstallRequirement +) -> InstallRequirement: + assert template.editable, "template not editable" + ireq = install_req_from_editable( + link.url, + user_supplied=template.user_supplied, + comes_from=template.comes_from, + use_pep517=template.use_pep517, + isolated=template.isolated, + constraint=template.constraint, + permit_editable_wheels=template.permit_editable_wheels, + global_options=template.global_options, + hash_options=template.hash_options, + config_settings=template.config_settings, + ) + ireq.extras = template.extras + return ireq + + +def _make_install_req_from_dist( + dist: BaseDistribution, template: InstallRequirement +) -> InstallRequirement: + if template.req: + line = str(template.req) + elif template.link: + line = f"{dist.canonical_name} @ {template.link.url}" + else: + line = f"{dist.canonical_name}=={dist.version}" + ireq = install_req_from_line( + line, + user_supplied=template.user_supplied, + comes_from=template.comes_from, + use_pep517=template.use_pep517, + isolated=template.isolated, + constraint=template.constraint, + global_options=template.global_options, + hash_options=template.hash_options, + config_settings=template.config_settings, + ) + ireq.satisfied_by = dist + return ireq + + +class _InstallRequirementBackedCandidate(Candidate): + """A candidate backed by an ``InstallRequirement``. + + This represents a package request with the target not being already + in the environment, and needs to be fetched and installed. The backing + ``InstallRequirement`` is responsible for most of the leg work; this + class exposes appropriate information to the resolver. + + :param link: The link passed to the ``InstallRequirement``. The backing + ``InstallRequirement`` will use this link to fetch the distribution. + :param source_link: The link this candidate "originates" from. This is + different from ``link`` when the link is found in the wheel cache. + ``link`` would point to the wheel cache, while this points to the + found remote link (e.g. from pypi.org). + """ + + dist: BaseDistribution + is_installed = False + + def __init__( + self, + link: Link, + source_link: Link, + ireq: InstallRequirement, + factory: "Factory", + name: Optional[NormalizedName] = None, + version: Optional[Version] = None, + ) -> None: + self._link = link + self._source_link = source_link + self._factory = factory + self._ireq = ireq + self._name = name + self._version = version + self.dist = self._prepare() + self._hash: Optional[int] = None + + def __str__(self) -> str: + return f"{self.name} {self.version}" + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({str(self._link)!r})" + + def __hash__(self) -> int: + if self._hash is not None: + return self._hash + + self._hash = hash((self.__class__, self._link)) + return self._hash + + def __eq__(self, other: Any) -> bool: + if isinstance(other, self.__class__): + return links_equivalent(self._link, other._link) + return False + + @property + def source_link(self) -> Optional[Link]: + return self._source_link + + @property + def project_name(self) -> NormalizedName: + """The normalised name of the project the candidate refers to""" + if self._name is None: + self._name = self.dist.canonical_name + return self._name + + @property + def name(self) -> str: + return self.project_name + + @property + def version(self) -> Version: + if self._version is None: + self._version = self.dist.version + return self._version + + def format_for_error(self) -> str: + return ( + f"{self.name} {self.version} " + f"(from {self._link.file_path if self._link.is_file else self._link})" + ) + + def _prepare_distribution(self) -> BaseDistribution: + raise NotImplementedError("Override in subclass") + + def _check_metadata_consistency(self, dist: BaseDistribution) -> None: + """Check for consistency of project name and version of dist.""" + if self._name is not None and self._name != dist.canonical_name: + raise MetadataInconsistent( + self._ireq, + "name", + self._name, + dist.canonical_name, + ) + if self._version is not None and self._version != dist.version: + raise MetadataInconsistent( + self._ireq, + "version", + str(self._version), + str(dist.version), + ) + # check dependencies are valid + # TODO performance: this means we iterate the dependencies at least twice, + # we may want to cache parsed Requires-Dist + try: + list(dist.iter_dependencies(list(dist.iter_provided_extras()))) + except InvalidRequirement as e: + raise MetadataInvalid(self._ireq, str(e)) + + def _prepare(self) -> BaseDistribution: + try: + dist = self._prepare_distribution() + except HashError as e: + # Provide HashError the underlying ireq that caused it. This + # provides context for the resulting error message to show the + # offending line to the user. + e.req = self._ireq + raise + except InstallationSubprocessError as exc: + # The output has been presented already, so don't duplicate it. + exc.context = "See above for output." + raise + + self._check_metadata_consistency(dist) + return dist + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + requires = self.dist.iter_dependencies() if with_requires else () + for r in requires: + yield from self._factory.make_requirements_from_spec(str(r), self._ireq) + yield self._factory.make_requires_python_requirement(self.dist.requires_python) + + def get_install_requirement(self) -> Optional[InstallRequirement]: + return self._ireq + + +class LinkCandidate(_InstallRequirementBackedCandidate): + is_editable = False + + def __init__( + self, + link: Link, + template: InstallRequirement, + factory: "Factory", + name: Optional[NormalizedName] = None, + version: Optional[Version] = None, + ) -> None: + source_link = link + cache_entry = factory.get_wheel_cache_entry(source_link, name) + if cache_entry is not None: + logger.debug("Using cached wheel link: %s", cache_entry.link) + link = cache_entry.link + ireq = make_install_req_from_link(link, template) + assert ireq.link == link + if ireq.link.is_wheel and not ireq.link.is_file: + wheel = Wheel(ireq.link.filename) + wheel_name = canonicalize_name(wheel.name) + assert name == wheel_name, f"{name!r} != {wheel_name!r} for wheel" + # Version may not be present for PEP 508 direct URLs + if version is not None: + wheel_version = Version(wheel.version) + assert ( + version == wheel_version + ), f"{version!r} != {wheel_version!r} for wheel {name}" + + if cache_entry is not None: + assert ireq.link.is_wheel + assert ireq.link.is_file + if cache_entry.persistent and template.link is template.original_link: + ireq.cached_wheel_source_link = source_link + if cache_entry.origin is not None: + ireq.download_info = cache_entry.origin + else: + # Legacy cache entry that does not have origin.json. + # download_info may miss the archive_info.hashes field. + ireq.download_info = direct_url_from_link( + source_link, link_is_in_wheel_cache=cache_entry.persistent + ) + + super().__init__( + link=link, + source_link=source_link, + ireq=ireq, + factory=factory, + name=name, + version=version, + ) + + def _prepare_distribution(self) -> BaseDistribution: + preparer = self._factory.preparer + return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True) + + +class EditableCandidate(_InstallRequirementBackedCandidate): + is_editable = True + + def __init__( + self, + link: Link, + template: InstallRequirement, + factory: "Factory", + name: Optional[NormalizedName] = None, + version: Optional[Version] = None, + ) -> None: + super().__init__( + link=link, + source_link=link, + ireq=make_install_req_from_editable(link, template), + factory=factory, + name=name, + version=version, + ) + + def _prepare_distribution(self) -> BaseDistribution: + return self._factory.preparer.prepare_editable_requirement(self._ireq) + + +class AlreadyInstalledCandidate(Candidate): + is_installed = True + source_link = None + + def __init__( + self, + dist: BaseDistribution, + template: InstallRequirement, + factory: "Factory", + ) -> None: + self.dist = dist + self._ireq = _make_install_req_from_dist(dist, template) + self._factory = factory + self._version = None + + # This is just logging some messages, so we can do it eagerly. + # The returned dist would be exactly the same as self.dist because we + # set satisfied_by in _make_install_req_from_dist. + # TODO: Supply reason based on force_reinstall and upgrade_strategy. + skip_reason = "already satisfied" + factory.preparer.prepare_installed_requirement(self._ireq, skip_reason) + + def __str__(self) -> str: + return str(self.dist) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.dist!r})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AlreadyInstalledCandidate): + return NotImplemented + return self.name == other.name and self.version == other.version + + def __hash__(self) -> int: + return hash((self.name, self.version)) + + @property + def project_name(self) -> NormalizedName: + return self.dist.canonical_name + + @property + def name(self) -> str: + return self.project_name + + @property + def version(self) -> Version: + if self._version is None: + self._version = self.dist.version + return self._version + + @property + def is_editable(self) -> bool: + return self.dist.editable + + def format_for_error(self) -> str: + return f"{self.name} {self.version} (Installed)" + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + if not with_requires: + return + + try: + for r in self.dist.iter_dependencies(): + yield from self._factory.make_requirements_from_spec(str(r), self._ireq) + except InvalidRequirement as exc: + raise InvalidInstalledPackage(dist=self.dist, invalid_exc=exc) from None + + def get_install_requirement(self) -> Optional[InstallRequirement]: + return None + + +class ExtrasCandidate(Candidate): + """A candidate that has 'extras', indicating additional dependencies. + + Requirements can be for a project with dependencies, something like + foo[extra]. The extras don't affect the project/version being installed + directly, but indicate that we need additional dependencies. We model that + by having an artificial ExtrasCandidate that wraps the "base" candidate. + + The ExtrasCandidate differs from the base in the following ways: + + 1. It has a unique name, of the form foo[extra]. This causes the resolver + to treat it as a separate node in the dependency graph. + 2. When we're getting the candidate's dependencies, + a) We specify that we want the extra dependencies as well. + b) We add a dependency on the base candidate. + See below for why this is needed. + 3. We return None for the underlying InstallRequirement, as the base + candidate will provide it, and we don't want to end up with duplicates. + + The dependency on the base candidate is needed so that the resolver can't + decide that it should recommend foo[extra1] version 1.0 and foo[extra2] + version 2.0. Having those candidates depend on foo=1.0 and foo=2.0 + respectively forces the resolver to recognise that this is a conflict. + """ + + def __init__( + self, + base: BaseCandidate, + extras: FrozenSet[str], + *, + comes_from: Optional[InstallRequirement] = None, + ) -> None: + """ + :param comes_from: the InstallRequirement that led to this candidate if it + differs from the base's InstallRequirement. This will often be the + case in the sense that this candidate's requirement has the extras + while the base's does not. Unlike the InstallRequirement backed + candidates, this requirement is used solely for reporting purposes, + it does not do any leg work. + """ + self.base = base + self.extras = frozenset(canonicalize_name(e) for e in extras) + self._comes_from = comes_from if comes_from is not None else self.base._ireq + + def __str__(self) -> str: + name, rest = str(self.base).split(" ", 1) + return "{}[{}] {}".format(name, ",".join(self.extras), rest) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(base={self.base!r}, extras={self.extras!r})" + + def __hash__(self) -> int: + return hash((self.base, self.extras)) + + def __eq__(self, other: Any) -> bool: + if isinstance(other, self.__class__): + return self.base == other.base and self.extras == other.extras + return False + + @property + def project_name(self) -> NormalizedName: + return self.base.project_name + + @property + def name(self) -> str: + """The normalised name of the project the candidate refers to""" + return format_name(self.base.project_name, self.extras) + + @property + def version(self) -> Version: + return self.base.version + + def format_for_error(self) -> str: + return "{} [{}]".format( + self.base.format_for_error(), ", ".join(sorted(self.extras)) + ) + + @property + def is_installed(self) -> bool: + return self.base.is_installed + + @property + def is_editable(self) -> bool: + return self.base.is_editable + + @property + def source_link(self) -> Optional[Link]: + return self.base.source_link + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + factory = self.base._factory + + # Add a dependency on the exact base + # (See note 2b in the class docstring) + yield factory.make_requirement_from_candidate(self.base) + if not with_requires: + return + + # The user may have specified extras that the candidate doesn't + # support. We ignore any unsupported extras here. + valid_extras = self.extras.intersection(self.base.dist.iter_provided_extras()) + invalid_extras = self.extras.difference(self.base.dist.iter_provided_extras()) + for extra in sorted(invalid_extras): + logger.warning( + "%s %s does not provide the extra '%s'", + self.base.name, + self.version, + extra, + ) + + for r in self.base.dist.iter_dependencies(valid_extras): + yield from factory.make_requirements_from_spec( + str(r), + self._comes_from, + valid_extras, + ) + + def get_install_requirement(self) -> Optional[InstallRequirement]: + # We don't return anything here, because we always + # depend on the base candidate, and we'll get the + # install requirement from that. + return None + + +class RequiresPythonCandidate(Candidate): + is_installed = False + source_link = None + + def __init__(self, py_version_info: Optional[Tuple[int, ...]]) -> None: + if py_version_info is not None: + version_info = normalize_version_info(py_version_info) + else: + version_info = sys.version_info[:3] + self._version = Version(".".join(str(c) for c in version_info)) + + # We don't need to implement __eq__() and __ne__() since there is always + # only one RequiresPythonCandidate in a resolution, i.e. the host Python. + # The built-in object.__eq__() and object.__ne__() do exactly what we want. + + def __str__(self) -> str: + return f"Python {self._version}" + + @property + def project_name(self) -> NormalizedName: + return REQUIRES_PYTHON_IDENTIFIER + + @property + def name(self) -> str: + return REQUIRES_PYTHON_IDENTIFIER + + @property + def version(self) -> Version: + return self._version + + def format_for_error(self) -> str: + return f"Python {self.version}" + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + return () + + def get_install_requirement(self) -> Optional[InstallRequirement]: + return None diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py new file mode 100644 index 0000000..6c273eb --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py @@ -0,0 +1,823 @@ +import contextlib +import functools +import logging +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + FrozenSet, + Iterable, + Iterator, + List, + Mapping, + NamedTuple, + Optional, + Protocol, + Sequence, + Set, + Tuple, + TypeVar, + cast, +) + +from pip._vendor.packaging.requirements import InvalidRequirement +from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import InvalidVersion, Version +from pip._vendor.resolvelib import ResolutionImpossible + +from pip._internal.cache import CacheEntry, WheelCache +from pip._internal.exceptions import ( + DistributionNotFound, + InstallationError, + InvalidInstalledPackage, + MetadataInconsistent, + MetadataInvalid, + UnsupportedPythonVersion, + UnsupportedWheel, +) +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import BaseDistribution, get_default_environment +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.constructors import ( + install_req_drop_extras, + install_req_from_link_and_ireq, +) +from pip._internal.req.req_install import ( + InstallRequirement, + check_invalid_constraint_type, +) +from pip._internal.resolution.base import InstallRequirementProvider +from pip._internal.utils.compatibility_tags import get_supported +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.packaging import get_requirement +from pip._internal.utils.virtualenv import running_under_virtualenv + +from .base import Candidate, Constraint, Requirement +from .candidates import ( + AlreadyInstalledCandidate, + BaseCandidate, + EditableCandidate, + ExtrasCandidate, + LinkCandidate, + RequiresPythonCandidate, + as_base_candidate, +) +from .found_candidates import FoundCandidates, IndexCandidateInfo +from .requirements import ( + ExplicitRequirement, + RequiresPythonRequirement, + SpecifierRequirement, + SpecifierWithoutExtrasRequirement, + UnsatisfiableRequirement, +) + +if TYPE_CHECKING: + + class ConflictCause(Protocol): + requirement: RequiresPythonRequirement + parent: Candidate + + +logger = logging.getLogger(__name__) + +C = TypeVar("C") +Cache = Dict[Link, C] + + +class CollectedRootRequirements(NamedTuple): + requirements: List[Requirement] + constraints: Dict[str, Constraint] + user_requested: Dict[str, int] + + +class Factory: + def __init__( + self, + finder: PackageFinder, + preparer: RequirementPreparer, + make_install_req: InstallRequirementProvider, + wheel_cache: Optional[WheelCache], + use_user_site: bool, + force_reinstall: bool, + ignore_installed: bool, + ignore_requires_python: bool, + py_version_info: Optional[Tuple[int, ...]] = None, + ) -> None: + self._finder = finder + self.preparer = preparer + self._wheel_cache = wheel_cache + self._python_candidate = RequiresPythonCandidate(py_version_info) + self._make_install_req_from_spec = make_install_req + self._use_user_site = use_user_site + self._force_reinstall = force_reinstall + self._ignore_requires_python = ignore_requires_python + + self._build_failures: Cache[InstallationError] = {} + self._link_candidate_cache: Cache[LinkCandidate] = {} + self._editable_candidate_cache: Cache[EditableCandidate] = {} + self._installed_candidate_cache: Dict[str, AlreadyInstalledCandidate] = {} + self._extras_candidate_cache: Dict[ + Tuple[int, FrozenSet[NormalizedName]], ExtrasCandidate + ] = {} + self._supported_tags_cache = get_supported() + + if not ignore_installed: + env = get_default_environment() + self._installed_dists = { + dist.canonical_name: dist + for dist in env.iter_installed_distributions(local_only=False) + } + else: + self._installed_dists = {} + + @property + def force_reinstall(self) -> bool: + return self._force_reinstall + + def _fail_if_link_is_unsupported_wheel(self, link: Link) -> None: + if not link.is_wheel: + return + wheel = Wheel(link.filename) + if wheel.supported(self._finder.target_python.get_unsorted_tags()): + return + msg = f"{link.filename} is not a supported wheel on this platform." + raise UnsupportedWheel(msg) + + def _make_extras_candidate( + self, + base: BaseCandidate, + extras: FrozenSet[str], + *, + comes_from: Optional[InstallRequirement] = None, + ) -> ExtrasCandidate: + cache_key = (id(base), frozenset(canonicalize_name(e) for e in extras)) + try: + candidate = self._extras_candidate_cache[cache_key] + except KeyError: + candidate = ExtrasCandidate(base, extras, comes_from=comes_from) + self._extras_candidate_cache[cache_key] = candidate + return candidate + + def _make_candidate_from_dist( + self, + dist: BaseDistribution, + extras: FrozenSet[str], + template: InstallRequirement, + ) -> Candidate: + try: + base = self._installed_candidate_cache[dist.canonical_name] + except KeyError: + base = AlreadyInstalledCandidate(dist, template, factory=self) + self._installed_candidate_cache[dist.canonical_name] = base + if not extras: + return base + return self._make_extras_candidate(base, extras, comes_from=template) + + def _make_candidate_from_link( + self, + link: Link, + extras: FrozenSet[str], + template: InstallRequirement, + name: Optional[NormalizedName], + version: Optional[Version], + ) -> Optional[Candidate]: + base: Optional[BaseCandidate] = self._make_base_candidate_from_link( + link, template, name, version + ) + if not extras or base is None: + return base + return self._make_extras_candidate(base, extras, comes_from=template) + + def _make_base_candidate_from_link( + self, + link: Link, + template: InstallRequirement, + name: Optional[NormalizedName], + version: Optional[Version], + ) -> Optional[BaseCandidate]: + # TODO: Check already installed candidate, and use it if the link and + # editable flag match. + + if link in self._build_failures: + # We already tried this candidate before, and it does not build. + # Don't bother trying again. + return None + + if template.editable: + if link not in self._editable_candidate_cache: + try: + self._editable_candidate_cache[link] = EditableCandidate( + link, + template, + factory=self, + name=name, + version=version, + ) + except (MetadataInconsistent, MetadataInvalid) as e: + logger.info( + "Discarding [blue underline]%s[/]: [yellow]%s[reset]", + link, + e, + extra={"markup": True}, + ) + self._build_failures[link] = e + return None + + return self._editable_candidate_cache[link] + else: + if link not in self._link_candidate_cache: + try: + self._link_candidate_cache[link] = LinkCandidate( + link, + template, + factory=self, + name=name, + version=version, + ) + except MetadataInconsistent as e: + logger.info( + "Discarding [blue underline]%s[/]: [yellow]%s[reset]", + link, + e, + extra={"markup": True}, + ) + self._build_failures[link] = e + return None + return self._link_candidate_cache[link] + + def _iter_found_candidates( + self, + ireqs: Sequence[InstallRequirement], + specifier: SpecifierSet, + hashes: Hashes, + prefers_installed: bool, + incompatible_ids: Set[int], + ) -> Iterable[Candidate]: + if not ireqs: + return () + + # The InstallRequirement implementation requires us to give it a + # "template". Here we just choose the first requirement to represent + # all of them. + # Hopefully the Project model can correct this mismatch in the future. + template = ireqs[0] + assert template.req, "Candidates found on index must be PEP 508" + name = canonicalize_name(template.req.name) + + extras: FrozenSet[str] = frozenset() + for ireq in ireqs: + assert ireq.req, "Candidates found on index must be PEP 508" + specifier &= ireq.req.specifier + hashes &= ireq.hashes(trust_internet=False) + extras |= frozenset(ireq.extras) + + def _get_installed_candidate() -> Optional[Candidate]: + """Get the candidate for the currently-installed version.""" + # If --force-reinstall is set, we want the version from the index + # instead, so we "pretend" there is nothing installed. + if self._force_reinstall: + return None + try: + installed_dist = self._installed_dists[name] + except KeyError: + return None + + try: + # Don't use the installed distribution if its version + # does not fit the current dependency graph. + if not specifier.contains(installed_dist.version, prereleases=True): + return None + except InvalidVersion as e: + raise InvalidInstalledPackage(dist=installed_dist, invalid_exc=e) + + candidate = self._make_candidate_from_dist( + dist=installed_dist, + extras=extras, + template=template, + ) + # The candidate is a known incompatibility. Don't use it. + if id(candidate) in incompatible_ids: + return None + return candidate + + def iter_index_candidate_infos() -> Iterator[IndexCandidateInfo]: + result = self._finder.find_best_candidate( + project_name=name, + specifier=specifier, + hashes=hashes, + ) + icans = result.applicable_candidates + + # PEP 592: Yanked releases are ignored unless the specifier + # explicitly pins a version (via '==' or '===') that can be + # solely satisfied by a yanked release. + all_yanked = all(ican.link.is_yanked for ican in icans) + + def is_pinned(specifier: SpecifierSet) -> bool: + for sp in specifier: + if sp.operator == "===": + return True + if sp.operator != "==": + continue + if sp.version.endswith(".*"): + continue + return True + return False + + pinned = is_pinned(specifier) + + # PackageFinder returns earlier versions first, so we reverse. + for ican in reversed(icans): + if not (all_yanked and pinned) and ican.link.is_yanked: + continue + func = functools.partial( + self._make_candidate_from_link, + link=ican.link, + extras=extras, + template=template, + name=name, + version=ican.version, + ) + yield ican.version, func + + return FoundCandidates( + iter_index_candidate_infos, + _get_installed_candidate(), + prefers_installed, + incompatible_ids, + ) + + def _iter_explicit_candidates_from_base( + self, + base_requirements: Iterable[Requirement], + extras: FrozenSet[str], + ) -> Iterator[Candidate]: + """Produce explicit candidates from the base given an extra-ed package. + + :param base_requirements: Requirements known to the resolver. The + requirements are guaranteed to not have extras. + :param extras: The extras to inject into the explicit requirements' + candidates. + """ + for req in base_requirements: + lookup_cand, _ = req.get_candidate_lookup() + if lookup_cand is None: # Not explicit. + continue + # We've stripped extras from the identifier, and should always + # get a BaseCandidate here, unless there's a bug elsewhere. + base_cand = as_base_candidate(lookup_cand) + assert base_cand is not None, "no extras here" + yield self._make_extras_candidate(base_cand, extras) + + def _iter_candidates_from_constraints( + self, + identifier: str, + constraint: Constraint, + template: InstallRequirement, + ) -> Iterator[Candidate]: + """Produce explicit candidates from constraints. + + This creates "fake" InstallRequirement objects that are basically clones + of what "should" be the template, but with original_link set to link. + """ + for link in constraint.links: + self._fail_if_link_is_unsupported_wheel(link) + candidate = self._make_base_candidate_from_link( + link, + template=install_req_from_link_and_ireq(link, template), + name=canonicalize_name(identifier), + version=None, + ) + if candidate: + yield candidate + + def find_candidates( + self, + identifier: str, + requirements: Mapping[str, Iterable[Requirement]], + incompatibilities: Mapping[str, Iterator[Candidate]], + constraint: Constraint, + prefers_installed: bool, + is_satisfied_by: Callable[[Requirement, Candidate], bool], + ) -> Iterable[Candidate]: + # Collect basic lookup information from the requirements. + explicit_candidates: Set[Candidate] = set() + ireqs: List[InstallRequirement] = [] + for req in requirements[identifier]: + cand, ireq = req.get_candidate_lookup() + if cand is not None: + explicit_candidates.add(cand) + if ireq is not None: + ireqs.append(ireq) + + # If the current identifier contains extras, add requires and explicit + # candidates from entries from extra-less identifier. + with contextlib.suppress(InvalidRequirement): + parsed_requirement = get_requirement(identifier) + if parsed_requirement.name != identifier: + explicit_candidates.update( + self._iter_explicit_candidates_from_base( + requirements.get(parsed_requirement.name, ()), + frozenset(parsed_requirement.extras), + ), + ) + for req in requirements.get(parsed_requirement.name, []): + _, ireq = req.get_candidate_lookup() + if ireq is not None: + ireqs.append(ireq) + + # Add explicit candidates from constraints. We only do this if there are + # known ireqs, which represent requirements not already explicit. If + # there are no ireqs, we're constraining already-explicit requirements, + # which is handled later when we return the explicit candidates. + if ireqs: + try: + explicit_candidates.update( + self._iter_candidates_from_constraints( + identifier, + constraint, + template=ireqs[0], + ), + ) + except UnsupportedWheel: + # If we're constrained to install a wheel incompatible with the + # target architecture, no candidates will ever be valid. + return () + + # Since we cache all the candidates, incompatibility identification + # can be made quicker by comparing only the id() values. + incompat_ids = {id(c) for c in incompatibilities.get(identifier, ())} + + # If none of the requirements want an explicit candidate, we can ask + # the finder for candidates. + if not explicit_candidates: + return self._iter_found_candidates( + ireqs, + constraint.specifier, + constraint.hashes, + prefers_installed, + incompat_ids, + ) + + return ( + c + for c in explicit_candidates + if id(c) not in incompat_ids + and constraint.is_satisfied_by(c) + and all(is_satisfied_by(req, c) for req in requirements[identifier]) + ) + + def _make_requirements_from_install_req( + self, ireq: InstallRequirement, requested_extras: Iterable[str] + ) -> Iterator[Requirement]: + """ + Returns requirement objects associated with the given InstallRequirement. In + most cases this will be a single object but the following special cases exist: + - the InstallRequirement has markers that do not apply -> result is empty + - the InstallRequirement has both a constraint (or link) and extras + -> result is split in two requirement objects: one with the constraint + (or link) and one with the extra. This allows centralized constraint + handling for the base, resulting in fewer candidate rejections. + """ + if not ireq.match_markers(requested_extras): + logger.info( + "Ignoring %s: markers '%s' don't match your environment", + ireq.name, + ireq.markers, + ) + elif not ireq.link: + if ireq.extras and ireq.req is not None and ireq.req.specifier: + yield SpecifierWithoutExtrasRequirement(ireq) + yield SpecifierRequirement(ireq) + else: + self._fail_if_link_is_unsupported_wheel(ireq.link) + # Always make the link candidate for the base requirement to make it + # available to `find_candidates` for explicit candidate lookup for any + # set of extras. + # The extras are required separately via a second requirement. + cand = self._make_base_candidate_from_link( + ireq.link, + template=install_req_drop_extras(ireq) if ireq.extras else ireq, + name=canonicalize_name(ireq.name) if ireq.name else None, + version=None, + ) + if cand is None: + # There's no way we can satisfy a URL requirement if the underlying + # candidate fails to build. An unnamed URL must be user-supplied, so + # we fail eagerly. If the URL is named, an unsatisfiable requirement + # can make the resolver do the right thing, either backtrack (and + # maybe find some other requirement that's buildable) or raise a + # ResolutionImpossible eventually. + if not ireq.name: + raise self._build_failures[ireq.link] + yield UnsatisfiableRequirement(canonicalize_name(ireq.name)) + else: + # require the base from the link + yield self.make_requirement_from_candidate(cand) + if ireq.extras: + # require the extras on top of the base candidate + yield self.make_requirement_from_candidate( + self._make_extras_candidate(cand, frozenset(ireq.extras)) + ) + + def collect_root_requirements( + self, root_ireqs: List[InstallRequirement] + ) -> CollectedRootRequirements: + collected = CollectedRootRequirements([], {}, {}) + for i, ireq in enumerate(root_ireqs): + if ireq.constraint: + # Ensure we only accept valid constraints + problem = check_invalid_constraint_type(ireq) + if problem: + raise InstallationError(problem) + if not ireq.match_markers(): + continue + assert ireq.name, "Constraint must be named" + name = canonicalize_name(ireq.name) + if name in collected.constraints: + collected.constraints[name] &= ireq + else: + collected.constraints[name] = Constraint.from_ireq(ireq) + else: + reqs = list( + self._make_requirements_from_install_req( + ireq, + requested_extras=(), + ) + ) + if not reqs: + continue + template = reqs[0] + if ireq.user_supplied and template.name not in collected.user_requested: + collected.user_requested[template.name] = i + collected.requirements.extend(reqs) + # Put requirements with extras at the end of the root requires. This does not + # affect resolvelib's picking preference but it does affect its initial criteria + # population: by putting extras at the end we enable the candidate finder to + # present resolvelib with a smaller set of candidates to resolvelib, already + # taking into account any non-transient constraints on the associated base. This + # means resolvelib will have fewer candidates to visit and reject. + # Python's list sort is stable, meaning relative order is kept for objects with + # the same key. + collected.requirements.sort(key=lambda r: r.name != r.project_name) + return collected + + def make_requirement_from_candidate( + self, candidate: Candidate + ) -> ExplicitRequirement: + return ExplicitRequirement(candidate) + + def make_requirements_from_spec( + self, + specifier: str, + comes_from: Optional[InstallRequirement], + requested_extras: Iterable[str] = (), + ) -> Iterator[Requirement]: + """ + Returns requirement objects associated with the given specifier. In most cases + this will be a single object but the following special cases exist: + - the specifier has markers that do not apply -> result is empty + - the specifier has both a constraint and extras -> result is split + in two requirement objects: one with the constraint and one with the + extra. This allows centralized constraint handling for the base, + resulting in fewer candidate rejections. + """ + ireq = self._make_install_req_from_spec(specifier, comes_from) + return self._make_requirements_from_install_req(ireq, requested_extras) + + def make_requires_python_requirement( + self, + specifier: SpecifierSet, + ) -> Optional[Requirement]: + if self._ignore_requires_python: + return None + # Don't bother creating a dependency for an empty Requires-Python. + if not str(specifier): + return None + return RequiresPythonRequirement(specifier, self._python_candidate) + + def get_wheel_cache_entry( + self, link: Link, name: Optional[str] + ) -> Optional[CacheEntry]: + """Look up the link in the wheel cache. + + If ``preparer.require_hashes`` is True, don't use the wheel cache, + because cached wheels, always built locally, have different hashes + than the files downloaded from the index server and thus throw false + hash mismatches. Furthermore, cached wheels at present have + nondeterministic contents due to file modification times. + """ + if self._wheel_cache is None: + return None + return self._wheel_cache.get_cache_entry( + link=link, + package_name=name, + supported_tags=self._supported_tags_cache, + ) + + def get_dist_to_uninstall(self, candidate: Candidate) -> Optional[BaseDistribution]: + # TODO: Are there more cases this needs to return True? Editable? + dist = self._installed_dists.get(candidate.project_name) + if dist is None: # Not installed, no uninstallation required. + return None + + # We're installing into global site. The current installation must + # be uninstalled, no matter it's in global or user site, because the + # user site installation has precedence over global. + if not self._use_user_site: + return dist + + # We're installing into user site. Remove the user site installation. + if dist.in_usersite: + return dist + + # We're installing into user site, but the installed incompatible + # package is in global site. We can't uninstall that, and would let + # the new user installation to "shadow" it. But shadowing won't work + # in virtual environments, so we error out. + if running_under_virtualenv() and dist.in_site_packages: + message = ( + f"Will not install to the user site because it will lack " + f"sys.path precedence to {dist.raw_name} in {dist.location}" + ) + raise InstallationError(message) + return None + + def _report_requires_python_error( + self, causes: Sequence["ConflictCause"] + ) -> UnsupportedPythonVersion: + assert causes, "Requires-Python error reported with no cause" + + version = self._python_candidate.version + + if len(causes) == 1: + specifier = str(causes[0].requirement.specifier) + message = ( + f"Package {causes[0].parent.name!r} requires a different " + f"Python: {version} not in {specifier!r}" + ) + return UnsupportedPythonVersion(message) + + message = f"Packages require a different Python. {version} not in:" + for cause in causes: + package = cause.parent.format_for_error() + specifier = str(cause.requirement.specifier) + message += f"\n{specifier!r} (required by {package})" + return UnsupportedPythonVersion(message) + + def _report_single_requirement_conflict( + self, req: Requirement, parent: Optional[Candidate] + ) -> DistributionNotFound: + if parent is None: + req_disp = str(req) + else: + req_disp = f"{req} (from {parent.name})" + + cands = self._finder.find_all_candidates(req.project_name) + skipped_by_requires_python = self._finder.requires_python_skipped_reasons() + + versions_set: Set[Version] = set() + yanked_versions_set: Set[Version] = set() + for c in cands: + is_yanked = c.link.is_yanked if c.link else False + if is_yanked: + yanked_versions_set.add(c.version) + else: + versions_set.add(c.version) + + versions = [str(v) for v in sorted(versions_set)] + yanked_versions = [str(v) for v in sorted(yanked_versions_set)] + + if yanked_versions: + # Saying "version X is yanked" isn't entirely accurate. + # https://github.com/pypa/pip/issues/11745#issuecomment-1402805842 + logger.critical( + "Ignored the following yanked versions: %s", + ", ".join(yanked_versions) or "none", + ) + if skipped_by_requires_python: + logger.critical( + "Ignored the following versions that require a different python " + "version: %s", + "; ".join(skipped_by_requires_python) or "none", + ) + logger.critical( + "Could not find a version that satisfies the requirement %s " + "(from versions: %s)", + req_disp, + ", ".join(versions) or "none", + ) + if str(req) == "requirements.txt": + logger.info( + "HINT: You are attempting to install a package literally " + 'named "requirements.txt" (which cannot exist). Consider ' + "using the '-r' flag to install the packages listed in " + "requirements.txt" + ) + + return DistributionNotFound(f"No matching distribution found for {req}") + + def get_installation_error( + self, + e: "ResolutionImpossible[Requirement, Candidate]", + constraints: Dict[str, Constraint], + ) -> InstallationError: + assert e.causes, "Installation error reported with no cause" + + # If one of the things we can't solve is "we need Python X.Y", + # that is what we report. + requires_python_causes = [ + cause + for cause in e.causes + if isinstance(cause.requirement, RequiresPythonRequirement) + and not cause.requirement.is_satisfied_by(self._python_candidate) + ] + if requires_python_causes: + # The comprehension above makes sure all Requirement instances are + # RequiresPythonRequirement, so let's cast for convenience. + return self._report_requires_python_error( + cast("Sequence[ConflictCause]", requires_python_causes), + ) + + # Otherwise, we have a set of causes which can't all be satisfied + # at once. + + # The simplest case is when we have *one* cause that can't be + # satisfied. We just report that case. + if len(e.causes) == 1: + req, parent = e.causes[0] + if req.name not in constraints: + return self._report_single_requirement_conflict(req, parent) + + # OK, we now have a list of requirements that can't all be + # satisfied at once. + + # A couple of formatting helpers + def text_join(parts: List[str]) -> str: + if len(parts) == 1: + return parts[0] + + return ", ".join(parts[:-1]) + " and " + parts[-1] + + def describe_trigger(parent: Candidate) -> str: + ireq = parent.get_install_requirement() + if not ireq or not ireq.comes_from: + return f"{parent.name}=={parent.version}" + if isinstance(ireq.comes_from, InstallRequirement): + return str(ireq.comes_from.name) + return str(ireq.comes_from) + + triggers = set() + for req, parent in e.causes: + if parent is None: + # This is a root requirement, so we can report it directly + trigger = req.format_for_error() + else: + trigger = describe_trigger(parent) + triggers.add(trigger) + + if triggers: + info = text_join(sorted(triggers)) + else: + info = "the requested packages" + + msg = ( + f"Cannot install {info} because these package versions " + "have conflicting dependencies." + ) + logger.critical(msg) + msg = "\nThe conflict is caused by:" + + relevant_constraints = set() + for req, parent in e.causes: + if req.name in constraints: + relevant_constraints.add(req.name) + msg = msg + "\n " + if parent: + msg = msg + f"{parent.name} {parent.version} depends on " + else: + msg = msg + "The user requested " + msg = msg + req.format_for_error() + for key in relevant_constraints: + spec = constraints[key].specifier + msg += f"\n The user requested (constraint) {key}{spec}" + + msg = ( + msg + + "\n\n" + + "To fix this you could try to:\n" + + "1. loosen the range of package versions you've specified\n" + + "2. remove package versions to allow pip to attempt to solve " + + "the dependency conflict\n" + ) + + logger.info(msg) + + return DistributionNotFound( + "ResolutionImpossible: for help visit " + "https://pip.pypa.io/en/latest/topics/dependency-resolution/" + "#dealing-with-dependency-conflicts" + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py new file mode 100644 index 0000000..a1d57e0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py @@ -0,0 +1,174 @@ +"""Utilities to lazily create and visit candidates found. + +Creating and visiting a candidate is a *very* costly operation. It involves +fetching, extracting, potentially building modules from source, and verifying +distribution metadata. It is therefore crucial for performance to keep +everything here lazy all the way down, so we only touch candidates that we +absolutely need, and not "download the world" when we only need one version of +something. +""" + +import functools +import logging +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Set, Tuple + +from pip._vendor.packaging.version import _BaseVersion + +from pip._internal.exceptions import MetadataInvalid + +from .base import Candidate + +logger = logging.getLogger(__name__) + +IndexCandidateInfo = Tuple[_BaseVersion, Callable[[], Optional[Candidate]]] + +if TYPE_CHECKING: + SequenceCandidate = Sequence[Candidate] +else: + # For compatibility: Python before 3.9 does not support using [] on the + # Sequence class. + # + # >>> from collections.abc import Sequence + # >>> Sequence[str] + # Traceback (most recent call last): + # File "", line 1, in + # TypeError: 'ABCMeta' object is not subscriptable + # + # TODO: Remove this block after dropping Python 3.8 support. + SequenceCandidate = Sequence + + +def _iter_built(infos: Iterator[IndexCandidateInfo]) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the package is not already installed. Candidates + from index come later in their normal ordering. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + try: + candidate = func() + except MetadataInvalid as e: + logger.warning( + "Ignoring version %s of %s since it has invalid metadata:\n" + "%s\n" + "Please use pip<24.1 if you need to use this version.", + version, + e.ireq.name, + e, + ) + # Mark version as found to avoid trying other candidates with the same + # version, since they most likely have invalid metadata as well. + versions_found.add(version) + else: + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_prepended( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers the already-installed + candidate and NOT to upgrade. The installed candidate is therefore + always yielded first, and candidates from index come later in their + normal ordering, except skipped when the version is already installed. + """ + yield installed + versions_found: Set[_BaseVersion] = {installed.version} + for version, func in infos: + if version in versions_found: + continue + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_inserted( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers to upgrade an + already-installed package. Candidates from index are returned in their + normal ordering, except replaced when the version is already installed. + + The implementation iterates through and yields other candidates, inserting + the installed candidate exactly once before we start yielding older or + equivalent candidates, or after all other candidates if they are all newer. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + # If the installed candidate is better, yield it first. + if installed.version >= version: + yield installed + versions_found.add(installed.version) + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + # If the installed candidate is older than all other candidates. + if installed.version not in versions_found: + yield installed + + +class FoundCandidates(SequenceCandidate): + """A lazy sequence to provide candidates to the resolver. + + The intended usage is to return this from `find_matches()` so the resolver + can iterate through the sequence multiple times, but only access the index + page when remote packages are actually needed. This improve performances + when suitable candidates are already installed on disk. + """ + + def __init__( + self, + get_infos: Callable[[], Iterator[IndexCandidateInfo]], + installed: Optional[Candidate], + prefers_installed: bool, + incompatible_ids: Set[int], + ): + self._get_infos = get_infos + self._installed = installed + self._prefers_installed = prefers_installed + self._incompatible_ids = incompatible_ids + + def __getitem__(self, index: Any) -> Any: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + def __iter__(self) -> Iterator[Candidate]: + infos = self._get_infos() + if not self._installed: + iterator = _iter_built(infos) + elif self._prefers_installed: + iterator = _iter_built_with_prepended(self._installed, infos) + else: + iterator = _iter_built_with_inserted(self._installed, infos) + return (c for c in iterator if id(c) not in self._incompatible_ids) + + def __len__(self) -> int: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + @functools.lru_cache(maxsize=1) + def __bool__(self) -> bool: + if self._prefers_installed and self._installed: + return True + return any(self) diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py new file mode 100644 index 0000000..fb0dd85 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py @@ -0,0 +1,258 @@ +import collections +import math +from functools import lru_cache +from typing import ( + TYPE_CHECKING, + Dict, + Iterable, + Iterator, + Mapping, + Sequence, + TypeVar, + Union, +) + +from pip._vendor.resolvelib.providers import AbstractProvider + +from .base import Candidate, Constraint, Requirement +from .candidates import REQUIRES_PYTHON_IDENTIFIER +from .factory import Factory + +if TYPE_CHECKING: + from pip._vendor.resolvelib.providers import Preference + from pip._vendor.resolvelib.resolvers import RequirementInformation + + PreferenceInformation = RequirementInformation[Requirement, Candidate] + + _ProviderBase = AbstractProvider[Requirement, Candidate, str] +else: + _ProviderBase = AbstractProvider + +# Notes on the relationship between the provider, the factory, and the +# candidate and requirement classes. +# +# The provider is a direct implementation of the resolvelib class. Its role +# is to deliver the API that resolvelib expects. +# +# Rather than work with completely abstract "requirement" and "candidate" +# concepts as resolvelib does, pip has concrete classes implementing these two +# ideas. The API of Requirement and Candidate objects are defined in the base +# classes, but essentially map fairly directly to the equivalent provider +# methods. In particular, `find_matches` and `is_satisfied_by` are +# requirement methods, and `get_dependencies` is a candidate method. +# +# The factory is the interface to pip's internal mechanisms. It is stateless, +# and is created by the resolver and held as a property of the provider. It is +# responsible for creating Requirement and Candidate objects, and provides +# services to those objects (access to pip's finder and preparer). + + +D = TypeVar("D") +V = TypeVar("V") + + +def _get_with_identifier( + mapping: Mapping[str, V], + identifier: str, + default: D, +) -> Union[D, V]: + """Get item from a package name lookup mapping with a resolver identifier. + + This extra logic is needed when the target mapping is keyed by package + name, which cannot be directly looked up with an identifier (which may + contain requested extras). Additional logic is added to also look up a value + by "cleaning up" the extras from the identifier. + """ + if identifier in mapping: + return mapping[identifier] + # HACK: Theoretically we should check whether this identifier is a valid + # "NAME[EXTRAS]" format, and parse out the name part with packaging or + # some regular expression. But since pip's resolver only spits out three + # kinds of identifiers: normalized PEP 503 names, normalized names plus + # extras, and Requires-Python, we can cheat a bit here. + name, open_bracket, _ = identifier.partition("[") + if open_bracket and name in mapping: + return mapping[name] + return default + + +class PipProvider(_ProviderBase): + """Pip's provider implementation for resolvelib. + + :params constraints: A mapping of constraints specified by the user. Keys + are canonicalized project names. + :params ignore_dependencies: Whether the user specified ``--no-deps``. + :params upgrade_strategy: The user-specified upgrade strategy. + :params user_requested: A set of canonicalized package names that the user + supplied for pip to install/upgrade. + """ + + def __init__( + self, + factory: Factory, + constraints: Dict[str, Constraint], + ignore_dependencies: bool, + upgrade_strategy: str, + user_requested: Dict[str, int], + ) -> None: + self._factory = factory + self._constraints = constraints + self._ignore_dependencies = ignore_dependencies + self._upgrade_strategy = upgrade_strategy + self._user_requested = user_requested + self._known_depths: Dict[str, float] = collections.defaultdict(lambda: math.inf) + + def identify(self, requirement_or_candidate: Union[Requirement, Candidate]) -> str: + return requirement_or_candidate.name + + def get_preference( + self, + identifier: str, + resolutions: Mapping[str, Candidate], + candidates: Mapping[str, Iterator[Candidate]], + information: Mapping[str, Iterable["PreferenceInformation"]], + backtrack_causes: Sequence["PreferenceInformation"], + ) -> "Preference": + """Produce a sort key for given requirement based on preference. + + The lower the return value is, the more preferred this group of + arguments is. + + Currently pip considers the following in order: + + * Prefer if any of the known requirements is "direct", e.g. points to an + explicit URL. + * If equal, prefer if any requirement is "pinned", i.e. contains + operator ``===`` or ``==``. + * If equal, calculate an approximate "depth" and resolve requirements + closer to the user-specified requirements first. If the depth cannot + by determined (eg: due to no matching parents), it is considered + infinite. + * Order user-specified requirements by the order they are specified. + * If equal, prefers "non-free" requirements, i.e. contains at least one + operator, such as ``>=`` or ``<``. + * If equal, order alphabetically for consistency (helps debuggability). + """ + try: + next(iter(information[identifier])) + except StopIteration: + # There is no information for this identifier, so there's no known + # candidates. + has_information = False + else: + has_information = True + + if has_information: + lookups = (r.get_candidate_lookup() for r, _ in information[identifier]) + candidate, ireqs = zip(*lookups) + else: + candidate, ireqs = None, () + + operators = [ + specifier.operator + for specifier_set in (ireq.specifier for ireq in ireqs if ireq) + for specifier in specifier_set + ] + + direct = candidate is not None + pinned = any(op[:2] == "==" for op in operators) + unfree = bool(operators) + + try: + requested_order: Union[int, float] = self._user_requested[identifier] + except KeyError: + requested_order = math.inf + if has_information: + parent_depths = ( + self._known_depths[parent.name] if parent is not None else 0.0 + for _, parent in information[identifier] + ) + inferred_depth = min(d for d in parent_depths) + 1.0 + else: + inferred_depth = math.inf + else: + inferred_depth = 1.0 + self._known_depths[identifier] = inferred_depth + + requested_order = self._user_requested.get(identifier, math.inf) + + # Requires-Python has only one candidate and the check is basically + # free, so we always do it first to avoid needless work if it fails. + requires_python = identifier == REQUIRES_PYTHON_IDENTIFIER + + # Prefer the causes of backtracking on the assumption that the problem + # resolving the dependency tree is related to the failures that caused + # the backtracking + backtrack_cause = self.is_backtrack_cause(identifier, backtrack_causes) + + return ( + not requires_python, + not direct, + not pinned, + not backtrack_cause, + inferred_depth, + requested_order, + not unfree, + identifier, + ) + + def find_matches( + self, + identifier: str, + requirements: Mapping[str, Iterator[Requirement]], + incompatibilities: Mapping[str, Iterator[Candidate]], + ) -> Iterable[Candidate]: + def _eligible_for_upgrade(identifier: str) -> bool: + """Are upgrades allowed for this project? + + This checks the upgrade strategy, and whether the project was one + that the user specified in the command line, in order to decide + whether we should upgrade if there's a newer version available. + + (Note that we don't need access to the `--upgrade` flag, because + an upgrade strategy of "to-satisfy-only" means that `--upgrade` + was not specified). + """ + if self._upgrade_strategy == "eager": + return True + elif self._upgrade_strategy == "only-if-needed": + user_order = _get_with_identifier( + self._user_requested, + identifier, + default=None, + ) + return user_order is not None + return False + + constraint = _get_with_identifier( + self._constraints, + identifier, + default=Constraint.empty(), + ) + return self._factory.find_candidates( + identifier=identifier, + requirements=requirements, + constraint=constraint, + prefers_installed=(not _eligible_for_upgrade(identifier)), + incompatibilities=incompatibilities, + is_satisfied_by=self.is_satisfied_by, + ) + + @lru_cache(maxsize=None) + def is_satisfied_by(self, requirement: Requirement, candidate: Candidate) -> bool: + return requirement.is_satisfied_by(candidate) + + def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]: + with_requires = not self._ignore_dependencies + return [r for r in candidate.iter_dependencies(with_requires) if r is not None] + + @staticmethod + def is_backtrack_cause( + identifier: str, backtrack_causes: Sequence["PreferenceInformation"] + ) -> bool: + for backtrack_cause in backtrack_causes: + if identifier == backtrack_cause.requirement.name: + return True + if backtrack_cause.parent and identifier == backtrack_cause.parent.name: + return True + return False diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py new file mode 100644 index 0000000..0594569 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py @@ -0,0 +1,81 @@ +from collections import defaultdict +from logging import getLogger +from typing import Any, DefaultDict + +from pip._vendor.resolvelib.reporters import BaseReporter + +from .base import Candidate, Requirement + +logger = getLogger(__name__) + + +class PipReporter(BaseReporter): + def __init__(self) -> None: + self.reject_count_by_package: DefaultDict[str, int] = defaultdict(int) + + self._messages_at_reject_count = { + 1: ( + "pip is looking at multiple versions of {package_name} to " + "determine which version is compatible with other " + "requirements. This could take a while." + ), + 8: ( + "pip is still looking at multiple versions of {package_name} to " + "determine which version is compatible with other " + "requirements. This could take a while." + ), + 13: ( + "This is taking longer than usual. You might need to provide " + "the dependency resolver with stricter constraints to reduce " + "runtime. See https://pip.pypa.io/warnings/backtracking for " + "guidance. If you want to abort this run, press Ctrl + C." + ), + } + + def rejecting_candidate(self, criterion: Any, candidate: Candidate) -> None: + self.reject_count_by_package[candidate.name] += 1 + + count = self.reject_count_by_package[candidate.name] + if count not in self._messages_at_reject_count: + return + + message = self._messages_at_reject_count[count] + logger.info("INFO: %s", message.format(package_name=candidate.name)) + + msg = "Will try a different candidate, due to conflict:" + for req_info in criterion.information: + req, parent = req_info.requirement, req_info.parent + # Inspired by Factory.get_installation_error + msg += "\n " + if parent: + msg += f"{parent.name} {parent.version} depends on " + else: + msg += "The user requested " + msg += req.format_for_error() + logger.debug(msg) + + +class PipDebuggingReporter(BaseReporter): + """A reporter that does an info log for every event it sees.""" + + def starting(self) -> None: + logger.info("Reporter.starting()") + + def starting_round(self, index: int) -> None: + logger.info("Reporter.starting_round(%r)", index) + + def ending_round(self, index: int, state: Any) -> None: + logger.info("Reporter.ending_round(%r, state)", index) + logger.debug("Reporter.ending_round(%r, %r)", index, state) + + def ending(self, state: Any) -> None: + logger.info("Reporter.ending(%r)", state) + + def adding_requirement(self, requirement: Requirement, parent: Candidate) -> None: + logger.info("Reporter.adding_requirement(%r, %r)", requirement, parent) + + def rejecting_candidate(self, criterion: Any, candidate: Candidate) -> None: + logger.info("Reporter.rejecting_candidate(%r, %r)", criterion, candidate) + + def pinning(self, candidate: Candidate) -> None: + logger.info("Reporter.pinning(%r)", candidate) diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py new file mode 100644 index 0000000..b04f41b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py @@ -0,0 +1,245 @@ +from typing import Any, Optional + +from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name + +from pip._internal.req.constructors import install_req_drop_extras +from pip._internal.req.req_install import InstallRequirement + +from .base import Candidate, CandidateLookup, Requirement, format_name + + +class ExplicitRequirement(Requirement): + def __init__(self, candidate: Candidate) -> None: + self.candidate = candidate + + def __str__(self) -> str: + return str(self.candidate) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.candidate!r})" + + def __hash__(self) -> int: + return hash(self.candidate) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExplicitRequirement): + return False + return self.candidate == other.candidate + + @property + def project_name(self) -> NormalizedName: + # No need to canonicalize - the candidate did this + return self.candidate.project_name + + @property + def name(self) -> str: + # No need to canonicalize - the candidate did this + return self.candidate.name + + def format_for_error(self) -> str: + return self.candidate.format_for_error() + + def get_candidate_lookup(self) -> CandidateLookup: + return self.candidate, None + + def is_satisfied_by(self, candidate: Candidate) -> bool: + return candidate == self.candidate + + +class SpecifierRequirement(Requirement): + def __init__(self, ireq: InstallRequirement) -> None: + assert ireq.link is None, "This is a link, not a specifier" + self._ireq = ireq + self._equal_cache: Optional[str] = None + self._hash: Optional[int] = None + self._extras = frozenset(canonicalize_name(e) for e in self._ireq.extras) + + @property + def _equal(self) -> str: + if self._equal_cache is not None: + return self._equal_cache + + self._equal_cache = str(self._ireq) + return self._equal_cache + + def __str__(self) -> str: + return str(self._ireq.req) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({str(self._ireq.req)!r})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SpecifierRequirement): + return NotImplemented + return self._equal == other._equal + + def __hash__(self) -> int: + if self._hash is not None: + return self._hash + + self._hash = hash(self._equal) + return self._hash + + @property + def project_name(self) -> NormalizedName: + assert self._ireq.req, "Specifier-backed ireq is always PEP 508" + return canonicalize_name(self._ireq.req.name) + + @property + def name(self) -> str: + return format_name(self.project_name, self._extras) + + def format_for_error(self) -> str: + # Convert comma-separated specifiers into "A, B, ..., F and G" + # This makes the specifier a bit more "human readable", without + # risking a change in meaning. (Hopefully! Not all edge cases have + # been checked) + parts = [s.strip() for s in str(self).split(",")] + if len(parts) == 0: + return "" + elif len(parts) == 1: + return parts[0] + + return ", ".join(parts[:-1]) + " and " + parts[-1] + + def get_candidate_lookup(self) -> CandidateLookup: + return None, self._ireq + + def is_satisfied_by(self, candidate: Candidate) -> bool: + assert candidate.name == self.name, ( + f"Internal issue: Candidate is not for this requirement " + f"{candidate.name} vs {self.name}" + ) + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + assert self._ireq.req, "Specifier-backed ireq is always PEP 508" + spec = self._ireq.req.specifier + return spec.contains(candidate.version, prereleases=True) + + +class SpecifierWithoutExtrasRequirement(SpecifierRequirement): + """ + Requirement backed by an install requirement on a base package. + Trims extras from its install requirement if there are any. + """ + + def __init__(self, ireq: InstallRequirement) -> None: + assert ireq.link is None, "This is a link, not a specifier" + self._ireq = install_req_drop_extras(ireq) + self._equal_cache: Optional[str] = None + self._hash: Optional[int] = None + self._extras = frozenset(canonicalize_name(e) for e in self._ireq.extras) + + @property + def _equal(self) -> str: + if self._equal_cache is not None: + return self._equal_cache + + self._equal_cache = str(self._ireq) + return self._equal_cache + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SpecifierWithoutExtrasRequirement): + return NotImplemented + return self._equal == other._equal + + def __hash__(self) -> int: + if self._hash is not None: + return self._hash + + self._hash = hash(self._equal) + return self._hash + + +class RequiresPythonRequirement(Requirement): + """A requirement representing Requires-Python metadata.""" + + def __init__(self, specifier: SpecifierSet, match: Candidate) -> None: + self.specifier = specifier + self._specifier_string = str(specifier) # for faster __eq__ + self._hash: Optional[int] = None + self._candidate = match + + def __str__(self) -> str: + return f"Python {self.specifier}" + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({str(self.specifier)!r})" + + def __hash__(self) -> int: + if self._hash is not None: + return self._hash + + self._hash = hash((self._specifier_string, self._candidate)) + return self._hash + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, RequiresPythonRequirement): + return False + return ( + self._specifier_string == other._specifier_string + and self._candidate == other._candidate + ) + + @property + def project_name(self) -> NormalizedName: + return self._candidate.project_name + + @property + def name(self) -> str: + return self._candidate.name + + def format_for_error(self) -> str: + return str(self) + + def get_candidate_lookup(self) -> CandidateLookup: + if self.specifier.contains(self._candidate.version, prereleases=True): + return self._candidate, None + return None, None + + def is_satisfied_by(self, candidate: Candidate) -> bool: + assert candidate.name == self._candidate.name, "Not Python candidate" + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + return self.specifier.contains(candidate.version, prereleases=True) + + +class UnsatisfiableRequirement(Requirement): + """A requirement that cannot be satisfied.""" + + def __init__(self, name: NormalizedName) -> None: + self._name = name + + def __str__(self) -> str: + return f"{self._name} (unavailable)" + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({str(self._name)!r})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UnsatisfiableRequirement): + return NotImplemented + return self._name == other._name + + def __hash__(self) -> int: + return hash(self._name) + + @property + def project_name(self) -> NormalizedName: + return self._name + + @property + def name(self) -> str: + return self._name + + def format_for_error(self) -> str: + return str(self) + + def get_candidate_lookup(self) -> CandidateLookup: + return None, None + + def is_satisfied_by(self, candidate: Candidate) -> bool: + return False diff --git a/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py new file mode 100644 index 0000000..c12beef --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py @@ -0,0 +1,317 @@ +import contextlib +import functools +import logging +import os +from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, cast + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible +from pip._vendor.resolvelib import Resolver as RLResolver +from pip._vendor.resolvelib.structs import DirectedGraph + +from pip._internal.cache import WheelCache +from pip._internal.index.package_finder import PackageFinder +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.constructors import install_req_extend_extras +from pip._internal.req.req_install import InstallRequirement +from pip._internal.req.req_set import RequirementSet +from pip._internal.resolution.base import BaseResolver, InstallRequirementProvider +from pip._internal.resolution.resolvelib.provider import PipProvider +from pip._internal.resolution.resolvelib.reporter import ( + PipDebuggingReporter, + PipReporter, +) +from pip._internal.utils.packaging import get_requirement + +from .base import Candidate, Requirement +from .factory import Factory + +if TYPE_CHECKING: + from pip._vendor.resolvelib.resolvers import Result as RLResult + + Result = RLResult[Requirement, Candidate, str] + + +logger = logging.getLogger(__name__) + + +class Resolver(BaseResolver): + _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} + + def __init__( + self, + preparer: RequirementPreparer, + finder: PackageFinder, + wheel_cache: Optional[WheelCache], + make_install_req: InstallRequirementProvider, + use_user_site: bool, + ignore_dependencies: bool, + ignore_installed: bool, + ignore_requires_python: bool, + force_reinstall: bool, + upgrade_strategy: str, + py_version_info: Optional[Tuple[int, ...]] = None, + ): + super().__init__() + assert upgrade_strategy in self._allowed_strategies + + self.factory = Factory( + finder=finder, + preparer=preparer, + make_install_req=make_install_req, + wheel_cache=wheel_cache, + use_user_site=use_user_site, + force_reinstall=force_reinstall, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + py_version_info=py_version_info, + ) + self.ignore_dependencies = ignore_dependencies + self.upgrade_strategy = upgrade_strategy + self._result: Optional[Result] = None + + def resolve( + self, root_reqs: List[InstallRequirement], check_supported_wheels: bool + ) -> RequirementSet: + collected = self.factory.collect_root_requirements(root_reqs) + provider = PipProvider( + factory=self.factory, + constraints=collected.constraints, + ignore_dependencies=self.ignore_dependencies, + upgrade_strategy=self.upgrade_strategy, + user_requested=collected.user_requested, + ) + if "PIP_RESOLVER_DEBUG" in os.environ: + reporter: BaseReporter = PipDebuggingReporter() + else: + reporter = PipReporter() + resolver: RLResolver[Requirement, Candidate, str] = RLResolver( + provider, + reporter, + ) + + try: + limit_how_complex_resolution_can_be = 200000 + result = self._result = resolver.resolve( + collected.requirements, max_rounds=limit_how_complex_resolution_can_be + ) + + except ResolutionImpossible as e: + error = self.factory.get_installation_error( + cast("ResolutionImpossible[Requirement, Candidate]", e), + collected.constraints, + ) + raise error from e + + req_set = RequirementSet(check_supported_wheels=check_supported_wheels) + # process candidates with extras last to ensure their base equivalent is + # already in the req_set if appropriate. + # Python's sort is stable so using a binary key function keeps relative order + # within both subsets. + for candidate in sorted( + result.mapping.values(), key=lambda c: c.name != c.project_name + ): + ireq = candidate.get_install_requirement() + if ireq is None: + if candidate.name != candidate.project_name: + # extend existing req's extras + with contextlib.suppress(KeyError): + req = req_set.get_requirement(candidate.project_name) + req_set.add_named_requirement( + install_req_extend_extras( + req, get_requirement(candidate.name).extras + ) + ) + continue + + # Check if there is already an installation under the same name, + # and set a flag for later stages to uninstall it, if needed. + installed_dist = self.factory.get_dist_to_uninstall(candidate) + if installed_dist is None: + # There is no existing installation -- nothing to uninstall. + ireq.should_reinstall = False + elif self.factory.force_reinstall: + # The --force-reinstall flag is set -- reinstall. + ireq.should_reinstall = True + elif installed_dist.version != candidate.version: + # The installation is different in version -- reinstall. + ireq.should_reinstall = True + elif candidate.is_editable or installed_dist.editable: + # The incoming distribution is editable, or different in + # editable-ness to installation -- reinstall. + ireq.should_reinstall = True + elif candidate.source_link and candidate.source_link.is_file: + # The incoming distribution is under file:// + if candidate.source_link.is_wheel: + # is a local wheel -- do nothing. + logger.info( + "%s is already installed with the same version as the " + "provided wheel. Use --force-reinstall to force an " + "installation of the wheel.", + ireq.name, + ) + continue + + # is a local sdist or path -- reinstall + ireq.should_reinstall = True + else: + continue + + link = candidate.source_link + if link and link.is_yanked: + # The reason can contain non-ASCII characters, Unicode + # is required for Python 2. + msg = ( + "The candidate selected for download or install is a " + "yanked version: {name!r} candidate (version {version} " + "at {link})\nReason for being yanked: {reason}" + ).format( + name=candidate.name, + version=candidate.version, + link=link, + reason=link.yanked_reason or "", + ) + logger.warning(msg) + + req_set.add_named_requirement(ireq) + + reqs = req_set.all_requirements + self.factory.preparer.prepare_linked_requirements_more(reqs) + for req in reqs: + req.prepared = True + req.needs_more_preparation = False + return req_set + + def get_installation_order( + self, req_set: RequirementSet + ) -> List[InstallRequirement]: + """Get order for installation of requirements in RequirementSet. + + The returned list contains a requirement before another that depends on + it. This helps ensure that the environment is kept consistent as they + get installed one-by-one. + + The current implementation creates a topological ordering of the + dependency graph, giving more weight to packages with less + or no dependencies, while breaking any cycles in the graph at + arbitrary points. We make no guarantees about where the cycle + would be broken, other than it *would* be broken. + """ + assert self._result is not None, "must call resolve() first" + + if not req_set.requirements: + # Nothing is left to install, so we do not need an order. + return [] + + graph = self._result.graph + weights = get_topological_weights(graph, set(req_set.requirements.keys())) + + sorted_items = sorted( + req_set.requirements.items(), + key=functools.partial(_req_set_item_sorter, weights=weights), + reverse=True, + ) + return [ireq for _, ireq in sorted_items] + + +def get_topological_weights( + graph: "DirectedGraph[Optional[str]]", requirement_keys: Set[str] +) -> Dict[Optional[str], int]: + """Assign weights to each node based on how "deep" they are. + + This implementation may change at any point in the future without prior + notice. + + We first simplify the dependency graph by pruning any leaves and giving them + the highest weight: a package without any dependencies should be installed + first. This is done again and again in the same way, giving ever less weight + to the newly found leaves. The loop stops when no leaves are left: all + remaining packages have at least one dependency left in the graph. + + Then we continue with the remaining graph, by taking the length for the + longest path to any node from root, ignoring any paths that contain a single + node twice (i.e. cycles). This is done through a depth-first search through + the graph, while keeping track of the path to the node. + + Cycles in the graph result would result in node being revisited while also + being on its own path. In this case, take no action. This helps ensure we + don't get stuck in a cycle. + + When assigning weight, the longer path (i.e. larger length) is preferred. + + We are only interested in the weights of packages that are in the + requirement_keys. + """ + path: Set[Optional[str]] = set() + weights: Dict[Optional[str], int] = {} + + def visit(node: Optional[str]) -> None: + if node in path: + # We hit a cycle, so we'll break it here. + return + + # Time to visit the children! + path.add(node) + for child in graph.iter_children(node): + visit(child) + path.remove(node) + + if node not in requirement_keys: + return + + last_known_parent_count = weights.get(node, 0) + weights[node] = max(last_known_parent_count, len(path)) + + # Simplify the graph, pruning leaves that have no dependencies. + # This is needed for large graphs (say over 200 packages) because the + # `visit` function is exponentially slower then, taking minutes. + # See https://github.com/pypa/pip/issues/10557 + # We will loop until we explicitly break the loop. + while True: + leaves = set() + for key in graph: + if key is None: + continue + for _child in graph.iter_children(key): + # This means we have at least one child + break + else: + # No child. + leaves.add(key) + if not leaves: + # We are done simplifying. + break + # Calculate the weight for the leaves. + weight = len(graph) - 1 + for leaf in leaves: + if leaf not in requirement_keys: + continue + weights[leaf] = weight + # Remove the leaves from the graph, making it simpler. + for leaf in leaves: + graph.remove(leaf) + + # Visit the remaining graph. + # `None` is guaranteed to be the root node by resolvelib. + visit(None) + + # Sanity check: all requirement keys should be in the weights, + # and no other keys should be in the weights. + difference = set(weights.keys()).difference(requirement_keys) + assert not difference, difference + + return weights + + +def _req_set_item_sorter( + item: Tuple[str, InstallRequirement], + weights: Dict[Optional[str], int], +) -> Tuple[int, str]: + """Key function used to sort install requirements for installation. + + Based on the "weight" mapping calculated in ``get_installation_order()``. + The canonical package name is returned as the second member as a tie- + breaker to ensure the result is predictable, which is useful in tests. + """ + name = canonicalize_name(item[0]) + return weights[name], name diff --git a/backend/venv/Lib/site-packages/pip/_internal/self_outdated_check.py b/backend/venv/Lib/site-packages/pip/_internal/self_outdated_check.py new file mode 100644 index 0000000..2e0e3df --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/self_outdated_check.py @@ -0,0 +1,252 @@ +import datetime +import functools +import hashlib +import json +import logging +import optparse +import os.path +import sys +from dataclasses import dataclass +from typing import Any, Callable, Dict, Optional + +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.rich.console import Group +from pip._vendor.rich.markup import escape +from pip._vendor.rich.text import Text + +from pip._internal.index.collector import LinkCollector +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import get_default_environment +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.network.session import PipSession +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.entrypoints import ( + get_best_invocation_for_this_pip, + get_best_invocation_for_this_python, +) +from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace +from pip._internal.utils.misc import ( + ExternallyManagedEnvironment, + check_externally_managed, + ensure_dir, +) + +_WEEK = datetime.timedelta(days=7) + +logger = logging.getLogger(__name__) + + +def _get_statefile_name(key: str) -> str: + key_bytes = key.encode() + name = hashlib.sha224(key_bytes).hexdigest() + return name + + +def _convert_date(isodate: str) -> datetime.datetime: + """Convert an ISO format string to a date. + + Handles the format 2020-01-22T14:24:01Z (trailing Z) + which is not supported by older versions of fromisoformat. + """ + return datetime.datetime.fromisoformat(isodate.replace("Z", "+00:00")) + + +class SelfCheckState: + def __init__(self, cache_dir: str) -> None: + self._state: Dict[str, Any] = {} + self._statefile_path = None + + # Try to load the existing state + if cache_dir: + self._statefile_path = os.path.join( + cache_dir, "selfcheck", _get_statefile_name(self.key) + ) + try: + with open(self._statefile_path, encoding="utf-8") as statefile: + self._state = json.load(statefile) + except (OSError, ValueError, KeyError): + # Explicitly suppressing exceptions, since we don't want to + # error out if the cache file is invalid. + pass + + @property + def key(self) -> str: + return sys.prefix + + def get(self, current_time: datetime.datetime) -> Optional[str]: + """Check if we have a not-outdated version loaded already.""" + if not self._state: + return None + + if "last_check" not in self._state: + return None + + if "pypi_version" not in self._state: + return None + + # Determine if we need to refresh the state + last_check = _convert_date(self._state["last_check"]) + time_since_last_check = current_time - last_check + if time_since_last_check > _WEEK: + return None + + return self._state["pypi_version"] + + def set(self, pypi_version: str, current_time: datetime.datetime) -> None: + # If we do not have a path to cache in, don't bother saving. + if not self._statefile_path: + return + + # Check to make sure that we own the directory + if not check_path_owner(os.path.dirname(self._statefile_path)): + return + + # Now that we've ensured the directory is owned by this user, we'll go + # ahead and make sure that all our directories are created. + ensure_dir(os.path.dirname(self._statefile_path)) + + state = { + # Include the key so it's easy to tell which pip wrote the + # file. + "key": self.key, + "last_check": current_time.isoformat(), + "pypi_version": pypi_version, + } + + text = json.dumps(state, sort_keys=True, separators=(",", ":")) + + with adjacent_tmp_file(self._statefile_path) as f: + f.write(text.encode()) + + try: + # Since we have a prefix-specific state file, we can just + # overwrite whatever is there, no need to check. + replace(f.name, self._statefile_path) + except OSError: + # Best effort. + pass + + +@dataclass +class UpgradePrompt: + old: str + new: str + + def __rich__(self) -> Group: + if WINDOWS: + pip_cmd = f"{get_best_invocation_for_this_python()} -m pip" + else: + pip_cmd = get_best_invocation_for_this_pip() + + notice = "[bold][[reset][blue]notice[reset][bold]][reset]" + return Group( + Text(), + Text.from_markup( + f"{notice} A new release of pip is available: " + f"[red]{self.old}[reset] -> [green]{self.new}[reset]" + ), + Text.from_markup( + f"{notice} To update, run: " + f"[green]{escape(pip_cmd)} install --upgrade pip" + ), + ) + + +def was_installed_by_pip(pkg: str) -> bool: + """Checks whether pkg was installed by pip + + This is used not to display the upgrade message when pip is in fact + installed by system package manager, such as dnf on Fedora. + """ + dist = get_default_environment().get_distribution(pkg) + return dist is not None and "pip" == dist.installer + + +def _get_current_remote_pip_version( + session: PipSession, options: optparse.Values +) -> Optional[str]: + # Lets use PackageFinder to see what the latest pip version is + link_collector = LinkCollector.create( + session, + options=options, + suppress_no_index=True, + ) + + # Pass allow_yanked=False so we don't suggest upgrading to a + # yanked version. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=False, # Explicitly set to False + ) + + finder = PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + ) + best_candidate = finder.find_best_candidate("pip").best_candidate + if best_candidate is None: + return None + + return str(best_candidate.version) + + +def _self_version_check_logic( + *, + state: SelfCheckState, + current_time: datetime.datetime, + local_version: Version, + get_remote_version: Callable[[], Optional[str]], +) -> Optional[UpgradePrompt]: + remote_version_str = state.get(current_time) + if remote_version_str is None: + remote_version_str = get_remote_version() + if remote_version_str is None: + logger.debug("No remote pip version found") + return None + state.set(remote_version_str, current_time) + + remote_version = parse_version(remote_version_str) + logger.debug("Remote version of pip: %s", remote_version) + logger.debug("Local version of pip: %s", local_version) + + pip_installed_by_pip = was_installed_by_pip("pip") + logger.debug("Was pip installed by pip? %s", pip_installed_by_pip) + if not pip_installed_by_pip: + return None # Only suggest upgrade if pip is installed by pip. + + local_version_is_older = ( + local_version < remote_version + and local_version.base_version != remote_version.base_version + ) + if local_version_is_older: + return UpgradePrompt(old=str(local_version), new=remote_version_str) + + return None + + +def pip_self_version_check(session: PipSession, options: optparse.Values) -> None: + """Check for an update for pip. + + Limit the frequency of checks to once per week. State is stored either in + the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix + of the pip script path. + """ + installed_dist = get_default_environment().get_distribution("pip") + if not installed_dist: + return + try: + check_externally_managed() + except ExternallyManagedEnvironment: + return + + upgrade_prompt = _self_version_check_logic( + state=SelfCheckState(cache_dir=options.cache_dir), + current_time=datetime.datetime.now(datetime.timezone.utc), + local_version=installed_dist.version, + get_remote_version=functools.partial( + _get_current_remote_pip_version, session, options + ), + ) + if upgrade_prompt is not None: + logger.warning("%s", upgrade_prompt, extra={"rich": True}) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1befdf00889bebb3b0c601d67277bf425f85ecd3 GIT binary patch literal 196 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a7a0ab931ecafec30f6c0ef32da7d48dd6b42168 GIT binary patch literal 1867 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3a8a4ef891c86e862119a1d50653a57a14ceba3 GIT binary patch literal 6351 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12ca27d4fbe185ea866679905205cdadfb23fb89 GIT binary patch literal 685 zcmZuvF>ljA6uz_1iB%j_sSGgHs0>($gry4tmbOf^18k8c%kdqF8{21{FNus?DFaI< z*xIops1jo2Kd^v0Ae|VHnAiegV&a`~goJp~d*6HS-n;kR)4lI>))2_no5%4Fz^^)3 ziQPEMo8X)viu#CRY9zRismTmVKrPS~GoRYD{hahkX?XUt?n5rz*@$Is9_Q{X%w*w8 z?nWaPja@lnE)6Afp+?3j>#lv%V-6H4Styj1@=T7DNyAdL1d|hyMP|c8g9WPN^uOK;Rk$+Fo7qRCGAlCPMd%6g@PTJ4TR%cSKoRXJ zOLE}sSweRRqK%#|^m>&wjHfIsbi&p0E84m1=YkJKn5JErPF|MhgV+YO98~J2kx9{i&1njlTgIA*YZ4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77fdb46f8b6576beb0bb9a44d2883df2e85d96b8 GIT binary patch literal 4192 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4deb3924787d86504e90054864393528f782cab7 GIT binary patch literal 3207 zcmbVO&2JmW6`x%$KShaFZGG5nQ3Z^)%SsvtoJ zBkyY$!f$)aRd8fexi{qB^#+yO1CXP-N=+Ojgis_wBv4~YL>EYl8w44X0g$;V83Fy z>0el-v4J)|)Mh}N`ycHHXis&FeD6Jg>sz-t4t{B&_!6AHkfi;M>%xW@mq{44jlzJ z(;S|O;`Xl47}-(YP_Xrz(oU%Yv<>2w-UVGRGj;gzWydH*PNir z+~EP+P6t;;56D9vsdzrLFV&Q4%4@}96|A?G3uWFYHaktHcwn>WN!enu_}bOi-^llm zy*BpKpM7VpHF1o{1u2T1?ngukqquhKB40Ppy-qhLc_Jj6z_d$2(=A-*hrrzH8-d=8etG(IYdT;Z+ z4{FbH7k8)5Kg|6rNoKC}Vq|irmm%3x;xrgO86F=47`92302l_aAmlNO#v;DiHR=eW zV?_yp5kop}^GRPqFRF+xb2#?EadX1}jU~)x0 z$T##LA?q%Hu@W6jVHGcMaR^di;m5ac+_G=qymR9U?yRpICVxHg)qLMxz~}l|{mWTC zYGi(3q{HO@XXViL4)z=!?2^lai)xY1@wP+cu;VCHlVCjE@fckZ4-g zc_2)^)!=T+XWtTe=t3rz4XAoC!!VwcwEkuOLN5G+y!CH0W|+M!iNCmOU4SRRh`FBZ zWwS=&gL03+XUBas|9fvA#okQDIQ3|@N8t0xr9aO9VQwGA-nke1YWVckpAiuCcK!>1 C`5;UH literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ffdbf576e74d9d701ab1663640596287ae5e274 GIT binary patch literal 3994 zcmb7HUu+Y}8J}IR|HS#@IB}eihGs~B$XwV|1*(GsBnVML1OZ)WY26@e;~mHATkmdX z)(J*Vl}aZas8ox~0V zOFQz;|M})O-#7F7KL4h*HHsh&{`_6-@68DPi8uTds#i8|3ka(R1Btr#ZWpV@Oc3}T#Te6Ze7xwiqUiw>OnO~0)?c%O`|OIH0plsBlNNO z|IJrJ|3P}MFSAjCbZIV-ZX;28R1K?>{Uh5pXgRi-HopUv6=d^1Hx=r~_S?KH1b4Q) zx+?ew7LXnG#~W&xMk!JG3bq_2hD{Y6FHps@2*o**Vnx@nsjHX|l`T^qC0Hdn%^<3b&yuWCVg#ExtT9$1%$223jcLXl&QY_7 zFQ2(GF^pN6$(Ca0hjFo_+nS{le7S7rO@j?%J5Mx<0SoMt#=S#D4)+~-#WlI@>c_ZG97&&(A_;K&@ zsq-3W00iZ<>vcuplA#i+mtBnf2FX!wl6g~8>*k>5tPZv>nu(nLr{Sn?QNbZNdB@$S=eTj zMxPz=>jl@5`7N&m=BZ0u6y6}a_0^TUwPQuwzmFEUR$fbLK$ZL*AJ>_+01o2yv_o>@ z^)a;VG#14j^LEq6E|@FZ3|tZC(PE$ypdZ-VuJ#;lcl^{r{qW}q&ip1ULG?I|L z&!6+SUik<@l8;63O`#hTS2#bLKmv1|T+EWq854Ml0UIgqQ2mkf#|u2Plk4E6Y1A}| z@Q!3BJneEAa{{xP;Yi%m&?eaMMi_gPkcw0OA{^0Vj>O%MBNf2uQEpTxWKnQq*PV!A z(qa|}%?a0~I|1+&PLNr;W;-i3ioaqaKstzYBHAV0aIb89q=o(obi|nsKsfm z_tY^)If#s

        >#j03)MNPDB}gWGBKq4A|0X&zZod8E9uqwgSBA#OrbzU5wu+?(ref zcCHBS8UG7N&7y~4nhYP~G0_tGa{pV);U%9Y+;nU8Cy$^b;hfl2~ zPA^^DilC0fO80X2dVF6kzVFk4hld^V;|Ji@>F&3=x-Cp>K*He{k6pYXZ&~IZ^1xU z$3_(O;16RP-DuCDtv(d{=33j4YU|M_!N$;=QhDtKufF9x< zZ$ZYmn*AF}5AbfDo##W-kS(DJcc+rKoi6+%5< zU#TotRwvfF55ql=L*>%JM=2%(nP(xhwdlrWX* zcA9upV4J4SJnSx5k2LJE1pxu&@F+L0lLVHMx81y))is&_J8**vr}x!CHwNHA5iV<4olsS|)e z!wn+b$LcBz{-6Y1%5a04Z+MSAa?I`aP0CJHhC)P}9x9^=NM`+PfabwJ5GO?W;-yyLGR|SC6a@9;ppNe!Mn#ygC4( z$~zljsY|S)_{%7gnxB1b@4fkZ!&RvpgeQmYes8_&V6E$5b?EKtiHo0gO>G7PdqRKc znz}i*5kO7Ncfz;AcY{A^d)77el8->-^Rgu&B=5d`@7!wV{qwcXgBu9iPX;%6u_5;e jryfBaij8kI3$aJjTL_AOeDwnXRx|z-e;Mr=6{LRwH2lo} literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec3d22c1d11169aaa98a9a240a133e1d5ab442d3 GIT binary patch literal 7330 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 KPcbnz^uGanTQ~gx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a699d386a81b6cb26e80421dba50d03655b70de6 GIT binary patch literal 1165 zcmZ8f&2JM&6rb5I+Z()2Tm^x+EO8E9q--RLB9#CYjf{wdQj|Dtw6e6UcgM-Xera}{ z;1z9s=mEsVa3M#IphzfxMy2+E1yZd&Rcd?4&1%Yp6K^(#hK#iDtueIoRPm>~jW(naz8=FBk&Yf+0GhArX!g9I4Hn zg&b0J3RgfoMWb{AFXgyQ#5QNhCt?$M?36Ka0xvV1$V5t+p2%g1N#m5GK-CHYWla;)LQc7#GRBeg(lH1|DUW)oZ)N2T<5(up zQ#Z;KWBK+mRO82~oB4f5(xREtxW0OfmI;C7lT4x{>CnK&>_^6j2hG026%fx*@+tNJ z?Tu{*vz^>!tP^K%?Ei=#;N;`h(Ke#E%XN88NWWgqE2<6Jfnm1QJFJg8svE18YKKAW zI)oBOwZIQli`rZ6Hc{I!ef@wHZ`{y$%I?iXFWezCt6pDSy1D#){n)>094#>h4||B= zB_dUQ?<`$zMl{@{mhZd4W^*SD?a=oLwTbBl+ayRr+HJNh`yL6LCivUUTW+fv!!qY0 zK&?#@HzPNi2X;beV0rVM#P#BN)*5>lu^x4^iW{5bo=p~@Q&9aheDRkcdgyPt+Q0Nz z-<=xB=l+n-59IT2Y$(wD_;yJCJ%v&RGjvBI+8>@wObn@P|s)oV=C|Y1JPwVSpWb4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32996bcecc60d9f56ffe66474fb960d8a31dfe55 GIT binary patch literal 2420 zcmb7G-ER{|5Z}G?*=Jt@Nn^)ALUV=C#N>;XhpK@>-87|;G*kpoNnN>@^E$c2_MLXm z1S3aEt4h!}s!EVZl>il~sgU>s`j)=-#b6}DQK?krrEf0D1EMdTJ^KO?IiGQ{yyV&`d2=LQ}LAc*j-^#i+xZ0s%Et_c?~3t?n)8<#x&IEvwm@1Al`Wa?DL znAFwtgfj4`GMgH?sb1Bj>X?}$s*zT6rmf}~Xsf3EaKCnUQ?j-xS>2S>&0HEpr)}$1 zyI>LaGg{+!dH&_lV8Wv26xFg>I65(Bn!1_I5~`D=kvmUvwn+<#Nll+6xl{t?=M$sG zWP%ws>9atqO%ax`3~K-fO9{5EDUS`JyE*KO6;C; z;(p)9<-QXo-wDdmQ5RrWMZE+hQHkr4{Fr_AS z0w>3-Lg=iP$yb#z(P^5><&zwl-kltrbOJTNF`f=pRjC3a4S0;t7y-6`)*FzlTq=H5 zyfSw$@cQcZmWm)t;osYKUmsi=EWLTC+;+Gm?^spZO3L2VmgwWiz6X(>yOEx9r0?6% zWqkRaii{ds7RH{f2T)_%565mzl#~NcksyWtgtH_VpR-o*bTt|m(VZ4xD`GglOI+EB zf!D!@*Ay2%yCB`yP!MVgR1q`}5+r;BB4Aacl&}E|3^sU1_Euhu00T6$k@y$-qLAd_ za7jQ#!2{2{Xg7QMqG-S7$+v3|X3a%$CgN#dj4y#yEQ&7hHbDO>!~m8XK;Lq81GKNM z0zBXQNXumSlmCDC)ZN0;Px-~h97$ukVZ;>2U)4Lx@vLQ1y9zSj(1)X=lxGg=10ZaQ z*mWqQJO+-eC-rHKCM_pG3FF5*ApPLmdt5c z!k|JCs&c*ZQjKIB3IN+0Zh2ZMXC3gdAAv2PieHq%kK{;Y4~(nrd#;ZxjV$}h?R_PA zXGNAk*Ky!M$MD^b;gZ~5*@imz|8(@`(UNb+eV_U;+Eb49EsQ)-B3EW_9lWn}t+u}L zptbvMYxi=r-1^pK<+0LQ^0hu&KZa35^eMtp_#vQKgz?|?PQd#nRR}fgdWzs8|M*c; zxDo*AIXejV{Mr{+(WU1209tB@A3-Z>Fy1S!^kB{hg7HJ*${^Rr6p%fpQNmgQ)g2sc&AP5D%``*EH4Ut&f3@_!EeZtM&&00PF3Q1B57{ekvW`~n`qi_o>nxLm*Zz;1KS034=;Bn_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e4fd3ab4a978205c27549e0419b48724b0fad9b GIT binary patch literal 7604 zcmbVRYfv0lcE0_Z7t9PWyfIP>u%wZANJ5frgk&QDf|Z5W66-C^B9EHs1_tJVZ#P1) zLq+RSB`7PGkSke@@~}|KiBNfy#Z{?_etPpOsr+G#z2IJN#ar2`B>zUnTlTv0Bj?=i z8O^Y)ok~;O_xpb5JLlZ_H?P-2;A{Se3(;7BkpI9;?vw1q)=waDm#9SLVkCqyALHVD zh>r^)Aufi*xD=A&j*uhn3_0Vjkc-1MLd+faggo(*P)WQrRLaW4m^bbV`8cBS)B$az z7>WBseyDSV%EpQ6{2MM*&Xco5b=@GU`#s)TL8yY2d7!LBt9VbaO9OLUu=Kw%GZb{1 z-r-B%?F*k7=sR<6aOkY*Ivq_YbZ+n!Q|ygK4AV7eXjB=EX{PvcREPXf@`7f}(1huF zW!i`)6G|*7n56@XK5;&(#}y+oVV2lAJ(?Id%Lfy>p~PYeHtwS|NrRkOLN!GVMX60w$Vg-$!O^*@lfOEePVR1)GjtY923l$NVLoJ;jvv%m~xFhe=iRHzkNz@9Mx`AW4C$73s~ zf_xRM6IbcT^@N#3wHj)w*{r-;1L+#oq1CdysMbQh&R%UDr0eJS;4`KJ4^PwQl^%JP zD$~;%m5m9-kVj{tF;$o2GchAN9n<6q)=Y+)WFn%;NqYmT$M+L zZz_?TO|*?Cld61GiOp!bhZPT*4r>t8K^X`lHqzLkIUq!gZLL6Xmqf_|pW=RWI>k+L ztiCA7opdj`+(F0)jI$sth=z?(LQ>*;cCTJ?TZ-`GB*I^=fL2mUn#@U9!HBu>?(nxN zMQ97{_>|BMEp8na38YClKlU6K;W^f3mIV3vB-=3jK?(^(ZbQhRV`s8>DImeoj=UTl9noPGZPQSyzzRpE zqthMG8sr^>x?{$O#`F&By4$DcU~NzrHNxR}zlFE~xSplZ>%SyH}M z(zw~!e1GKL$UCp!aW4r=!@uc#;c?49cCYV#>HY2%Wtn^EeBk_B_iA@$_e)F8wD5Lm zRwBDvvkp=xFN$w@fA_gS3wBb65hq~>XbZ;wwYz}S!-xr?3HzlOVP9t39D0izWB^E%r z+Jf@V?Nb7h%vGXeF9{%ByA9GOL{cCsd`?s@0;qGqe#8w0CDRiH5(fSSfv2FSi0KQWBU%n`8Hpur+ z-8;3>(2;5A_(j9vo97nKELCs%E7C3Z+wQex{QEY`YCmZXuGjQEIG$EkUR`bZr?&Uo zJ`gfTdOvLI{R?jSc&4Tg`UrnIkad!0j(h<#RWC(;{KGX@JwmCrpVLcWO+T-!KFvFR zeo%xkl7|aaAkG++UV}s-lvM5pfMhZcC#bf+Z{nfeJVc&ePLLleniA323IAJ1AUH=j zm^MW&gYH}43Xz-};3wQ&jw83qMKVYJUYO-*3v>hRDa5oykT?1EL#ET_8XZ?F%ho-) zyT`SJc5RxTn%`^Rl+`R8NzNpU_U>3RqQvx5?fG^{n>vExzsOhD$y!B!rlW89?4NZm z&ED;X+ z;8a1myY z;=7cP!)#s&H-Zx8fGq(e3u20&L9s1nJo1E}67p~v>G zV7$F~j&`IRlU3VWKIQYBaZ3$q2Tb*)B)N3raO31$#7!-!cx zUGh+{)RKAxrRl__#iFAWx!?4>hBhO!^-cHi+_aUXNWTEYUJD%foN&0B>V0bmPCkx4{=wS*!S(9ztd)HyD`3UfdI{|2LG9^I z{+~N{ohg?nZjt&hKs*-F0unjXdhL)X)OtH>ycCzC#y4&C!&5{ygTf=;x;A#A1qz7v zK#O^=eFxSRUxFeXWfp7%Uw!)M{gd}juC%QCI@Vkr7Kw>t(U?}W);y^rjiRdD$*(9d zi?|#K}#EIwY zc7!QbjbL{))c~ZWq^xqozdz&O|I>!m;q_qGy8pzQ>x6x3(~2=sbZU9xpMdT~H_WN| z+dPK88re}D=4mOy!^;EwOy9(^0TW#N@P=pyy!j zoF;r3(v+P?ktW=BAh?e|a3ENv!XP?w3E;VD)Y8DwyWXUF8?h+TY270LL?TNMOO& z!Le{)v+=;@o!cx4B{7F=U0_f!qLLK~{<&>U4EF&GMiUeiQHCQN*4}_k=9!db zb!>*i{JysZw}}d7S$gPu;LG^i*Iezte~0MYvTgq{Bnr2!ayxO9zR8xguw~PS zcW|wK2<`OeAYiUlmWVYKzi#cx)b39U=^y;EsV(gQfvc*$J8)+p9a%n}zPwR+@Ux~i zENuOxwa0e7_6511M0;_8$Xc`(gS;zGcMuR1q#^;a3a&v%{Uij4p1@|Q|MtMmflte- zpWwniYd!R{^N-GNw7!^Weet8#o-GLqw}@C?u_ZXXzAeF3=E)M5+rv9yyIUQ-Iehim;&g{KWW?B2r9gbk5LpOAVv-K~cDw7NXz9)CCN_2Z8CZ6g~Yu zmV_aAM6BJ&SP;ksxD_29=*bQ8gcl^&6OTud)7MtSm5Zw_tNQ!FmDe--;VJ86mO#b7 zRBmCkRa-7KWcLz>FUxb%SuPy`(+%P+Azzer@Y1Q3K$bxCxS2&Cv}|E6>#CCKSDs(( zd-P(KK=QG%g;BPhlMbbiE(^=wUoOowv}Iw$L#qe2Fv>a{Qup$;EP-gXcMGFz8801P z)^Xs&D=-2?S(hYLEmtl_Ryvm_9_-2z$YN`VvOZpFPP6%&vo1mENcU$6M9a_gM#ynW+) zymOIU<3cWA0k`P|-voa|u*7Qq19;$0(kX=*Xk$sr+!yeHW^_$O=R6_LYWqNQ#;snm zVmU0>Qjw|l#!Qs5XD`dD8#H8iBb}ZBpfCljL=1qU)y3Ay1%23aIrC1y0n7PKxHb=R zfOajSv0p=EeIhxF55rLd--c1K!|JH*O;LnV5wGES33y&8vVYD2|3YkiH@Osf3xwe5 zqvbe>azD*mwdi7kNwKFlnb?Pq)MNI`#FZ;3+M0gliaa%|(DC*l$DWag;IT&1XFzh8 zEScW^p4VQvFgV;79_YC^U~3)I9S%ogimr#lmhQPuWmpdDF<)JD9r^d)ThM?Rr|?z; z&u(ttO=rec`)=bZzb1FCxoSUl9ktMM8b|sTKLpzpYN5i1TznM$rZ=~oCdv6G0!2@V zCNOvjg8>K%RjTEgRBqcAyXCjBDVpx+pwy*X{%Rpp-?mZzT&DiH_4*gqeO+s=F19N; zIK0)NpqpNSm?{{IVi3WA(H2q}RWU#^GQIX0N3<9iEpR=|OaXEsFIlHOg-tQI0snds zg0GNwB+2z#pC}#6mU7aGZ5(i7^}v_F0hSxU`UWd$H}o_e#@sX@k|NA39%Rcwp0t=1 zEn`NxW-a^#(4PMZpgoUj-E#8SX`&auy&?OppdG|6!kixKj`7${@5SK@uMC}K5bL{W z@hRI~6eq>kDz;{ntV{N7MrcisCrL>j7U5&B+el3kc^y6l{Jf#kYtj0Yf}|_ceZw_wsyB0F{AbcYN=UQZTw$j$>rIp zef_?3`=v&nP3=+jd4A_{&-vcx=s#9eI0S^wzZeY<^$Eg%qe4E|a+%d7Nf2%dilB%Q z!EdCZU*u)UFY(lrOJ%>z%Vxisrxw2jsT8qBZGM|beN7R2)ZusVyd06DPQR1q%@J3$ z!e0?}``yt>e`VC;_e3}OH$|)bRncmHHHWc8YNECN+Gw4>E?V!ek2d%lqK*E>Xp_H* zw_794(H4IT&)Xuc(Kde@&)XyIQLo?2^NvVIbhCdm&pRWX(Jp^iwAa*z9 zL-CjvkEpskmoXqUeN(PHs>T$Ib&f!adFrjZjPj_eO-C@tXgGBKP*6)?WtAh-k;n_- ziSrTsXo;fkq~;fbF(tx_)-iP=s>TS|JeHV=s6I)zo*o)Kcw%fww@;{vRWu0VT|mo~iIupEiANip4{! zro~yP^yG4AEv$M_ds9#aVgn$3(QlfOd?vl&Ad6p6V`B*=KFt>qj!g_P7H7#54llxJ zFs!MHH$3h&08fUeRNn55heFd#^Nz=vH*sF|YJ3DFObtf8m(GVHsyBjZPrx>v;gA zi9+2Z7Y8Lx>swvxTc|WHT@=OypK0XO5zta)*|{>JP~8#M!Z9rojD=L)3LGVj(9J4i zvAAv-8Xh@4cw9FRog6+n14kEQmWOl>=vl27up(M_@GD86N6B$P*Wj4RN_($TFxKy*wHaTtk0d!Az!45}M^ zk{3C74SGXy;P>T(HyVrq=NZvp=)Ct*I1=%Og43GH$rMQM1*K0-C%lQc_nhhtgWsW_ z!U;JTo8f~IR20mFXveEY!wCWaLWC7`NaX3+q*sD-fvjkRAaPufHM$0XI0;pEmNfW8 zwi7$4(HZ3M!(lX22eud0`>1^c(LV{lydtc*g|^=1*1oGR-jkai$nF)n>8{+g5K7A( zKa-oXlF7W~zOCX@Th)rK?XInDu`_M!{<*E~mv1@NSNu<{8AHC=JGeusvEkTL$xYS)uvcgD>N1tWUgJQP#u$XeAIOjhmm<-_f?nQ zH7{Hi{T2AgO1)~BA2RswkvNOu3ssif)ctC2ceJ-#Io18b{_d~u?;bk>(Nqyslt3a3 z>`4TpQ@R{v6B^r(d34K#OT4fZg(9^QM$oob;aE4jP1%{LdV1A+NlH1*ub5DG)!H@W#)nGa9FXBI0fHl~YZhqcGC` zsUT#Icis2w$N1;s@d%MkI0T%J704+Pj)7RT^YQ73LWDKN)ba3TRVj=|tGg6VoToK} znU|@dI8(M_N%_q(=!(Ebd?sVh%-S@RACjBlSU3>~_{_SjsgZHs%AUohu;&oz_JARp z0s)OSlg7AWAl=tcOg2Axe0}*Lj{`t!M+BPRj^%F(*ZLWxYw zF>elAI%Yu*7Q5!glx9pmImaAnKSsH@<_G}PWI%{BIA!Di|7eZ>RRg{1w=;ONNk$kF}Yq;+U?^u*|XFHX;jNk}Kst+{61 z!B?XZX0RrF1>`D00|O4A#12w)2$4qHitjL_>n7s7ITlU)mL-y18yxZzP`^ndJ%b2` zP4f1gGdBY_0(YHVnd;h%vu4HFo_4n1^X|Ln9LQRPnz{`5)0vyE-FWS;b91J;?NMce zfd|lj2z}RSKcqMDvws?=MPyt&`)d{uE>3t>yq!DAIcZkd=*(v&;6gzc!ic$$*NWy$ zv!+>zES5QFv2$Pu8|g=^2KCN--(p&v|NAg<|5!qQS&h?B&c z%EGKPN&LGkD5m_^9Twg;holK83a?>T=FGG5teMt)Lwd_Dqjt`mhr~WeW2g~%?Ii&? z`#S|(I~0sW44#D}jwwOL#k9eHcX-c1h;#97Ff=cK^GIES%7wuU26b)*@}GI3yE91b zocQO$+so;>h{J3M3)V&NDW9D^Pg#pWD(poRI7%8k%3)NW0vqGfO_wL*VW zllrU%E+3OX-%;<(e@pp|T-mYxp0Zn}pUeQ6v2R zx035%z0K!lZ748ez|4zCuU6FYAS_HSL<6}krw+PIl7|sP*G;gqbQ263<1mg;o&9)x zVw6)QqrK8Aaxx*LMj|k$L}Oox{024H4;vp_^ti|kzr4O zP32e_stN&Y2O_OJ%t}S}RW$lGVso=bG_;&Y?p5A%$ z{hG%4!w;$&7djW^_nq%K(@oo#t9IOV?a0(OzkOo<1T}U2Vehi5{jn9?f0sgXp(~N1nE2xh>f5p=N__)7ePpj)Gox$_L!H+V zP#yaZMF1DO+ zQMVl%diBhS(Zgf9#qho9wpbkW6oIdWZ{9jSM(Q#+g0OlTQJIQnGE}r8kAM{h73+h7 zxeM&UUjhn^5pL(w59Hg#9}!@U2|n}4DL5A8ad-fkhDzP8#m5tYOK{{K@tN7{M%DTF zB`)EhCs3B_9)P6$R4{Q~cb+ftr^;Lb;i8Y9FssHOz={J%7^8?LG6bBATv2NvX_;)@ zXy*zB(DwkM?L-94A#e6PsA*d~a_5zw*4(QZ$<#Gx>RS*$XxIwzpLGiM#xDem-C^L> zG4x!g1`}TKJ)Qy~(JjoJR3xEUvDAS87a~FO0C_@7FAF6mP>!ZG=|$m9GMF}iJ`0I7 zXDS)fRCE+33XZ}=!6`Uy%F89q@ggj0D8;5fmh$KNrkE(GzO$x8LE+7}q^8B4|9oP_Ny>ObJyB)WAIQx!OF z%$#TFmKmsv@k_cTJQ0gC6_jj?UsTyR)yW|ipVG}5zrd(r1L)02TyaN)Zca>3f#eBg z7)efch9WN9$gg84rEX*XyyJv&O#>xgvo6oZbd+lMZPRIZwVE$}-P z?vTza9Ylfbw+OzHJ~dGMM6R;v*1Ri|D6>@ikjb@~Y}}ALP}3sdwMNhs{L~%Y^JYjW zSM~LM3;P!L-gEjMRJSgS|KP&A7e3f~uXH@VOvzpcPk3+SRgf`sc2$tO-?y ziuCWEZa>^0{G_4j@LtnT_K1kr@k7FH&JTZ%43|0BQ6p@mE9bcj@yRCPEI7=Z1fySK z&(E6JbD)MCwdBX3bR$i==zQ2nU&eJzUBa0k15SqmCuEK%-2vc)q{8vQeUKfct_*Sm zCwGyp4lnto^J*;bf+PZ*j?rZz`H9FT*Wyt%=YQ`T`HZ-y&kkd5M$>I{y%dhY-g_Oj zY#I?sbh?(~cP7Ri)$`Ogj|hVF0OdLEcT;W)MT3aSJ%9wB^lpgcCB*a()DsMo+s_uE zsr3gf@3wruZAn_%lxp05%{_0w{?ucaP*L}Zr#j=Qx#_y$TJdzGJsm$Bd*A<_Kkey% z;OSlr->JUm+52f#4|MC4YsaURHPuUquk1eDs-)--@iWZZ-xe}`JFmPjfByRA zMR{@TJ$t&oC+*(8Ebq+9RB;ZB4a~3D(H6T zmzT;u>t!??O4go$E6uuqd+d0?}QJF2yxn<~p7g_t$jmtGmtx zHI+VzN`|w^9EeY;F<1Zx(8s`QBA2{ddja`m`&aHsAMc$45VxneW>@vj?wbQQ25x@s z#@812taR>4ckWrP-h0os?*U=ywYlGWBV}td><&vgh7!+VH0Q>s_6O8L(SN~DBby7J zlq@cg+po`kDIj@Fk%0{awhkNe{A~3AT1sp+-~!$6;N^%6i-F(pOcpdZfaU^h5i4NG z?O}t<+p4?29=v>4M?Jd*vxbHoOQBJ|8j04k6hF{Nl{b1P zK%TR4(x-XBGZZrpCay(4NOYDotfkg4c5Q zT6h@3;zoY1@>JPc8wpylpL4EaU+?K+i#u#$e9L6(`RxHnjTli(^j ze=Z+s+w<2abp8hSpz#XMWCBSxZSakK1|IwZ?HVrYbJDP;@x}oBOIwz!eNeLs?ujQb z0ct_1fGQ%vh5~AlpecHYpGNW6`@HIZjl zFf(JLs5kNY(lJQME(?H#;-<(?z-}N|0J{aS<_k@juXNmkcqtAJSWn67H(-u1h6{pm zvY^5hM_A`>l@!ag2s72p%(K#*MX}CVV=&U@EVJ^Q73P}#BJTMWM@&SEO>rtNrQ((} zXII=xrQ$)(F@Z;ee+qM!nUtytF(yt3NlZ28ELkI+LRr|zYzE`6R%%N6ZLq6K?JY^E zOVs3t+sJTM>H*X6&wy#XWhxreN|VxjOIlZMQCe@Al(t(EZn7LoJGs7KxZ4#k<&+L( z^Ms^yDqXkm;9y;Qx6wW!8m%S0?Fw&$Lu3nY-HN_e^xekCwkSTOMd?wtqjtwFdDc4X zRC@6(eMbJ6QDdRB8W7@1a$TQWx8%g+eGKKnlipZ#x& z{uiPV-F$fH;LAso_I^dZ*dN35Ks*kShewW_Fzj41ag!dr*4f|R5ADCtQ1r`c;BtrD zy$(=r380wVIfci5g@Q9)LVP0;AfR(;ZYjEeC^jJuo zX?j(@Tzq_}+w%P9NV4bGO}t+C`lMe;+k9NnNV@Z1V+a>4|F0W!18xqz z8Jo-nQvi=oVmMVzuLE`@;3&WiTRc#*_NqK&u`cQC-j;J7__W+oxE})^PQET);MbsN z<=&K9<5DR=_xZ(lFvf1uQL?|G=&vXuc=#|#U4i$7Ub7l*Oxk(fY6v1tFTA*5j1+42 z*Tr7!Z>fSG6!(Ar9ToqcA~GM7=IO+E@6+tZ$mgcv9dsMX2CjG8)L1C4&~pT{qDF!< zyfgf&uhSSGQ1s^%{RJX?A77}=uo;<_bn?T%gG&XjX0CHtbt~kNMi0Rnl(0sIZ$Q0_ z7rB^$gc8U{W3)&;cV`TPMq~emDr6RqCydt-sPk1AX5Nozb`ryePiUARZHGpOPYoX$ zJkI_V6^ z0Iv$q0nhm-d%`gTh4RR)SL5kN*mz=G5Vp8l#3$q&*;U52s0wf9L+VcK0G?{l`&dn{ z%x$CbY)3VAK_dx9Dpo!iZ#^o&#-^wE+Od)BKLO~U@Y5P0uJMe+E!Z|)AAIv$59-@) z&fS>1=E~Tst_Od&4P_&L?swa%?Ts66tSc8_jrNuLt?Bx$*Ib_hboR#Vyz5g}^@_`z zc6k?DmR)^UhTw^6=w3REEAf6$WeG{-C9IrDb=z zWjCs}^Qz-wY2DVU$JG@L?lrH_+>1p6s<{eJ1b89S?R#vMd#WBg9nJ1+lhD?gY2C5( zO1gDl#=9-k=3Cm9ZhI=@-ILn)LaKc@)8TtuVQs0(RtarezXGs*uL0Frm8~lst}xcN zjQ8nO`!fdARz6lYjdeQRx+mksWEi<4)A2NBYOQ)a(AntDz9vvJFk zHMQ$dYAa4-=<%>LB-$NorlX?Sk{y)2W>EP?&}z-NE;BId2kIngbI-oytegTYI6csh(X)$JPrC@P-5&_lv_ z%y|7}Y*5)S(XbXWoG0c;JQR!=&rAP3ZP9lqqAL!);vk$T5Q2uM-0+z7Qv(TZI{Vzi zVB=nTFZJ6^&GsYtC!L%n8Xo%#)I3EIXV29e`JMiNn#mI7MvURHBj!|Q^6IwdjHmw3 zvtOW<)Fq9ya(IwM@xHL>zTmnqxbF+~_XYcX!Es;kJQO+}3M~(XrvEAouL#3wVfahg zDoS4ph`#U$;xiA0oezZ_4~1?2T^M*M^gR>~J{0;NRkX~%`gY)2V7a30isO@-)>PZh z<(ge7Vbhw$B-$2c)&wM3mqUC>Ts*bZo9=!(D^TIXIU`NI^ztgN03VQCD`HbxY3|mE5fz?wd~y%$HG4dKTA z#&A=AQ+Qqfx^Q!UbGW6yCG73@hS&G64{zw-z{+uiTElJqZ7l2zwTCzMZ)9OtXj6D| z|7I3;hqi>b_HPYu>)*!SOG4YjJNkF9aA{~~cvt@}7WRa8hdcT^Shy^-C;V9dV>~y+ zN#(!G_djmpWb?TR1NeDg-uE%Dz4bqVG+wD9_ueTt%Pn%(3VfEkukO9=|_0g@D_vgnICG19yZ|HqHf%gu)`{XAFd1;TlN_q@qS0%5J zUzB)^4#OYx^l|jmFI`}{_F)XP{y%}(0lg%`DBu9ANsu~GWcJ+G%a1PDEi_mKWh*zgSA z!_sM#`YdL|!66=H)fpIHfcFRGLpnsP(sRfYDJZia@6lXK*gQnZ&m(r2l}zmeL>IME zOQpeB8yP`*0XbgMb5PsP;9V(r{|4S;l22}95D=sn@gBzvE0Oko-*39ELBnG_^lr1Cg1-)!~AH@5pG(`BoX7X9QUz9FNLHJ{+?*wSVIfTchF*fe!8Eyeq z^8OrLLKu;krLcj$$hDTBY0w-UpCTw_LW%;~oq#sVWmrzRI$4OIrH2haSHm#!PO=`p zgdQsL#vD$)g0{x+_0=)nJN{Ebv>q?7IwXJG9|-wlF}&D@{YpIO44lZU8j&OsK{YCLakrcH4+R-U1+Bqkq$?r=c!$?f-f$g?}Dtvkk{v^~P(eBodOu3i+%wVgiFv;V~D zUIZ~1L-8xHx$e8YgZ>Lk#P z4Ev;@qMH4&^Qs*mgK+=?BNkP{{Mo>R}~1q&nqDY($Y+@+tr;dO`O2N8)FFgGw~)8&N{)^1xX+aNdUsbvU5A3=pc= z9gPeIhmc(=4qTP*0}7UL=$afKQ6d42@M*3M9#O*k58zzk;#w@+bNULIi=a45;hPqI zL=Gx{$rHC55eAi@6~UN0laFeH!7Cbtz@OlZk|x37#oflI_rT*#aBzjV$A~lN4`MCf zv-NUbYtOi;y?tC54i1asR*@hsjyuGb;j#GHXhc+buh*`cqA^uqm>`^s1|zBsh(Lp= z+I>FESlQ=OZT^86rBGI*DrGGk!fKT28$LfoBO4>$O8k|tyW<5Kbj2SAt`5C08jS{k z>#`D%fjSp3Pom1$3xsc&A}`?m!VAZO124pYZEeGd1@^~YK(QNVdO{RFX6aJE>c-66-wEUQYC#RYhzm2sC1%GWjCBfXe}Uu`f>jboGYB8 z0I`cv(LA#A+!)`$#VJ2~8ad_3Nq&Mqhh6Z}C!UKtm!qHgH0O7sVGWPW$#&rRTohtC z`PaGUFySWoSNJhLAJSq*`BCno`8jTs_nOAVXsn&6TzlAmUM8X@js`&|N8;jv1J54m z?Q8GxT9sWWSG5}{RNIMOZ5g-7iV}&cRxPROIM8#V@4)eseb0GK45}(G#|RTdkqxr4 z5n<*GA`t6=GsR^Ei>2a@-FeA1<4WxRv3RVecH>g8P0(Ye8VZBOSq z^AFcq5DXwb_vEP7zef}s-rT2R!&`Kb{I!E8@x*F=tW(2DEN7DG0;g0K40(}(qs8re zre37(<$y%FMK4}zG%sFega*w(Ei;cn9usndY3X6p4ucBbE9?(~@xt;kZfXmR+r%~y ztl+R}hU0ax0o6vxKHvu>q?OMc8^fCDSB5TteYq$HM&gW>EbWYgn;jU5%i5Sbh%wZH z&Ld#AF0wF|Mu8T=f+?-EqqWQ#Mj+;cgV8qGEG2h5<(EchMsIu8WISs=G=F5jW}hv; z=9>4kP74bzPr9-t<7&CHY{iwxz&q47xzO4Pp+$~v)=r}wLDy9KRyoO56|6wphjh}cy!q3 zAH+qRmFttPqi zQ(OHP_R>owGbM>Ys^*XE-u&CnKeBINOM`0hVLrqbQ4dta5fgl$nsWsZyUzDqhohXu zdm;J{;9Vi-JM@8ue~McW?5yBlSK{lOa*nc|CnrRCiIC{Mri=M;Xbxwo5K3>x-~F?A`w9yiZ_u!F)Y&D^q%a}mF}&C!HjY|iTNW*!MKF7U ze`Gm;cOFL_oQd!}*EU*o^H@G%%F|0DPs}=DdI9~Ov`m^NEy#^c1Zp)ITNHiS&e8N7 zZOtu|pvMn=eS42Vd5eC1()j8%`624nIMNrj8S$dXrV_Y0HYbSnYsRiKAUBJCk+vV; zy=c#<^H-tZd09kOv2E~0@L7ykTQ43NG!lc6Q)IssjfBR)@5vD{7;nZpu3(2D4uP#Q)qJy%OEBHlyb~6qU<$*&D4ngn`5(C%<(?&+yROy{* zX>V^Qj+uzV;|7sNa6C1NK;JShe1S-24p7d z0RIv}7Pj0eQ3?@tQxqzO_r+*jiK-ZMMWT=7{0{zNb8xU~iGszW@1c^7@3h^nXwFnL zPusFi&RzL#-<30$&wxM43QkA$9e3%a!!w5yeaW34_I-5b+L_GCEw|iTvreI;`m?gC zMBls4g|cN2?3{a9;_Qbdw_NQDE7s1GPV>{d5>I_5IHnsDLgMU?g*Cr?;6>p-<4hLM zpV&*Y7WjYhU^Q2@63ZSdDr<)S7Y{sKSq-8b<)69B5alTURcsp?{rZ|N8~2ZzyPCKk zuCjM6<9=jwbXA&vRKb(G%+XbE{?S^V+$KlYX7i6W@o*P0!2}mZE1qDqBEPnMWgZCy zXiw1`L_?Q6c}CixJH$Jkb1X@Q*Zdx_*jj0b1Rl}m9EX)Je;h%hZlyuuC%C+z;j7hY zFh-ghW?L5?w$*CkQn1%GG+GZY&@zc_@i5s^6YRuPOg?M#DlOzRLP zD+mE7L|{~6lM3@@I2wxuA^dAsdGP1jG||~P+D1WCCo7Mma@C2cqr_vx(yLa85l{yB zJZygt;w#oH+WHhOFYEBGkn_*!!yp`NxvU&;8jSdD*UF4*<@;S99J+ewgA-Rz%b8uhjWK*vN43?~3~5*($1|aF0e=h!{}lpIBl6&@cyLO1)1IQ3 zMXTJBhxnpJW4mL*B=Jn*fD+?5T*R6HY^R5f-QPq_{M$Q>+JOhA@fQv<*`7#SETVtJ zdy{0sFM{us10*b>(Pm_JWSAw0? z4I!-ZMF@an81=Yf@K&$ltI9`I2T30zB%)oyTQyU5a{ev;V*PMH1Ff9HIn}vPRylR# zj?;aqd8YYN`%HVXGC6j2%`K;Q!S0xTYQ{RvFI3gM-;ngbx9;+>X~zQ#=PFs8_Qy^y z%5r-WD`xhkg<5UsZIGYFAPEDT$%uBWI36U>l&>Sygh0|{a0BOZqm9D!$DkPdxijEU zhazQOi#rIq75jedwJoByk7q4hWfxC# z*)u(ww9UK3v>(#8x@O7rtdGLhK!d%4;5IzMLi3ghce(PjaB ziOvs!v_bS0j0|ILfN21?5gi3%qPhvZJturedQLvwH@>~cNHgk>iSk7V&Eh1BYAj4e z43Bq@2o(nyi)f@n>@lXrTj-hcHXO(+3?2cbkcOgw6k?O3N$4X{@X=_H@-7m5Mu})& zJH>rrb9`(3wefGg^4cqj$Sqsbozj|x((apwZthOIkKZ?&JkBgYjB$YZm_pL3xROCHci)4AMUGygHq zcN_D`7;m17pk=+>+k;r`p6HC7XS7S7*Ccoa;|UzUAcw|UnUJY~wiyc=7QEOn$dMcy z-}_v2M9IC2EibQCCcPq!cqAG(B(#i|G!P({w?lk+a@^D^dTngbR0|tGOg-?q!>Wal z3VN+!=;-3ARnzt;9q8hs32Dz2S2!iv#AVK(AVbU#XNtS)blrg<(ss)(-l<%kta)ee zw0)s+<(0jc_s&-~+^+OyD!ucS8xZNLOzzCM>hHMAvnIa0`j4wuUVbKdI3;})ycV3Z z&9B=vU%mV17IR4{ILoTK=@Z#%&gFi1mQsrt_7Ex-m%A6o9Z)NNypG0(xDI`y6^=|h zcKw9t%HJaA9XN$^!a?*%n+@N?r!0N0f`i#0R3;AH66)@_$`Uni?M(|Seod>1cs;t+ z#n$%xEMPrZYxKk~4nqq&8db2ZDApa-2HHzW9_o^tx@2TlQfS%#z+a36c!j;HxU_F( zUvlTXt065ku&$|Quy2bvW&wHFsE~-`3URK5lofIG7_*c~1+m5`{1|AXWM(0uK&t^= z$9twiis`kEKgeq|2$#VD`$cR5SuxEhvYCnwa<0-#-Wl&(8>YG!Y|eD)mW*x7f~Rc3;ZB!r&p5Ut z{6*>V^vaEM=GoEoikE$Nz@i<7dWM;1Lo&ZfJ z6BJ8UrWPyDZ%qi5D3w8!Ayl^MY0WIHBUc)g!@d>fF34x6d|pRS@QE&uE;xPS(i6cy z1B#EE+cyu6o5kZ@!7{Lk2%YbOs+IK#qCzv~AYe&*=K@$N>+#MUH|9l*_T&(V+1%4F ze`>2;sHjP&r-k8GY zmbATvK39Fa&d6SwE^kWpraj&?@zZCJm=#3i99OQ95|a zTd@a=Z0hYJb|b`ObzNH-z+tqkm}nbi>hk_p!`|qp9wR1F&Z-}mtii{r z18MiM&kjC0?>_oN=|*h2_tLX7&%PUYzu^P#Rd1?ywrPIZrumZ1w@Y?qN_PFYq~oSU zIgUc(l4zQKEG^Xh`Oj>ed&{4z?qm2n8Y@H7zA1LC5q@9nY7~B0yRXYDEFyANBw%w5 z)~mz=;8lByt@g#Z+&l*mgKF~;`E#?+s0EUvT(D@3xjkMk84==#<{(z>N67~Mrs@`! z&VQ;KW@r{a(d{EKa6VY?X}44$KnO%5aR^*#AsrrrUhW*WNbT`xI7G|AjRW*38F)H0(T?c!-!g!H;O4lyx|q8M)q&Yl&gB?=4U%@wth zwiQcY!dj*=BnQV!7k}&F3}o{kxZWv1LYMUR^g(!0q+VqO*FMN zCFz4QUE+4>@tMbyRkvKL7d%yWu-_bgZIt$#?+#oUx;#W$@zl1oclZ3Vj$5`p3!cg^ zNithIziitr8~Bk*Ok8~xq!y_HQJzJT7Mhz4_`AOs&QXrX9CdsNC!601(yo$b`@R?mg3%&pcHy99Sr={I)CWz{fvlqOaFiuHyUDGHm&xA(-mL#=@Z>N_+@3jC27i zzai-Y^Up(=hgND&QBqWdfaHlE45ijQB7ad*_A%N{&u?ax$2MO*Y)0jGB#aJW-w}j` z6-b0W~*6bhL95GJxw#h z7n*6prB`QOO~&Uvjnl#%$S-rk@8te@*V?qOmQA8X3mahu!;arZpm1|rY;5!6_yU-_ zNha1Vw%8erRxyzdEG+f0R7xhmT1w_xZo)*+!E^*8ND2tDJ(@5PV+Pi%^%$uU4RasE z+_hDNX$QC``ZPEwwnJZl&0}<2pwLhM@~{5tuOK*69T3n2F(eoSFKW!DHUK>%CpvK6<>>N92ascrLREw3G!+CSYuY6OVX-k7*; ztIOEHx8JfgE|gXzwj{Pr2a^pm(P=YiSfV>|YI=+*4ic5qyVF9IM$*jD5R@Acd34dN z6;K-+mse2t*J3zwaAsp=nlw+ClpPahW!od>U$Oa{6M)95^SiEMs`I=e0)iYD`oNxZ zMO0RW!f2#5l73}--zB)H^{*EFt68MDFU=L43lz3-4CJ5Lz7Yq=o`;p_v>+HbsGCf; zcs2af6yc=ChB}0ncYi>Ej!Tr}3qdR$SP%+qmJ~9mP+lkJ2sxytQU%hNt4>XCj#W3N zJc($?eCH|2Etcdg)(Qv^NX1NOL0q|2N z%gV@_%#LzW7ayNFo^1TFdksYN<<(R1UqVR#kV>}#ZTivj>aI=Pk2X2F9y9-F4-a<{ z1Hwvyg|RBndQNjKVu#7^{!d7FKGpLfJaM&jNjNwA2(R)Ffz#8+TKSNj< zewY6}>vzG-jA;f(Fp0BWkR|otkjlDe9JwCe)j%hL|x%zjt+$Oo1VrYMp=;f#}F%9Bwof6CUH1C zWPVdHP`KYJ+a!~0$8jN{Al5Nvft0YM7Y9B3;nNDvx}Xy-GF$Os&y6@`I|^O2E|5@# ztqb+65oA(iR6^_Lgo#*j?IEQGGs%KX>%Slhr+UnRP>h9DGpuJ8t#&v+LT5a*ddF8R zYEyf`r%8fYHHw?!{-m`0Eg5TDZPT>*Z4b2N)6Rz(3?$bYtjYW#UDjH+$SpS5M&nId zgRyD{qNF{(4jwxuhXxCGBmWJhjW1i=W+VMKslio90ELIAQZwGX?P^Ak=Op+=<!i>=a=tJeW^2}sw{LO_hUAK$fIl`c!(4B3Nfw(J-K3r=;j$mujKrO99l8dz=V)@OS?Y z;S|ogyvPkEBnHBBh2lVihUR?2NIZjl5W9m9Atoivk}u1EDKGMQ+~up`zE zjtK`MBVh)8%rrp?24E{Jw?r>|s*3e^%1D8htw(g|JQ-jw*|7Q3zD@cb|wnq{RFbP~Rb-B>jZH!Qf#q}hSk9RwB{Z!=@PwY7qs<`Vs4M2=$#Ft))|T^rSg6)32QP*lD{ z<)2siGa9^2iW!hl1Of*kiO#jC?g2V`=hKQ)9Qgd(lw>QCu$`~nJvD*lWZDJo#I*F< z%XiBw65A5%lKk|`;GRn>rk_b{PV^-Xrd=yRtQpd)R;@IcV4Z|=zKI&!zND)CI>aI!P83icMIRnyNV zdXvkN_VlB6iDYe1NH6kSIFtrDCBXSS0m+s;#rA@WMKQ%VH&7CyRZAYWGvvp&IEfY3 zIXIGiEyl@W(8u&9SgBS(FcchsHr)?uq1y4Pho}r9m<(^RL!@y~&2;q9%2G&+S4}sI zG>~~Y63^lqs)w8@#r>w9$^IGZ#{7BUc0mf?gB zmAT}REK71hSrZYkD@RV4ujNLy*twu$6d!6Cw3!~-eZIElYm|`Nd16%|18DS_jlOk! zn2r8P8b4-~M(SGK{Frcoj;(_K*3>j)H_Q%H8dOYY)-~LTb%-t6L~0dVNOnWx-wL{> zsph@<88M|4ow;u6>0$cY9yXD^7SfN<5nOF|SAir-B^=c@5_xGP8kez^V<;q0gH+S- zs47qui+6JBGFC>xSzCQ#izw<7{Keh{5J4T?I7XIOm$5Bh@Kh%z(w>I2y@6~lYOg$g z`SDa`%0FM(^4c-%_tq^eubb-9DJaB=Rm-n*T<*XEvw6OgP+ErcHNYowYw%pXf-tR;7hizXo5w zizXMR6$~S_b)U(Qv?U2gPryDy8E695t^JLt39z5I;rAd}0-5ze%du_}}DvMrkiea+gZem$Ogw*P}=tEOWpqSIsL5uG>-+Ad+E5Y^@22cixBYFRSz+db|hLMo@i#z59=hr+A9%bra z#$7kvm)He~7_H&e(jfb+gTJ7Sr#m0CTyy( zkt#;yK1S*E5IHNlT;Y^2ncx&(wh&uP5N0Z-(;l=;3XkYT5e@f*kZYl3!V;&gEqlP_ z<(30RKF$79=n5`t&_K%6*RaW9lR`&+HW9Gy>A1cW{F;I-Cz^mHmgHYFq4fM3JtmB2 zf-#2OOzo_l4IYH73)3mYZe$=q1`~B?Cx)RA(+V2Z3u9SW38aRD3?`ROn^U<{AUZ)8 zjib|$uowzODlyjyNLbK{l!fT07${=$ekO}YB8!{8a4xBIuhne*sODRjInd| zFjl#bjz4>y1+$L$3~jZ@v3I)44F;bIF3K2G{6ln?gz7}fk%*R-9X+7GBuUu+l&!K^Ij+!fk7AZEa} zRI+v8v&x3l{*R7cJ33#vY3kVBie*YVTgj!zsnw*8Baf6{R?{%oCqr8a8%2i(brIioz z`Ra)XDqELSUg}#+DRE$*f@=aYXiFW8m?`!l z<_HOVy4ISpD6P3din2?r0oP3o!PqEZ`O#?j(t@;I&ME>Dbw7`*wFUf;j^<1TMR<$L z#JK;5vNSWeVg+j1F&Fq}d*+)DWrRlPRW3&o7n1P>*UIEGslN1=jCc;*q;!20xHYN{ z@In=!kr>er#ryCW5w0BgnhoBOt^H)x`9!nMl1lB&q))-6XoR-}jRL$?NchPdC+J6v z@ZU$-0Wr*vvhWYJjoHF>pmY$MkzVj{HGV^>Nv zLm|Xg$PlKW3o5RQVQc~+Q0}@IWiL{dQ=h6>pT2OdK#yJlO_+Ttx$V9sP_BCj$^`{0T}Zu*pp9D?fI)X*=(+RTJMZ8a)7G~x zPJ8aSN~dFQ?b6OeCA;Z7)UBr7HyZv$^FL{xZ|a(Nb*F`HHXsm0STWzmAwy*_)g3}M zdhS07=Sw8uBnvl@&`vVTu&pC`H!eoh!WM+B63N2NkcGpH6Yq{OI}FmChl99=D?&Fq zL53p-u;!8ioiIw4G%2_~yi`Az!+H@fv?tDMCG(8jdpHWf1X<>uara~S3PhFP3(&rS ztjd3fQ;5Y717idfpKrV}pP}7|tS8uNvhRiRRqqE%)_in#@SL zwyG4Dee0_VsKOznf2c(^AIap=po&EeVsTB>9%3nBkm{+tG&wVww%2Jh$`ZxIRu=Kd zIiL+7$6|_S;B)~PbL!&}9+q1WIuzriAx1zGmOke}Qi)df90bMqzwuQ$h@K(*e^8hy z(PPtyB&`rJtllhGfb zIC54|GiXYEle_Eoym54)wET_ZS%J5-B^&NT1mBjm@|IP}N(!&a+O3ui$?hx%FSY*x zd0LsQI1a@vB6PVysYCgT2Swt)pEKYCIL$o@ZElofaDcv496Tzp5P_X%p-}W`_MW}? zwuRbGqJ9D)42x5Pw_I&$p^devcuTfC)DiGQ-q`yT}tylfOp;?_2Qh zG>R;?Ydl9|y5uQn1F@V-9?47~HinYKfTXBVP8Q@MZT*r*f@X85&}Ot)$rj0~pBgsD zi9E7LvYo3j!g*h^pQC0hdGdlnqkV>t6L(gxV?1$EfhxkeW!yF2`1T^CjCV2op@dFYq@&_a>zubi80(A1e3o3rryV{uER;pC_Vc9YuZIL zA}$SJUzC&Rf-*)9u$RMaHDTp71bW7|_C-alY$_OH#E=a0BC;A_o7%xBoerceG2ONX z_PfLR@}%;Qk=0wmE*Vi|gjEZ>MGzicBdF9PDt|aud5T_p$>}3!4LN_CoDMkPC!WD1 zfbA2mUL#3nOs&;==Yu!u1C#30`s5>(ybG2`KD{YRnD7?pF$w52+ccK05Y)Ik1)Bl} zYUKbn2-OW4D`kW}0{2 zZhkz|{CIlZ-n4yR)+Ur&r;cRHILES2?I+)FhV$XTM?=?!Zm-*sS-0c&V}Ee*lZ!X` zPhOs1*L`y=z3wCqEn3#lWh(V|YHF{%a`}~1eD>+|vaP=#_=B^boW1eV4P`ErS=Ke} zx>H)a;O@HZK9X@C!O7q&_RIF<%K5S;oPR7Sy>Axi5Tt-ZkQNlBQA+eH_vD04e}iLP_FUWX&YsRg2ll`CB4z~LAgSFXf>H*d3WMS0m(;_iAyO3>(L7wOw!y_g z-2=G`D<8hN6D`)}G@a_jeIhjLd%%XqC8&tTD;{ntthyQj)`A&H6Hj%(TuAGJex)Ya z9sWy7DAH%mz(Pwv40hPBoQEQSMpd`x+DvK5d79=D&2nr5OF6rE%eHpGUV5j*bLsTV zX;LG-@4a2ynyGD_eRjTfM|#(>`I6&P2X&LrOM7SbCfD6^u`JGYx1C!u&Mk90=A9jB zq2pm}CJbUrC)uL`o8f9tv4u?HM|dnxtG|xLo-sR!R~WB5LNY#m_@Xd*FF60WuLpWJ zW{!lTuQ2%_OLTu6<`jz=G<6w_l4$gi9j7~U=X8}JfK(y~HlQOg*~B(z_ss4jPM3(E zx^{lp`_XgPp1a+&J=3&(zG-J#*vVj`ItHNKKL3zqd2T2Arzos&vKIr7(M2fQ=)Q-X z0Y%|ijO{piRItZ{dhPo;*(}cSuZ48kGGWdWg9(c<@!7o(Bzbn}BUIq!Q^AhCL4fr; zR&M+=cBwpM(%M<425vJr#!(a9!p7sD5wBmZXBpqFOE_9!RR#%>b|Iseok?KEX4*jp z`iSY#9y{ybvVBL3mo0;;Nf`iB`mfP2+`mUxV6jAWQx>IC1uVZ2X78?9URXzlp>!dm zi`~egkX@O|&v&#t&#y><*l#zjNZA zgBB;r>w8j8QWg>GxBw{*7KU?@j;h%+3E*i!+i*c{u0 zKp_(4DQw}@px~`@7e`^X@Z$rFCh6ls_7;#|>!R~w=gU}XqGB z{xsdrfKxxX84`RUlh-S@0p6R$E#fwDhqw!gsX%eFxK-RP?i6>kwt=?MZbc!4 zhLnX}vkjhY6i{VAS55KF_}j9C8FS?7RVI*hiUvU28p8y$v^=r=tuwD3oa&l3(ICW= zr*KoohwEmmW|jH+MI!gyI3Q4}zuf;bl=v+ShGEm_0Q~?3snM(%A<-eJjv!lPftYv6 zf)M056lU)>osJ{PN_SgYJJYM?d_3aplLq%Qf&sVk7W^ed;XL~0M~L9OKa zlKxi7Wd-o5Mvn5YltUjW9j?oeuVNbe%>GJ{la&hX@YNEH6Y-tJ`2(1pI%BxE0#`rN z$*&U4%82gr!C46yY-s`Q+Hfn`KjW%&Q#riZSAe#-Mv94*D6G6n z&J;PXk@Gq^Z@^I&qbp)T;e1O+C^Y{1U{k zf^(G4*fRFz3+`pflGMc9GwH{B9+>F{6)U%T!?f^YyM9%W2Yj;}BKTrUh1-%;k3Il6 zgGVXjh8?Us*R2}#rzv?Zk7^3Uly4y_uY=S<{T)P( zw>}co1vR`+&?a*#KpW;Sr4_eJ)?`Z7+%DOeDcJ~W=c$?*&3Nh;+$(2KrT0IBEnpdh za;7rv8XJwZ^WZ!quHnmpK6kk!^*FaS6UX`21ZaUx)C{albbuCIWvYRbXQ25~NV3+! zAfMrJA_vJ!6k<@MF)zT^cm6s+WQBi3K-_>*2#C%v1!8L7&91bke%^B^Z9k;#6mkfI z%>SRGp7J(&_Ar=AHFUsY&W@TZ-$km2Fza^+C>y^bW*J5O;42|lQz3G#TY_ARcpI8T zjL#$K&|edmOa+q@rl$;-=%QWpiyo*6e!D1i>PY3SYk^`u7|8evX3up&!zwm4^9V(w znx}tP2y~A>5_G?=o_`8J-lwB-gkaV$L$IxcURw*%3)ynd|4P7Pvqnh*Fa{f@6R`Jw zBUrIwZ=%!6Rg|O6u>aX0So0<0YRr*hQ1~7};fb${F-FP%23?Om5@~kaRMMUu^PVTu z_9u06?qfHs`M|rgYh45XzY-~0AI)rO)E2zI16VvvvuN`HjvWUPj5U4f%+yy-T4VDC zDfu~?+wkg`ca31)`AC>Qs^0&dfWAYYsb9LD?p#>2d7*CgLfwX}jVs%ApA%?7g-G;& z#;TAi3gL!d(^CV(l;1_xhn9*D36lGN6G$56fA*DtiDMiEz}&M0m{9D&q_`Gs(hh5x zdiuOoOVyX8s?>CtRTQF)n?h`>LMDC+aa9U&1q!W#3aMZeBI*iJD}^Sj@)S9QLJIX> zEz$YmfE)@z&&q3j2EK4lXgo1(5!gQAJJiL;;QaDU;=h_VENt4guwmmpkK3~0ZcT00 z0v{B=dU@7HAv?ExW!6Cfp84Ku5LZlN^j|JO`^w0QYP`GWF~^4SXNl-PLB;Q~bKa84I~QD{)S zovU4)rIb1}DI|XF0xGDRzi^?DdmJ1_H5fVtfLFOE$9jK(s6tVYAxCA36ygimlV_0f zH`_2J29Zkk6tl^d%w&%cEBqA;+5#?lB!N<~`t*G$^u{?2Y(BBkGRdO-U1 z>Tv58)fyNZLWl{E{R5ysr?g*0V;w`&NcYoBWjC|J>4FYe)Wt?Z>}>UbLI(08gaY`@ zDRv()6SxJilMmsfA1PS}Wc>6{kgnupXQ8P)XlcmiSN{zwT|uQlQLEif4bVX7A+u`= zas3a*MoT{u8Htf#w_QBKZh6Hvo_;P1Ng*?2gNHHIJ6t$YkTaq_ztka~jmL*$IOYYg z;~Jx3e|s>xQ3q;lBmKZuyGVjdYGYd)b-IlJ+NRyG3(Yl?UIqt6v`Rc5iH_njAlyq& zZ*-lZgx>?h1q2W{j{2dILz5sb!5WF{2$-Tpuc;jZlSZH`6V5}cqG(zyrf#vr_AE{& z_R2@JQru<9^n6Q|FO?MU3l91q4)Xb9K5DP>d&u@*X~B3FSr_ZBTovzbNnE_;5~0X? zK*w0v`LxkbZL2?Q_^9<->s-sH^&R*|_tTEOHulEL3H(q}4MpH&cF$`)S(DY_{khq0 zu`*)fH66rlJGkxxS4n&MJ~}zazzfj@2@CK|*#_S`r5uH)d_c~5v`)3rS#dy0>vo#r z2g!Mf9D;)KA|-RfIEB<3;NdU^6%^$n(F~I!$uWh967E)`llgR2l=j0RreIVd>Y+MF zlCFIq+N245iR#eLEyhW2qB!WyLPt(x3eg$GMG;m+P~+HoPug2;sV6P1LJC@?oSX`B z*viki0k+EeHvtxTt6ql}B4!_S7Jv$-Xr}7lqV?R zA#yg7(@qZKxtb_6Ku&-hiJW!hG?R0QoOj8=>H}7doD?}ffP+gxLs3A2#Qe%layF1N zN6x<^r1clu+0ogVhL*)9+RO4NAd(F18nw z0>Amd^FQI-KjBJ^|BjzLTYMmKJX2af z<rS0`uB&c&{W(`)u*Ry>xjdMs1=I1<>)60IpA6;79Ln+v4NcW3M!Qx+q3 zC|%w@hl@hDX6)OhEO#qbO?k3bfq#}K^Fi{nrDgo4*#mP8bFsOW>nE}tUT<1%2L5ns z`eg6TaOR1=`xKR3XX7gpy;%-k5>fE7RSq8P<$Vs`y;{y>OY$l6Exz&Y{=@goZoU;4 zyk?odYOUsP>A11|lZ`BV*W&n@1!-`ZfT<~KLMXeM=N)9n2rsoCrj5KKYv*}q5_Q5$ zp-y<JX=32*#3(jR(GyJY90ju+V z358DaR=z9|gTW+UmWyNYGja~xY z+H9#sYal#oAiQjuo3Be$W;uA;n6cm-ppBU9YBOI;b;F~&;bq-szA@QAQH?186JFL` z!tYLO&2sRPTkn&X743XeVuYI3ltNkXvddij^29D&i;aCrrgD9j!~5*WT;Gj`PoBFe z-0c0KBfb4dX5*9h=|i@zlrN`_z@w(Z%QkXrH{CPa`KkqHMV9%stC)Y+Qi^K$b z#EfO_eGAguTju2Jljs<{Ie~dM&G+doTWjU3sk!iy+i@r~kXn9q9|5*HTY-8A8dNz_ zQ03dS%IjVHPRax?i70s4Iv$_{_~E4h5O}kVH0pH^>?OQ6argls;my_yd;_I|m+EHT z?EbmR>qlrr8nUGhlo87UC+kuzvs@H zhWq4;E!a#}&spXIH@425{lt^@?#qZzWX33TvM+h;4Ubx?F;*6!ffvr6D=1(_31CwI~IcD7}1>-Dzu%AJ|&U1`^@ zjAi$I3sPm53;agHZg{BxL2F~S)WmP0D0mbF4?n=e@8?tJDcOF0j-}hr-z()zu0-Q4 zzJ_Sw2I}qxn!3xg>=n&!*9NXVd5+rGp0%401-QUVuBVdQv(6gcd1HSTm$N!=0t4aQ z-{$7`WLKN`T`7Um?7HW40F}CF%&KW{;myf6x^GtAIQ&VJhOj!j+|F-+(%*b}k|x83 z+2wOhH_SJBZ`eQCnDKVe%-E0xs%`~NCpr^blR{#5#tF2hDDUREwbxg&Fu`nBqH|_X o(w-{6ia}_|SQ_tJkm^D0X%L!p^WzV2%@yx_5I3#nH6HN)1($PS?f?J) literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac8d80eb0368a0f46a9c2ba4901f6c269d938c12 GIT binary patch literal 2661 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 aZYGv{mtSA*ztz3koxQJ*Kh_~wF8>dlcMrk< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..961479a7877221d86cc3a62b5f14e4de12e187d0 GIT binary patch literal 4551 zcmaJ_&2JmW72hS7Q3Z)W+WHeG9H=i|LM z@BQA#4E?8UHl@Hb{`-5@;-I4Z9S5zaKkU4|tt!ehg(_6Fm1X%=msJ=?>_|Df94%|h zS~<2HQmO@tn_zug<`Lf|yy_6aGgH}?@;RIrV0`wS?_9EeiI4nKm;yVVt|1l$qz5B}TT^S!koQ0HAVQu+8y& zM2Pmt0xUeT>TP>7CNFJ%^7eh9k-yGJ)uD{r+o;BB3$fK{DZPzGXN7ofs3YlykGjlr zCVfE0ayFo4#4B*C0_woFMqzbEy3^crEsFRtQgm(G-NJ3ROzyyUt}U04vguew=K1-u zxxx4x0h0tkqzExWCXK?Ru(jxd_G3MUmYBo1=?m1nb*tRvNN_M&2RXKY90O{mP%Ig) zV{f-zD`kbAbiHW;kYNaHFvr?qDWRgzx23Kaydh~PJ_QMTSYTlMEfHroh1*O|`me)U z;g;i133`--&)Cg-_wL@CBR5P(7>KD+^;wr^h-X3abVDEd-P|-STZF0Qkg;B=i1%96 zvMEIJro~;S%p8AaY`TXEp}mF?;`tB}yt9~Vli@0RX!%p`phdNUQ%Uq>mP?@hJVa~)JrpktOYXD zKa?3Suspa7{Oa=Ul{GkDnL}4#yt#7QT3hifpBeJhW!?&07iNLlXB;4#6=(HqCvo$l zUVY4rF{rHo< zJ?&7__m;jG8vo1CTaBT&es}H9L*K1u<{H`@5{@8YUqc_=)55{|`oM*TegXK>{ktE& z2JuRe6)LrJwjZtrzU2t_=HW8(zcceHa6)E=Iix5xrKVE#^TuER>^;-NnB-1(#SCK}1acjudNC6?T~e=z@iww`&np}o61j|kss zXs4iunDHUtEp*qRcC~sNR{k$0ky?ZTCSk>ak;H+Y0LCDOmoaB2W*BhI;&^e-K~;l~ z1W8zo;6k8Edru#=R|t@no&&=B@Oqb_0Za97u=FSUrFv$xp^bK17sM-^6|IMXw(gc$ zkcE_!RU8Ao&~iDN-8P-W;F(g3aV*7=A1XgrdqblZ`CM&>M!XiM07M8w95@m%gP|e= z1WNg1oPl!Oo{0&XI8C%?;sBn$kPBl7lR8LHw#jU_vXd00g0hOYqZ@{_2J1(7i8Uas zcjAVqB}gj?u1U}nU7(9nF$$vjd29$a!Vy?Vz!CUJXPiCij8GNnj&UGghu8ZQnqB4V zW6I#@Z!gugTs@upM|uKc@bJV%_7X#)*El?9!^uuJc(~!d&t= zw9Tlhs$VLpFO~kkDVH0{#8Z3Yk3W8$#?iO>Lw@)o|Kig-%^3876-GCnUTY?Bq$|fyHIvxuu;XY#582_{ zW`{nohr1+jbo@+6247U_oY*IUBOO&tVlSm+NA?$=+-at9lu^<{`&XVA%`A@kl;M-j ne(Vjj1P|iqY9YEytc7GQ3H`NciMGxU<(u literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd361569b82b8a84650fb07da2d9a37b5fc474a2 GIT binary patch literal 8640 zcmbU`TWlLwc6T_#_wXT-l1S<`dfA~YQ*mr3UdM4_OLpwokz7mJMQ9sbnlq9}lSA#D zp=B$hg%G5z6l7rwn^rQqZL~#!YGL>B(GM3WP;XJRTNDjMOR4Cw7je)O+y2p&gJ!co zJ@=9$Qu3o|uf&=AIQQIh&pG$pbI$y;%jG~&I{*A^s<{)Pe_lF`gmw*^Dde zj=5=_%XqThm^WJ&tD|jm#+UWS{IqV#1hVz9`fNk2fwrxg#%wSaWRPT&cqt?WM@@uC z@{5JVN}m)SWl4`{hZ-k3KHy?abj&7&NI&$_Suh@gaVLy7KV!Ty1E6?-YO$m3e`1U1 z0!p@Hc1x|IM{<_e6TM=c=!2G3YBQ)6{m^#64$RdZhye;iX{7YmL)%Mh4Nz;PwZ_d_ zPzuo<1jWz?=9nOcY1<+;5jdc@87OYQ%0ycK6WVAnV$<0p@>Si|pU7kq7c-J>JE=;T z*0|FtMb)jRQ=}uKTi;GhOr+#7-8M9#rgAcLnctD25@B?Uq$Cp)QpBWthXF>G@JShF zjV6+k&gUj1Ij)qu0k-L+tf*u)f@C;NHzijq7cT~T!|fyWfxf+aPNrQiHX(~gfOsKyF)bz4CB%u|%ARozsn zG{Lg1sCJ`6V+@Low;Xu>-0FsqI1Hl-(SJd}O$5?@XiSo&D--ze)DGYZu*;A%Rk-M(OfH$oD2Jn) zaJvYKL-6s2${>It<$1LjTUGD#@@LKz!kIdJcbIyRBkai-cOLWRh609|8}rZJQ>T@b#7gn2Lt zL_@a~nbDYe(?=Z~;F$(GDmaH$xS?O)bq*O1YP){UC6%Ctu_<2ucgCRSuy(aeU4g0(Ghy9R(BFTgf#1B9mL6`3kMA2o2m zc9nP}w4{jv+E!F@LTS-9jkp>#`qHgNt@?icsAgBZH4s8|o>7xMHRDggubDKD$ll^^ z5>o+Xx(@Wj4|u=O>e4&PeYH=;^cH%bfw32Ad&~9bjire#-Bt{FFu=E`ua@4uZ3;Av zSHYs3zeHR5mF;VRM*0oq zP;dg^6i){!cY+3X*f9^D;L|zVP=(SOzXk3P#T}~7dJgW!DwNhRT@O1X*YmalmIK1A zr;lmeWo9}IvW;xYHVodeHU0WFB+wM?)z##>XTUhBFj^QFG*)z8g0q2tq#iLaYK~{n z;!;eSUuHz+7JrjiYbeuAnhj@btmV;if9+FrX-%SAw4|6@9%CNZ!%fFA{S<2~dR5}Z z(xSd;)T&m<*ad`d|2Mq8DqhWWg;Bs25I42(No-mZSPxbVP#$&F(0sz6srnY{pUFAX z&C2Zra;_gnfU$vMWZ@h_TRml95gRr34@`f!8Rx+2Fy4t&;!@Glg>c)n54he~Lrs@4 zT78RV%?I~SMNSNQADs1R-w%D0%p|(PzKbTA&SzM$|KAy(L96UZGs5t?g2kL@Vqnw?J0Pc*0u>jFp1rK1NP6fOm zoXaXvK^Ou*4NrncQ^q%N?C3jhLid0)n#gA$ssP-_!B>{bPMaV+&BZwgO9(W~h6r59 zjS3|6f`C^j`%e(7fZGD(LD-VO(k3m5WKx$-g zbHQ(~?o${~D4U2Ne1;GlqJAKouDpr4JU;;%wwdD)z;T|)t3pZAM?dr1VZWD?3amLOtHN)ZbLc&eC^bxV1-^bP8ZiD#g*AV|n2kR*#T)k%{r zLO0n0_{*S^QWApvEh~)Zj6;W@kxtP$5j03QQ@%%7-CyfY;}p#Y>2~Q#iUf)x$@$RD z#6b%rWy%Efau{?EqB=9x|EZpH7jqd=$U?S3RudOS^O=mXyK{XP4hrWkX7bX7ZUq{; zC7ZyP@)J|Rt#cs8prGB#l>J;vhEteQFX$WzDyF*n%lQ$Zqg&|!nTP`220ch*+i+Td zCQCW+m})sGUruCFA}BbldJt5sCjNLWvI7&ZS?5ynXim3QWT2HgfWNhBIa6NgOah(Xdhl1T(bzmn7)V1VLf9VCe~!jVdgg*U)ptlOYQ z6;!uDvs`l%6mig(IMo-rZ>1TQAQ#HBN;zlZAx5u;OiW@vA|2(A;39;S#LLLmykhMv zwzaR=nv2%JinX~I49~hA3CQOEGWz;@bf6F&m~}s>Z(cY*e}2yK*oMNp)9!&1>At z4;=ipp1GcDeRF-Qj;5LZd)7eF=Dg;Zb6kII&DMV3+cL|M4(putI(J?C%+^$5QC(|^ z^O@ZbJfU?@Tfx)zCCS;X@?8&n%?o|=eGmLC3$M?=ey{hHj}NZx=%zg;(ca{qbwF14X`Joo^}dEsNsP z$c;;De9t3DCN?eZTjPZ|I6Pd+p@h$&XGw zEYnl;1{R$2&UJ5l!Q1|sx3gI1Uuc|fTnw+)be{FDXaPgJT_|Auw`pav4$31I((HUHP z^RBb=L7=bL^_VGId zw-0~jeT()+3f@RD@Wz8cc&#bAtgJTeT@CCjHgztItb}{MvT}94#|~82vFX0X>t6nYX`^&(!!(u|n z_5X#eW;bw#F0rG)?O#^NRvb%p%@&M3pN{1k|O!RNNyg_o_rf-yPIH!O2 z@{#sIJNk#c-obt7Q@ed|5BsSvJlM;A+G{5DeUYISR=0xZqrj~dF+~TrBoIjkhvt!f z2P(e{nI!U2NVJNkYVN0+7$&I?k*(&9wvBK#BP1tEOBF`lj9O|w6PZP3)HaJo8PW2A z3%+-dZx6Pq&(Gl8<&;RiJ5()b9D_dr-X(P?iGc+#OQ@vLz&)hJ?R1F+3u0agUriSzZ(}%E@tX zAt%A51wR{7&2VSJDi^Ol3-1%umz}@C@})!X8+yx-WLA>M!6<}Rq;q2w9>2#d)I@)C z+|5cPxF1ck>gFsB&2bt7`5yKbbF-4Trym;OBV{#qP1(60y{g7NDa1V`5$Ufj9n>R1|kz&DXI($ZB7G!|QT6@zVGIV~>tf3wKl zx$f#HxH`U32+Mv{x0C%-^NUv43;Bvbv=Dca2g#RW0)Yv?U`K>vd<7o#6Tfd?b)aDQbdwPtELXmUSdKR$>_USSZ*$ni)ACV?&T2mtTZielw`j%bq+Vv(8{LMb43vWshA8XGN@qKig(xH=9mXF3>ExU!OYkhQ48z<< z?)%7oAMy85-REd{9SyId;eSUxze2};iQf1e9sMQhgNyw7{zd;{da)xO-2rCtB=|6gzf4s+UZRuV{DA zs@MDHt}gCc@pKpLJ4!6+eppvuGLs5iLJr^c&bgM7l{Uc_;l zdrD5)$D=^=;+sqT%l@Skh34G_f3)PH18y>KVrlrs+Xa75$wT|R$lb8gu%qDGS*oKQ zK2+bbI5Iz2^3!Gj`NE4`^Q|RHX(@>O4W$qr2_uVrqls3}nCltevcH7j^_Rihk;0yV J$D~dr_&+-`9HamM literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b92b998fcc909d46378ce4c24ff9b44cce4ffe7a GIT binary patch literal 12025 zcmcgyS#TW3dG48=y?|Zp;=TxCNF2mc1V9iJ#ZxgwkRoLgl0`_eAj<2-&Hz|w4`^mU z5F1dTRje}LP(?D94JeW#sG=&95fd{Nr-GMMQBhKHRbH@yB*0_3LMMKRtMafEs8CV- zkniu=3*gFjB8LWxb4%P}xWU4r}Gdsn6uGYVg zSyCEoK%Yv*p*U~2-WM}eaT~D%z)nK*O(Tj{O1AbRRtzF-{wy@JnV{I1xA0 zb4Dx_4~?i=Krp4JLdIyoW!etMr%cz8P&67EimIm67YQ4t`*Ag{Y9S+`nbOIKZkVno z$BjrL9*UaIfvIuz*^p-1pNXRe!$@j;B4#?Yn4zhvDFz2j?|>Q`?~7<^7#OB7n0+WQ z5m%D#p@~RT=~UxqljZ98s2b~>997k5XE+odRg-Q_eYunO2-r;bW6zv8*%v(8|EyVl z^r_=VPX(Vle)Q+kOmXU>af zM8z%muO$J#&IC}hk)agEvb+5-JI{;^tuQvt!s2-$B)CDbKeWvW0-Me}DX7VwhQOwP zm|7;;IotDWQfOg4Ocy3afjy6LsNJgnOWUMyUBKaJM0i>a0Cv!>^FyjkM3s%J(P=8O z{AKva{xjoRVnhqYVv+dBnaM;VoQTC#EvyD3@v~~2cKXZ^&RUHtXYhRX%*n{m89idC zo#Uv*sq1IPBjerZZKxVfvU|daMD=dky&$%)YkbPA8Hpx_LeY(L(3&uZZTRa)0RDr0 zae>`)u#(D4jq~=~JHK|TZOPTSP(9^ckj5-{_Dp?A6i(!fPenwt1;Td`s-Mz2iP0T$6U#Z`itRKeq36{=|7ec;NW(9$O=} znqw*>u>+AK4BEiX(nSek$FABHhw4y7#WoDKN1c<`iK=5*Qe1d;P1yn^X8k$}C6azx z9RZ-X; z8gcz~!7K~vqlpQev7$y*Lq(0GtI=VdP|4aRK+_e(`9zFhFuCdMOfDO#9hTbV3c&#IlLXe4<-Xm}Ar8G#ksd739+bZ82ntn0(SG*S=s}8(8-3T5|2;`*vNlXg}a4I*o^7YA|S) z1cR}JG7+V+Cm4KrA{5QEIDahCp0!SZ>x|>&GuN7_mcTCj z^+y0MvY$zTHA%4VN;@R`_IW+ckX_r&vzvWu^py5U_Fk){cfq)as$L5xVKU2eqD;%M zcNo>VL}%ZE|JqXk8HJE*gc``5dR94vn41~79zPVhLSP}V3dBG1toSD}4~m$0N=uxL zD5{QQ*Tac%5QQaSxom-Gk+ahR3xz;Dp*Xlkp3u?JNI>?44R9W(i!AqL*TXCvR)uo84+cMr17qp8TH6^NRxMYS63rgul?_h~qs(7Gd zM8#WR+Icc{Wzaib#iy3xxeR&;hUB16DTirUfqy0b9z`5>DKHBM%lQa|OH!)wT%pt| zHOMPx*g0Xa3X-NyE62n_ry#|StI=_Y{`ivlX*CG7?W{YB00vpsHyJO%G>XMUW`ht2X3o{|WE|0p>Q< z@-*w1X0L%?vyv5twP=t$=4pay&S~L0Hbpou#^F?+7pH{_<#|CZF@f>OwJ3_ z0xYi_7KNTjCh$bYPB1sSX&at$*rx4xa^-qT+Gc}HIi4}lyg7ql{0>!vekk+o?L@_nWjvIiCI4}j6KgAP-PyaUqdZc$ucMt~xX%GzRv^wGjS-xOtSklAEngN_~U)HM4*^(OC^zQ)%Y3Hm&+9mwe4>2Wx1)>VRR@u=xsQ9{u01(C98E!$h@mHn~;^RR@EVMueR-6nr8n8zVwUD! z{fa(h&Gjd@LSkX7xcEuPp>SA*jLn>sOb54LhN68OIJIL0S^x^PszyhYtXRL>^x6-o zADKWG*d1)#p+7ma-K@Dn(qTy zE_2puQQDY_?|?#Pe~wG?@4N}G>1{h!FZG+kK~s=T;ZbPd6X;>7VNP`$)=8!yX#=<{ z50I8s|EG9gZwG*zQeJUo_uQjbA6=>3o~qowRPoTYo@)a?e*XIN*G?^#FZm8Exeiz- z--`b0R!lt3S4=ESCx6=Vt1OFPS}ooZj=& zw4{+pbZ_W}$1H*8gwa62Zb=Jn7n131Np)vNc%zv%Tzi@T`C!^<0wj;PQN^VQ7b0}r zq-2U6w^hGDFFgi;eJ%A}J}`S=sdVdVb^Y86S6`St_6zUk+tuwW)jg@|o|~a`xnF{b?KXR9JLh$i*bn_#x0Jh5Dozr5D>;gD~(kmXr6{ z8d!VKAa5d6`L^vwPOId$T{KFvJ;%J+Qa)FtX))^$k~RY$*^>v4a0^B*YJ+h*O-JBH zl_Q4EWr`e$%M=snB1!S3gn&(_DRd%I;DEg~969%8vxTszNwi;X(*sUZOz2$rm@bSR zwNwmAvf&8gd(PNP3O$&PXkrABK+~?MLlYzGoN(?E(k|oJEzNNh56S8cjAUssqBWfe z1$x87{1ulcXD3&D%_(2=d#)9EXG-3=*t%#e4&OSwSoX2}__FW#jC9*ocG)xQS*qT% z2yJjE&wlGTp3aA#^&)uxyP_rKf~d4o0SgtfX{NQPrND}vdG>sDVM-if--8UypR*zv zoZ1~ z(wVF$9PlRhJgvqOXJPynH-K|SK6x$VR2VYCp@urpZ%V@x@o<+#%uWdAAR<~k1hFot zMI2p;|Jpgw30awnFh<&9L&|&e#dKd@E`W{l&N(v<< zNi2C=o4!p}CO|(4$hWSNWJQ}U4_mKIMvPIa><@TNX)F7r{h4It3>O!8TkHARZMN*IvY`Ovgk#8i~I|HwQ$ird^A{ZPY?&(}oC8=)rV^ z#>Wv{hptqpjvGTNHF&LoU@6jAro-}ta*ETkzD;KWS1NFklI`o|XhsEh9gM>Hjp~nf zW%~U+Q0tcfV3DUitZBqq? zwdHfCR9*q;U0zGoOHDmDcdzvJrF#2r#Xj~Ata>UgpPD^2zwHyxR<4ncA*kfdcz@Pf zQDMil&xMmOJaC}gbBRO0LA4bgZr(Ac6YeT`J~6=qV0vg+jZQ%laG?<~$O%SJF*?;1 zD6`CMIx|ZsIAC(yW_p>DCe9aUfIq_#e2t9@(_`-eU9k$T&Q zbpoK)h3Y`{#&Fy&)M|YMN(uB5AlpdWO@IP$8SfW&S8#=mDT{5Mqz003+BXRBLwlA= zWN2u#*QPh)$cEKuG#I=ta5seeSD6!`AQ+E?5jp4|0eo?h-4!eBuJjJp+_KuWXSJ$f zbxZqd`}VuuE%u%}Wi?my*;v|+GI*uD=87`kx6rXvvpwa1DD9+L7xPu5-Bc=Jjm_y& zDtVaP`Z>LyJ|-{+c38AGTnS_Q>TqH+h1jfNtKuaZ$SJP}<#BSM)CVHR0;erzk8ux|AKpV(#6*ZE4A&_g0GV0SMa?W+ie=3w7R;0w%ZK)6VQ{<#5iu>^ z$QfGXr{cOkDR!R;2z>Z}q(w1|_D2Mc5NHEHZELQUd=5(}kogZfu=FhNnA}{HNORGy zFYt!m0sxV{S|`8bd&76lzFgPEWw*=AV_yr7C0E@iu5DIaK%z^nbr**uv>?DxQk@`^C-rY54w0IHCo(+JVbPSKebJgg2yocr=L? z7>A-FH83hu1Yufu2{&!JaH(Zl`k_GAS(iE_cIhdp;LC`Dl@xVYvge)6vAW~`_th1w z3%mRKuj_#o$+;D^VMR|!FjD!ooIT{hfn`2$v99J+jjq$^B0DFf=(u5Q=2(-2Oei`6 z9x+B^bo~*947AuE7cB~x6r&;7o{$~f)FHt@NOBmstqSp$xu^-j>xVlNQDm}m^(h@= z%i$b~9Ww4pWa<=87&#o)3z_dZIC@>~fHaeb5|B7gP2oZUMi%@i1P&0Z9HwsxaGgSH z%i+kp9mq?eUlW^}!Yd}e8gjt+4aG-P(-u`>P2=+s&A^?lZZ_d_lOf1njxR`yp|BtA zLJVTj^qxF=xbH;&%091L+B|0>#nkbRn%U2`K^|D<;}pS<*hS^Z#T8CH1(yL z`d0mwEB-Ah|CWWGg_qxb_`hu8=CUhpm;;-d7b<>K`)=*E`sFRXsm9)$%3{yruA8H& z#z(KXRx2CljpfRg)rPI#@4s7$cVJglwB4g|Uf1V)R~mPu8h0$$c79skReZ4DHc+Z@ zf3YF%Vu<9F-iQ7$yL7Xh>XOK1%8hGg1?^ga;> z(ivbqFOq{>%mL0z8F2qMNw(y#dWweTib*PQTFP?&c{>6nnUNVQ=15Q5vok|@!kQvr z(Xq(t-;nZepSQzF-V1q`>+$>IFi1u6G?oj{WNUs$DA8^-WP6S^WlQ-Sp+tLjClE?R zNFE`XTtEOJnU3?0X-BaDQ-QNzmB*JYk*wE*SMg06uGAc_I4*r^<&(MZ)&ll^4adi{ z=LrlFI0F#yaYxy5y6pORG-6n)`7-q&W;g8!EW&607FC?%6>tsX3Da@(=r>QC9?&Ro zr+u41hyc0O*~_eLD4UX&NElpJXs=NRa<5HMJy&pzWyuKcBP5%?LM~V)Ukyk{{{$E= zu-nzObI)CUZtlgaFD~r<(V=$_Em!xq%4&VnN_}UlzVn*$X?^d^iQARcbB|no z#Jb8_h%8s`oasx8E-##`iaFO+*L>CMWpI+~8s;XiPOj8$OVw_>CV}a%NI&yer>j}R z?t2Zas)lf^RJNolTi!dq(z-jGTNCe0zcKw$YxR*1@xu;xU%maqp3Qw# z_J6Fhqs%`xgQwh0o4Aue4*~9|eUD1qN8{ewZh9oU$}Ht~hB1Djt;NPer2Ed&!51g-dR^5K#)LlumcPzlkL3VBQrg1&ai$9e<3AtD|H^j$g4Nv@-GX?Z0l+ausfG!=?zkIfYFFG1 zDR;yC-eq^|1;;P#o|%F9=8x@x3*y}pR$jeYR=-*k0KA7#l6b+JE@OetCFZ}2g}`NB#{sCs^|1?)$2z zXC}rF!D@A7Pd&f-s=Df{?^X4$4u_RMsQJey0`D{t@+T~4fwn+lwNppPEa6Ev;Tc{R zWV#ue>bi9_)pzS@%679fHFO(jYV0=B)YNT)R39`CTDmQR)^6*dt=q;RE;eWyw0GNS z-Vk&QI=h`TZw$Hy-QDg%Pq$|*cPQjwqK${n8T~J%Yy8+fi;l2GvJ`d_@)41{>zfr}->j1t0%A5E?!Jh741m(?q zHD3(9OW;>3czG*8n)$Mq4c&E_daN_@GO z`uS?cDxQ=B!GIhPBu*59ep%o-zu0#!a6yoothaIKPM=;ecgTY1?+pqHdn_Qyin(h@ z4unJgppQ{Z-GQNwP=6S*o{o?t`-6Z68V`wLSoE=q^Fa5uoN(baiEah}}& zL~hw}synyn?Cy9hrwmxFLP#1Gg&sa2j+OV0ZQ};R{BTg<0umPr%bfp$KM=&Zja3B4 z2L0dGsu)E<9u`A=+2tfe4+Z?Kc0)8vfcTG0^U?I4q)(aNgY4{K4I)hs5w%(LXo{XikrW!+qhwK|$;jdSD0` zH7t&v?)CSb7ef4LC|@{zEYN#e3dlm^5Y+n53exGJz)&+l!+yi|HV*@JNX^3`YzCA~ zL!*i#{RKUA3SvGCjVwT_f@p$#W^+unL|dl!|LvZMwiVX+%8?h3OrCtXGih^899;zv zqOe1L`CMOSsiBI6AKiwpATtX~Hjvv2br`bCziz8eTk>&$jF1aN+{f!^S_AkH`D&16 z3V~y13`(*X7*g2&K!{fi(h!`~HyN=I+SM%=^AOZS8+w9*pNBodb0XqqY)3F;y%Pjh ze`-&3&$N`Vl`q@8aho@`BVntXXiJ)`ll+U9k`~8wL9}A7_BG!XU+my7o91`?{-HM? zS~&UE!ylLJzAAsTBmQvLEm!{3SafWzX70xcSM{Q~I^8RouCI+T372=#?7ihKnC_h% zTQrx71vozgZn(7mjz0kaAk>&~*t0hBEJw(=E_)0knLRiSYdfwVXCrz^$BzrS@XFoSW`@`^)4nQ

        9gk0%}Z)8h$8E!3u5 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..942914a423bd635bf93492f6a0180e94bd1adfb2 GIT binary patch literal 2078 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 Uc5w?qQ9clY_sSat1=r{Q0Qjs|00000 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..890b19432395265babc89e02a0eee545aa9a1bea GIT binary patch literal 5904 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py b/backend/venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py new file mode 100644 index 0000000..6ccf53b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py @@ -0,0 +1,109 @@ +"""Functions brought over from jaraco.text. + +These functions are not supposed to be used within `pip._internal`. These are +helper functions brought over from `jaraco.text` to enable vendoring newer +copies of `pkg_resources` without having to vendor `jaraco.text` and its entire +dependency cone; something that our vendoring setup is not currently capable of +handling. + +License reproduced from original source below: + +Copyright Jason R. Coombs + +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. +""" + +import functools +import itertools + + +def _nonblank(str): + return str and not str.startswith("#") + + +@functools.singledispatch +def yield_lines(iterable): + r""" + Yield valid lines of a string or iterable. + + >>> list(yield_lines('')) + [] + >>> list(yield_lines(['foo', 'bar'])) + ['foo', 'bar'] + >>> list(yield_lines('foo\nbar')) + ['foo', 'bar'] + >>> list(yield_lines('\nfoo\n#bar\nbaz #comment')) + ['foo', 'baz #comment'] + >>> list(yield_lines(['foo\nbar', 'baz', 'bing\n\n\n'])) + ['foo', 'bar', 'baz', 'bing'] + """ + return itertools.chain.from_iterable(map(yield_lines, iterable)) + + +@yield_lines.register(str) +def _(text): + return filter(_nonblank, map(str.strip, text.splitlines())) + + +def drop_comment(line): + """ + Drop comments. + + >>> drop_comment('foo # bar') + 'foo' + + A hash without a space may be in a URL. + + >>> drop_comment('http://example.com/foo#bar') + 'http://example.com/foo#bar' + """ + return line.partition(" #")[0] + + +def join_continuation(lines): + r""" + Join lines continued by a trailing backslash. + + >>> list(join_continuation(['foo \\', 'bar', 'baz'])) + ['foobar', 'baz'] + >>> list(join_continuation(['foo \\', 'bar', 'baz'])) + ['foobar', 'baz'] + >>> list(join_continuation(['foo \\', 'bar \\', 'baz'])) + ['foobarbaz'] + + Not sure why, but... + The character preceding the backslash is also elided. + + >>> list(join_continuation(['goo\\', 'dly'])) + ['godly'] + + A terrible idea, but... + If no line is available to continue, suppress the lines. + + >>> list(join_continuation(['foo', 'bar\\', 'baz\\'])) + ['foo'] + """ + lines = iter(lines) + for item in lines: + while item.endswith("\\"): + try: + item = item[:-2].strip() + next(lines) + except StopIteration: + return + yield item diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/_log.py b/backend/venv/Lib/site-packages/pip/_internal/utils/_log.py new file mode 100644 index 0000000..92c4c6a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/_log.py @@ -0,0 +1,38 @@ +"""Customize logging + +Defines custom logger class for the `logger.verbose(...)` method. + +init_logging() must be called before any other modules that call logging.getLogger. +""" + +import logging +from typing import Any, cast + +# custom log level for `--verbose` output +# between DEBUG and INFO +VERBOSE = 15 + + +class VerboseLogger(logging.Logger): + """Custom Logger, defining a verbose log-level + + VERBOSE is between INFO and DEBUG. + """ + + def verbose(self, msg: str, *args: Any, **kwargs: Any) -> None: + return self.log(VERBOSE, msg, *args, **kwargs) + + +def getLogger(name: str) -> VerboseLogger: + """logging.getLogger, but ensures our VerboseLogger class is returned""" + return cast(VerboseLogger, logging.getLogger(name)) + + +def init_logging() -> None: + """Register our VerboseLogger and VERBOSE log level. + + Should be called before any calls to getLogger(), + i.e. in pip._internal.__init__ + """ + logging.setLoggerClass(VerboseLogger) + logging.addLevelName(VERBOSE, "VERBOSE") diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/appdirs.py b/backend/venv/Lib/site-packages/pip/_internal/utils/appdirs.py new file mode 100644 index 0000000..16933bf --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/appdirs.py @@ -0,0 +1,52 @@ +""" +This code wraps the vendored appdirs module to so the return values are +compatible for the current pip code base. + +The intention is to rewrite current usages gradually, keeping the tests pass, +and eventually drop this after all usages are changed. +""" + +import os +import sys +from typing import List + +from pip._vendor import platformdirs as _appdirs + + +def user_cache_dir(appname: str) -> str: + return _appdirs.user_cache_dir(appname, appauthor=False) + + +def _macos_user_config_dir(appname: str, roaming: bool = True) -> str: + # Use ~/Application Support/pip, if the directory exists. + path = _appdirs.user_data_dir(appname, appauthor=False, roaming=roaming) + if os.path.isdir(path): + return path + + # Use a Linux-like ~/.config/pip, by default. + linux_like_path = "~/.config/" + if appname: + linux_like_path = os.path.join(linux_like_path, appname) + + return os.path.expanduser(linux_like_path) + + +def user_config_dir(appname: str, roaming: bool = True) -> str: + if sys.platform == "darwin": + return _macos_user_config_dir(appname, roaming) + + return _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) + + +# for the discussion regarding site_config_dir locations +# see +def site_config_dirs(appname: str) -> List[str]: + if sys.platform == "darwin": + return [_appdirs.site_data_dir(appname, appauthor=False, multipath=True)] + + dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) + if sys.platform == "win32": + return [dirval] + + # Unix-y system. Look in /etc as well. + return dirval.split(os.pathsep) + ["/etc"] diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/compat.py b/backend/venv/Lib/site-packages/pip/_internal/utils/compat.py new file mode 100644 index 0000000..d8b54e4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/compat.py @@ -0,0 +1,79 @@ +"""Stuff that differs in different Python versions and platform +distributions.""" + +import importlib.resources +import logging +import os +import sys +from typing import IO + +__all__ = ["get_path_uid", "stdlib_pkgs", "WINDOWS"] + + +logger = logging.getLogger(__name__) + + +def has_tls() -> bool: + try: + import _ssl # noqa: F401 # ignore unused + + return True + except ImportError: + pass + + from pip._vendor.urllib3.util import IS_PYOPENSSL + + return IS_PYOPENSSL + + +def get_path_uid(path: str) -> int: + """ + Return path's uid. + + Does not follow symlinks: + https://github.com/pypa/pip/pull/935#discussion_r5307003 + + Placed this function in compat due to differences on AIX and + Jython, that should eventually go away. + + :raises OSError: When path is a symlink or can't be read. + """ + if hasattr(os, "O_NOFOLLOW"): + fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) + file_uid = os.fstat(fd).st_uid + os.close(fd) + else: # AIX and Jython + # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW + if not os.path.islink(path): + # older versions of Jython don't have `os.fstat` + file_uid = os.stat(path).st_uid + else: + # raise OSError for parity with os.O_NOFOLLOW above + raise OSError(f"{path} is a symlink; Will not return uid for symlinks") + return file_uid + + +# The importlib.resources.open_text function was deprecated in 3.11 with suggested +# replacement we use below. +if sys.version_info < (3, 11): + open_text_resource = importlib.resources.open_text +else: + + def open_text_resource( + package: str, resource: str, encoding: str = "utf-8", errors: str = "strict" + ) -> IO[str]: + return (importlib.resources.files(package) / resource).open( + "r", encoding=encoding, errors=errors + ) + + +# packages in the stdlib that may have installation metadata, but should not be +# considered 'installed'. this theoretically could be determined based on +# dist.location (py27:`sysconfig.get_paths()['stdlib']`, +# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may +# make this ineffective, so hard-coding +stdlib_pkgs = {"python", "wsgiref", "argparse"} + + +# windows detection, covers cpython and ironpython +WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py b/backend/venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py new file mode 100644 index 0000000..2e7b745 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py @@ -0,0 +1,188 @@ +"""Generate and work with PEP 425 Compatibility Tags. +""" + +import re +from typing import List, Optional, Tuple + +from pip._vendor.packaging.tags import ( + PythonVersion, + Tag, + compatible_tags, + cpython_tags, + generic_tags, + interpreter_name, + interpreter_version, + ios_platforms, + mac_platforms, +) + +_apple_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)") + + +def version_info_to_nodot(version_info: Tuple[int, ...]) -> str: + # Only use up to the first two numbers. + return "".join(map(str, version_info[:2])) + + +def _mac_platforms(arch: str) -> List[str]: + match = _apple_arch_pat.match(arch) + if match: + name, major, minor, actual_arch = match.groups() + mac_version = (int(major), int(minor)) + arches = [ + # Since we have always only checked that the platform starts + # with "macosx", for backwards-compatibility we extract the + # actual prefix provided by the user in case they provided + # something like "macosxcustom_". It may be good to remove + # this as undocumented or deprecate it in the future. + "{}_{}".format(name, arch[len("macosx_") :]) + for arch in mac_platforms(mac_version, actual_arch) + ] + else: + # arch pattern didn't match (?!) + arches = [arch] + return arches + + +def _ios_platforms(arch: str) -> List[str]: + match = _apple_arch_pat.match(arch) + if match: + name, major, minor, actual_multiarch = match.groups() + ios_version = (int(major), int(minor)) + arches = [ + # Since we have always only checked that the platform starts + # with "ios", for backwards-compatibility we extract the + # actual prefix provided by the user in case they provided + # something like "ioscustom_". It may be good to remove + # this as undocumented or deprecate it in the future. + "{}_{}".format(name, arch[len("ios_") :]) + for arch in ios_platforms(ios_version, actual_multiarch) + ] + else: + # arch pattern didn't match (?!) + arches = [arch] + return arches + + +def _custom_manylinux_platforms(arch: str) -> List[str]: + arches = [arch] + arch_prefix, arch_sep, arch_suffix = arch.partition("_") + if arch_prefix == "manylinux2014": + # manylinux1/manylinux2010 wheels run on most manylinux2014 systems + # with the exception of wheels depending on ncurses. PEP 599 states + # manylinux1/manylinux2010 wheels should be considered + # manylinux2014 wheels: + # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels + if arch_suffix in {"i686", "x86_64"}: + arches.append("manylinux2010" + arch_sep + arch_suffix) + arches.append("manylinux1" + arch_sep + arch_suffix) + elif arch_prefix == "manylinux2010": + # manylinux1 wheels run on most manylinux2010 systems with the + # exception of wheels depending on ncurses. PEP 571 states + # manylinux1 wheels should be considered manylinux2010 wheels: + # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels + arches.append("manylinux1" + arch_sep + arch_suffix) + return arches + + +def _get_custom_platforms(arch: str) -> List[str]: + arch_prefix, arch_sep, arch_suffix = arch.partition("_") + if arch.startswith("macosx"): + arches = _mac_platforms(arch) + elif arch.startswith("ios"): + arches = _ios_platforms(arch) + elif arch_prefix in ["manylinux2014", "manylinux2010"]: + arches = _custom_manylinux_platforms(arch) + else: + arches = [arch] + return arches + + +def _expand_allowed_platforms(platforms: Optional[List[str]]) -> Optional[List[str]]: + if not platforms: + return None + + seen = set() + result = [] + + for p in platforms: + if p in seen: + continue + additions = [c for c in _get_custom_platforms(p) if c not in seen] + seen.update(additions) + result.extend(additions) + + return result + + +def _get_python_version(version: str) -> PythonVersion: + if len(version) > 1: + return int(version[0]), int(version[1:]) + else: + return (int(version[0]),) + + +def _get_custom_interpreter( + implementation: Optional[str] = None, version: Optional[str] = None +) -> str: + if implementation is None: + implementation = interpreter_name() + if version is None: + version = interpreter_version() + return f"{implementation}{version}" + + +def get_supported( + version: Optional[str] = None, + platforms: Optional[List[str]] = None, + impl: Optional[str] = None, + abis: Optional[List[str]] = None, +) -> List[Tag]: + """Return a list of supported tags for each version specified in + `versions`. + + :param version: a string version, of the form "33" or "32", + or None. The version will be assumed to support our ABI. + :param platform: specify a list of platforms you want valid + tags for, or None. If None, use the local system platform. + :param impl: specify the exact implementation you want valid + tags for, or None. If None, use the local interpreter impl. + :param abis: specify a list of abis you want valid + tags for, or None. If None, use the local interpreter abi. + """ + supported: List[Tag] = [] + + python_version: Optional[PythonVersion] = None + if version is not None: + python_version = _get_python_version(version) + + interpreter = _get_custom_interpreter(impl, version) + + platforms = _expand_allowed_platforms(platforms) + + is_cpython = (impl or interpreter_name()) == "cp" + if is_cpython: + supported.extend( + cpython_tags( + python_version=python_version, + abis=abis, + platforms=platforms, + ) + ) + else: + supported.extend( + generic_tags( + interpreter=interpreter, + abis=abis, + platforms=platforms, + ) + ) + supported.extend( + compatible_tags( + python_version=python_version, + interpreter=interpreter, + platforms=platforms, + ) + ) + + return supported diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/datetime.py b/backend/venv/Lib/site-packages/pip/_internal/utils/datetime.py new file mode 100644 index 0000000..8668b3b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/datetime.py @@ -0,0 +1,11 @@ +"""For when pip wants to check the date or time. +""" + +import datetime + + +def today_is_later_than(year: int, month: int, day: int) -> bool: + today = datetime.date.today() + given = datetime.date(year, month, day) + + return today > given diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/deprecation.py b/backend/venv/Lib/site-packages/pip/_internal/utils/deprecation.py new file mode 100644 index 0000000..0911147 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/deprecation.py @@ -0,0 +1,124 @@ +""" +A module that implements tooling to enable easy warnings about deprecations. +""" + +import logging +import warnings +from typing import Any, Optional, TextIO, Type, Union + +from pip._vendor.packaging.version import parse + +from pip import __version__ as current_version # NOTE: tests patch this name. + +DEPRECATION_MSG_PREFIX = "DEPRECATION: " + + +class PipDeprecationWarning(Warning): + pass + + +_original_showwarning: Any = None + + +# Warnings <-> Logging Integration +def _showwarning( + message: Union[Warning, str], + category: Type[Warning], + filename: str, + lineno: int, + file: Optional[TextIO] = None, + line: Optional[str] = None, +) -> None: + if file is not None: + if _original_showwarning is not None: + _original_showwarning(message, category, filename, lineno, file, line) + elif issubclass(category, PipDeprecationWarning): + # We use a specially named logger which will handle all of the + # deprecation messages for pip. + logger = logging.getLogger("pip._internal.deprecations") + logger.warning(message) + else: + _original_showwarning(message, category, filename, lineno, file, line) + + +def install_warning_logger() -> None: + # Enable our Deprecation Warnings + warnings.simplefilter("default", PipDeprecationWarning, append=True) + + global _original_showwarning + + if _original_showwarning is None: + _original_showwarning = warnings.showwarning + warnings.showwarning = _showwarning + + +def deprecated( + *, + reason: str, + replacement: Optional[str], + gone_in: Optional[str], + feature_flag: Optional[str] = None, + issue: Optional[int] = None, +) -> None: + """Helper to deprecate existing functionality. + + reason: + Textual reason shown to the user about why this functionality has + been deprecated. Should be a complete sentence. + replacement: + Textual suggestion shown to the user about what alternative + functionality they can use. + gone_in: + The version of pip does this functionality should get removed in. + Raises an error if pip's current version is greater than or equal to + this. + feature_flag: + Command-line flag of the form --use-feature={feature_flag} for testing + upcoming functionality. + issue: + Issue number on the tracker that would serve as a useful place for + users to find related discussion and provide feedback. + """ + + # Determine whether or not the feature is already gone in this version. + is_gone = gone_in is not None and parse(current_version) >= parse(gone_in) + + message_parts = [ + (reason, f"{DEPRECATION_MSG_PREFIX}{{}}"), + ( + gone_in, + ( + "pip {} will enforce this behaviour change." + if not is_gone + else "Since pip {}, this is no longer supported." + ), + ), + ( + replacement, + "A possible replacement is {}.", + ), + ( + feature_flag, + ( + "You can use the flag --use-feature={} to test the upcoming behaviour." + if not is_gone + else None + ), + ), + ( + issue, + "Discussion can be found at https://github.com/pypa/pip/issues/{}", + ), + ] + + message = " ".join( + format_str.format(value) + for value, format_str in message_parts + if format_str is not None and value is not None + ) + + # Raise as an error if this behaviour is deprecated. + if is_gone: + raise PipDeprecationWarning(message) + + warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py b/backend/venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py new file mode 100644 index 0000000..66020d3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py @@ -0,0 +1,87 @@ +from typing import Optional + +from pip._internal.models.direct_url import ArchiveInfo, DirectUrl, DirInfo, VcsInfo +from pip._internal.models.link import Link +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs import vcs + + +def direct_url_as_pep440_direct_reference(direct_url: DirectUrl, name: str) -> str: + """Convert a DirectUrl to a pip requirement string.""" + direct_url.validate() # if invalid, this is a pip bug + requirement = name + " @ " + fragments = [] + if isinstance(direct_url.info, VcsInfo): + requirement += ( + f"{direct_url.info.vcs}+{direct_url.url}@{direct_url.info.commit_id}" + ) + elif isinstance(direct_url.info, ArchiveInfo): + requirement += direct_url.url + if direct_url.info.hash: + fragments.append(direct_url.info.hash) + else: + assert isinstance(direct_url.info, DirInfo) + requirement += direct_url.url + if direct_url.subdirectory: + fragments.append("subdirectory=" + direct_url.subdirectory) + if fragments: + requirement += "#" + "&".join(fragments) + return requirement + + +def direct_url_for_editable(source_dir: str) -> DirectUrl: + return DirectUrl( + url=path_to_url(source_dir), + info=DirInfo(editable=True), + ) + + +def direct_url_from_link( + link: Link, source_dir: Optional[str] = None, link_is_in_wheel_cache: bool = False +) -> DirectUrl: + if link.is_vcs: + vcs_backend = vcs.get_backend_for_scheme(link.scheme) + assert vcs_backend + url, requested_revision, _ = vcs_backend.get_url_rev_and_auth( + link.url_without_fragment + ) + # For VCS links, we need to find out and add commit_id. + if link_is_in_wheel_cache: + # If the requested VCS link corresponds to a cached + # wheel, it means the requested revision was an + # immutable commit hash, otherwise it would not have + # been cached. In that case we don't have a source_dir + # with the VCS checkout. + assert requested_revision + commit_id = requested_revision + else: + # If the wheel was not in cache, it means we have + # had to checkout from VCS to build and we have a source_dir + # which we can inspect to find out the commit id. + assert source_dir + commit_id = vcs_backend.get_revision(source_dir) + return DirectUrl( + url=url, + info=VcsInfo( + vcs=vcs_backend.name, + commit_id=commit_id, + requested_revision=requested_revision, + ), + subdirectory=link.subdirectory_fragment, + ) + elif link.is_existing_dir(): + return DirectUrl( + url=link.url_without_fragment, + info=DirInfo(), + subdirectory=link.subdirectory_fragment, + ) + else: + hash = None + hash_name = link.hash_name + if hash_name: + hash = f"{hash_name}={link.hash}" + return DirectUrl( + url=link.url_without_fragment, + info=ArchiveInfo(hash=hash), + subdirectory=link.subdirectory_fragment, + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/egg_link.py b/backend/venv/Lib/site-packages/pip/_internal/utils/egg_link.py new file mode 100644 index 0000000..4a384a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/egg_link.py @@ -0,0 +1,80 @@ +import os +import re +import sys +from typing import List, Optional + +from pip._internal.locations import site_packages, user_site +from pip._internal.utils.virtualenv import ( + running_under_virtualenv, + virtualenv_no_global, +) + +__all__ = [ + "egg_link_path_from_sys_path", + "egg_link_path_from_location", +] + + +def _egg_link_names(raw_name: str) -> List[str]: + """ + Convert a Name metadata value to a .egg-link name, by applying + the same substitution as pkg_resources's safe_name function. + Note: we cannot use canonicalize_name because it has a different logic. + + We also look for the raw name (without normalization) as setuptools 69 changed + the way it names .egg-link files (https://github.com/pypa/setuptools/issues/4167). + """ + return [ + re.sub("[^A-Za-z0-9.]+", "-", raw_name) + ".egg-link", + f"{raw_name}.egg-link", + ] + + +def egg_link_path_from_sys_path(raw_name: str) -> Optional[str]: + """ + Look for a .egg-link file for project name, by walking sys.path. + """ + egg_link_names = _egg_link_names(raw_name) + for path_item in sys.path: + for egg_link_name in egg_link_names: + egg_link = os.path.join(path_item, egg_link_name) + if os.path.isfile(egg_link): + return egg_link + return None + + +def egg_link_path_from_location(raw_name: str) -> Optional[str]: + """ + Return the path for the .egg-link file if it exists, otherwise, None. + + There's 3 scenarios: + 1) not in a virtualenv + try to find in site.USER_SITE, then site_packages + 2) in a no-global virtualenv + try to find in site_packages + 3) in a yes-global virtualenv + try to find in site_packages, then site.USER_SITE + (don't look in global location) + + For #1 and #3, there could be odd cases, where there's an egg-link in 2 + locations. + + This method will just return the first one found. + """ + sites: List[str] = [] + if running_under_virtualenv(): + sites.append(site_packages) + if not virtualenv_no_global() and user_site: + sites.append(user_site) + else: + if user_site: + sites.append(user_site) + sites.append(site_packages) + + egg_link_names = _egg_link_names(raw_name) + for site in sites: + for egg_link_name in egg_link_names: + egglink = os.path.join(site, egg_link_name) + if os.path.isfile(egglink): + return egglink + return None diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/entrypoints.py b/backend/venv/Lib/site-packages/pip/_internal/utils/entrypoints.py new file mode 100644 index 0000000..1501369 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/entrypoints.py @@ -0,0 +1,84 @@ +import itertools +import os +import shutil +import sys +from typing import List, Optional + +from pip._internal.cli.main import main +from pip._internal.utils.compat import WINDOWS + +_EXECUTABLE_NAMES = [ + "pip", + f"pip{sys.version_info.major}", + f"pip{sys.version_info.major}.{sys.version_info.minor}", +] +if WINDOWS: + _allowed_extensions = {"", ".exe"} + _EXECUTABLE_NAMES = [ + "".join(parts) + for parts in itertools.product(_EXECUTABLE_NAMES, _allowed_extensions) + ] + + +def _wrapper(args: Optional[List[str]] = None) -> int: + """Central wrapper for all old entrypoints. + + Historically pip has had several entrypoints defined. Because of issues + arising from PATH, sys.path, multiple Pythons, their interactions, and most + of them having a pip installed, users suffer every time an entrypoint gets + moved. + + To alleviate this pain, and provide a mechanism for warning users and + directing them to an appropriate place for help, we now define all of + our old entrypoints as wrappers for the current one. + """ + sys.stderr.write( + "WARNING: pip is being invoked by an old script wrapper. This will " + "fail in a future version of pip.\n" + "Please see https://github.com/pypa/pip/issues/5599 for advice on " + "fixing the underlying issue.\n" + "To avoid this problem you can invoke Python with '-m pip' instead of " + "running pip directly.\n" + ) + return main(args) + + +def get_best_invocation_for_this_pip() -> str: + """Try to figure out the best way to invoke pip in the current environment.""" + binary_directory = "Scripts" if WINDOWS else "bin" + binary_prefix = os.path.join(sys.prefix, binary_directory) + + # Try to use pip[X[.Y]] names, if those executables for this environment are + # the first on PATH with that name. + path_parts = os.path.normcase(os.environ.get("PATH", "")).split(os.pathsep) + exe_are_in_PATH = os.path.normcase(binary_prefix) in path_parts + if exe_are_in_PATH: + for exe_name in _EXECUTABLE_NAMES: + found_executable = shutil.which(exe_name) + binary_executable = os.path.join(binary_prefix, exe_name) + if ( + found_executable + and os.path.exists(binary_executable) + and os.path.samefile( + found_executable, + binary_executable, + ) + ): + return exe_name + + # Use the `-m` invocation, if there's no "nice" invocation. + return f"{get_best_invocation_for_this_python()} -m pip" + + +def get_best_invocation_for_this_python() -> str: + """Try to figure out the best way to invoke the current Python.""" + exe = sys.executable + exe_name = os.path.basename(exe) + + # Try to use the basename, if it's the first executable. + found_executable = shutil.which(exe_name) + if found_executable and os.path.samefile(found_executable, exe): + return exe_name + + # Use the full executable name, because we couldn't find something simpler. + return exe diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/filesystem.py b/backend/venv/Lib/site-packages/pip/_internal/utils/filesystem.py new file mode 100644 index 0000000..22e356c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/filesystem.py @@ -0,0 +1,149 @@ +import fnmatch +import os +import os.path +import random +import sys +from contextlib import contextmanager +from tempfile import NamedTemporaryFile +from typing import Any, BinaryIO, Generator, List, Union, cast + +from pip._internal.utils.compat import get_path_uid +from pip._internal.utils.misc import format_size +from pip._internal.utils.retry import retry + + +def check_path_owner(path: str) -> bool: + # If we don't have a way to check the effective uid of this process, then + # we'll just assume that we own the directory. + if sys.platform == "win32" or not hasattr(os, "geteuid"): + return True + + assert os.path.isabs(path) + + previous = None + while path != previous: + if os.path.lexists(path): + # Check if path is writable by current user. + if os.geteuid() == 0: + # Special handling for root user in order to handle properly + # cases where users use sudo without -H flag. + try: + path_uid = get_path_uid(path) + except OSError: + return False + return path_uid == 0 + else: + return os.access(path, os.W_OK) + else: + previous, path = path, os.path.dirname(path) + return False # assume we don't own the path + + +@contextmanager +def adjacent_tmp_file(path: str, **kwargs: Any) -> Generator[BinaryIO, None, None]: + """Return a file-like object pointing to a tmp file next to path. + + The file is created securely and is ensured to be written to disk + after the context reaches its end. + + kwargs will be passed to tempfile.NamedTemporaryFile to control + the way the temporary file will be opened. + """ + with NamedTemporaryFile( + delete=False, + dir=os.path.dirname(path), + prefix=os.path.basename(path), + suffix=".tmp", + **kwargs, + ) as f: + result = cast(BinaryIO, f) + try: + yield result + finally: + result.flush() + os.fsync(result.fileno()) + + +replace = retry(stop_after_delay=1, wait=0.25)(os.replace) + + +# test_writable_dir and _test_writable_dir_win are copied from Flit, +# with the author's agreement to also place them under pip's license. +def test_writable_dir(path: str) -> bool: + """Check if a directory is writable. + + Uses os.access() on POSIX, tries creating files on Windows. + """ + # If the directory doesn't exist, find the closest parent that does. + while not os.path.isdir(path): + parent = os.path.dirname(path) + if parent == path: + break # Should never get here, but infinite loops are bad + path = parent + + if os.name == "posix": + return os.access(path, os.W_OK) + + return _test_writable_dir_win(path) + + +def _test_writable_dir_win(path: str) -> bool: + # os.access doesn't work on Windows: http://bugs.python.org/issue2528 + # and we can't use tempfile: http://bugs.python.org/issue22107 + basename = "accesstest_deleteme_fishfingers_custard_" + alphabet = "abcdefghijklmnopqrstuvwxyz0123456789" + for _ in range(10): + name = basename + "".join(random.choice(alphabet) for _ in range(6)) + file = os.path.join(path, name) + try: + fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL) + except FileExistsError: + pass + except PermissionError: + # This could be because there's a directory with the same name. + # But it's highly unlikely there's a directory called that, + # so we'll assume it's because the parent dir is not writable. + # This could as well be because the parent dir is not readable, + # due to non-privileged user access. + return False + else: + os.close(fd) + os.unlink(file) + return True + + # This should never be reached + raise OSError("Unexpected condition testing for writable directory") + + +def find_files(path: str, pattern: str) -> List[str]: + """Returns a list of absolute paths of files beneath path, recursively, + with filenames which match the UNIX-style shell glob pattern.""" + result: List[str] = [] + for root, _, files in os.walk(path): + matches = fnmatch.filter(files, pattern) + result.extend(os.path.join(root, f) for f in matches) + return result + + +def file_size(path: str) -> Union[int, float]: + # If it's a symlink, return 0. + if os.path.islink(path): + return 0 + return os.path.getsize(path) + + +def format_file_size(path: str) -> str: + return format_size(file_size(path)) + + +def directory_size(path: str) -> Union[int, float]: + size = 0.0 + for root, _dirs, files in os.walk(path): + for filename in files: + file_path = os.path.join(root, filename) + size += file_size(file_path) + return size + + +def format_directory_size(path: str) -> str: + return format_size(directory_size(path)) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/filetypes.py b/backend/venv/Lib/site-packages/pip/_internal/utils/filetypes.py new file mode 100644 index 0000000..5948570 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/filetypes.py @@ -0,0 +1,27 @@ +"""Filetype information. +""" + +from typing import Tuple + +from pip._internal.utils.misc import splitext + +WHEEL_EXTENSION = ".whl" +BZ2_EXTENSIONS: Tuple[str, ...] = (".tar.bz2", ".tbz") +XZ_EXTENSIONS: Tuple[str, ...] = ( + ".tar.xz", + ".txz", + ".tlz", + ".tar.lz", + ".tar.lzma", +) +ZIP_EXTENSIONS: Tuple[str, ...] = (".zip", WHEEL_EXTENSION) +TAR_EXTENSIONS: Tuple[str, ...] = (".tar.gz", ".tgz", ".tar") +ARCHIVE_EXTENSIONS = ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS + + +def is_archive_file(name: str) -> bool: + """Return True if `name` is a considered as an archive file.""" + ext = splitext(name)[1].lower() + if ext in ARCHIVE_EXTENSIONS: + return True + return False diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/glibc.py b/backend/venv/Lib/site-packages/pip/_internal/utils/glibc.py new file mode 100644 index 0000000..998868f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/glibc.py @@ -0,0 +1,101 @@ +import os +import sys +from typing import Optional, Tuple + + +def glibc_version_string() -> Optional[str]: + "Returns glibc version string, or None if not using glibc." + return glibc_version_string_confstr() or glibc_version_string_ctypes() + + +def glibc_version_string_confstr() -> Optional[str]: + "Primary implementation of glibc_version_string using os.confstr." + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module: + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 + if sys.platform == "win32": + return None + try: + gnu_libc_version = os.confstr("CS_GNU_LIBC_VERSION") + if gnu_libc_version is None: + return None + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17": + _, version = gnu_libc_version.split() + except (AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def glibc_version_string_ctypes() -> Optional[str]: + "Fallback implementation of glibc_version_string using ctypes." + + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can't proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# platform.libc_ver regularly returns completely nonsensical glibc +# versions. E.g. on my computer, platform says: +# +# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.7') +# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.9') +# +# But the truth is: +# +# ~$ ldd --version +# ldd (Debian GLIBC 2.22-11) 2.22 +# +# This is unfortunate, because it means that the linehaul data on libc +# versions that was generated by pip 8.1.2 and earlier is useless and +# misleading. Solution: instead of using platform, use our code that actually +# works. +def libc_ver() -> Tuple[str, str]: + """Try to determine the glibc version + + Returns a tuple of strings (lib, version) which default to empty strings + in case the lookup fails. + """ + glibc_version = glibc_version_string() + if glibc_version is None: + return ("", "") + else: + return ("glibc", glibc_version) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/hashes.py b/backend/venv/Lib/site-packages/pip/_internal/utils/hashes.py new file mode 100644 index 0000000..535e94f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/hashes.py @@ -0,0 +1,147 @@ +import hashlib +from typing import TYPE_CHECKING, BinaryIO, Dict, Iterable, List, NoReturn, Optional + +from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError +from pip._internal.utils.misc import read_chunks + +if TYPE_CHECKING: + from hashlib import _Hash + + +# The recommended hash algo of the moment. Change this whenever the state of +# the art changes; it won't hurt backward compatibility. +FAVORITE_HASH = "sha256" + + +# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` +# Currently, those are the ones at least as collision-resistant as sha256. +STRONG_HASHES = ["sha256", "sha384", "sha512"] + + +class Hashes: + """A wrapper that builds multiple hashes at once and checks them against + known-good values + + """ + + def __init__(self, hashes: Optional[Dict[str, List[str]]] = None) -> None: + """ + :param hashes: A dict of algorithm names pointing to lists of allowed + hex digests + """ + allowed = {} + if hashes is not None: + for alg, keys in hashes.items(): + # Make sure values are always sorted (to ease equality checks) + allowed[alg] = [k.lower() for k in sorted(keys)] + self._allowed = allowed + + def __and__(self, other: "Hashes") -> "Hashes": + if not isinstance(other, Hashes): + return NotImplemented + + # If either of the Hashes object is entirely empty (i.e. no hash + # specified at all), all hashes from the other object are allowed. + if not other: + return self + if not self: + return other + + # Otherwise only hashes that present in both objects are allowed. + new = {} + for alg, values in other._allowed.items(): + if alg not in self._allowed: + continue + new[alg] = [v for v in values if v in self._allowed[alg]] + return Hashes(new) + + @property + def digest_count(self) -> int: + return sum(len(digests) for digests in self._allowed.values()) + + def is_hash_allowed(self, hash_name: str, hex_digest: str) -> bool: + """Return whether the given hex digest is allowed.""" + return hex_digest in self._allowed.get(hash_name, []) + + def check_against_chunks(self, chunks: Iterable[bytes]) -> None: + """Check good hashes against ones built from iterable of chunks of + data. + + Raise HashMismatch if none match. + + """ + gots = {} + for hash_name in self._allowed.keys(): + try: + gots[hash_name] = hashlib.new(hash_name) + except (ValueError, TypeError): + raise InstallationError(f"Unknown hash name: {hash_name}") + + for chunk in chunks: + for hash in gots.values(): + hash.update(chunk) + + for hash_name, got in gots.items(): + if got.hexdigest() in self._allowed[hash_name]: + return + self._raise(gots) + + def _raise(self, gots: Dict[str, "_Hash"]) -> "NoReturn": + raise HashMismatch(self._allowed, gots) + + def check_against_file(self, file: BinaryIO) -> None: + """Check good hashes against a file-like object + + Raise HashMismatch if none match. + + """ + return self.check_against_chunks(read_chunks(file)) + + def check_against_path(self, path: str) -> None: + with open(path, "rb") as file: + return self.check_against_file(file) + + def has_one_of(self, hashes: Dict[str, str]) -> bool: + """Return whether any of the given hashes are allowed.""" + for hash_name, hex_digest in hashes.items(): + if self.is_hash_allowed(hash_name, hex_digest): + return True + return False + + def __bool__(self) -> bool: + """Return whether I know any known-good hashes.""" + return bool(self._allowed) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Hashes): + return NotImplemented + return self._allowed == other._allowed + + def __hash__(self) -> int: + return hash( + ",".join( + sorted( + ":".join((alg, digest)) + for alg, digest_list in self._allowed.items() + for digest in digest_list + ) + ) + ) + + +class MissingHashes(Hashes): + """A workalike for Hashes used when we're missing a hash for a requirement + + It computes the actual hash of the requirement and raises a HashMissing + exception showing it to the user. + + """ + + def __init__(self) -> None: + """Don't offer the ``hashes`` kwarg.""" + # Pass our favorite hash in to generate a "gotten hash". With the + # empty list, it will never match, so an error will always raise. + super().__init__(hashes={FAVORITE_HASH: []}) + + def _raise(self, gots: Dict[str, "_Hash"]) -> "NoReturn": + raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/logging.py b/backend/venv/Lib/site-packages/pip/_internal/utils/logging.py new file mode 100644 index 0000000..62035fc --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/logging.py @@ -0,0 +1,354 @@ +import contextlib +import errno +import logging +import logging.handlers +import os +import sys +import threading +from dataclasses import dataclass +from io import TextIOWrapper +from logging import Filter +from typing import Any, ClassVar, Generator, List, Optional, TextIO, Type + +from pip._vendor.rich.console import ( + Console, + ConsoleOptions, + ConsoleRenderable, + RenderableType, + RenderResult, + RichCast, +) +from pip._vendor.rich.highlighter import NullHighlighter +from pip._vendor.rich.logging import RichHandler +from pip._vendor.rich.segment import Segment +from pip._vendor.rich.style import Style + +from pip._internal.utils._log import VERBOSE, getLogger +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX +from pip._internal.utils.misc import ensure_dir + +_log_state = threading.local() +subprocess_logger = getLogger("pip.subprocessor") + + +class BrokenStdoutLoggingError(Exception): + """ + Raised if BrokenPipeError occurs for the stdout stream while logging. + """ + + +def _is_broken_pipe_error(exc_class: Type[BaseException], exc: BaseException) -> bool: + if exc_class is BrokenPipeError: + return True + + # On Windows, a broken pipe can show up as EINVAL rather than EPIPE: + # https://bugs.python.org/issue19612 + # https://bugs.python.org/issue30418 + if not WINDOWS: + return False + + return isinstance(exc, OSError) and exc.errno in (errno.EINVAL, errno.EPIPE) + + +@contextlib.contextmanager +def indent_log(num: int = 2) -> Generator[None, None, None]: + """ + A context manager which will cause the log output to be indented for any + log messages emitted inside it. + """ + # For thread-safety + _log_state.indentation = get_indentation() + _log_state.indentation += num + try: + yield + finally: + _log_state.indentation -= num + + +def get_indentation() -> int: + return getattr(_log_state, "indentation", 0) + + +class IndentingFormatter(logging.Formatter): + default_time_format = "%Y-%m-%dT%H:%M:%S" + + def __init__( + self, + *args: Any, + add_timestamp: bool = False, + **kwargs: Any, + ) -> None: + """ + A logging.Formatter that obeys the indent_log() context manager. + + :param add_timestamp: A bool indicating output lines should be prefixed + with their record's timestamp. + """ + self.add_timestamp = add_timestamp + super().__init__(*args, **kwargs) + + def get_message_start(self, formatted: str, levelno: int) -> str: + """ + Return the start of the formatted log message (not counting the + prefix to add to each line). + """ + if levelno < logging.WARNING: + return "" + if formatted.startswith(DEPRECATION_MSG_PREFIX): + # Then the message already has a prefix. We don't want it to + # look like "WARNING: DEPRECATION: ...." + return "" + if levelno < logging.ERROR: + return "WARNING: " + + return "ERROR: " + + def format(self, record: logging.LogRecord) -> str: + """ + Calls the standard formatter, but will indent all of the log message + lines by our current indentation level. + """ + formatted = super().format(record) + message_start = self.get_message_start(formatted, record.levelno) + formatted = message_start + formatted + + prefix = "" + if self.add_timestamp: + prefix = f"{self.formatTime(record)} " + prefix += " " * get_indentation() + formatted = "".join([prefix + line for line in formatted.splitlines(True)]) + return formatted + + +@dataclass +class IndentedRenderable: + renderable: RenderableType + indent: int + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + segments = console.render(self.renderable, options) + lines = Segment.split_lines(segments) + for line in lines: + yield Segment(" " * self.indent) + yield from line + yield Segment("\n") + + +class PipConsole(Console): + def on_broken_pipe(self) -> None: + # Reraise the original exception, rich 13.8.0+ exits by default + # instead, preventing our handler from firing. + raise BrokenPipeError() from None + + +class RichPipStreamHandler(RichHandler): + KEYWORDS: ClassVar[Optional[List[str]]] = [] + + def __init__(self, stream: Optional[TextIO], no_color: bool) -> None: + super().__init__( + console=PipConsole(file=stream, no_color=no_color, soft_wrap=True), + show_time=False, + show_level=False, + show_path=False, + highlighter=NullHighlighter(), + ) + + # Our custom override on Rich's logger, to make things work as we need them to. + def emit(self, record: logging.LogRecord) -> None: + style: Optional[Style] = None + + # If we are given a diagnostic error to present, present it with indentation. + if getattr(record, "rich", False): + assert isinstance(record.args, tuple) + (rich_renderable,) = record.args + assert isinstance( + rich_renderable, (ConsoleRenderable, RichCast, str) + ), f"{rich_renderable} is not rich-console-renderable" + + renderable: RenderableType = IndentedRenderable( + rich_renderable, indent=get_indentation() + ) + else: + message = self.format(record) + renderable = self.render_message(record, message) + if record.levelno is not None: + if record.levelno >= logging.ERROR: + style = Style(color="red") + elif record.levelno >= logging.WARNING: + style = Style(color="yellow") + + try: + self.console.print(renderable, overflow="ignore", crop=False, style=style) + except Exception: + self.handleError(record) + + def handleError(self, record: logging.LogRecord) -> None: + """Called when logging is unable to log some output.""" + + exc_class, exc = sys.exc_info()[:2] + # If a broken pipe occurred while calling write() or flush() on the + # stdout stream in logging's Handler.emit(), then raise our special + # exception so we can handle it in main() instead of logging the + # broken pipe error and continuing. + if ( + exc_class + and exc + and self.console.file is sys.stdout + and _is_broken_pipe_error(exc_class, exc) + ): + raise BrokenStdoutLoggingError() + + return super().handleError(record) + + +class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): + def _open(self) -> TextIOWrapper: + ensure_dir(os.path.dirname(self.baseFilename)) + return super()._open() + + +class MaxLevelFilter(Filter): + def __init__(self, level: int) -> None: + self.level = level + + def filter(self, record: logging.LogRecord) -> bool: + return record.levelno < self.level + + +class ExcludeLoggerFilter(Filter): + """ + A logging Filter that excludes records from a logger (or its children). + """ + + def filter(self, record: logging.LogRecord) -> bool: + # The base Filter class allows only records from a logger (or its + # children). + return not super().filter(record) + + +def setup_logging(verbosity: int, no_color: bool, user_log_file: Optional[str]) -> int: + """Configures and sets up all of the logging + + Returns the requested logging level, as its integer value. + """ + + # Determine the level to be logging at. + if verbosity >= 2: + level_number = logging.DEBUG + elif verbosity == 1: + level_number = VERBOSE + elif verbosity == -1: + level_number = logging.WARNING + elif verbosity == -2: + level_number = logging.ERROR + elif verbosity <= -3: + level_number = logging.CRITICAL + else: + level_number = logging.INFO + + level = logging.getLevelName(level_number) + + # The "root" logger should match the "console" level *unless* we also need + # to log to a user log file. + include_user_log = user_log_file is not None + if include_user_log: + additional_log_file = user_log_file + root_level = "DEBUG" + else: + additional_log_file = "/dev/null" + root_level = level + + # Disable any logging besides WARNING unless we have DEBUG level logging + # enabled for vendored libraries. + vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" + + # Shorthands for clarity + log_streams = { + "stdout": "ext://sys.stdout", + "stderr": "ext://sys.stderr", + } + handler_classes = { + "stream": "pip._internal.utils.logging.RichPipStreamHandler", + "file": "pip._internal.utils.logging.BetterRotatingFileHandler", + } + handlers = ["console", "console_errors", "console_subprocess"] + ( + ["user_log"] if include_user_log else [] + ) + + logging.config.dictConfig( + { + "version": 1, + "disable_existing_loggers": False, + "filters": { + "exclude_warnings": { + "()": "pip._internal.utils.logging.MaxLevelFilter", + "level": logging.WARNING, + }, + "restrict_to_subprocess": { + "()": "logging.Filter", + "name": subprocess_logger.name, + }, + "exclude_subprocess": { + "()": "pip._internal.utils.logging.ExcludeLoggerFilter", + "name": subprocess_logger.name, + }, + }, + "formatters": { + "indent": { + "()": IndentingFormatter, + "format": "%(message)s", + }, + "indent_with_timestamp": { + "()": IndentingFormatter, + "format": "%(message)s", + "add_timestamp": True, + }, + }, + "handlers": { + "console": { + "level": level, + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stdout"], + "filters": ["exclude_subprocess", "exclude_warnings"], + "formatter": "indent", + }, + "console_errors": { + "level": "WARNING", + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stderr"], + "filters": ["exclude_subprocess"], + "formatter": "indent", + }, + # A handler responsible for logging to the console messages + # from the "subprocessor" logger. + "console_subprocess": { + "level": level, + "class": handler_classes["stream"], + "stream": log_streams["stderr"], + "no_color": no_color, + "filters": ["restrict_to_subprocess"], + "formatter": "indent", + }, + "user_log": { + "level": "DEBUG", + "class": handler_classes["file"], + "filename": additional_log_file, + "encoding": "utf-8", + "delay": True, + "formatter": "indent_with_timestamp", + }, + }, + "root": { + "level": root_level, + "handlers": handlers, + }, + "loggers": {"pip._vendor": {"level": vendored_log_level}}, + } + ) + + return level_number diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/misc.py b/backend/venv/Lib/site-packages/pip/_internal/utils/misc.py new file mode 100644 index 0000000..44f6a05 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/misc.py @@ -0,0 +1,773 @@ +import errno +import getpass +import hashlib +import logging +import os +import posixpath +import shutil +import stat +import sys +import sysconfig +import urllib.parse +from dataclasses import dataclass +from functools import partial +from io import StringIO +from itertools import filterfalse, tee, zip_longest +from pathlib import Path +from types import FunctionType, TracebackType +from typing import ( + Any, + BinaryIO, + Callable, + Generator, + Iterable, + Iterator, + List, + Mapping, + Optional, + Sequence, + TextIO, + Tuple, + Type, + TypeVar, + Union, + cast, +) + +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip import __version__ +from pip._internal.exceptions import CommandError, ExternallyManagedEnvironment +from pip._internal.locations import get_major_minor_version +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.retry import retry +from pip._internal.utils.virtualenv import running_under_virtualenv + +__all__ = [ + "rmtree", + "display_path", + "backup_dir", + "ask", + "splitext", + "format_size", + "is_installable_dir", + "normalize_path", + "renames", + "get_prog", + "ensure_dir", + "remove_auth_from_url", + "check_externally_managed", + "ConfiguredBuildBackendHookCaller", +] + +logger = logging.getLogger(__name__) + +T = TypeVar("T") +ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType] +VersionInfo = Tuple[int, int, int] +NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]] +OnExc = Callable[[FunctionType, Path, BaseException], Any] +OnErr = Callable[[FunctionType, Path, ExcInfo], Any] + +FILE_CHUNK_SIZE = 1024 * 1024 + + +def get_pip_version() -> str: + pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") + pip_pkg_dir = os.path.abspath(pip_pkg_dir) + + return f"pip {__version__} from {pip_pkg_dir} (python {get_major_minor_version()})" + + +def normalize_version_info(py_version_info: Tuple[int, ...]) -> Tuple[int, int, int]: + """ + Convert a tuple of ints representing a Python version to one of length + three. + + :param py_version_info: a tuple of ints representing a Python version, + or None to specify no version. The tuple can have any length. + + :return: a tuple of length three if `py_version_info` is non-None. + Otherwise, return `py_version_info` unchanged (i.e. None). + """ + if len(py_version_info) < 3: + py_version_info += (3 - len(py_version_info)) * (0,) + elif len(py_version_info) > 3: + py_version_info = py_version_info[:3] + + return cast("VersionInfo", py_version_info) + + +def ensure_dir(path: str) -> None: + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + # Windows can raise spurious ENOTEMPTY errors. See #6426. + if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY: + raise + + +def get_prog() -> str: + try: + prog = os.path.basename(sys.argv[0]) + if prog in ("__main__.py", "-c"): + return f"{sys.executable} -m pip" + else: + return prog + except (AttributeError, TypeError, IndexError): + pass + return "pip" + + +# Retry every half second for up to 3 seconds +@retry(stop_after_delay=3, wait=0.5) +def rmtree( + dir: str, ignore_errors: bool = False, onexc: Optional[OnExc] = None +) -> None: + if ignore_errors: + onexc = _onerror_ignore + if onexc is None: + onexc = _onerror_reraise + handler: OnErr = partial(rmtree_errorhandler, onexc=onexc) + if sys.version_info >= (3, 12): + # See https://docs.python.org/3.12/whatsnew/3.12.html#shutil. + shutil.rmtree(dir, onexc=handler) # type: ignore + else: + shutil.rmtree(dir, onerror=handler) # type: ignore + + +def _onerror_ignore(*_args: Any) -> None: + pass + + +def _onerror_reraise(*_args: Any) -> None: + raise # noqa: PLE0704 - Bare exception used to reraise existing exception + + +def rmtree_errorhandler( + func: FunctionType, + path: Path, + exc_info: Union[ExcInfo, BaseException], + *, + onexc: OnExc = _onerror_reraise, +) -> None: + """ + `rmtree` error handler to 'force' a file remove (i.e. like `rm -f`). + + * If a file is readonly then it's write flag is set and operation is + retried. + + * `onerror` is the original callback from `rmtree(... onerror=onerror)` + that is chained at the end if the "rm -f" still fails. + """ + try: + st_mode = os.stat(path).st_mode + except OSError: + # it's equivalent to os.path.exists + return + + if not st_mode & stat.S_IWRITE: + # convert to read/write + try: + os.chmod(path, st_mode | stat.S_IWRITE) + except OSError: + pass + else: + # use the original function to repeat the operation + try: + func(path) + return + except OSError: + pass + + if not isinstance(exc_info, BaseException): + _, exc_info, _ = exc_info + onexc(func, path, exc_info) + + +def display_path(path: str) -> str: + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if path.startswith(os.getcwd() + os.path.sep): + path = "." + path[len(os.getcwd()) :] + return path + + +def backup_dir(dir: str, ext: str = ".bak") -> str: + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def ask_path_exists(message: str, options: Iterable[str]) -> str: + for action in os.environ.get("PIP_EXISTS_ACTION", "").split(): + if action in options: + return action + return ask(message, options) + + +def _check_no_input(message: str) -> None: + """Raise an error if no input is allowed.""" + if os.environ.get("PIP_NO_INPUT"): + raise Exception( + f"No input was expected ($PIP_NO_INPUT set); question: {message}" + ) + + +def ask(message: str, options: Iterable[str]) -> str: + """Ask the message interactively, with the given possible responses""" + while 1: + _check_no_input(message) + response = input(message) + response = response.strip().lower() + if response not in options: + print( + "Your response ({!r}) was not one of the expected responses: " + "{}".format(response, ", ".join(options)) + ) + else: + return response + + +def ask_input(message: str) -> str: + """Ask for input interactively.""" + _check_no_input(message) + return input(message) + + +def ask_password(message: str) -> str: + """Ask for a password interactively.""" + _check_no_input(message) + return getpass.getpass(message) + + +def strtobool(val: str) -> int: + """Convert a string representation of truth to true (1) or false (0). + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + """ + val = val.lower() + if val in ("y", "yes", "t", "true", "on", "1"): + return 1 + elif val in ("n", "no", "f", "false", "off", "0"): + return 0 + else: + raise ValueError(f"invalid truth value {val!r}") + + +def format_size(bytes: float) -> str: + if bytes > 1000 * 1000: + return f"{bytes / 1000.0 / 1000:.1f} MB" + elif bytes > 10 * 1000: + return f"{int(bytes / 1000)} kB" + elif bytes > 1000: + return f"{bytes / 1000.0:.1f} kB" + else: + return f"{int(bytes)} bytes" + + +def tabulate(rows: Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]: + """Return a list of formatted rows and a list of column sizes. + + For example:: + + >>> tabulate([['foobar', 2000], [0xdeadbeef]]) + (['foobar 2000', '3735928559'], [10, 4]) + """ + rows = [tuple(map(str, row)) for row in rows] + sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")] + table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] + return table, sizes + + +def is_installable_dir(path: str) -> bool: + """Is path is a directory containing pyproject.toml or setup.py? + + If pyproject.toml exists, this is a PEP 517 project. Otherwise we look for + a legacy setuptools layout by identifying setup.py. We don't check for the + setup.cfg because using it without setup.py is only available for PEP 517 + projects, which are already covered by the pyproject.toml check. + """ + if not os.path.isdir(path): + return False + if os.path.isfile(os.path.join(path, "pyproject.toml")): + return True + if os.path.isfile(os.path.join(path, "setup.py")): + return True + return False + + +def read_chunks( + file: BinaryIO, size: int = FILE_CHUNK_SIZE +) -> Generator[bytes, None, None]: + """Yield pieces of data from a file-like object until EOF.""" + while True: + chunk = file.read(size) + if not chunk: + break + yield chunk + + +def normalize_path(path: str, resolve_symlinks: bool = True) -> str: + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + path = os.path.expanduser(path) + if resolve_symlinks: + path = os.path.realpath(path) + else: + path = os.path.abspath(path) + return os.path.normcase(path) + + +def splitext(path: str) -> Tuple[str, str]: + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith(".tar"): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old: str, new: str) -> None: + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path: str) -> bool: + """ + Return True if path is within sys.prefix, if we're running in a virtualenv. + + If we're not in a virtualenv, all paths are considered "local." + + Caution: this function assumes the head of path has been normalized + with normalize_path. + """ + if not running_under_virtualenv(): + return True + return path.startswith(normalize_path(sys.prefix)) + + +def write_output(msg: Any, *args: Any) -> None: + logger.info(msg, *args) + + +class StreamWrapper(StringIO): + orig_stream: TextIO + + @classmethod + def from_stream(cls, orig_stream: TextIO) -> "StreamWrapper": + ret = cls() + ret.orig_stream = orig_stream + return ret + + # compileall.compile_dir() needs stdout.encoding to print to stdout + # type ignore is because TextIOBase.encoding is writeable + @property + def encoding(self) -> str: # type: ignore + return self.orig_stream.encoding + + +# Simulates an enum +def enum(*sequential: Any, **named: Any) -> Type[Any]: + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = {value: key for key, value in enums.items()} + enums["reverse_mapping"] = reverse + return type("Enum", (), enums) + + +def build_netloc(host: str, port: Optional[int]) -> str: + """ + Build a netloc from a host-port pair + """ + if port is None: + return host + if ":" in host: + # Only wrap host with square brackets when it is IPv6 + host = f"[{host}]" + return f"{host}:{port}" + + +def build_url_from_netloc(netloc: str, scheme: str = "https") -> str: + """ + Build a full URL from a netloc. + """ + if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc: + # It must be a bare IPv6 address, so wrap it with brackets. + netloc = f"[{netloc}]" + return f"{scheme}://{netloc}" + + +def parse_netloc(netloc: str) -> Tuple[Optional[str], Optional[int]]: + """ + Return the host-port pair from a netloc. + """ + url = build_url_from_netloc(netloc) + parsed = urllib.parse.urlparse(url) + return parsed.hostname, parsed.port + + +def split_auth_from_netloc(netloc: str) -> NetlocTuple: + """ + Parse out and remove the auth information from a netloc. + + Returns: (netloc, (username, password)). + """ + if "@" not in netloc: + return netloc, (None, None) + + # Split from the right because that's how urllib.parse.urlsplit() + # behaves if more than one @ is present (which can be checked using + # the password attribute of urlsplit()'s return value). + auth, netloc = netloc.rsplit("@", 1) + pw: Optional[str] = None + if ":" in auth: + # Split from the left because that's how urllib.parse.urlsplit() + # behaves if more than one : is present (which again can be checked + # using the password attribute of the return value) + user, pw = auth.split(":", 1) + else: + user, pw = auth, None + + user = urllib.parse.unquote(user) + if pw is not None: + pw = urllib.parse.unquote(pw) + + return netloc, (user, pw) + + +def redact_netloc(netloc: str) -> str: + """ + Replace the sensitive data in a netloc with "****", if it exists. + + For example: + - "user:pass@example.com" returns "user:****@example.com" + - "accesstoken@example.com" returns "****@example.com" + """ + netloc, (user, password) = split_auth_from_netloc(netloc) + if user is None: + return netloc + if password is None: + user = "****" + password = "" + else: + user = urllib.parse.quote(user) + password = ":****" + return f"{user}{password}@{netloc}" + + +def _transform_url( + url: str, transform_netloc: Callable[[str], Tuple[Any, ...]] +) -> Tuple[str, NetlocTuple]: + """Transform and replace netloc in a url. + + transform_netloc is a function taking the netloc and returning a + tuple. The first element of this tuple is the new netloc. The + entire tuple is returned. + + Returns a tuple containing the transformed url as item 0 and the + original tuple returned by transform_netloc as item 1. + """ + purl = urllib.parse.urlsplit(url) + netloc_tuple = transform_netloc(purl.netloc) + # stripped url + url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment) + surl = urllib.parse.urlunsplit(url_pieces) + return surl, cast("NetlocTuple", netloc_tuple) + + +def _get_netloc(netloc: str) -> NetlocTuple: + return split_auth_from_netloc(netloc) + + +def _redact_netloc(netloc: str) -> Tuple[str]: + return (redact_netloc(netloc),) + + +def split_auth_netloc_from_url( + url: str, +) -> Tuple[str, str, Tuple[Optional[str], Optional[str]]]: + """ + Parse a url into separate netloc, auth, and url with no auth. + + Returns: (url_without_auth, netloc, (username, password)) + """ + url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc) + return url_without_auth, netloc, auth + + +def remove_auth_from_url(url: str) -> str: + """Return a copy of url with 'username:password@' removed.""" + # username/pass params are passed to subversion through flags + # and are not recognized in the url. + return _transform_url(url, _get_netloc)[0] + + +def redact_auth_from_url(url: str) -> str: + """Replace the password in a given url with ****.""" + return _transform_url(url, _redact_netloc)[0] + + +def redact_auth_from_requirement(req: Requirement) -> str: + """Replace the password in a given requirement url with ****.""" + if not req.url: + return str(req) + return str(req).replace(req.url, redact_auth_from_url(req.url)) + + +@dataclass(frozen=True) +class HiddenText: + secret: str + redacted: str + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return self.redacted + + # This is useful for testing. + def __eq__(self, other: Any) -> bool: + if type(self) is not type(other): + return False + + # The string being used for redaction doesn't also have to match, + # just the raw, original string. + return self.secret == other.secret + + +def hide_value(value: str) -> HiddenText: + return HiddenText(value, redacted="****") + + +def hide_url(url: str) -> HiddenText: + redacted = redact_auth_from_url(url) + return HiddenText(url, redacted=redacted) + + +def protect_pip_from_modification_on_windows(modifying_pip: bool) -> None: + """Protection of pip.exe from modification on Windows + + On Windows, any operation modifying pip should be run as: + python -m pip ... + """ + pip_names = [ + "pip", + f"pip{sys.version_info.major}", + f"pip{sys.version_info.major}.{sys.version_info.minor}", + ] + + # See https://github.com/pypa/pip/issues/1299 for more discussion + should_show_use_python_msg = ( + modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names + ) + + if should_show_use_python_msg: + new_command = [sys.executable, "-m", "pip"] + sys.argv[1:] + raise CommandError( + "To modify pip, please run the following command:\n{}".format( + " ".join(new_command) + ) + ) + + +def check_externally_managed() -> None: + """Check whether the current environment is externally managed. + + If the ``EXTERNALLY-MANAGED`` config file is found, the current environment + is considered externally managed, and an ExternallyManagedEnvironment is + raised. + """ + if running_under_virtualenv(): + return + marker = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED") + if not os.path.isfile(marker): + return + raise ExternallyManagedEnvironment.from_config(marker) + + +def is_console_interactive() -> bool: + """Is this console interactive?""" + return sys.stdin is not None and sys.stdin.isatty() + + +def hash_file(path: str, blocksize: int = 1 << 20) -> Tuple[Any, int]: + """Return (hash, length) for path using hashlib.sha256()""" + + h = hashlib.sha256() + length = 0 + with open(path, "rb") as f: + for block in read_chunks(f, size=blocksize): + length += len(block) + h.update(block) + return h, length + + +def pairwise(iterable: Iterable[Any]) -> Iterator[Tuple[Any, Any]]: + """ + Return paired elements. + + For example: + s -> (s0, s1), (s2, s3), (s4, s5), ... + """ + iterable = iter(iterable) + return zip_longest(iterable, iterable) + + +def partition( + pred: Callable[[T], bool], iterable: Iterable[T] +) -> Tuple[Iterable[T], Iterable[T]]: + """ + Use a predicate to partition entries into false entries and true entries, + like + + partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 + """ + t1, t2 = tee(iterable) + return filterfalse(pred, t1), filter(pred, t2) + + +class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller): + def __init__( + self, + config_holder: Any, + source_dir: str, + build_backend: str, + backend_path: Optional[str] = None, + runner: Optional[Callable[..., None]] = None, + python_executable: Optional[str] = None, + ): + super().__init__( + source_dir, build_backend, backend_path, runner, python_executable + ) + self.config_holder = config_holder + + def build_wheel( + self, + wheel_directory: str, + config_settings: Optional[Mapping[str, Any]] = None, + metadata_directory: Optional[str] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_wheel( + wheel_directory, config_settings=cs, metadata_directory=metadata_directory + ) + + def build_sdist( + self, + sdist_directory: str, + config_settings: Optional[Mapping[str, Any]] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_sdist(sdist_directory, config_settings=cs) + + def build_editable( + self, + wheel_directory: str, + config_settings: Optional[Mapping[str, Any]] = None, + metadata_directory: Optional[str] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_editable( + wheel_directory, config_settings=cs, metadata_directory=metadata_directory + ) + + def get_requires_for_build_wheel( + self, config_settings: Optional[Mapping[str, Any]] = None + ) -> Sequence[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_wheel(config_settings=cs) + + def get_requires_for_build_sdist( + self, config_settings: Optional[Mapping[str, Any]] = None + ) -> Sequence[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_sdist(config_settings=cs) + + def get_requires_for_build_editable( + self, config_settings: Optional[Mapping[str, Any]] = None + ) -> Sequence[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_editable(config_settings=cs) + + def prepare_metadata_for_build_wheel( + self, + metadata_directory: str, + config_settings: Optional[Mapping[str, Any]] = None, + _allow_fallback: bool = True, + ) -> str: + cs = self.config_holder.config_settings + return super().prepare_metadata_for_build_wheel( + metadata_directory=metadata_directory, + config_settings=cs, + _allow_fallback=_allow_fallback, + ) + + def prepare_metadata_for_build_editable( + self, + metadata_directory: str, + config_settings: Optional[Mapping[str, Any]] = None, + _allow_fallback: bool = True, + ) -> Optional[str]: + cs = self.config_holder.config_settings + return super().prepare_metadata_for_build_editable( + metadata_directory=metadata_directory, + config_settings=cs, + _allow_fallback=_allow_fallback, + ) + + +def warn_if_run_as_root() -> None: + """Output a warning for sudo users on Unix. + + In a virtual environment, sudo pip still writes to virtualenv. + On Windows, users may run pip as Administrator without issues. + This warning only applies to Unix root users outside of virtualenv. + """ + if running_under_virtualenv(): + return + if not hasattr(os, "getuid"): + return + # On Windows, there are no "system managed" Python packages. Installing as + # Administrator via pip is the correct way of updating system environments. + # + # We choose sys.platform over utils.compat.WINDOWS here to enable Mypy platform + # checks: https://mypy.readthedocs.io/en/stable/common_issues.html + if sys.platform == "win32" or sys.platform == "cygwin": + return + + if os.getuid() != 0: + return + + logger.warning( + "Running pip as the 'root' user can result in broken permissions and " + "conflicting behaviour with the system package manager, possibly " + "rendering your system unusable. " + "It is recommended to use a virtual environment instead: " + "https://pip.pypa.io/warnings/venv. " + "Use the --root-user-action option if you know what you are doing and " + "want to suppress this warning." + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/packaging.py b/backend/venv/Lib/site-packages/pip/_internal/utils/packaging.py new file mode 100644 index 0000000..caad70f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/packaging.py @@ -0,0 +1,58 @@ +import functools +import logging +import re +from typing import NewType, Optional, Tuple, cast + +from pip._vendor.packaging import specifiers, version +from pip._vendor.packaging.requirements import Requirement + +NormalizedExtra = NewType("NormalizedExtra", str) + +logger = logging.getLogger(__name__) + + +@functools.lru_cache(maxsize=32) +def check_requires_python( + requires_python: Optional[str], version_info: Tuple[int, ...] +) -> bool: + """ + Check if the given Python version matches a "Requires-Python" specifier. + + :param version_info: A 3-tuple of ints representing a Python + major-minor-micro version to check (e.g. `sys.version_info[:3]`). + + :return: `True` if the given Python version satisfies the requirement. + Otherwise, return `False`. + + :raises InvalidSpecifier: If `requires_python` has an invalid format. + """ + if requires_python is None: + # The package provides no information + return True + requires_python_specifier = specifiers.SpecifierSet(requires_python) + + python_version = version.parse(".".join(map(str, version_info))) + return python_version in requires_python_specifier + + +@functools.lru_cache(maxsize=2048) +def get_requirement(req_string: str) -> Requirement: + """Construct a packaging.Requirement object with caching""" + # Parsing requirement strings is expensive, and is also expected to happen + # with a low diversity of different arguments (at least relative the number + # constructed). This method adds a cache to requirement object creation to + # minimize repeated parsing of the same string to construct equivalent + # Requirement objects. + return Requirement(req_string) + + +def safe_extra(extra: str) -> NormalizedExtra: + """Convert an arbitrary string to a standard 'extra' name + + Any runs of non-alphanumeric characters are replaced with a single '_', + and the result is always lowercased. + + This function is duplicated from ``pkg_resources``. Note that this is not + the same to either ``canonicalize_name`` or ``_egg_link_name``. + """ + return cast(NormalizedExtra, re.sub("[^A-Za-z0-9.-]+", "_", extra).lower()) diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/retry.py b/backend/venv/Lib/site-packages/pip/_internal/utils/retry.py new file mode 100644 index 0000000..abfe072 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/retry.py @@ -0,0 +1,42 @@ +import functools +from time import perf_counter, sleep +from typing import Callable, TypeVar + +from pip._vendor.typing_extensions import ParamSpec + +T = TypeVar("T") +P = ParamSpec("P") + + +def retry( + wait: float, stop_after_delay: float +) -> Callable[[Callable[P, T]], Callable[P, T]]: + """Decorator to automatically retry a function on error. + + If the function raises, the function is recalled with the same arguments + until it returns or the time limit is reached. When the time limit is + surpassed, the last exception raised is reraised. + + :param wait: The time to wait after an error before retrying, in seconds. + :param stop_after_delay: The time limit after which retries will cease, + in seconds. + """ + + def wrapper(func: Callable[P, T]) -> Callable[P, T]: + + @functools.wraps(func) + def retry_wrapped(*args: P.args, **kwargs: P.kwargs) -> T: + # The performance counter is monotonic on all platforms we care + # about and has much better resolution than time.monotonic(). + start_time = perf_counter() + while True: + try: + return func(*args, **kwargs) + except Exception: + if perf_counter() - start_time > stop_after_delay: + raise + sleep(wait) + + return retry_wrapped + + return wrapper diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py b/backend/venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py new file mode 100644 index 0000000..96d1b24 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py @@ -0,0 +1,146 @@ +import sys +import textwrap +from typing import List, Optional, Sequence + +# Shim to wrap setup.py invocation with setuptools +# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on +# Windows are correctly handled (it should be "C:\\Users" not "C:\Users"). +_SETUPTOOLS_SHIM = textwrap.dedent( + """ + exec(compile(''' + # This is -- a caller that pip uses to run setup.py + # + # - It imports setuptools before invoking setup.py, to enable projects that directly + # import from `distutils.core` to work with newer packaging standards. + # - It provides a clear error message when setuptools is not installed. + # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so + # setuptools doesn't think the script is `-c`. This avoids the following warning: + # manifest_maker: standard file '-c' not found". + # - It generates a shim setup.py, for handling setup.cfg-only projects. + import os, sys, tokenize + + try: + import setuptools + except ImportError as error: + print( + "ERROR: Can not execute `setup.py` since setuptools is not available in " + "the build environment.", + file=sys.stderr, + ) + sys.exit(1) + + __file__ = %r + sys.argv[0] = __file__ + + if os.path.exists(__file__): + filename = __file__ + with tokenize.open(__file__) as f: + setup_py_code = f.read() + else: + filename = "" + setup_py_code = "from setuptools import setup; setup()" + + exec(compile(setup_py_code, filename, "exec")) + ''' % ({!r},), "", "exec")) + """ +).rstrip() + + +def make_setuptools_shim_args( + setup_py_path: str, + global_options: Optional[Sequence[str]] = None, + no_user_config: bool = False, + unbuffered_output: bool = False, +) -> List[str]: + """ + Get setuptools command arguments with shim wrapped setup file invocation. + + :param setup_py_path: The path to setup.py to be wrapped. + :param global_options: Additional global options. + :param no_user_config: If True, disables personal user configuration. + :param unbuffered_output: If True, adds the unbuffered switch to the + argument list. + """ + args = [sys.executable] + if unbuffered_output: + args += ["-u"] + args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)] + if global_options: + args += global_options + if no_user_config: + args += ["--no-user-cfg"] + return args + + +def make_setuptools_bdist_wheel_args( + setup_py_path: str, + global_options: Sequence[str], + build_options: Sequence[str], + destination_dir: str, +) -> List[str]: + # NOTE: Eventually, we'd want to also -S to the flags here, when we're + # isolating. Currently, it breaks Python in virtualenvs, because it + # relies on site.py to find parts of the standard library outside the + # virtualenv. + args = make_setuptools_shim_args( + setup_py_path, global_options=global_options, unbuffered_output=True + ) + args += ["bdist_wheel", "-d", destination_dir] + args += build_options + return args + + +def make_setuptools_clean_args( + setup_py_path: str, + global_options: Sequence[str], +) -> List[str]: + args = make_setuptools_shim_args( + setup_py_path, global_options=global_options, unbuffered_output=True + ) + args += ["clean", "--all"] + return args + + +def make_setuptools_develop_args( + setup_py_path: str, + *, + global_options: Sequence[str], + no_user_config: bool, + prefix: Optional[str], + home: Optional[str], + use_user_site: bool, +) -> List[str]: + assert not (use_user_site and prefix) + + args = make_setuptools_shim_args( + setup_py_path, + global_options=global_options, + no_user_config=no_user_config, + ) + + args += ["develop", "--no-deps"] + + if prefix: + args += ["--prefix", prefix] + if home is not None: + args += ["--install-dir", home] + + if use_user_site: + args += ["--user", "--prefix="] + + return args + + +def make_setuptools_egg_info_args( + setup_py_path: str, + egg_info_dir: Optional[str], + no_user_config: bool, +) -> List[str]: + args = make_setuptools_shim_args(setup_py_path, no_user_config=no_user_config) + + args += ["egg_info"] + + if egg_info_dir: + args += ["--egg-base", egg_info_dir] + + return args diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/subprocess.py b/backend/venv/Lib/site-packages/pip/_internal/utils/subprocess.py new file mode 100644 index 0000000..cb2e23f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/subprocess.py @@ -0,0 +1,245 @@ +import logging +import os +import shlex +import subprocess +from typing import Any, Callable, Iterable, List, Literal, Mapping, Optional, Union + +from pip._vendor.rich.markup import escape + +from pip._internal.cli.spinners import SpinnerInterface, open_spinner +from pip._internal.exceptions import InstallationSubprocessError +from pip._internal.utils.logging import VERBOSE, subprocess_logger +from pip._internal.utils.misc import HiddenText + +CommandArgs = List[Union[str, HiddenText]] + + +def make_command(*args: Union[str, HiddenText, CommandArgs]) -> CommandArgs: + """ + Create a CommandArgs object. + """ + command_args: CommandArgs = [] + for arg in args: + # Check for list instead of CommandArgs since CommandArgs is + # only known during type-checking. + if isinstance(arg, list): + command_args.extend(arg) + else: + # Otherwise, arg is str or HiddenText. + command_args.append(arg) + + return command_args + + +def format_command_args(args: Union[List[str], CommandArgs]) -> str: + """ + Format command arguments for display. + """ + # For HiddenText arguments, display the redacted form by calling str(). + # Also, we don't apply str() to arguments that aren't HiddenText since + # this can trigger a UnicodeDecodeError in Python 2 if the argument + # has type unicode and includes a non-ascii character. (The type + # checker doesn't ensure the annotations are correct in all cases.) + return " ".join( + shlex.quote(str(arg)) if isinstance(arg, HiddenText) else shlex.quote(arg) + for arg in args + ) + + +def reveal_command_args(args: Union[List[str], CommandArgs]) -> List[str]: + """ + Return the arguments in their raw, unredacted form. + """ + return [arg.secret if isinstance(arg, HiddenText) else arg for arg in args] + + +def call_subprocess( + cmd: Union[List[str], CommandArgs], + show_stdout: bool = False, + cwd: Optional[str] = None, + on_returncode: 'Literal["raise", "warn", "ignore"]' = "raise", + extra_ok_returncodes: Optional[Iterable[int]] = None, + extra_environ: Optional[Mapping[str, Any]] = None, + unset_environ: Optional[Iterable[str]] = None, + spinner: Optional[SpinnerInterface] = None, + log_failed_cmd: Optional[bool] = True, + stdout_only: Optional[bool] = False, + *, + command_desc: str, +) -> str: + """ + Args: + show_stdout: if true, use INFO to log the subprocess's stderr and + stdout streams. Otherwise, use DEBUG. Defaults to False. + extra_ok_returncodes: an iterable of integer return codes that are + acceptable, in addition to 0. Defaults to None, which means []. + unset_environ: an iterable of environment variable names to unset + prior to calling subprocess.Popen(). + log_failed_cmd: if false, failed commands are not logged, only raised. + stdout_only: if true, return only stdout, else return both. When true, + logging of both stdout and stderr occurs when the subprocess has + terminated, else logging occurs as subprocess output is produced. + """ + if extra_ok_returncodes is None: + extra_ok_returncodes = [] + if unset_environ is None: + unset_environ = [] + # Most places in pip use show_stdout=False. What this means is-- + # + # - We connect the child's output (combined stderr and stdout) to a + # single pipe, which we read. + # - We log this output to stderr at DEBUG level as it is received. + # - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't + # requested), then we show a spinner so the user can still see the + # subprocess is in progress. + # - If the subprocess exits with an error, we log the output to stderr + # at ERROR level if it hasn't already been displayed to the console + # (e.g. if --verbose logging wasn't enabled). This way we don't log + # the output to the console twice. + # + # If show_stdout=True, then the above is still done, but with DEBUG + # replaced by INFO. + if show_stdout: + # Then log the subprocess output at INFO level. + log_subprocess: Callable[..., None] = subprocess_logger.info + used_level = logging.INFO + else: + # Then log the subprocess output using VERBOSE. This also ensures + # it will be logged to the log file (aka user_log), if enabled. + log_subprocess = subprocess_logger.verbose + used_level = VERBOSE + + # Whether the subprocess will be visible in the console. + showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level + + # Only use the spinner if we're not showing the subprocess output + # and we have a spinner. + use_spinner = not showing_subprocess and spinner is not None + + log_subprocess("Running command %s", command_desc) + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + for name in unset_environ: + env.pop(name, None) + try: + proc = subprocess.Popen( + # Convert HiddenText objects to the underlying str. + reveal_command_args(cmd), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT if not stdout_only else subprocess.PIPE, + cwd=cwd, + env=env, + errors="backslashreplace", + ) + except Exception as exc: + if log_failed_cmd: + subprocess_logger.critical( + "Error %s while executing command %s", + exc, + command_desc, + ) + raise + all_output = [] + if not stdout_only: + assert proc.stdout + assert proc.stdin + proc.stdin.close() + # In this mode, stdout and stderr are in the same pipe. + while True: + line: str = proc.stdout.readline() + if not line: + break + line = line.rstrip() + all_output.append(line + "\n") + + # Show the line immediately. + log_subprocess(line) + # Update the spinner. + if use_spinner: + assert spinner + spinner.spin() + try: + proc.wait() + finally: + if proc.stdout: + proc.stdout.close() + output = "".join(all_output) + else: + # In this mode, stdout and stderr are in different pipes. + # We must use communicate() which is the only safe way to read both. + out, err = proc.communicate() + # log line by line to preserve pip log indenting + for out_line in out.splitlines(): + log_subprocess(out_line) + all_output.append(out) + for err_line in err.splitlines(): + log_subprocess(err_line) + all_output.append(err) + output = out + + proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes + if use_spinner: + assert spinner + if proc_had_error: + spinner.finish("error") + else: + spinner.finish("done") + if proc_had_error: + if on_returncode == "raise": + error = InstallationSubprocessError( + command_description=command_desc, + exit_code=proc.returncode, + output_lines=all_output if not showing_subprocess else None, + ) + if log_failed_cmd: + subprocess_logger.error("%s", error, extra={"rich": True}) + subprocess_logger.verbose( + "[bold magenta]full command[/]: [blue]%s[/]", + escape(format_command_args(cmd)), + extra={"markup": True}, + ) + subprocess_logger.verbose( + "[bold magenta]cwd[/]: %s", + escape(cwd or "[inherit]"), + extra={"markup": True}, + ) + + raise error + elif on_returncode == "warn": + subprocess_logger.warning( + 'Command "%s" had error code %s in %s', + command_desc, + proc.returncode, + cwd, + ) + elif on_returncode == "ignore": + pass + else: + raise ValueError(f"Invalid value: on_returncode={on_returncode!r}") + return output + + +def runner_with_spinner_message(message: str) -> Callable[..., None]: + """Provide a subprocess_runner that shows a spinner message. + + Intended for use with for BuildBackendHookCaller. Thus, the runner has + an API that matches what's expected by BuildBackendHookCaller.subprocess_runner. + """ + + def runner( + cmd: List[str], + cwd: Optional[str] = None, + extra_environ: Optional[Mapping[str, Any]] = None, + ) -> None: + with open_spinner(message) as spinner: + call_subprocess( + cmd, + command_desc=message, + cwd=cwd, + extra_environ=extra_environ, + spinner=spinner, + ) + + return runner diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/temp_dir.py b/backend/venv/Lib/site-packages/pip/_internal/utils/temp_dir.py new file mode 100644 index 0000000..06668e8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/temp_dir.py @@ -0,0 +1,296 @@ +import errno +import itertools +import logging +import os.path +import tempfile +import traceback +from contextlib import ExitStack, contextmanager +from pathlib import Path +from typing import ( + Any, + Callable, + Dict, + Generator, + List, + Optional, + TypeVar, + Union, +) + +from pip._internal.utils.misc import enum, rmtree + +logger = logging.getLogger(__name__) + +_T = TypeVar("_T", bound="TempDirectory") + + +# Kinds of temporary directories. Only needed for ones that are +# globally-managed. +tempdir_kinds = enum( + BUILD_ENV="build-env", + EPHEM_WHEEL_CACHE="ephem-wheel-cache", + REQ_BUILD="req-build", +) + + +_tempdir_manager: Optional[ExitStack] = None + + +@contextmanager +def global_tempdir_manager() -> Generator[None, None, None]: + global _tempdir_manager + with ExitStack() as stack: + old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack + try: + yield + finally: + _tempdir_manager = old_tempdir_manager + + +class TempDirectoryTypeRegistry: + """Manages temp directory behavior""" + + def __init__(self) -> None: + self._should_delete: Dict[str, bool] = {} + + def set_delete(self, kind: str, value: bool) -> None: + """Indicate whether a TempDirectory of the given kind should be + auto-deleted. + """ + self._should_delete[kind] = value + + def get_delete(self, kind: str) -> bool: + """Get configured auto-delete flag for a given TempDirectory type, + default True. + """ + return self._should_delete.get(kind, True) + + +_tempdir_registry: Optional[TempDirectoryTypeRegistry] = None + + +@contextmanager +def tempdir_registry() -> Generator[TempDirectoryTypeRegistry, None, None]: + """Provides a scoped global tempdir registry that can be used to dictate + whether directories should be deleted. + """ + global _tempdir_registry + old_tempdir_registry = _tempdir_registry + _tempdir_registry = TempDirectoryTypeRegistry() + try: + yield _tempdir_registry + finally: + _tempdir_registry = old_tempdir_registry + + +class _Default: + pass + + +_default = _Default() + + +class TempDirectory: + """Helper class that owns and cleans up a temporary directory. + + This class can be used as a context manager or as an OO representation of a + temporary directory. + + Attributes: + path + Location to the created temporary directory + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + Methods: + cleanup() + Deletes the temporary directory + + When used as a context manager, if the delete attribute is True, on + exiting the context the temporary directory is deleted. + """ + + def __init__( + self, + path: Optional[str] = None, + delete: Union[bool, None, _Default] = _default, + kind: str = "temp", + globally_managed: bool = False, + ignore_cleanup_errors: bool = True, + ): + super().__init__() + + if delete is _default: + if path is not None: + # If we were given an explicit directory, resolve delete option + # now. + delete = False + else: + # Otherwise, we wait until cleanup and see what + # tempdir_registry says. + delete = None + + # The only time we specify path is in for editables where it + # is the value of the --src option. + if path is None: + path = self._create(kind) + + self._path = path + self._deleted = False + self.delete = delete + self.kind = kind + self.ignore_cleanup_errors = ignore_cleanup_errors + + if globally_managed: + assert _tempdir_manager is not None + _tempdir_manager.enter_context(self) + + @property + def path(self) -> str: + assert not self._deleted, f"Attempted to access deleted path: {self._path}" + return self._path + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.path!r}>" + + def __enter__(self: _T) -> _T: + return self + + def __exit__(self, exc: Any, value: Any, tb: Any) -> None: + if self.delete is not None: + delete = self.delete + elif _tempdir_registry: + delete = _tempdir_registry.get_delete(self.kind) + else: + delete = True + + if delete: + self.cleanup() + + def _create(self, kind: str) -> str: + """Create a temporary directory and store its path in self.path""" + # We realpath here because some systems have their default tmpdir + # symlinked to another directory. This tends to confuse build + # scripts, so we canonicalize the path by traversing potential + # symlinks here. + path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-")) + logger.debug("Created temporary directory: %s", path) + return path + + def cleanup(self) -> None: + """Remove the temporary directory created and reset state""" + self._deleted = True + if not os.path.exists(self._path): + return + + errors: List[BaseException] = [] + + def onerror( + func: Callable[..., Any], + path: Path, + exc_val: BaseException, + ) -> None: + """Log a warning for a `rmtree` error and continue""" + formatted_exc = "\n".join( + traceback.format_exception_only(type(exc_val), exc_val) + ) + formatted_exc = formatted_exc.rstrip() # remove trailing new line + if func in (os.unlink, os.remove, os.rmdir): + logger.debug( + "Failed to remove a temporary file '%s' due to %s.\n", + path, + formatted_exc, + ) + else: + logger.debug("%s failed with %s.", func.__qualname__, formatted_exc) + errors.append(exc_val) + + if self.ignore_cleanup_errors: + try: + # first try with @retry; retrying to handle ephemeral errors + rmtree(self._path, ignore_errors=False) + except OSError: + # last pass ignore/log all errors + rmtree(self._path, onexc=onerror) + if errors: + logger.warning( + "Failed to remove contents in a temporary directory '%s'.\n" + "You can safely remove it manually.", + self._path, + ) + else: + rmtree(self._path) + + +class AdjacentTempDirectory(TempDirectory): + """Helper class that creates a temporary directory adjacent to a real one. + + Attributes: + original + The original directory to create a temp directory for. + path + After calling create() or entering, contains the full + path to the temporary directory. + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + """ + + # The characters that may be used to name the temp directory + # We always prepend a ~ and then rotate through these until + # a usable name is found. + # pkg_resources raises a different error for .dist-info folder + # with leading '-' and invalid metadata + LEADING_CHARS = "-~.=%0123456789" + + def __init__(self, original: str, delete: Optional[bool] = None) -> None: + self.original = original.rstrip("/\\") + super().__init__(delete=delete) + + @classmethod + def _generate_names(cls, name: str) -> Generator[str, None, None]: + """Generates a series of temporary names. + + The algorithm replaces the leading characters in the name + with ones that are valid filesystem characters, but are not + valid package names (for both Python and pip definitions of + package). + """ + for i in range(1, len(name)): + for candidate in itertools.combinations_with_replacement( + cls.LEADING_CHARS, i - 1 + ): + new_name = "~" + "".join(candidate) + name[i:] + if new_name != name: + yield new_name + + # If we make it this far, we will have to make a longer name + for i in range(len(cls.LEADING_CHARS)): + for candidate in itertools.combinations_with_replacement( + cls.LEADING_CHARS, i + ): + new_name = "~" + "".join(candidate) + name + if new_name != name: + yield new_name + + def _create(self, kind: str) -> str: + root, name = os.path.split(self.original) + for candidate in self._generate_names(name): + path = os.path.join(root, candidate) + try: + os.mkdir(path) + except OSError as ex: + # Continue if the name exists already + if ex.errno != errno.EEXIST: + raise + else: + path = os.path.realpath(path) + break + else: + # Final fallback on the default behavior. + path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-")) + + logger.debug("Created temporary directory: %s", path) + return path diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/unpacking.py b/backend/venv/Lib/site-packages/pip/_internal/utils/unpacking.py new file mode 100644 index 0000000..87a6d19 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/unpacking.py @@ -0,0 +1,337 @@ +"""Utilities related archives. +""" + +import logging +import os +import shutil +import stat +import sys +import tarfile +import zipfile +from typing import Iterable, List, Optional +from zipfile import ZipInfo + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.filetypes import ( + BZ2_EXTENSIONS, + TAR_EXTENSIONS, + XZ_EXTENSIONS, + ZIP_EXTENSIONS, +) +from pip._internal.utils.misc import ensure_dir + +logger = logging.getLogger(__name__) + + +SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS + +try: + import bz2 # noqa + + SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS +except ImportError: + logger.debug("bz2 module is not available") + +try: + # Only for Python 3.3+ + import lzma # noqa + + SUPPORTED_EXTENSIONS += XZ_EXTENSIONS +except ImportError: + logger.debug("lzma module is not available") + + +def current_umask() -> int: + """Get the current umask which involves having to set it temporarily.""" + mask = os.umask(0) + os.umask(mask) + return mask + + +def split_leading_dir(path: str) -> List[str]: + path = path.lstrip("/").lstrip("\\") + if "/" in path and ( + ("\\" in path and path.find("/") < path.find("\\")) or "\\" not in path + ): + return path.split("/", 1) + elif "\\" in path: + return path.split("\\", 1) + else: + return [path, ""] + + +def has_leading_dir(paths: Iterable[str]) -> bool: + """Returns true if all the paths have the same leading path name + (i.e., everything is in one subdirectory in an archive)""" + common_prefix = None + for path in paths: + prefix, rest = split_leading_dir(path) + if not prefix: + return False + elif common_prefix is None: + common_prefix = prefix + elif prefix != common_prefix: + return False + return True + + +def is_within_directory(directory: str, target: str) -> bool: + """ + Return true if the absolute path of target is within the directory + """ + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + return prefix == abs_directory + + +def _get_default_mode_plus_executable() -> int: + return 0o777 & ~current_umask() | 0o111 + + +def set_extracted_file_to_default_mode_plus_executable(path: str) -> None: + """ + Make file present at path have execute for user/group/world + (chmod +x) is no-op on windows per python docs + """ + os.chmod(path, _get_default_mode_plus_executable()) + + +def zip_item_is_executable(info: ZipInfo) -> bool: + mode = info.external_attr >> 16 + # if mode and regular file and any execute permissions for + # user/group/world? + return bool(mode and stat.S_ISREG(mode) and mode & 0o111) + + +def unzip_file(filename: str, location: str, flatten: bool = True) -> None: + """ + Unzip the file (with path `filename`) to the destination `location`. All + files are written based on system defaults and umask (i.e. permissions are + not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + zipfp = open(filename, "rb") + try: + zip = zipfile.ZipFile(zipfp, allowZip64=True) + leading = has_leading_dir(zip.namelist()) and flatten + for info in zip.infolist(): + name = info.filename + fn = name + if leading: + fn = split_leading_dir(name)[1] + fn = os.path.join(location, fn) + dir = os.path.dirname(fn) + if not is_within_directory(location, fn): + message = ( + "The zip file ({}) has a file ({}) trying to install " + "outside target directory ({})" + ) + raise InstallationError(message.format(filename, fn, location)) + if fn.endswith("/") or fn.endswith("\\"): + # A directory + ensure_dir(fn) + else: + ensure_dir(dir) + # Don't use read() to avoid allocating an arbitrarily large + # chunk of memory for the file's content + fp = zip.open(name) + try: + with open(fn, "wb") as destfp: + shutil.copyfileobj(fp, destfp) + finally: + fp.close() + if zip_item_is_executable(info): + set_extracted_file_to_default_mode_plus_executable(fn) + finally: + zipfp.close() + + +def untar_file(filename: str, location: str) -> None: + """ + Untar the file (with path `filename`) to the destination `location`. + All files are written based on system defaults and umask (i.e. permissions + are not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied on top of the + default. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + if filename.lower().endswith(".gz") or filename.lower().endswith(".tgz"): + mode = "r:gz" + elif filename.lower().endswith(BZ2_EXTENSIONS): + mode = "r:bz2" + elif filename.lower().endswith(XZ_EXTENSIONS): + mode = "r:xz" + elif filename.lower().endswith(".tar"): + mode = "r" + else: + logger.warning( + "Cannot determine compression type for file %s", + filename, + ) + mode = "r:*" + + tar = tarfile.open(filename, mode, encoding="utf-8") # type: ignore + try: + leading = has_leading_dir([member.name for member in tar.getmembers()]) + + # PEP 706 added `tarfile.data_filter`, and made some other changes to + # Python's tarfile module (see below). The features were backported to + # security releases. + try: + data_filter = tarfile.data_filter + except AttributeError: + _untar_without_filter(filename, location, tar, leading) + else: + default_mode_plus_executable = _get_default_mode_plus_executable() + + if leading: + # Strip the leading directory from all files in the archive, + # including hardlink targets (which are relative to the + # unpack location). + for member in tar.getmembers(): + name_lead, name_rest = split_leading_dir(member.name) + member.name = name_rest + if member.islnk(): + lnk_lead, lnk_rest = split_leading_dir(member.linkname) + if lnk_lead == name_lead: + member.linkname = lnk_rest + + def pip_filter(member: tarfile.TarInfo, path: str) -> tarfile.TarInfo: + orig_mode = member.mode + try: + try: + member = data_filter(member, location) + except tarfile.LinkOutsideDestinationError: + if sys.version_info[:3] in { + (3, 8, 17), + (3, 9, 17), + (3, 10, 12), + (3, 11, 4), + }: + # The tarfile filter in specific Python versions + # raises LinkOutsideDestinationError on valid input + # (https://github.com/python/cpython/issues/107845) + # Ignore the error there, but do use the + # more lax `tar_filter` + member = tarfile.tar_filter(member, location) + else: + raise + except tarfile.TarError as exc: + message = "Invalid member in the tar file {}: {}" + # Filter error messages mention the member name. + # No need to add it here. + raise InstallationError( + message.format( + filename, + exc, + ) + ) + if member.isfile() and orig_mode & 0o111: + member.mode = default_mode_plus_executable + else: + # See PEP 706 note above. + # The PEP changed this from `int` to `Optional[int]`, + # where None means "use the default". Mypy doesn't + # know this yet. + member.mode = None # type: ignore [assignment] + return member + + tar.extractall(location, filter=pip_filter) + + finally: + tar.close() + + +def _untar_without_filter( + filename: str, + location: str, + tar: tarfile.TarFile, + leading: bool, +) -> None: + """Fallback for Python without tarfile.data_filter""" + for member in tar.getmembers(): + fn = member.name + if leading: + fn = split_leading_dir(fn)[1] + path = os.path.join(location, fn) + if not is_within_directory(location, path): + message = ( + "The tar file ({}) has a file ({}) trying to install " + "outside target directory ({})" + ) + raise InstallationError(message.format(filename, path, location)) + if member.isdir(): + ensure_dir(path) + elif member.issym(): + try: + tar._extract_member(member, path) + except Exception as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + "In the tar file %s the member %s is invalid: %s", + filename, + member.name, + exc, + ) + continue + else: + try: + fp = tar.extractfile(member) + except (KeyError, AttributeError) as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + "In the tar file %s the member %s is invalid: %s", + filename, + member.name, + exc, + ) + continue + ensure_dir(os.path.dirname(path)) + assert fp is not None + with open(path, "wb") as destfp: + shutil.copyfileobj(fp, destfp) + fp.close() + # Update the timestamp (useful for cython compiled files) + tar.utime(member, path) + # member have any execute permissions for user/group/world? + if member.mode & 0o111: + set_extracted_file_to_default_mode_plus_executable(path) + + +def unpack_file( + filename: str, + location: str, + content_type: Optional[str] = None, +) -> None: + filename = os.path.realpath(filename) + if ( + content_type == "application/zip" + or filename.lower().endswith(ZIP_EXTENSIONS) + or zipfile.is_zipfile(filename) + ): + unzip_file(filename, location, flatten=not filename.endswith(".whl")) + elif ( + content_type == "application/x-gzip" + or tarfile.is_tarfile(filename) + or filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS) + ): + untar_file(filename, location) + else: + # FIXME: handle? + # FIXME: magic signatures? + logger.critical( + "Cannot unpack file %s (downloaded from %s, content-type: %s); " + "cannot detect archive format", + filename, + location, + content_type, + ) + raise InstallationError(f"Cannot determine archive format of {location}") diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/urls.py b/backend/venv/Lib/site-packages/pip/_internal/utils/urls.py new file mode 100644 index 0000000..9f34f88 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/urls.py @@ -0,0 +1,55 @@ +import os +import string +import urllib.parse +import urllib.request + +from .compat import WINDOWS + + +def path_to_url(path: str) -> str: + """ + Convert a path to a file: URL. The path will be made absolute and have + quoted path parts. + """ + path = os.path.normpath(os.path.abspath(path)) + url = urllib.parse.urljoin("file:", urllib.request.pathname2url(path)) + return url + + +def url_to_path(url: str) -> str: + """ + Convert a file: URL to a path. + """ + assert url.startswith( + "file:" + ), f"You can only turn file: urls into filenames (not {url!r})" + + _, netloc, path, _, _ = urllib.parse.urlsplit(url) + + if not netloc or netloc == "localhost": + # According to RFC 8089, same as empty authority. + netloc = "" + elif WINDOWS: + # If we have a UNC path, prepend UNC share notation. + netloc = "\\\\" + netloc + else: + raise ValueError( + f"non-local file URIs are not supported on this platform: {url!r}" + ) + + path = urllib.request.url2pathname(netloc + path) + + # On Windows, urlsplit parses the path as something like "/C:/Users/foo". + # This creates issues for path-related functions like io.open(), so we try + # to detect and strip the leading slash. + if ( + WINDOWS + and not netloc # Not UNC. + and len(path) >= 3 + and path[0] == "/" # Leading slash to strip. + and path[1] in string.ascii_letters # Drive letter. + and path[2:4] in (":", ":/") # Colon + end of string, or colon + absolute path. + ): + path = path[1:] + + return path diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/virtualenv.py b/backend/venv/Lib/site-packages/pip/_internal/utils/virtualenv.py new file mode 100644 index 0000000..882e36f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/virtualenv.py @@ -0,0 +1,104 @@ +import logging +import os +import re +import site +import sys +from typing import List, Optional + +logger = logging.getLogger(__name__) +_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile( + r"include-system-site-packages\s*=\s*(?Ptrue|false)" +) + + +def _running_under_venv() -> bool: + """Checks if sys.base_prefix and sys.prefix match. + + This handles PEP 405 compliant virtual environments. + """ + return sys.prefix != getattr(sys, "base_prefix", sys.prefix) + + +def _running_under_legacy_virtualenv() -> bool: + """Checks if sys.real_prefix is set. + + This handles virtual environments created with pypa's virtualenv. + """ + # pypa/virtualenv case + return hasattr(sys, "real_prefix") + + +def running_under_virtualenv() -> bool: + """True if we're running inside a virtual environment, False otherwise.""" + return _running_under_venv() or _running_under_legacy_virtualenv() + + +def _get_pyvenv_cfg_lines() -> Optional[List[str]]: + """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines + + Returns None, if it could not read/access the file. + """ + pyvenv_cfg_file = os.path.join(sys.prefix, "pyvenv.cfg") + try: + # Although PEP 405 does not specify, the built-in venv module always + # writes with UTF-8. (pypa/pip#8717) + with open(pyvenv_cfg_file, encoding="utf-8") as f: + return f.read().splitlines() # avoids trailing newlines + except OSError: + return None + + +def _no_global_under_venv() -> bool: + """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion + + PEP 405 specifies that when system site-packages are not supposed to be + visible from a virtual environment, `pyvenv.cfg` must contain the following + line: + + include-system-site-packages = false + + Additionally, log a warning if accessing the file fails. + """ + cfg_lines = _get_pyvenv_cfg_lines() + if cfg_lines is None: + # We're not in a "sane" venv, so assume there is no system + # site-packages access (since that's PEP 405's default state). + logger.warning( + "Could not access 'pyvenv.cfg' despite a virtual environment " + "being active. Assuming global site-packages is not accessible " + "in this environment." + ) + return True + + for line in cfg_lines: + match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) + if match is not None and match.group("value") == "false": + return True + return False + + +def _no_global_under_legacy_virtualenv() -> bool: + """Check if "no-global-site-packages.txt" exists beside site.py + + This mirrors logic in pypa/virtualenv for determining whether system + site-packages are visible in the virtual environment. + """ + site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) + no_global_site_packages_file = os.path.join( + site_mod_dir, + "no-global-site-packages.txt", + ) + return os.path.exists(no_global_site_packages_file) + + +def virtualenv_no_global() -> bool: + """Returns a boolean, whether running in venv with no system site-packages.""" + # PEP 405 compliance needs to be checked first since virtualenv >=20 would + # return True for both checks, but is only able to use the PEP 405 config. + if _running_under_venv(): + return _no_global_under_venv() + + if _running_under_legacy_virtualenv(): + return _no_global_under_legacy_virtualenv() + + return False diff --git a/backend/venv/Lib/site-packages/pip/_internal/utils/wheel.py b/backend/venv/Lib/site-packages/pip/_internal/utils/wheel.py new file mode 100644 index 0000000..f85aee8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/utils/wheel.py @@ -0,0 +1,134 @@ +"""Support functions for working with wheel files. +""" + +import logging +from email.message import Message +from email.parser import Parser +from typing import Tuple +from zipfile import BadZipFile, ZipFile + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import UnsupportedWheel + +VERSION_COMPATIBLE = (1, 0) + + +logger = logging.getLogger(__name__) + + +def parse_wheel(wheel_zip: ZipFile, name: str) -> Tuple[str, Message]: + """Extract information from the provided wheel, ensuring it meets basic + standards. + + Returns the name of the .dist-info directory and the parsed WHEEL metadata. + """ + try: + info_dir = wheel_dist_info_dir(wheel_zip, name) + metadata = wheel_metadata(wheel_zip, info_dir) + version = wheel_version(metadata) + except UnsupportedWheel as e: + raise UnsupportedWheel(f"{name} has an invalid wheel, {e}") + + check_compatibility(version, name) + + return info_dir, metadata + + +def wheel_dist_info_dir(source: ZipFile, name: str) -> str: + """Returns the name of the contained .dist-info directory. + + Raises AssertionError or UnsupportedWheel if not found, >1 found, or + it doesn't match the provided name. + """ + # Zip file path separators must be / + subdirs = {p.split("/", 1)[0] for p in source.namelist()} + + info_dirs = [s for s in subdirs if s.endswith(".dist-info")] + + if not info_dirs: + raise UnsupportedWheel(".dist-info directory not found") + + if len(info_dirs) > 1: + raise UnsupportedWheel( + "multiple .dist-info directories found: {}".format(", ".join(info_dirs)) + ) + + info_dir = info_dirs[0] + + info_dir_name = canonicalize_name(info_dir) + canonical_name = canonicalize_name(name) + if not info_dir_name.startswith(canonical_name): + raise UnsupportedWheel( + f".dist-info directory {info_dir!r} does not start with {canonical_name!r}" + ) + + return info_dir + + +def read_wheel_metadata_file(source: ZipFile, path: str) -> bytes: + try: + return source.read(path) + # BadZipFile for general corruption, KeyError for missing entry, + # and RuntimeError for password-protected files + except (BadZipFile, KeyError, RuntimeError) as e: + raise UnsupportedWheel(f"could not read {path!r} file: {e!r}") + + +def wheel_metadata(source: ZipFile, dist_info_dir: str) -> Message: + """Return the WHEEL metadata of an extracted wheel, if possible. + Otherwise, raise UnsupportedWheel. + """ + path = f"{dist_info_dir}/WHEEL" + # Zip file path separators must be / + wheel_contents = read_wheel_metadata_file(source, path) + + try: + wheel_text = wheel_contents.decode() + except UnicodeDecodeError as e: + raise UnsupportedWheel(f"error decoding {path!r}: {e!r}") + + # FeedParser (used by Parser) does not raise any exceptions. The returned + # message may have .defects populated, but for backwards-compatibility we + # currently ignore them. + return Parser().parsestr(wheel_text) + + +def wheel_version(wheel_data: Message) -> Tuple[int, ...]: + """Given WHEEL metadata, return the parsed Wheel-Version. + Otherwise, raise UnsupportedWheel. + """ + version_text = wheel_data["Wheel-Version"] + if version_text is None: + raise UnsupportedWheel("WHEEL is missing Wheel-Version") + + version = version_text.strip() + + try: + return tuple(map(int, version.split("."))) + except ValueError: + raise UnsupportedWheel(f"invalid Wheel-Version: {version!r}") + + +def check_compatibility(version: Tuple[int, ...], name: str) -> None: + """Raises errors or warns if called with an incompatible Wheel-Version. + + pip should refuse to install a Wheel-Version that's a major series + ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when + installing a version only minor version ahead (e.g 1.2 > 1.1). + + version: a 2-tuple representing a Wheel-Version (Major, Minor) + name: name of wheel or package to raise exception about + + :raises UnsupportedWheel: when an incompatible Wheel-Version is given + """ + if version[0] > VERSION_COMPATIBLE[0]: + raise UnsupportedWheel( + "{}'s Wheel-Version ({}) is not compatible with this version " + "of pip".format(name, ".".join(map(str, version))) + ) + elif version > VERSION_COMPATIBLE: + logger.warning( + "Installing from a newer Wheel-Version (%s)", + ".".join(map(str, version)), + ) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/__init__.py b/backend/venv/Lib/site-packages/pip/_internal/vcs/__init__.py new file mode 100644 index 0000000..b6beddb --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/vcs/__init__.py @@ -0,0 +1,15 @@ +# Expose a limited set of classes and functions so callers outside of +# the vcs package don't need to import deeper than `pip._internal.vcs`. +# (The test directory may still need to import from a vcs sub-package.) +# Import all vcs modules to register each VCS in the VcsSupport object. +import pip._internal.vcs.bazaar +import pip._internal.vcs.git +import pip._internal.vcs.mercurial +import pip._internal.vcs.subversion # noqa: F401 +from pip._internal.vcs.versioncontrol import ( # noqa: F401 + RemoteNotFoundError, + RemoteNotValidError, + is_url, + make_vcs_requirement_url, + vcs, +) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..669254d839f24d5552fbd2e841f7bc0b503d81cc GIT binary patch literal 535 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�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�-I*J?8oV0Up=Q?1#fJXn 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 Ym!302EO?&zhV5&%Oz`KFm%PXS0u>s+P5=M^ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0879d6ce886d05181b6d5fcd280705347db020c GIT binary patch literal 29001 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 List[str]: + return ["-r", rev] + + def fetch_new( + self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int + ) -> None: + rev_display = rev_options.to_display() + logger.info( + "Checking out %s%s to %s", + url, + rev_display, + display_path(dest), + ) + if verbosity <= 0: + flags = ["--quiet"] + elif verbosity == 1: + flags = [] + else: + flags = [f"-{'v'*verbosity}"] + cmd_args = make_command( + "checkout", "--lightweight", *flags, rev_options.to_args(), url, dest + ) + self.run_command(cmd_args) + + def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + self.run_command(make_command("switch", url), cwd=dest) + + def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + output = self.run_command( + make_command("info"), show_stdout=False, stdout_only=True, cwd=dest + ) + if output.startswith("Standalone "): + # Older versions of pip used to create standalone branches. + # Convert the standalone branch to a checkout by calling "bzr bind". + cmd_args = make_command("bind", "-q", url) + self.run_command(cmd_args, cwd=dest) + + cmd_args = make_command("update", "-q", rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + @classmethod + def get_url_rev_and_auth(cls, url: str) -> Tuple[str, Optional[str], AuthInfo]: + # hotfix the URL scheme after removing bzr+ from bzr+ssh:// re-add it + url, rev, user_pass = super().get_url_rev_and_auth(url) + if url.startswith("ssh://"): + url = "bzr+" + url + return url, rev, user_pass + + @classmethod + def get_remote_url(cls, location: str) -> str: + urls = cls.run_command( + ["info"], show_stdout=False, stdout_only=True, cwd=location + ) + for line in urls.splitlines(): + line = line.strip() + for x in ("checkout of branch: ", "parent branch: "): + if line.startswith(x): + repo = line.split(x)[1] + if cls._is_local_repository(repo): + return path_to_url(repo) + return repo + raise RemoteNotFoundError + + @classmethod + def get_revision(cls, location: str) -> str: + revision = cls.run_command( + ["revno"], + show_stdout=False, + stdout_only=True, + cwd=location, + ) + return revision.splitlines()[-1] + + @classmethod + def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool: + """Always assume the versions don't match""" + return False + + +vcs.register(Bazaar) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/git.py b/backend/venv/Lib/site-packages/pip/_internal/vcs/git.py new file mode 100644 index 0000000..0425deb --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/vcs/git.py @@ -0,0 +1,527 @@ +import logging +import os.path +import pathlib +import re +import urllib.parse +import urllib.request +from dataclasses import replace +from typing import List, Optional, Tuple + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.misc import HiddenText, display_path, hide_url +from pip._internal.utils.subprocess import make_command +from pip._internal.vcs.versioncontrol import ( + AuthInfo, + RemoteNotFoundError, + RemoteNotValidError, + RevOptions, + VersionControl, + find_path_to_project_root_from_repo_root, + vcs, +) + +urlsplit = urllib.parse.urlsplit +urlunsplit = urllib.parse.urlunsplit + + +logger = logging.getLogger(__name__) + + +GIT_VERSION_REGEX = re.compile( + r"^git version " # Prefix. + r"(\d+)" # Major. + r"\.(\d+)" # Dot, minor. + r"(?:\.(\d+))?" # Optional dot, patch. + r".*$" # Suffix, including any pre- and post-release segments we don't care about. +) + +HASH_REGEX = re.compile("^[a-fA-F0-9]{40}$") + +# SCP (Secure copy protocol) shorthand. e.g. 'git@example.com:foo/bar.git' +SCP_REGEX = re.compile( + r"""^ + # Optional user, e.g. 'git@' + (\w+@)? + # Server, e.g. 'github.com'. + ([^/:]+): + # The server-side path. e.g. 'user/project.git'. Must start with an + # alphanumeric character so as not to be confusable with a Windows paths + # like 'C:/foo/bar' or 'C:\foo\bar'. + (\w[^:]*) + $""", + re.VERBOSE, +) + + +def looks_like_hash(sha: str) -> bool: + return bool(HASH_REGEX.match(sha)) + + +class Git(VersionControl): + name = "git" + dirname = ".git" + repo_name = "clone" + schemes = ( + "git+http", + "git+https", + "git+ssh", + "git+git", + "git+file", + ) + # Prevent the user's environment variables from interfering with pip: + # https://github.com/pypa/pip/issues/1130 + unset_environ = ("GIT_DIR", "GIT_WORK_TREE") + default_arg_rev = "HEAD" + + @staticmethod + def get_base_rev_args(rev: str) -> List[str]: + return [rev] + + def is_immutable_rev_checkout(self, url: str, dest: str) -> bool: + _, rev_options = self.get_url_rev_options(hide_url(url)) + if not rev_options.rev: + return False + if not self.is_commit_id_equal(dest, rev_options.rev): + # the current commit is different from rev, + # which means rev was something else than a commit hash + return False + # return False in the rare case rev is both a commit hash + # and a tag or a branch; we don't want to cache in that case + # because that branch/tag could point to something else in the future + is_tag_or_branch = bool(self.get_revision_sha(dest, rev_options.rev)[0]) + return not is_tag_or_branch + + def get_git_version(self) -> Tuple[int, ...]: + version = self.run_command( + ["version"], + command_desc="git version", + show_stdout=False, + stdout_only=True, + ) + match = GIT_VERSION_REGEX.match(version) + if not match: + logger.warning("Can't parse git version: %s", version) + return () + return (int(match.group(1)), int(match.group(2))) + + @classmethod + def get_current_branch(cls, location: str) -> Optional[str]: + """ + Return the current branch, or None if HEAD isn't at a branch + (e.g. detached HEAD). + """ + # git-symbolic-ref exits with empty stdout if "HEAD" is a detached + # HEAD rather than a symbolic ref. In addition, the -q causes the + # command to exit with status code 1 instead of 128 in this case + # and to suppress the message to stderr. + args = ["symbolic-ref", "-q", "HEAD"] + output = cls.run_command( + args, + extra_ok_returncodes=(1,), + show_stdout=False, + stdout_only=True, + cwd=location, + ) + ref = output.strip() + + if ref.startswith("refs/heads/"): + return ref[len("refs/heads/") :] + + return None + + @classmethod + def get_revision_sha(cls, dest: str, rev: str) -> Tuple[Optional[str], bool]: + """ + Return (sha_or_none, is_branch), where sha_or_none is a commit hash + if the revision names a remote branch or tag, otherwise None. + + Args: + dest: the repository directory. + rev: the revision name. + """ + # Pass rev to pre-filter the list. + output = cls.run_command( + ["show-ref", rev], + cwd=dest, + show_stdout=False, + stdout_only=True, + on_returncode="ignore", + ) + refs = {} + # NOTE: We do not use splitlines here since that would split on other + # unicode separators, which can be maliciously used to install a + # different revision. + for line in output.strip().split("\n"): + line = line.rstrip("\r") + if not line: + continue + try: + ref_sha, ref_name = line.split(" ", maxsplit=2) + except ValueError: + # Include the offending line to simplify troubleshooting if + # this error ever occurs. + raise ValueError(f"unexpected show-ref line: {line!r}") + + refs[ref_name] = ref_sha + + branch_ref = f"refs/remotes/origin/{rev}" + tag_ref = f"refs/tags/{rev}" + + sha = refs.get(branch_ref) + if sha is not None: + return (sha, True) + + sha = refs.get(tag_ref) + + return (sha, False) + + @classmethod + def _should_fetch(cls, dest: str, rev: str) -> bool: + """ + Return true if rev is a ref or is a commit that we don't have locally. + + Branches and tags are not considered in this method because they are + assumed to be always available locally (which is a normal outcome of + ``git clone`` and ``git fetch --tags``). + """ + if rev.startswith("refs/"): + # Always fetch remote refs. + return True + + if not looks_like_hash(rev): + # Git fetch would fail with abbreviated commits. + return False + + if cls.has_commit(dest, rev): + # Don't fetch if we have the commit locally. + return False + + return True + + @classmethod + def resolve_revision( + cls, dest: str, url: HiddenText, rev_options: RevOptions + ) -> RevOptions: + """ + Resolve a revision to a new RevOptions object with the SHA1 of the + branch, tag, or ref if found. + + Args: + rev_options: a RevOptions object. + """ + rev = rev_options.arg_rev + # The arg_rev property's implementation for Git ensures that the + # rev return value is always non-None. + assert rev is not None + + sha, is_branch = cls.get_revision_sha(dest, rev) + + if sha is not None: + rev_options = rev_options.make_new(sha) + rev_options = replace(rev_options, branch_name=(rev if is_branch else None)) + + return rev_options + + # Do not show a warning for the common case of something that has + # the form of a Git commit hash. + if not looks_like_hash(rev): + logger.warning( + "Did not find branch or tag '%s', assuming revision or ref.", + rev, + ) + + if not cls._should_fetch(dest, rev): + return rev_options + + # fetch the requested revision + cls.run_command( + make_command("fetch", "-q", url, rev_options.to_args()), + cwd=dest, + ) + # Change the revision to the SHA of the ref we fetched + sha = cls.get_revision(dest, rev="FETCH_HEAD") + rev_options = rev_options.make_new(sha) + + return rev_options + + @classmethod + def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool: + """ + Return whether the current commit hash equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + if not name: + # Then avoid an unnecessary subprocess call. + return False + + return cls.get_revision(dest) == name + + def fetch_new( + self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int + ) -> None: + rev_display = rev_options.to_display() + logger.info("Cloning %s%s to %s", url, rev_display, display_path(dest)) + if verbosity <= 0: + flags: Tuple[str, ...] = ("--quiet",) + elif verbosity == 1: + flags = () + else: + flags = ("--verbose", "--progress") + if self.get_git_version() >= (2, 17): + # Git added support for partial clone in 2.17 + # https://git-scm.com/docs/partial-clone + # Speeds up cloning by functioning without a complete copy of repository + self.run_command( + make_command( + "clone", + "--filter=blob:none", + *flags, + url, + dest, + ) + ) + else: + self.run_command(make_command("clone", *flags, url, dest)) + + if rev_options.rev: + # Then a specific revision was requested. + rev_options = self.resolve_revision(dest, url, rev_options) + branch_name = getattr(rev_options, "branch_name", None) + logger.debug("Rev options %s, branch_name %s", rev_options, branch_name) + if branch_name is None: + # Only do a checkout if the current commit id doesn't match + # the requested revision. + if not self.is_commit_id_equal(dest, rev_options.rev): + cmd_args = make_command( + "checkout", + "-q", + rev_options.to_args(), + ) + self.run_command(cmd_args, cwd=dest) + elif self.get_current_branch(dest) != branch_name: + # Then a specific branch was requested, and that branch + # is not yet checked out. + track_branch = f"origin/{branch_name}" + cmd_args = [ + "checkout", + "-b", + branch_name, + "--track", + track_branch, + ] + self.run_command(cmd_args, cwd=dest) + else: + sha = self.get_revision(dest) + rev_options = rev_options.make_new(sha) + + logger.info("Resolved %s to commit %s", url, rev_options.rev) + + #: repo may contain submodules + self.update_submodules(dest) + + def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + self.run_command( + make_command("config", "remote.origin.url", url), + cwd=dest, + ) + cmd_args = make_command("checkout", "-q", rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + self.update_submodules(dest) + + def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + # First fetch changes from the default remote + if self.get_git_version() >= (1, 9): + # fetch tags in addition to everything else + self.run_command(["fetch", "-q", "--tags"], cwd=dest) + else: + self.run_command(["fetch", "-q"], cwd=dest) + # Then reset to wanted revision (maybe even origin/master) + rev_options = self.resolve_revision(dest, url, rev_options) + cmd_args = make_command("reset", "--hard", "-q", rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + #: update submodules + self.update_submodules(dest) + + @classmethod + def get_remote_url(cls, location: str) -> str: + """ + Return URL of the first remote encountered. + + Raises RemoteNotFoundError if the repository does not have a remote + url configured. + """ + # We need to pass 1 for extra_ok_returncodes since the command + # exits with return code 1 if there are no matching lines. + stdout = cls.run_command( + ["config", "--get-regexp", r"remote\..*\.url"], + extra_ok_returncodes=(1,), + show_stdout=False, + stdout_only=True, + cwd=location, + ) + remotes = stdout.splitlines() + try: + found_remote = remotes[0] + except IndexError: + raise RemoteNotFoundError + + for remote in remotes: + if remote.startswith("remote.origin.url "): + found_remote = remote + break + url = found_remote.split(" ")[1] + return cls._git_remote_to_pip_url(url.strip()) + + @staticmethod + def _git_remote_to_pip_url(url: str) -> str: + """ + Convert a remote url from what git uses to what pip accepts. + + There are 3 legal forms **url** may take: + + 1. A fully qualified url: ssh://git@example.com/foo/bar.git + 2. A local project.git folder: /path/to/bare/repository.git + 3. SCP shorthand for form 1: git@example.com:foo/bar.git + + Form 1 is output as-is. Form 2 must be converted to URI and form 3 must + be converted to form 1. + + See the corresponding test test_git_remote_url_to_pip() for examples of + sample inputs/outputs. + """ + if re.match(r"\w+://", url): + # This is already valid. Pass it though as-is. + return url + if os.path.exists(url): + # A local bare remote (git clone --mirror). + # Needs a file:// prefix. + return pathlib.PurePath(url).as_uri() + scp_match = SCP_REGEX.match(url) + if scp_match: + # Add an ssh:// prefix and replace the ':' with a '/'. + return scp_match.expand(r"ssh://\1\2/\3") + # Otherwise, bail out. + raise RemoteNotValidError(url) + + @classmethod + def has_commit(cls, location: str, rev: str) -> bool: + """ + Check if rev is a commit that is available in the local repository. + """ + try: + cls.run_command( + ["rev-parse", "-q", "--verify", "sha^" + rev], + cwd=location, + log_failed_cmd=False, + ) + except InstallationError: + return False + else: + return True + + @classmethod + def get_revision(cls, location: str, rev: Optional[str] = None) -> str: + if rev is None: + rev = "HEAD" + current_rev = cls.run_command( + ["rev-parse", rev], + show_stdout=False, + stdout_only=True, + cwd=location, + ) + return current_rev.strip() + + @classmethod + def get_subdirectory(cls, location: str) -> Optional[str]: + """ + Return the path to Python project root, relative to the repo root. + Return None if the project root is in the repo root. + """ + # find the repo root + git_dir = cls.run_command( + ["rev-parse", "--git-dir"], + show_stdout=False, + stdout_only=True, + cwd=location, + ).strip() + if not os.path.isabs(git_dir): + git_dir = os.path.join(location, git_dir) + repo_root = os.path.abspath(os.path.join(git_dir, "..")) + return find_path_to_project_root_from_repo_root(location, repo_root) + + @classmethod + def get_url_rev_and_auth(cls, url: str) -> Tuple[str, Optional[str], AuthInfo]: + """ + Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. + That's required because although they use SSH they sometimes don't + work with a ssh:// scheme (e.g. GitHub). But we need a scheme for + parsing. Hence we remove it again afterwards and return it as a stub. + """ + # Works around an apparent Git bug + # (see https://article.gmane.org/gmane.comp.version-control.git/146500) + scheme, netloc, path, query, fragment = urlsplit(url) + if scheme.endswith("file"): + initial_slashes = path[: -len(path.lstrip("/"))] + newpath = initial_slashes + urllib.request.url2pathname(path).replace( + "\\", "/" + ).lstrip("/") + after_plus = scheme.find("+") + 1 + url = scheme[:after_plus] + urlunsplit( + (scheme[after_plus:], netloc, newpath, query, fragment), + ) + + if "://" not in url: + assert "file:" not in url + url = url.replace("git+", "git+ssh://") + url, rev, user_pass = super().get_url_rev_and_auth(url) + url = url.replace("ssh://", "") + else: + url, rev, user_pass = super().get_url_rev_and_auth(url) + + return url, rev, user_pass + + @classmethod + def update_submodules(cls, location: str) -> None: + if not os.path.exists(os.path.join(location, ".gitmodules")): + return + cls.run_command( + ["submodule", "update", "--init", "--recursive", "-q"], + cwd=location, + ) + + @classmethod + def get_repository_root(cls, location: str) -> Optional[str]: + loc = super().get_repository_root(location) + if loc: + return loc + try: + r = cls.run_command( + ["rev-parse", "--show-toplevel"], + cwd=location, + show_stdout=False, + stdout_only=True, + on_returncode="raise", + log_failed_cmd=False, + ) + except BadCommand: + logger.debug( + "could not determine if %s is under git control " + "because git is not available", + location, + ) + return None + except InstallationError: + return None + return os.path.normpath(r.rstrip("\r\n")) + + @staticmethod + def should_add_vcs_url_prefix(repo_url: str) -> bool: + """In either https or ssh form, requirements must be prefixed with git+.""" + return True + + +vcs.register(Git) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/mercurial.py b/backend/venv/Lib/site-packages/pip/_internal/vcs/mercurial.py new file mode 100644 index 0000000..c183d41 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/vcs/mercurial.py @@ -0,0 +1,163 @@ +import configparser +import logging +import os +from typing import List, Optional, Tuple + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.misc import HiddenText, display_path +from pip._internal.utils.subprocess import make_command +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs.versioncontrol import ( + RevOptions, + VersionControl, + find_path_to_project_root_from_repo_root, + vcs, +) + +logger = logging.getLogger(__name__) + + +class Mercurial(VersionControl): + name = "hg" + dirname = ".hg" + repo_name = "clone" + schemes = ( + "hg+file", + "hg+http", + "hg+https", + "hg+ssh", + "hg+static-http", + ) + + @staticmethod + def get_base_rev_args(rev: str) -> List[str]: + return [f"--rev={rev}"] + + def fetch_new( + self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int + ) -> None: + rev_display = rev_options.to_display() + logger.info( + "Cloning hg %s%s to %s", + url, + rev_display, + display_path(dest), + ) + if verbosity <= 0: + flags: Tuple[str, ...] = ("--quiet",) + elif verbosity == 1: + flags = () + elif verbosity == 2: + flags = ("--verbose",) + else: + flags = ("--verbose", "--debug") + self.run_command(make_command("clone", "--noupdate", *flags, url, dest)) + self.run_command( + make_command("update", *flags, rev_options.to_args()), + cwd=dest, + ) + + def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + repo_config = os.path.join(dest, self.dirname, "hgrc") + config = configparser.RawConfigParser() + try: + config.read(repo_config) + config.set("paths", "default", url.secret) + with open(repo_config, "w") as config_file: + config.write(config_file) + except (OSError, configparser.NoSectionError) as exc: + logger.warning("Could not switch Mercurial repository to %s: %s", url, exc) + else: + cmd_args = make_command("update", "-q", rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + self.run_command(["pull", "-q"], cwd=dest) + cmd_args = make_command("update", "-q", rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + @classmethod + def get_remote_url(cls, location: str) -> str: + url = cls.run_command( + ["showconfig", "paths.default"], + show_stdout=False, + stdout_only=True, + cwd=location, + ).strip() + if cls._is_local_repository(url): + url = path_to_url(url) + return url.strip() + + @classmethod + def get_revision(cls, location: str) -> str: + """ + Return the repository-local changeset revision number, as an integer. + """ + current_revision = cls.run_command( + ["parents", "--template={rev}"], + show_stdout=False, + stdout_only=True, + cwd=location, + ).strip() + return current_revision + + @classmethod + def get_requirement_revision(cls, location: str) -> str: + """ + Return the changeset identification hash, as a 40-character + hexadecimal string + """ + current_rev_hash = cls.run_command( + ["parents", "--template={node}"], + show_stdout=False, + stdout_only=True, + cwd=location, + ).strip() + return current_rev_hash + + @classmethod + def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool: + """Always assume the versions don't match""" + return False + + @classmethod + def get_subdirectory(cls, location: str) -> Optional[str]: + """ + Return the path to Python project root, relative to the repo root. + Return None if the project root is in the repo root. + """ + # find the repo root + repo_root = cls.run_command( + ["root"], show_stdout=False, stdout_only=True, cwd=location + ).strip() + if not os.path.isabs(repo_root): + repo_root = os.path.abspath(os.path.join(location, repo_root)) + return find_path_to_project_root_from_repo_root(location, repo_root) + + @classmethod + def get_repository_root(cls, location: str) -> Optional[str]: + loc = super().get_repository_root(location) + if loc: + return loc + try: + r = cls.run_command( + ["root"], + cwd=location, + show_stdout=False, + stdout_only=True, + on_returncode="raise", + log_failed_cmd=False, + ) + except BadCommand: + logger.debug( + "could not determine if %s is under hg control " + "because hg is not available", + location, + ) + return None + except InstallationError: + return None + return os.path.normpath(r.rstrip("\r\n")) + + +vcs.register(Mercurial) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/subversion.py b/backend/venv/Lib/site-packages/pip/_internal/vcs/subversion.py new file mode 100644 index 0000000..f359266 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/vcs/subversion.py @@ -0,0 +1,324 @@ +import logging +import os +import re +from typing import List, Optional, Tuple + +from pip._internal.utils.misc import ( + HiddenText, + display_path, + is_console_interactive, + is_installable_dir, + split_auth_from_netloc, +) +from pip._internal.utils.subprocess import CommandArgs, make_command +from pip._internal.vcs.versioncontrol import ( + AuthInfo, + RemoteNotFoundError, + RevOptions, + VersionControl, + vcs, +) + +logger = logging.getLogger(__name__) + +_svn_xml_url_re = re.compile('url="([^"]+)"') +_svn_rev_re = re.compile(r'committed-rev="(\d+)"') +_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') +_svn_info_xml_url_re = re.compile(r"(.*)") + + +class Subversion(VersionControl): + name = "svn" + dirname = ".svn" + repo_name = "checkout" + schemes = ("svn+ssh", "svn+http", "svn+https", "svn+svn", "svn+file") + + @classmethod + def should_add_vcs_url_prefix(cls, remote_url: str) -> bool: + return True + + @staticmethod + def get_base_rev_args(rev: str) -> List[str]: + return ["-r", rev] + + @classmethod + def get_revision(cls, location: str) -> str: + """ + Return the maximum revision for all files under a given location + """ + # Note: taken from setuptools.command.egg_info + revision = 0 + + for base, dirs, _ in os.walk(location): + if cls.dirname not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove(cls.dirname) + entries_fn = os.path.join(base, cls.dirname, "entries") + if not os.path.exists(entries_fn): + # FIXME: should we warn? + continue + + dirurl, localrev = cls._get_svn_url_rev(base) + + if base == location: + assert dirurl is not None + base = dirurl + "/" # save the root url + elif not dirurl or not dirurl.startswith(base): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + return str(revision) + + @classmethod + def get_netloc_and_auth( + cls, netloc: str, scheme: str + ) -> Tuple[str, Tuple[Optional[str], Optional[str]]]: + """ + This override allows the auth information to be passed to svn via the + --username and --password options instead of via the URL. + """ + if scheme == "ssh": + # The --username and --password options can't be used for + # svn+ssh URLs, so keep the auth information in the URL. + return super().get_netloc_and_auth(netloc, scheme) + + return split_auth_from_netloc(netloc) + + @classmethod + def get_url_rev_and_auth(cls, url: str) -> Tuple[str, Optional[str], AuthInfo]: + # hotfix the URL scheme after removing svn+ from svn+ssh:// re-add it + url, rev, user_pass = super().get_url_rev_and_auth(url) + if url.startswith("ssh://"): + url = "svn+" + url + return url, rev, user_pass + + @staticmethod + def make_rev_args( + username: Optional[str], password: Optional[HiddenText] + ) -> CommandArgs: + extra_args: CommandArgs = [] + if username: + extra_args += ["--username", username] + if password: + extra_args += ["--password", password] + + return extra_args + + @classmethod + def get_remote_url(cls, location: str) -> str: + # In cases where the source is in a subdirectory, we have to look up in + # the location until we find a valid project root. + orig_location = location + while not is_installable_dir(location): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding a Python project. + logger.warning( + "Could not find Python project for directory %s (tried all " + "parent directories)", + orig_location, + ) + raise RemoteNotFoundError + + url, _rev = cls._get_svn_url_rev(location) + if url is None: + raise RemoteNotFoundError + + return url + + @classmethod + def _get_svn_url_rev(cls, location: str) -> Tuple[Optional[str], int]: + from pip._internal.exceptions import InstallationError + + entries_path = os.path.join(location, cls.dirname, "entries") + if os.path.exists(entries_path): + with open(entries_path) as f: + data = f.read() + else: # subversion >= 1.7 does not have the 'entries' file + data = "" + + url = None + if data.startswith("8") or data.startswith("9") or data.startswith("10"): + entries = list(map(str.splitlines, data.split("\n\x0c\n"))) + del entries[0][0] # get rid of the '8' + url = entries[0][3] + revs = [int(d[9]) for d in entries if len(d) > 9 and d[9]] + [0] + elif data.startswith("= 1.7 + # Note that using get_remote_call_options is not necessary here + # because `svn info` is being run against a local directory. + # We don't need to worry about making sure interactive mode + # is being used to prompt for passwords, because passwords + # are only potentially needed for remote server requests. + xml = cls.run_command( + ["info", "--xml", location], + show_stdout=False, + stdout_only=True, + ) + match = _svn_info_xml_url_re.search(xml) + assert match is not None + url = match.group(1) + revs = [int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml)] + except InstallationError: + url, revs = None, [] + + if revs: + rev = max(revs) + else: + rev = 0 + + return url, rev + + @classmethod + def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool: + """Always assume the versions don't match""" + return False + + def __init__(self, use_interactive: Optional[bool] = None) -> None: + if use_interactive is None: + use_interactive = is_console_interactive() + self.use_interactive = use_interactive + + # This member is used to cache the fetched version of the current + # ``svn`` client. + # Special value definitions: + # None: Not evaluated yet. + # Empty tuple: Could not parse version. + self._vcs_version: Optional[Tuple[int, ...]] = None + + super().__init__() + + def call_vcs_version(self) -> Tuple[int, ...]: + """Query the version of the currently installed Subversion client. + + :return: A tuple containing the parts of the version information or + ``()`` if the version returned from ``svn`` could not be parsed. + :raises: BadCommand: If ``svn`` is not installed. + """ + # Example versions: + # svn, version 1.10.3 (r1842928) + # compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0 + # svn, version 1.7.14 (r1542130) + # compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu + # svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0) + # compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2 + version_prefix = "svn, version " + version = self.run_command(["--version"], show_stdout=False, stdout_only=True) + if not version.startswith(version_prefix): + return () + + version = version[len(version_prefix) :].split()[0] + version_list = version.partition("-")[0].split(".") + try: + parsed_version = tuple(map(int, version_list)) + except ValueError: + return () + + return parsed_version + + def get_vcs_version(self) -> Tuple[int, ...]: + """Return the version of the currently installed Subversion client. + + If the version of the Subversion client has already been queried, + a cached value will be used. + + :return: A tuple containing the parts of the version information or + ``()`` if the version returned from ``svn`` could not be parsed. + :raises: BadCommand: If ``svn`` is not installed. + """ + if self._vcs_version is not None: + # Use cached version, if available. + # If parsing the version failed previously (empty tuple), + # do not attempt to parse it again. + return self._vcs_version + + vcs_version = self.call_vcs_version() + self._vcs_version = vcs_version + return vcs_version + + def get_remote_call_options(self) -> CommandArgs: + """Return options to be used on calls to Subversion that contact the server. + + These options are applicable for the following ``svn`` subcommands used + in this class. + + - checkout + - switch + - update + + :return: A list of command line arguments to pass to ``svn``. + """ + if not self.use_interactive: + # --non-interactive switch is available since Subversion 0.14.4. + # Subversion < 1.8 runs in interactive mode by default. + return ["--non-interactive"] + + svn_version = self.get_vcs_version() + # By default, Subversion >= 1.8 runs in non-interactive mode if + # stdin is not a TTY. Since that is how pip invokes SVN, in + # call_subprocess(), pip must pass --force-interactive to ensure + # the user can be prompted for a password, if required. + # SVN added the --force-interactive option in SVN 1.8. Since + # e.g. RHEL/CentOS 7, which is supported until 2024, ships with + # SVN 1.7, pip should continue to support SVN 1.7. Therefore, pip + # can't safely add the option if the SVN version is < 1.8 (or unknown). + if svn_version >= (1, 8): + return ["--force-interactive"] + + return [] + + def fetch_new( + self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int + ) -> None: + rev_display = rev_options.to_display() + logger.info( + "Checking out %s%s to %s", + url, + rev_display, + display_path(dest), + ) + if verbosity <= 0: + flags = ["--quiet"] + else: + flags = [] + cmd_args = make_command( + "checkout", + *flags, + self.get_remote_call_options(), + rev_options.to_args(), + url, + dest, + ) + self.run_command(cmd_args) + + def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + cmd_args = make_command( + "switch", + self.get_remote_call_options(), + rev_options.to_args(), + url, + dest, + ) + self.run_command(cmd_args) + + def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + cmd_args = make_command( + "update", + self.get_remote_call_options(), + rev_options.to_args(), + dest, + ) + self.run_command(cmd_args) + + +vcs.register(Subversion) diff --git a/backend/venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py b/backend/venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py new file mode 100644 index 0000000..a413316 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py @@ -0,0 +1,688 @@ +"""Handles all VCS (version control) support""" + +import logging +import os +import shutil +import sys +import urllib.parse +from dataclasses import dataclass, field +from typing import ( + Any, + Dict, + Iterable, + Iterator, + List, + Literal, + Mapping, + Optional, + Tuple, + Type, + Union, +) + +from pip._internal.cli.spinners import SpinnerInterface +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.misc import ( + HiddenText, + ask_path_exists, + backup_dir, + display_path, + hide_url, + hide_value, + is_installable_dir, + rmtree, +) +from pip._internal.utils.subprocess import ( + CommandArgs, + call_subprocess, + format_command_args, + make_command, +) + +__all__ = ["vcs"] + + +logger = logging.getLogger(__name__) + +AuthInfo = Tuple[Optional[str], Optional[str]] + + +def is_url(name: str) -> bool: + """ + Return true if the name looks like a URL. + """ + scheme = urllib.parse.urlsplit(name).scheme + if not scheme: + return False + return scheme in ["http", "https", "file", "ftp"] + vcs.all_schemes + + +def make_vcs_requirement_url( + repo_url: str, rev: str, project_name: str, subdir: Optional[str] = None +) -> str: + """ + Return the URL for a VCS requirement. + + Args: + repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+"). + project_name: the (unescaped) project name. + """ + egg_project_name = project_name.replace("-", "_") + req = f"{repo_url}@{rev}#egg={egg_project_name}" + if subdir: + req += f"&subdirectory={subdir}" + + return req + + +def find_path_to_project_root_from_repo_root( + location: str, repo_root: str +) -> Optional[str]: + """ + Find the the Python project's root by searching up the filesystem from + `location`. Return the path to project root relative to `repo_root`. + Return None if the project root is `repo_root`, or cannot be found. + """ + # find project root. + orig_location = location + while not is_installable_dir(location): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding a Python project. + logger.warning( + "Could not find a Python project for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + + if os.path.samefile(repo_root, location): + return None + + return os.path.relpath(location, repo_root) + + +class RemoteNotFoundError(Exception): + pass + + +class RemoteNotValidError(Exception): + def __init__(self, url: str): + super().__init__(url) + self.url = url + + +@dataclass(frozen=True) +class RevOptions: + """ + Encapsulates a VCS-specific revision to install, along with any VCS + install options. + + Args: + vc_class: a VersionControl subclass. + rev: the name of the revision to install. + extra_args: a list of extra options. + """ + + vc_class: Type["VersionControl"] + rev: Optional[str] = None + extra_args: CommandArgs = field(default_factory=list) + branch_name: Optional[str] = None + + def __repr__(self) -> str: + return f"" + + @property + def arg_rev(self) -> Optional[str]: + if self.rev is None: + return self.vc_class.default_arg_rev + + return self.rev + + def to_args(self) -> CommandArgs: + """ + Return the VCS-specific command arguments. + """ + args: CommandArgs = [] + rev = self.arg_rev + if rev is not None: + args += self.vc_class.get_base_rev_args(rev) + args += self.extra_args + + return args + + def to_display(self) -> str: + if not self.rev: + return "" + + return f" (to revision {self.rev})" + + def make_new(self, rev: str) -> "RevOptions": + """ + Make a copy of the current instance, but with a new rev. + + Args: + rev: the name of the revision for the new object. + """ + return self.vc_class.make_rev_options(rev, extra_args=self.extra_args) + + +class VcsSupport: + _registry: Dict[str, "VersionControl"] = {} + schemes = ["ssh", "git", "hg", "bzr", "sftp", "svn"] + + def __init__(self) -> None: + # Register more schemes with urlparse for various version control + # systems + urllib.parse.uses_netloc.extend(self.schemes) + super().__init__() + + def __iter__(self) -> Iterator[str]: + return self._registry.__iter__() + + @property + def backends(self) -> List["VersionControl"]: + return list(self._registry.values()) + + @property + def dirnames(self) -> List[str]: + return [backend.dirname for backend in self.backends] + + @property + def all_schemes(self) -> List[str]: + schemes: List[str] = [] + for backend in self.backends: + schemes.extend(backend.schemes) + return schemes + + def register(self, cls: Type["VersionControl"]) -> None: + if not hasattr(cls, "name"): + logger.warning("Cannot register VCS %s", cls.__name__) + return + if cls.name not in self._registry: + self._registry[cls.name] = cls() + logger.debug("Registered VCS backend: %s", cls.name) + + def unregister(self, name: str) -> None: + if name in self._registry: + del self._registry[name] + + def get_backend_for_dir(self, location: str) -> Optional["VersionControl"]: + """ + Return a VersionControl object if a repository of that type is found + at the given directory. + """ + vcs_backends = {} + for vcs_backend in self._registry.values(): + repo_path = vcs_backend.get_repository_root(location) + if not repo_path: + continue + logger.debug("Determine that %s uses VCS: %s", location, vcs_backend.name) + vcs_backends[repo_path] = vcs_backend + + if not vcs_backends: + return None + + # Choose the VCS in the inner-most directory. Since all repository + # roots found here would be either `location` or one of its + # parents, the longest path should have the most path components, + # i.e. the backend representing the inner-most repository. + inner_most_repo_path = max(vcs_backends, key=len) + return vcs_backends[inner_most_repo_path] + + def get_backend_for_scheme(self, scheme: str) -> Optional["VersionControl"]: + """ + Return a VersionControl object or None. + """ + for vcs_backend in self._registry.values(): + if scheme in vcs_backend.schemes: + return vcs_backend + return None + + def get_backend(self, name: str) -> Optional["VersionControl"]: + """ + Return a VersionControl object or None. + """ + name = name.lower() + return self._registry.get(name) + + +vcs = VcsSupport() + + +class VersionControl: + name = "" + dirname = "" + repo_name = "" + # List of supported schemes for this Version Control + schemes: Tuple[str, ...] = () + # Iterable of environment variable names to pass to call_subprocess(). + unset_environ: Tuple[str, ...] = () + default_arg_rev: Optional[str] = None + + @classmethod + def should_add_vcs_url_prefix(cls, remote_url: str) -> bool: + """ + Return whether the vcs prefix (e.g. "git+") should be added to a + repository's remote url when used in a requirement. + """ + return not remote_url.lower().startswith(f"{cls.name}:") + + @classmethod + def get_subdirectory(cls, location: str) -> Optional[str]: + """ + Return the path to Python project root, relative to the repo root. + Return None if the project root is in the repo root. + """ + return None + + @classmethod + def get_requirement_revision(cls, repo_dir: str) -> str: + """ + Return the revision string that should be used in a requirement. + """ + return cls.get_revision(repo_dir) + + @classmethod + def get_src_requirement(cls, repo_dir: str, project_name: str) -> str: + """ + Return the requirement string to use to redownload the files + currently at the given repository directory. + + Args: + project_name: the (unescaped) project name. + + The return value has a form similar to the following: + + {repository_url}@{revision}#egg={project_name} + """ + repo_url = cls.get_remote_url(repo_dir) + + if cls.should_add_vcs_url_prefix(repo_url): + repo_url = f"{cls.name}+{repo_url}" + + revision = cls.get_requirement_revision(repo_dir) + subdir = cls.get_subdirectory(repo_dir) + req = make_vcs_requirement_url(repo_url, revision, project_name, subdir=subdir) + + return req + + @staticmethod + def get_base_rev_args(rev: str) -> List[str]: + """ + Return the base revision arguments for a vcs command. + + Args: + rev: the name of a revision to install. Cannot be None. + """ + raise NotImplementedError + + def is_immutable_rev_checkout(self, url: str, dest: str) -> bool: + """ + Return true if the commit hash checked out at dest matches + the revision in url. + + Always return False, if the VCS does not support immutable commit + hashes. + + This method does not check if there are local uncommitted changes + in dest after checkout, as pip currently has no use case for that. + """ + return False + + @classmethod + def make_rev_options( + cls, rev: Optional[str] = None, extra_args: Optional[CommandArgs] = None + ) -> RevOptions: + """ + Return a RevOptions object. + + Args: + rev: the name of a revision to install. + extra_args: a list of extra options. + """ + return RevOptions(cls, rev, extra_args=extra_args or []) + + @classmethod + def _is_local_repository(cls, repo: str) -> bool: + """ + posix absolute paths start with os.path.sep, + win32 ones start with drive (like c:\\folder) + """ + drive, tail = os.path.splitdrive(repo) + return repo.startswith(os.path.sep) or bool(drive) + + @classmethod + def get_netloc_and_auth( + cls, netloc: str, scheme: str + ) -> Tuple[str, Tuple[Optional[str], Optional[str]]]: + """ + Parse the repository URL's netloc, and return the new netloc to use + along with auth information. + + Args: + netloc: the original repository URL netloc. + scheme: the repository URL's scheme without the vcs prefix. + + This is mainly for the Subversion class to override, so that auth + information can be provided via the --username and --password options + instead of through the URL. For other subclasses like Git without + such an option, auth information must stay in the URL. + + Returns: (netloc, (username, password)). + """ + return netloc, (None, None) + + @classmethod + def get_url_rev_and_auth(cls, url: str) -> Tuple[str, Optional[str], AuthInfo]: + """ + Parse the repository URL to use, and return the URL, revision, + and auth info to use. + + Returns: (url, rev, (username, password)). + """ + scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) + if "+" not in scheme: + raise ValueError( + f"Sorry, {url!r} is a malformed VCS url. " + "The format is +://, " + "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" + ) + # Remove the vcs prefix. + scheme = scheme.split("+", 1)[1] + netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme) + rev = None + if "@" in path: + path, rev = path.rsplit("@", 1) + if not rev: + raise InstallationError( + f"The URL {url!r} has an empty revision (after @) " + "which is not supported. Include a revision after @ " + "or remove @ from the URL." + ) + url = urllib.parse.urlunsplit((scheme, netloc, path, query, "")) + return url, rev, user_pass + + @staticmethod + def make_rev_args( + username: Optional[str], password: Optional[HiddenText] + ) -> CommandArgs: + """ + Return the RevOptions "extra arguments" to use in obtain(). + """ + return [] + + def get_url_rev_options(self, url: HiddenText) -> Tuple[HiddenText, RevOptions]: + """ + Return the URL and RevOptions object to use in obtain(), + as a tuple (url, rev_options). + """ + secret_url, rev, user_pass = self.get_url_rev_and_auth(url.secret) + username, secret_password = user_pass + password: Optional[HiddenText] = None + if secret_password is not None: + password = hide_value(secret_password) + extra_args = self.make_rev_args(username, password) + rev_options = self.make_rev_options(rev, extra_args=extra_args) + + return hide_url(secret_url), rev_options + + @staticmethod + def normalize_url(url: str) -> str: + """ + Normalize a URL for comparison by unquoting it and removing any + trailing slash. + """ + return urllib.parse.unquote(url).rstrip("/") + + @classmethod + def compare_urls(cls, url1: str, url2: str) -> bool: + """ + Compare two repo URLs for identity, ignoring incidental differences. + """ + return cls.normalize_url(url1) == cls.normalize_url(url2) + + def fetch_new( + self, dest: str, url: HiddenText, rev_options: RevOptions, verbosity: int + ) -> None: + """ + Fetch a revision from a repository, in the case that this is the + first fetch from the repository. + + Args: + dest: the directory to fetch the repository to. + rev_options: a RevOptions object. + verbosity: verbosity level. + """ + raise NotImplementedError + + def switch(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + """ + Switch the repo at ``dest`` to point to ``URL``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def update(self, dest: str, url: HiddenText, rev_options: RevOptions) -> None: + """ + Update an already-existing repo to the given ``rev_options``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + @classmethod + def is_commit_id_equal(cls, dest: str, name: Optional[str]) -> bool: + """ + Return whether the id of the current commit equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + raise NotImplementedError + + def obtain(self, dest: str, url: HiddenText, verbosity: int) -> None: + """ + Install or update in editable mode the package represented by this + VersionControl object. + + :param dest: the repository directory in which to install or update. + :param url: the repository URL starting with a vcs prefix. + :param verbosity: verbosity level. + """ + url, rev_options = self.get_url_rev_options(url) + + if not os.path.exists(dest): + self.fetch_new(dest, url, rev_options, verbosity=verbosity) + return + + rev_display = rev_options.to_display() + if self.is_repository_directory(dest): + existing_url = self.get_remote_url(dest) + if self.compare_urls(existing_url, url.secret): + logger.debug( + "%s in %s exists, and has correct URL (%s)", + self.repo_name.title(), + display_path(dest), + url, + ) + if not self.is_commit_id_equal(dest, rev_options.rev): + logger.info( + "Updating %s %s%s", + display_path(dest), + self.repo_name, + rev_display, + ) + self.update(dest, url, rev_options) + else: + logger.info("Skipping because already up-to-date.") + return + + logger.warning( + "%s %s in %s exists with URL %s", + self.name, + self.repo_name, + display_path(dest), + existing_url, + ) + prompt = ("(s)witch, (i)gnore, (w)ipe, (b)ackup ", ("s", "i", "w", "b")) + else: + logger.warning( + "Directory %s already exists, and is not a %s %s.", + dest, + self.name, + self.repo_name, + ) + # https://github.com/python/mypy/issues/1174 + prompt = ("(i)gnore, (w)ipe, (b)ackup ", ("i", "w", "b")) # type: ignore + + logger.warning( + "The plan is to install the %s repository %s", + self.name, + url, + ) + response = ask_path_exists(f"What to do? {prompt[0]}", prompt[1]) + + if response == "a": + sys.exit(-1) + + if response == "w": + logger.warning("Deleting %s", display_path(dest)) + rmtree(dest) + self.fetch_new(dest, url, rev_options, verbosity=verbosity) + return + + if response == "b": + dest_dir = backup_dir(dest) + logger.warning("Backing up %s to %s", display_path(dest), dest_dir) + shutil.move(dest, dest_dir) + self.fetch_new(dest, url, rev_options, verbosity=verbosity) + return + + # Do nothing if the response is "i". + if response == "s": + logger.info( + "Switching %s %s to %s%s", + self.repo_name, + display_path(dest), + url, + rev_display, + ) + self.switch(dest, url, rev_options) + + def unpack(self, location: str, url: HiddenText, verbosity: int) -> None: + """ + Clean up current location and download the url repository + (and vcs infos) into location + + :param url: the repository URL starting with a vcs prefix. + :param verbosity: verbosity level. + """ + if os.path.exists(location): + rmtree(location) + self.obtain(location, url=url, verbosity=verbosity) + + @classmethod + def get_remote_url(cls, location: str) -> str: + """ + Return the url used at location + + Raises RemoteNotFoundError if the repository does not have a remote + url configured. + """ + raise NotImplementedError + + @classmethod + def get_revision(cls, location: str) -> str: + """ + Return the current commit id of the files at the given location. + """ + raise NotImplementedError + + @classmethod + def run_command( + cls, + cmd: Union[List[str], CommandArgs], + show_stdout: bool = True, + cwd: Optional[str] = None, + on_returncode: 'Literal["raise", "warn", "ignore"]' = "raise", + extra_ok_returncodes: Optional[Iterable[int]] = None, + command_desc: Optional[str] = None, + extra_environ: Optional[Mapping[str, Any]] = None, + spinner: Optional[SpinnerInterface] = None, + log_failed_cmd: bool = True, + stdout_only: bool = False, + ) -> str: + """ + Run a VCS subcommand + This is simply a wrapper around call_subprocess that adds the VCS + command name, and checks that the VCS is available + """ + cmd = make_command(cls.name, *cmd) + if command_desc is None: + command_desc = format_command_args(cmd) + try: + return call_subprocess( + cmd, + show_stdout, + cwd, + on_returncode=on_returncode, + extra_ok_returncodes=extra_ok_returncodes, + command_desc=command_desc, + extra_environ=extra_environ, + unset_environ=cls.unset_environ, + spinner=spinner, + log_failed_cmd=log_failed_cmd, + stdout_only=stdout_only, + ) + except NotADirectoryError: + raise BadCommand(f"Cannot find command {cls.name!r} - invalid PATH") + except FileNotFoundError: + # errno.ENOENT = no such file or directory + # In other words, the VCS executable isn't available + raise BadCommand( + f"Cannot find command {cls.name!r} - do you have " + f"{cls.name!r} installed and in your PATH?" + ) + except PermissionError: + # errno.EACCES = Permission denied + # This error occurs, for instance, when the command is installed + # only for another user. So, the current user don't have + # permission to call the other user command. + raise BadCommand( + f"No permission to execute {cls.name!r} - install it " + f"locally, globally (ask admin), or check your PATH. " + f"See possible solutions at " + f"https://pip.pypa.io/en/latest/reference/pip_freeze/" + f"#fixing-permission-denied." + ) + + @classmethod + def is_repository_directory(cls, path: str) -> bool: + """ + Return whether a directory path is a repository directory. + """ + logger.debug("Checking in %s for %s (%s)...", path, cls.dirname, cls.name) + return os.path.exists(os.path.join(path, cls.dirname)) + + @classmethod + def get_repository_root(cls, location: str) -> Optional[str]: + """ + Return the "root" (top-level) directory controlled by the vcs, + or `None` if the directory is not in any. + + It is meant to be overridden to implement smarter detection + mechanisms for specific vcs. + + This can do more than is_repository_directory() alone. For + example, the Git override checks that Git is actually available. + """ + if cls.is_repository_directory(location): + return location + return None diff --git a/backend/venv/Lib/site-packages/pip/_internal/wheel_builder.py b/backend/venv/Lib/site-packages/pip/_internal/wheel_builder.py new file mode 100644 index 0000000..93f8e1f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_internal/wheel_builder.py @@ -0,0 +1,354 @@ +"""Orchestrator for building wheels from InstallRequirements. +""" + +import logging +import os.path +import re +import shutil +from typing import Iterable, List, Optional, Tuple + +from pip._vendor.packaging.utils import canonicalize_name, canonicalize_version +from pip._vendor.packaging.version import InvalidVersion, Version + +from pip._internal.cache import WheelCache +from pip._internal.exceptions import InvalidWheelFilename, UnsupportedWheel +from pip._internal.metadata import FilesystemWheel, get_wheel_distribution +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.operations.build.wheel import build_wheel_pep517 +from pip._internal.operations.build.wheel_editable import build_wheel_editable +from pip._internal.operations.build.wheel_legacy import build_wheel_legacy +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ensure_dir, hash_file +from pip._internal.utils.setuptools_build import make_setuptools_clean_args +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs import vcs + +logger = logging.getLogger(__name__) + +_egg_info_re = re.compile(r"([a-z0-9_.]+)-([a-z0-9_.!+-]+)", re.IGNORECASE) + +BuildResult = Tuple[List[InstallRequirement], List[InstallRequirement]] + + +def _contains_egg_info(s: str) -> bool: + """Determine whether the string looks like an egg_info. + + :param s: The string to parse. E.g. foo-2.1 + """ + return bool(_egg_info_re.search(s)) + + +def _should_build( + req: InstallRequirement, + need_wheel: bool, +) -> bool: + """Return whether an InstallRequirement should be built into a wheel.""" + if req.constraint: + # never build requirements that are merely constraints + return False + if req.is_wheel: + if need_wheel: + logger.info( + "Skipping %s, due to already being wheel.", + req.name, + ) + return False + + if need_wheel: + # i.e. pip wheel, not pip install + return True + + # From this point, this concerns the pip install command only + # (need_wheel=False). + + if not req.source_dir: + return False + + if req.editable: + # we only build PEP 660 editable requirements + return req.supports_pyproject_editable + + return True + + +def should_build_for_wheel_command( + req: InstallRequirement, +) -> bool: + return _should_build(req, need_wheel=True) + + +def should_build_for_install_command( + req: InstallRequirement, +) -> bool: + return _should_build(req, need_wheel=False) + + +def _should_cache( + req: InstallRequirement, +) -> Optional[bool]: + """ + Return whether a built InstallRequirement can be stored in the persistent + wheel cache, assuming the wheel cache is available, and _should_build() + has determined a wheel needs to be built. + """ + if req.editable or not req.source_dir: + # never cache editable requirements + return False + + if req.link and req.link.is_vcs: + # VCS checkout. Do not cache + # unless it points to an immutable commit hash. + assert not req.editable + assert req.source_dir + vcs_backend = vcs.get_backend_for_scheme(req.link.scheme) + assert vcs_backend + if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir): + return True + return False + + assert req.link + base, ext = req.link.splitext() + if _contains_egg_info(base): + return True + + # Otherwise, do not cache. + return False + + +def _get_cache_dir( + req: InstallRequirement, + wheel_cache: WheelCache, +) -> str: + """Return the persistent or temporary cache directory where the built + wheel need to be stored. + """ + cache_available = bool(wheel_cache.cache_dir) + assert req.link + if cache_available and _should_cache(req): + cache_dir = wheel_cache.get_path_for_link(req.link) + else: + cache_dir = wheel_cache.get_ephem_path_for_link(req.link) + return cache_dir + + +def _verify_one(req: InstallRequirement, wheel_path: str) -> None: + canonical_name = canonicalize_name(req.name or "") + w = Wheel(os.path.basename(wheel_path)) + if canonicalize_name(w.name) != canonical_name: + raise InvalidWheelFilename( + f"Wheel has unexpected file name: expected {canonical_name!r}, " + f"got {w.name!r}", + ) + dist = get_wheel_distribution(FilesystemWheel(wheel_path), canonical_name) + dist_verstr = str(dist.version) + if canonicalize_version(dist_verstr) != canonicalize_version(w.version): + raise InvalidWheelFilename( + f"Wheel has unexpected file name: expected {dist_verstr!r}, " + f"got {w.version!r}", + ) + metadata_version_value = dist.metadata_version + if metadata_version_value is None: + raise UnsupportedWheel("Missing Metadata-Version") + try: + metadata_version = Version(metadata_version_value) + except InvalidVersion: + msg = f"Invalid Metadata-Version: {metadata_version_value}" + raise UnsupportedWheel(msg) + if metadata_version >= Version("1.2") and not isinstance(dist.version, Version): + raise UnsupportedWheel( + f"Metadata 1.2 mandates PEP 440 version, but {dist_verstr!r} is not" + ) + + +def _build_one( + req: InstallRequirement, + output_dir: str, + verify: bool, + build_options: List[str], + global_options: List[str], + editable: bool, +) -> Optional[str]: + """Build one wheel. + + :return: The filename of the built wheel, or None if the build failed. + """ + artifact = "editable" if editable else "wheel" + try: + ensure_dir(output_dir) + except OSError as e: + logger.warning( + "Building %s for %s failed: %s", + artifact, + req.name, + e, + ) + return None + + # Install build deps into temporary directory (PEP 518) + with req.build_env: + wheel_path = _build_one_inside_env( + req, output_dir, build_options, global_options, editable + ) + if wheel_path and verify: + try: + _verify_one(req, wheel_path) + except (InvalidWheelFilename, UnsupportedWheel) as e: + logger.warning("Built %s for %s is invalid: %s", artifact, req.name, e) + return None + return wheel_path + + +def _build_one_inside_env( + req: InstallRequirement, + output_dir: str, + build_options: List[str], + global_options: List[str], + editable: bool, +) -> Optional[str]: + with TempDirectory(kind="wheel") as temp_dir: + assert req.name + if req.use_pep517: + assert req.metadata_directory + assert req.pep517_backend + if global_options: + logger.warning( + "Ignoring --global-option when building %s using PEP 517", req.name + ) + if build_options: + logger.warning( + "Ignoring --build-option when building %s using PEP 517", req.name + ) + if editable: + wheel_path = build_wheel_editable( + name=req.name, + backend=req.pep517_backend, + metadata_directory=req.metadata_directory, + tempd=temp_dir.path, + ) + else: + wheel_path = build_wheel_pep517( + name=req.name, + backend=req.pep517_backend, + metadata_directory=req.metadata_directory, + tempd=temp_dir.path, + ) + else: + wheel_path = build_wheel_legacy( + name=req.name, + setup_py_path=req.setup_py_path, + source_dir=req.unpacked_source_directory, + global_options=global_options, + build_options=build_options, + tempd=temp_dir.path, + ) + + if wheel_path is not None: + wheel_name = os.path.basename(wheel_path) + dest_path = os.path.join(output_dir, wheel_name) + try: + wheel_hash, length = hash_file(wheel_path) + shutil.move(wheel_path, dest_path) + logger.info( + "Created wheel for %s: filename=%s size=%d sha256=%s", + req.name, + wheel_name, + length, + wheel_hash.hexdigest(), + ) + logger.info("Stored in directory: %s", output_dir) + return dest_path + except Exception as e: + logger.warning( + "Building wheel for %s failed: %s", + req.name, + e, + ) + # Ignore return, we can't do anything else useful. + if not req.use_pep517: + _clean_one_legacy(req, global_options) + return None + + +def _clean_one_legacy(req: InstallRequirement, global_options: List[str]) -> bool: + clean_args = make_setuptools_clean_args( + req.setup_py_path, + global_options=global_options, + ) + + logger.info("Running setup.py clean for %s", req.name) + try: + call_subprocess( + clean_args, command_desc="python setup.py clean", cwd=req.source_dir + ) + return True + except Exception: + logger.error("Failed cleaning build dir for %s", req.name) + return False + + +def build( + requirements: Iterable[InstallRequirement], + wheel_cache: WheelCache, + verify: bool, + build_options: List[str], + global_options: List[str], +) -> BuildResult: + """Build wheels. + + :return: The list of InstallRequirement that succeeded to build and + the list of InstallRequirement that failed to build. + """ + if not requirements: + return [], [] + + # Build the wheels. + logger.info( + "Building wheels for collected packages: %s", + ", ".join(req.name for req in requirements), # type: ignore + ) + + with indent_log(): + build_successes, build_failures = [], [] + for req in requirements: + assert req.name + cache_dir = _get_cache_dir(req, wheel_cache) + wheel_file = _build_one( + req, + cache_dir, + verify, + build_options, + global_options, + req.editable and req.permit_editable_wheels, + ) + if wheel_file: + # Record the download origin in the cache + if req.download_info is not None: + # download_info is guaranteed to be set because when we build an + # InstallRequirement it has been through the preparer before, but + # let's be cautious. + wheel_cache.record_download_origin(cache_dir, req.download_info) + # Update the link for this. + req.link = Link(path_to_url(wheel_file)) + req.local_file_path = req.link.file_path + assert req.link.is_wheel + build_successes.append(req) + else: + build_failures.append(req) + + # notify success/failure + if build_successes: + logger.info( + "Successfully built %s", + " ".join([req.name for req in build_successes]), # type: ignore + ) + if build_failures: + logger.info( + "Failed to build %s", + " ".join([req.name for req in build_failures]), # type: ignore + ) + # Return a list of requirements that failed to build + return build_successes, build_failures diff --git a/backend/venv/Lib/site-packages/pip/_vendor/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/__init__.py new file mode 100644 index 0000000..561089c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/__init__.py @@ -0,0 +1,116 @@ +""" +pip._vendor is for vendoring dependencies of pip to prevent needing pip to +depend on something external. + +Files inside of pip._vendor should be considered immutable and should only be +updated to versions from upstream. +""" +from __future__ import absolute_import + +import glob +import os.path +import sys + +# Downstream redistributors which have debundled our dependencies should also +# patch this value to be true. This will trigger the additional patching +# to cause things like "six" to be available as pip. +DEBUNDLED = False + +# By default, look in this directory for a bunch of .whl files which we will +# add to the beginning of sys.path before attempting to import anything. This +# is done to support downstream re-distributors like Debian and Fedora who +# wish to create their own Wheels for our dependencies to aid in debundling. +WHEEL_DIR = os.path.abspath(os.path.dirname(__file__)) + + +# Define a small helper function to alias our vendored modules to the real ones +# if the vendored ones do not exist. This idea of this was taken from +# https://github.com/kennethreitz/requests/pull/2567. +def vendored(modulename): + vendored_name = "{0}.{1}".format(__name__, modulename) + + try: + __import__(modulename, globals(), locals(), level=0) + except ImportError: + # We can just silently allow import failures to pass here. If we + # got to this point it means that ``import pip._vendor.whatever`` + # failed and so did ``import whatever``. Since we're importing this + # upfront in an attempt to alias imports, not erroring here will + # just mean we get a regular import error whenever pip *actually* + # tries to import one of these modules to use it, which actually + # gives us a better error message than we would have otherwise + # gotten. + pass + else: + sys.modules[vendored_name] = sys.modules[modulename] + base, head = vendored_name.rsplit(".", 1) + setattr(sys.modules[base], head, sys.modules[modulename]) + + +# If we're operating in a debundled setup, then we want to go ahead and trigger +# the aliasing of our vendored libraries as well as looking for wheels to add +# to our sys.path. This will cause all of this code to be a no-op typically +# however downstream redistributors can enable it in a consistent way across +# all platforms. +if DEBUNDLED: + # Actually look inside of WHEEL_DIR to find .whl files and add them to the + # front of our sys.path. + sys.path[:] = glob.glob(os.path.join(WHEEL_DIR, "*.whl")) + sys.path + + # Actually alias all of our vendored dependencies. + vendored("cachecontrol") + vendored("certifi") + vendored("distlib") + vendored("distro") + vendored("packaging") + vendored("packaging.version") + vendored("packaging.specifiers") + vendored("pkg_resources") + vendored("platformdirs") + vendored("progress") + vendored("pyproject_hooks") + vendored("requests") + vendored("requests.exceptions") + vendored("requests.packages") + vendored("requests.packages.urllib3") + vendored("requests.packages.urllib3._collections") + vendored("requests.packages.urllib3.connection") + vendored("requests.packages.urllib3.connectionpool") + vendored("requests.packages.urllib3.contrib") + vendored("requests.packages.urllib3.contrib.ntlmpool") + vendored("requests.packages.urllib3.contrib.pyopenssl") + vendored("requests.packages.urllib3.exceptions") + vendored("requests.packages.urllib3.fields") + vendored("requests.packages.urllib3.filepost") + vendored("requests.packages.urllib3.packages") + vendored("requests.packages.urllib3.packages.ordered_dict") + vendored("requests.packages.urllib3.packages.six") + vendored("requests.packages.urllib3.packages.ssl_match_hostname") + vendored("requests.packages.urllib3.packages.ssl_match_hostname." + "_implementation") + vendored("requests.packages.urllib3.poolmanager") + vendored("requests.packages.urllib3.request") + vendored("requests.packages.urllib3.response") + vendored("requests.packages.urllib3.util") + vendored("requests.packages.urllib3.util.connection") + vendored("requests.packages.urllib3.util.request") + vendored("requests.packages.urllib3.util.response") + vendored("requests.packages.urllib3.util.retry") + vendored("requests.packages.urllib3.util.ssl_") + vendored("requests.packages.urllib3.util.timeout") + vendored("requests.packages.urllib3.util.url") + vendored("resolvelib") + vendored("rich") + vendored("rich.console") + vendored("rich.highlighter") + vendored("rich.logging") + vendored("rich.markup") + vendored("rich.progress") + vendored("rich.segment") + vendored("rich.style") + vendored("rich.text") + vendored("rich.traceback") + if sys.version_info < (3, 11): + vendored("tomli") + vendored("truststore") + vendored("urllib3") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce5a8d5fc861f4f91e8148da67dda4fc7aff605e GIT binary patch literal 4554 zcmbVOT}&L;6~423_m^G3{1{^l3_t!^J6?>9{|Iqg0)eQ+RwK2I*EFkP=fV!m?o967 zwY_6oqEe-T6v;%YWLvG2R;pAYtk#cxZ1d8GzJxNCorzznJoyd(RI2jSb7y~mo3KP3 zY4@J*obR4{=iGD8nSaLPQ3OxlpWoLa%?N$XLFEaSg;$R-Lido0Qb?6lpDyKmDWAk; zzwS@@y%DDZ-WW^;Rh$Zuz}O4`bpim8ELp;VlNR(v$* zL&QH{+4HvPyR6W;jZzj#ObxF2cCJB!-}NRokiOfZ`c;1ig1yAmP-UM|35Nw75pYz% z)%PvWj|uj;fa?X^AmBy;?-Ov7fSU!}BH&g5?-y{JfDZ_`UBCwg+#%pY0`3%Wmw>wk zEDN|tz`X+Q6L7zP4-5E+fR76Jn1B-kJ}%%B0)9ilCk31o@PL3%33yPzrv-dQz(WE) zE8ueiJ}=-40=~F~;VyN3`#!3}3ve50*t<<{Zm~T)BH*{SaM54%Cob8~qNZjh)7ME} zHK?pv@+=G`q~+&im6%{5`HV&^*_f4qEHgtkDFF_X^Mt6JR#HbxY}v@mmXRYY%T44a zBQ&q*$!PQ)O$RSp-qKW3c2-^4${Gb-m1l^YF+2h#s;uR51*XjCL{{>uT&5U#y$HN$ z!BiCnB-qY%LM;uZ$+OhR$pzD5lqk7m^f?b#LUJ3F8OzWMjHI=kX;60golLn(dhz7- z&=0>?AA%NYxHP}r>QNA4<(h}kZB(g$ccchnfieN~EL4%#DzhS@M)f`PuR*WikA#@l zS-3nOgOGzcg}LE$IxO$)->FYf$|+2 zfLFY`kHaIc51=E7KVAF7wMPfn508B8zgxFlxANY4xc6ym?~~TVdTU~} zZ}p>%*1_fI5?)fDg&Th3zgPE3-Tkrk#-85~J#79<$7danQtOEyJ`Vrrzppz`tnDR= z1mZ86P$a(D4AM6iPnrAOqcZwjj*PzH|NMjm|90Sb@@!``tF%W@mcBFOV3!_ry9SO60x9~FqjEW5cPCCSYUF&Qrt_P(mJazb|dw^Ydj z)nWf<>?6CHlIe`0>#(fnwSRXWL?>UO*~h*Q%QOt#?y1RSRGYDn?@3AKnGX36?oRB@ zHH!w6d&|=88t<|#j`Hp<;rw*fvU_VWbYdD7tHr4v&%o|}Dx9Q2RRUcjt!f!o>(Htb zEbXR!_Io&nfTW=wWwMZ67UPw}9{<0lC3zLoNe+sJ!gIzxT*D2VSx(7A`JlBjq3obm z5aIrqkoCmw+I_VG({wvg+n(H(#Wn5(ca^Mc>*yXXt9z@FaAk*#7VW-0-0_pDb@ZMq zrsarHsF`;j5AMGk<;6#b_5_6tQ!SIVWBi|o0`$ag^iWot%j)ohFP*YoH|FMerK|Jo zIfX71Ogrv@O4TYeEi%XR!H#-Hixt6Z#FH6(I@$Flkt!L&drZRjocG%2b@1l~n32;p zH_B)MN*(ke;)cpaE79nN(rMMml$z&kffXn;QpzX0n0HV&WLQa4VOiH_STxS{k+Jd7 zpI#oD8Xt49X9>Y~Q%Qh=>vc?M$+Pek2VNsTpBx{bN{_w!zSp~4Ja1@uH&(9a(Bo!} z&(JGyi|BstJUmiryqD+&fV|UNS@;0h^h=WT!WWeAf9jER^lMc26{`OVMK_};-n1Cm zjG=hL-HGLiyH}R4+#mgP;=#nHR~}qho!mHdb|ZFfG4e9jB#lZhhY*f$22t~&mHvB) zPZDM3)Pt$j_D2&NhekG<-uj#WAK|};*PA96-~RRFFDI9OviRc{K@^BDedyprU*g!( zRR_0iA3t#LevYp>xE;nX;!t9#RfI;1RkU+|3PDMX!VVJWJKb zF$X6+%~=PZ^Mo@F9`c0q4!+1CX(vAUn40X|C_(pkb}>9yy|*YUnd=$^h_5Vd~v6*a}GZ5X{uW}?cg&z zIb}af(+)lemZhILxP_19fPE3~cCfrnvGfZEcW^95w&I|A7M%|6dK!v83AL?<+U_6y fSE%R9aN|mw6Xr)%UGM5++_rg3g5;p*A>;lBjpWIY literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d7b4ff44fb0cdbc86fa5be35f1b46f3045f1122 GIT binary patch literal 139456 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py new file mode 100644 index 0000000..2191624 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +"""CacheControl import Interface. + +Make it easy to import from cachecontrol without long namespaces. +""" + +__author__ = "Eric Larson" +__email__ = "eric@ionrock.org" +__version__ = "0.14.1" + +from pip._vendor.cachecontrol.adapter import CacheControlAdapter +from pip._vendor.cachecontrol.controller import CacheController +from pip._vendor.cachecontrol.wrapper import CacheControl + +__all__ = [ + "__author__", + "__email__", + "__version__", + "CacheControlAdapter", + "CacheController", + "CacheControl", +] + +import logging + +logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72961201b40ec2ed15792f89bb2414612fdddccc GIT binary patch literal 907 zcmaJ<&ui2`6rR~%*(Cj`QiNg&6uR!AsRb`CRVzhMs6BWQLSUF?rs;GinJ~$A**)!_ z;LWQDf>Q7w@nR{`5-14b!CSRAPrht->0WdWZ@%|t-uJ%uW#WWmaKTS&6D%6(hhkS&IzM7-B=#Bhxc63K6Tn!=44_ zrnEh~gt&chdtBgp=hH{{$~(Ao9UY@#*3#I!-j7CboQqMG9 z(wXx-&bZ#A0e3Cy1#NRjWDcik&&kyI%AQt{6BN0@D7P!Jebvbvsp8OyX~fe67*f~j z+fTI!oNcO875C>jIGaMnS_N%a>9AkB=dRy(*MAlQn>fEYsptu#321@v>||IDLsOHX zW-Ye}p&byR3CT@DctnK+XcKbCbqXa3(Pb#2i^tMcFgwk;+#rOh0FG)!)F@0HOztEi zaUnBiO1qPty7WrakSkyQ=e5ybK+hW&GMaEa*;o3ChsSmxajYhCGIf69;93mscO?r8KBT}p*`6Immg^RD5 zz5;Vm#u)#y%D8f2p_#>jbvCs$FwbTd2KEoMd5#{RqX)k$hFuyMmp2fe{f6cT#wnUV kM)R-lo}k53v~rAAzBF2IyQhuTaiew8*!YSb>RZ757i)b8xc~qF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b09889c4161e5f4b23148188b5a60168e8f8e525 GIT binary patch literal 2651 zcmaJ@O>7fK6rS~t?Ty!V9FjmNNiaBt_<*CTs6}a;md212fSR+K|;kwPy$_08;VY-s2x-g)z8 z=Iz_}z3;vJ5{pF;jMTShwVy)>J*5kO1YCjJ{2qiQq#%XUk-_CTj>-W&kPpDj>%4*U znCY+{G(!0hlY@HL5b^?(Lwb)9$w!zR)?gxDw<^gq3>Af_L5D@}M9eCh*&!Kvt9!U59Mb~N0 z5#>t7v}Ic}D^?EH@uQ?vGt`QGMkba@KodLv$(du)^z5reQ#QR7tB`24qZ9FI<$1m(+?j?8Gu*sgrAjxM-#2#$o11#Pk%MD zbn5o06}*2fKG=?@TJh9!{PpGx?6&b>3lH8ZJ;9@!a09)79mRlQ_Y(-+*x3|SHvCvC z9Ar0o7le-{Y7qpE7PFAG!!1t@%f2faR$F|29>wNn3J~NzQCPB>0s`B zns-DNOG&lmlI28z9-6Fc4M4PKUab+$vbAC(Ja608$%%=EKm`k=beM#}PeOB!P_s_> zoN8IXI45YBwTkUTJa}kwB;0p&H0gj7mR)8!*n*1|{lH|B^ixw}Nwp=a1#=_`nql}^ zAHxG+jPF|$`fiGM2Of?6IQENh3hA-p14uJa}bdB zSB*Pwui(`0!>RUgrZt>tW>@g;Rk62uk_>|B7vQGQF}MpLbi?g~ya<#jZ$S@-yaC_` z9`apqq4E~^{uzXPD*yt{Ied-ijiK}NYVyL_xuk6-ZBkDHf08U}z$QGe>eVz)s8>!D zh$hKiL31KiTGHs6R<00R5tnstECm`%x=jwkZ77|{Is^|0WNgoJY@~U7m1h2~7T$Fy z_;_sUG2XR;-(MB`+Tw6a99|YjALG&giO&=eeEazPml!O;w}}Qsaw{>xHE;L@X)$1L zk;0D~M`^H4iZAjDd^zS@=*$a&a=f$hCD0~(xifcR$Cqh3zBIPC<$Ft_Hccir6wcQ| zgF;>UK({{4=NjQ@TF;byjabgKUD%c6B)gi@E# zoNxpPhD#epuaI4@LW?3aPaP3@PR8pwZk0=RX)-MOUQx?<<&2d@XY`fF*d10joz$xj zxt$G4C+ouO1BggnrcI6IgPR!?9~zhn{0|~Y-yp_RkNEEzrc%?@DKZ6zXdkxDz+;2w zIPPx&ajB;$zK&AsDEW;3eXx!WucNpA;1lb3|1&(j8REIUo6#OFu{p$~0dDU`2I1(9 T#;^SD->~rcaX=Qo#@_fZtKv<* literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab2009334ac147b34eee6d8cbe17fc3ed835b16a GIT binary patch literal 6469 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d54b579bea9c65cd66ec1bf854dcdaeefc600f7b GIT binary patch literal 3792 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41d5cfc7a39239fc7c7556171f60a3899d2ab383 GIT binary patch literal 4352 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 Pn(w`P?n@3{Y#sjx$hZHp literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7170603b92a68946e5296e5b6651d86d7060899b GIT binary patch literal 5266 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90fe109b27fedcf2135942d5b98477840e7aa0fe GIT binary patch literal 1679 zcmaJ>TW{k;6rPD4$8qAuNkg~WmfdVqSj;6sqClxw#1g8#6e2|T1ve;i?IAVz62{Ih ziCig2NPx8Ot@s6?A|Cc{@P_(eEJa#`R){xCU0(Ky8RyajC=+G;opZi9o;l|m|163E zAfx=#hsL)_0Dh;&crZf%PahC)2y~!B6If7zkm7`yuo#80ScQ#k#!OnA!o`?1Qx>oA z5FiF$BHW~zwgg3pV;qTPluV3MX4VoFF~+<(XXTV!jMJuM<&``H>6xFNowfhV(nUS< zRZ=N*1$pjIdH@-Q8P&EOPxTDPcI8AU-udW*t!C}!R&D!M{YEI%9MeP^jS}vBP1W{M z&9Ob~nAdf+?IBFu>30pyi$lcVG5WlNT+gL}cT^XR1G(wNX1q|O@tdfF4c9X?vOw5D z*icQQhj3lvhb4|@ib=`g>30Mi0w4AT502xw%kx~Cr1j? z`{T2Qk~XX&DMV862u_8P9?p_kgktG1BaXdCTnlf-lfSL0oc zPFuZ))pi@gyBe^3Z1s*_KVi!c zGr9iuDM=6HRQ*n!4!MBoOP@$%(N=ayC5hPaQ^ehqCi*S;rMhFIxVRy^=Qw6u;$Hqt zuwx3XdapR6>~VS!t#`R_7!J00n_j8|1c-l$Hf`STs=4E*`>?U9Z+@s0PqsUi*zObrse1z z6TOA65|e&O+(R-&421A69>DS+;KfJa?EzT-jgbcI+9P&jz}5!r^#OY=62Rqhu(%Se zJr_LteDLZU!E2kr%j;480+a$_DPqX;VP-i>l4rz$!a|gyhzI%AC{2+7q_rqRQ5IZy dB@!u`1I6_yN09^;D{-!<0Jw$6^TZc#{BOLS(lG!4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py new file mode 100644 index 0000000..2c84208 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import logging +from argparse import ArgumentParser +from typing import TYPE_CHECKING + +from pip._vendor import requests + +from pip._vendor.cachecontrol.adapter import CacheControlAdapter +from pip._vendor.cachecontrol.cache import DictCache +from pip._vendor.cachecontrol.controller import logger + +if TYPE_CHECKING: + from argparse import Namespace + + from pip._vendor.cachecontrol.controller import CacheController + + +def setup_logging() -> None: + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + logger.addHandler(handler) + + +def get_session() -> requests.Session: + adapter = CacheControlAdapter( + DictCache(), cache_etags=True, serializer=None, heuristic=None + ) + sess = requests.Session() + sess.mount("http://", adapter) + sess.mount("https://", adapter) + + sess.cache_controller = adapter.controller # type: ignore[attr-defined] + return sess + + +def get_args() -> Namespace: + parser = ArgumentParser() + parser.add_argument("url", help="The URL to try and cache") + return parser.parse_args() + + +def main() -> None: + args = get_args() + sess = get_session() + + # Make a request to get a response + resp = sess.get(args.url) + + # Turn on logging + setup_logging() + + # try setting the cache + cache_controller: CacheController = ( + sess.cache_controller # type: ignore[attr-defined] + ) + cache_controller.cache_response(resp.request, resp.raw) + + # Now try to get it + if cache_controller.cached_request(resp.request): + print("Cached!") + else: + print("Not cached :(") + + +if __name__ == "__main__": + main() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py new file mode 100644 index 0000000..34a9eb8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import functools +import types +import zlib +from typing import TYPE_CHECKING, Any, Collection, Mapping + +from pip._vendor.requests.adapters import HTTPAdapter + +from pip._vendor.cachecontrol.cache import DictCache +from pip._vendor.cachecontrol.controller import PERMANENT_REDIRECT_STATUSES, CacheController +from pip._vendor.cachecontrol.filewrapper import CallbackFileWrapper + +if TYPE_CHECKING: + from pip._vendor.requests import PreparedRequest, Response + from pip._vendor.urllib3 import HTTPResponse + + from pip._vendor.cachecontrol.cache import BaseCache + from pip._vendor.cachecontrol.heuristics import BaseHeuristic + from pip._vendor.cachecontrol.serialize import Serializer + + +class CacheControlAdapter(HTTPAdapter): + invalidating_methods = {"PUT", "PATCH", "DELETE"} + + def __init__( + self, + cache: BaseCache | None = None, + cache_etags: bool = True, + controller_class: type[CacheController] | None = None, + serializer: Serializer | None = None, + heuristic: BaseHeuristic | None = None, + cacheable_methods: Collection[str] | None = None, + *args: Any, + **kw: Any, + ) -> None: + super().__init__(*args, **kw) + self.cache = DictCache() if cache is None else cache + self.heuristic = heuristic + self.cacheable_methods = cacheable_methods or ("GET",) + + controller_factory = controller_class or CacheController + self.controller = controller_factory( + self.cache, cache_etags=cache_etags, serializer=serializer + ) + + def send( + self, + request: PreparedRequest, + stream: bool = False, + timeout: None | float | tuple[float, float] | tuple[float, None] = None, + verify: bool | str = True, + cert: (None | bytes | str | tuple[bytes | str, bytes | str]) = None, + proxies: Mapping[str, str] | None = None, + cacheable_methods: Collection[str] | None = None, + ) -> Response: + """ + Send a request. Use the request information to see if it + exists in the cache and cache the response if we need to and can. + """ + cacheable = cacheable_methods or self.cacheable_methods + if request.method in cacheable: + try: + cached_response = self.controller.cached_request(request) + except zlib.error: + cached_response = None + if cached_response: + return self.build_response(request, cached_response, from_cache=True) + + # check for etags and add headers if appropriate + request.headers.update(self.controller.conditional_headers(request)) + + resp = super().send(request, stream, timeout, verify, cert, proxies) + + return resp + + def build_response( # type: ignore[override] + self, + request: PreparedRequest, + response: HTTPResponse, + from_cache: bool = False, + cacheable_methods: Collection[str] | None = None, + ) -> Response: + """ + Build a response by making a request or using the cache. + + This will end up calling send and returning a potentially + cached response + """ + cacheable = cacheable_methods or self.cacheable_methods + if not from_cache and request.method in cacheable: + # Check for any heuristics that might update headers + # before trying to cache. + if self.heuristic: + response = self.heuristic.apply(response) + + # apply any expiration heuristics + if response.status == 304: + # We must have sent an ETag request. This could mean + # that we've been expired already or that we simply + # have an etag. In either case, we want to try and + # update the cache if that is the case. + cached_response = self.controller.update_cached_response( + request, response + ) + + if cached_response is not response: + from_cache = True + + # We are done with the server response, read a + # possible response body (compliant servers will + # not return one, but we cannot be 100% sure) and + # release the connection back to the pool. + response.read(decode_content=False) + response.release_conn() + + response = cached_response + + # We always cache the 301 responses + elif int(response.status) in PERMANENT_REDIRECT_STATUSES: + self.controller.cache_response(request, response) + else: + # Wrap the response file with a wrapper that will cache the + # response when the stream has been consumed. + response._fp = CallbackFileWrapper( # type: ignore[assignment] + response._fp, # type: ignore[arg-type] + functools.partial( + self.controller.cache_response, request, response + ), + ) + if response.chunked: + super_update_chunk_length = response._update_chunk_length + + def _update_chunk_length(self: HTTPResponse) -> None: + super_update_chunk_length() + if self.chunk_left == 0: + self._fp._close() # type: ignore[union-attr] + + response._update_chunk_length = types.MethodType( # type: ignore[method-assign] + _update_chunk_length, response + ) + + resp: Response = super().build_response(request, response) + + # See if we should invalidate the cache. + if request.method in self.invalidating_methods and resp.ok: + assert request.url is not None + cache_url = self.controller.cache_url(request.url) + self.cache.delete(cache_url) + + # Give the request a from_cache attr to let people use it + resp.from_cache = from_cache # type: ignore[attr-defined] + + return resp + + def close(self) -> None: + self.cache.close() + super().close() # type: ignore[no-untyped-call] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py new file mode 100644 index 0000000..91598e9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py @@ -0,0 +1,75 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +""" +The cache object API for implementing caches. The default is a thread +safe in-memory dictionary. +""" + +from __future__ import annotations + +from threading import Lock +from typing import IO, TYPE_CHECKING, MutableMapping + +if TYPE_CHECKING: + from datetime import datetime + + +class BaseCache: + def get(self, key: str) -> bytes | None: + raise NotImplementedError() + + def set( + self, key: str, value: bytes, expires: int | datetime | None = None + ) -> None: + raise NotImplementedError() + + def delete(self, key: str) -> None: + raise NotImplementedError() + + def close(self) -> None: + pass + + +class DictCache(BaseCache): + def __init__(self, init_dict: MutableMapping[str, bytes] | None = None) -> None: + self.lock = Lock() + self.data = init_dict or {} + + def get(self, key: str) -> bytes | None: + return self.data.get(key, None) + + def set( + self, key: str, value: bytes, expires: int | datetime | None = None + ) -> None: + with self.lock: + self.data.update({key: value}) + + def delete(self, key: str) -> None: + with self.lock: + if key in self.data: + self.data.pop(key) + + +class SeparateBodyBaseCache(BaseCache): + """ + In this variant, the body is not stored mixed in with the metadata, but is + passed in (as a bytes-like object) in a separate call to ``set_body()``. + + That is, the expected interaction pattern is:: + + cache.set(key, serialized_metadata) + cache.set_body(key) + + Similarly, the body should be loaded separately via ``get_body()``. + """ + + def set_body(self, key: str, body: bytes) -> None: + raise NotImplementedError() + + def get_body(self, key: str) -> IO[bytes] | None: + """ + Return the body as file-like object. + """ + raise NotImplementedError() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py new file mode 100644 index 0000000..24ff469 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +from pip._vendor.cachecontrol.caches.file_cache import FileCache, SeparateBodyFileCache +from pip._vendor.cachecontrol.caches.redis_cache import RedisCache + +__all__ = ["FileCache", "SeparateBodyFileCache", "RedisCache"] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a32bc6709a5f7024a6f9f5d6d1580a9ae89012ca GIT binary patch literal 440 zcmah`Jx{|h5Vez(LPRITFJK`ck{zKAt;B>F%7P+GmK&R3VaJgZiZb#m*x6Y4Bm4tP zEHJSlbwFa`+?J1x8=mf+{q8;Ko(6*$LG3(FWQGxX_2j#PRWsj(<_>Yhu|gW>SOL_EC5d9RC--kX;tf!jEiN{m@?Dcts%sF`K07#ZIEj1%nQiQuwXd`dza zg3v}DdH|=%n%k>oozj`8xUp&BcNL~;tx-$Tq!-{p7Z1N`xBs8Yde@cATe&`^Oesnq z&>SfGG~+{3TT@!5wX8~VV@zSR7Pb&nR*>lr*vx2Q^GtDH;MP zvQ_r%Z}uf=G776?OKDnnZv99beyzmNZh}8t0ySFz?;*zcBS!cfKcmr0JiP5&f3Po` CMuR5+ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a43974f1f4b08f32c3a5a4d17b4683ee98ae7d9e GIT binary patch literal 7749 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iYZs90Rm|UK| z8|_~Z5v5CiQ>ySnxZ?q=S>SS@y!%(tibP^N9|0b>_rqF+J3f!K!&-$q9$Of%A9cJ& zJ^?5eZi^hygm^qN4-uI8cOc0`h~@HP5VE{dQt;e{)uWC$VwzdkZG{Y+%^7o4eS z*4sl^d1H{PsuNUIsOzU-hpsvyRsHFdmaVq4N`wR>>rs>)BEHtIcuxB6x&T~-aXv|U zWj*4Tx+?ADE$$Ro5k#qH4aQ^l=XbmJ7ml*~7lH7)1nujgu=M;!w@>PDr+^=xhX2}C z4N`6$>zU>qyDsWH?4rejkdT}J);MevT}(6RJxet`gC~z#w!T3;1UqQGpkyq?f{hpM zvGYm}j(2EbpJJH`Y@8HpDr0LSS%dAjvl<<9_mR3elh2x(Zn?nTR4$6}X$*oe!k-R7 z_2WLQFrZ|1V8`JuAYZR6ES#|y_i$j!!ai1;-GD3kH7Hq_NFm;#WC$&Wmd})X@5{TG z8Iw1~27j;np+w(LZ*8W>V9T@L0BB5S;4tLb zi>WDA^}tve1&7$Dz#>nj;iQd?HEC!Us_PAh2XL15ti{CXJ$*56RjU!V+L_}w?Eq@k z2|MLP2VvKf86qJhA4>!1mGlUxBm_6g(c9e&A=F*N%?#jam>Jx}AVWQ_V((&i<4JkV zhyz~xb?9Zi3Zywf%-oIc!OC5L%Dt_#ESB}vw!W26-=hanWmA!kPVnoNUh+|3K=>^; zAZ(q5-v+I3Y&AG$+OilInu~D=6`F-{>03aWQYNGuFdQa@<~qocp~`-yUA*>x!oIyg zwz5mT8sB|iex7;#)`5?B{PbBj20qNV>N(J*c0tu#^B4vWLXzsx>Q380ZWKr(Hn6ZQ z?%aCSU68<&4R%7>1QPe;U3JL#)_u9xg$%IkQG5?3T9(?1u@l4Zu`KE3Xvl+g6%+NE z^B^4uS;D_1$mCFc63JF@Gl30A{sI0iERU*ivmTVBuJs5nDH}2`^|`=S3A?@Im-!C%^_(r)ZV|KtgZ?;GF=zkTo&W zTTQ_q0}a(SRn$>&(?O?UsNccA)dysrYy?TmbDstK?gsm=53L6G&JV4%v@gBB_E4C}(uW^@XQI4Er>ekgqj z2|ERnZDZD+q1vQ-_UVH<5I~t?sZD)A96x?PoVrmzK6S%^>p=AQ5Z*1C_B~ z05$ubu37tSkXe|vV4r>@h-6ejf`RYOgLxpDZ&N08c_B}cWtr)u&rcS7oIqv^t z!u9=uME;8e9+DmZO?E#dUH?l?J|u7aUWh#ud;Ul4U-#|dB43~8hB>a|PXy_P&ilFU f<>>Y88w8k*_BO7sJiM}haDxE1vCqf3`St$+t6OUP literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b61777ee617bc452c1a18fbb263cd15a855c098 GIT binary patch literal 2738 zcmbVO-ES0C6uCSDLWp-x0GYjmx zC4J~an`jEYbbS&N5+yapNB;+3XlkXIK!Pzo_*SwI6Q4Zi&My4`AMj3c?$^2Zobx*$ zcYaBwS_rh>A1^q0g^)jR(rhrtCe%L#I!|n33oa=LSwXRa~u*%q9gQk|AQN)5K2D#Dc`HC)t*=mP!7FlZ+5;u{_TYt0vxKH0`=u=0{R5> zT3O0$jas-sEa!(imZRMQrd0?p=Poo^{4X11F?Mi?C`< z&|tLa6#GrsvwhZ|Lx4bB$b2`R1pN%LGWkwlu^ee8TpES5xdYaM9Y8?M*7mvbYk(>;)*%C0| zI)4QkfX-5|_f_<+iVF?53#3fKM&1y(CsdmvnjGx&5T)^!*P5fXKIHj`^E_g(sWlOr zl&ex60ol~1wpZmm+PA6MzS~(giaD?87B*zP*R0vhZH3Q5CJIJU!ycn7oDc3BwM56?~QFIs$q6FM&!flaa zQ#Z5%^r^vH9D?02-w=Wz1_cLmK&HqOm9%xO=xuYuv%_=eX3y1nYo%p9{V>&4OWf`L zHFfx5=e~LOwtIKryOZCZTUrnqOUwG;GfWfP%+ziq8$>qHe{!ou!TAZFIFba#?T5%G{7yD&W7BXUG_zZQ6 zlo{hbGjcAq7*uJ)a$O_5LJcfbhT|EQ0Z*7U2Jcg!aVen2btk;i5{HjrKXv=mZ|%J^gN-nGpzm4K z_tY*f>pf2-(sA%bP|;2fDxy0d8~834Wt0LM82C)l9BOM6ecuIBj~JeBc$C^k=!5+} z7>9c$yhn0!R1J0 zG%PVMl1K1&K#sFk3PQ$?!0C$4*^H`z+i_fKoQI(VW&nv4&ck|;e+Se9;BNkDG!Nok z>?n|ig!uH@s>r3q97%jQJ*z-XGiou-f^U~x9P6g}S;=za9oB|7Vr^wuGGZ^I^B6jh z9Y%t+J5CjR2N)7O6$}BHCUsFzcGguvIk2jcGs0P6RnnC=R@yt`e*eL^?|+~7kCUmo z0{itng0io!%F2PKx~QaL8F=$ZW(#UNUIH{hTZZMDm(jR_s$sbZZf02TqJ8iq(bxEq z=v)6I5l2}YkvYZQ1{Ms7;58ttk{}4rG$Qo=trFqTBVznX X-uzu^dnE6Esv1J-*3M@HI IO[bytes]: + # We only want to write to this file, so open it in write only mode + flags = os.O_WRONLY + + # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only + # will open *new* files. + # We specify this because we want to ensure that the mode we pass is the + # mode of the file. + flags |= os.O_CREAT | os.O_EXCL + + # Do not follow symlinks to prevent someone from making a symlink that + # we follow and insecurely open a cache file. + if hasattr(os, "O_NOFOLLOW"): + flags |= os.O_NOFOLLOW + + # On Windows we'll mark this file as binary + if hasattr(os, "O_BINARY"): + flags |= os.O_BINARY + + # Before we open our file, we want to delete any existing file that is + # there + try: + os.remove(filename) + except OSError: + # The file must not exist already, so we can just skip ahead to opening + pass + + # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a + # race condition happens between the os.remove and this line, that an + # error will be raised. Because we utilize a lockfile this should only + # happen if someone is attempting to attack us. + fd = os.open(filename, flags, fmode) + try: + return os.fdopen(fd, "wb") + + except: + # An error occurred wrapping our FD in a file object + os.close(fd) + raise + + +class _FileCacheMixin: + """Shared implementation for both FileCache variants.""" + + def __init__( + self, + directory: str | Path, + forever: bool = False, + filemode: int = 0o0600, + dirmode: int = 0o0700, + lock_class: type[BaseFileLock] | None = None, + ) -> None: + try: + if lock_class is None: + from filelock import FileLock + + lock_class = FileLock + except ImportError: + notice = dedent( + """ + NOTE: In order to use the FileCache you must have + filelock installed. You can install it via pip: + pip install cachecontrol[filecache] + """ + ) + raise ImportError(notice) + + self.directory = directory + self.forever = forever + self.filemode = filemode + self.dirmode = dirmode + self.lock_class = lock_class + + @staticmethod + def encode(x: str) -> str: + return hashlib.sha224(x.encode()).hexdigest() + + def _fn(self, name: str) -> str: + # NOTE: This method should not change as some may depend on it. + # See: https://github.com/ionrock/cachecontrol/issues/63 + hashed = self.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key: str) -> bytes | None: + name = self._fn(key) + try: + with open(name, "rb") as fh: + return fh.read() + + except FileNotFoundError: + return None + + def set( + self, key: str, value: bytes, expires: int | datetime | None = None + ) -> None: + name = self._fn(key) + self._write(name, value) + + def _write(self, path: str, data: bytes) -> None: + """ + Safely write the data to the given path. + """ + # Make sure the directory exists + try: + os.makedirs(os.path.dirname(path), self.dirmode) + except OSError: + pass + + with self.lock_class(path + ".lock"): + # Write our actual file + with _secure_open_write(path, self.filemode) as fh: + fh.write(data) + + def _delete(self, key: str, suffix: str) -> None: + name = self._fn(key) + suffix + if not self.forever: + try: + os.remove(name) + except FileNotFoundError: + pass + + +class FileCache(_FileCacheMixin, BaseCache): + """ + Traditional FileCache: body is stored in memory, so not suitable for large + downloads. + """ + + def delete(self, key: str) -> None: + self._delete(key, "") + + +class SeparateBodyFileCache(_FileCacheMixin, SeparateBodyBaseCache): + """ + Memory-efficient FileCache: body is stored in a separate file, reducing + peak memory usage. + """ + + def get_body(self, key: str) -> IO[bytes] | None: + name = self._fn(key) + ".body" + try: + return open(name, "rb") + except FileNotFoundError: + return None + + def set_body(self, key: str, body: bytes) -> None: + name = self._fn(key) + ".body" + self._write(name, body) + + def delete(self, key: str) -> None: + self._delete(key, "") + self._delete(key, ".body") + + +def url_to_file_path(url: str, filecache: FileCache) -> str: + """Return the file cache path based on the URL. + + This does not ensure the file exists! + """ + key = CacheController.cache_url(url) + return filecache._fn(key) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py new file mode 100644 index 0000000..f4f68c4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + + +from datetime import datetime, timezone +from typing import TYPE_CHECKING + +from pip._vendor.cachecontrol.cache import BaseCache + +if TYPE_CHECKING: + from redis import Redis + + +class RedisCache(BaseCache): + def __init__(self, conn: Redis[bytes]) -> None: + self.conn = conn + + def get(self, key: str) -> bytes | None: + return self.conn.get(key) + + def set( + self, key: str, value: bytes, expires: int | datetime | None = None + ) -> None: + if not expires: + self.conn.set(key, value) + elif isinstance(expires, datetime): + now_utc = datetime.now(timezone.utc) + if expires.tzinfo is None: + now_utc = now_utc.replace(tzinfo=None) + delta = expires - now_utc + self.conn.setex(key, int(delta.total_seconds()), value) + else: + self.conn.setex(key, expires, value) + + def delete(self, key: str) -> None: + self.conn.delete(key) + + def clear(self) -> None: + """Helper for clearing all the keys in a database. Use with + caution!""" + for key in self.conn.keys(): + self.conn.delete(key) + + def close(self) -> None: + """Redis uses connection pooling, no need to close the connection.""" + pass diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py new file mode 100644 index 0000000..f0ff6e1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py @@ -0,0 +1,500 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +""" +The httplib2 algorithms ported for use with requests. +""" + +from __future__ import annotations + +import calendar +import logging +import re +import time +from email.utils import parsedate_tz +from typing import TYPE_CHECKING, Collection, Mapping + +from pip._vendor.requests.structures import CaseInsensitiveDict + +from pip._vendor.cachecontrol.cache import DictCache, SeparateBodyBaseCache +from pip._vendor.cachecontrol.serialize import Serializer + +if TYPE_CHECKING: + from typing import Literal + + from pip._vendor.requests import PreparedRequest + from pip._vendor.urllib3 import HTTPResponse + + from pip._vendor.cachecontrol.cache import BaseCache + +logger = logging.getLogger(__name__) + +URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") + +PERMANENT_REDIRECT_STATUSES = (301, 308) + + +def parse_uri(uri: str) -> tuple[str, str, str, str, str]: + """Parses a URI using the regex given in Appendix B of RFC 3986. + + (scheme, authority, path, query, fragment) = parse_uri(uri) + """ + match = URI.match(uri) + assert match is not None + groups = match.groups() + return (groups[1], groups[3], groups[4], groups[6], groups[8]) + + +class CacheController: + """An interface to see if request should cached or not.""" + + def __init__( + self, + cache: BaseCache | None = None, + cache_etags: bool = True, + serializer: Serializer | None = None, + status_codes: Collection[int] | None = None, + ): + self.cache = DictCache() if cache is None else cache + self.cache_etags = cache_etags + self.serializer = serializer or Serializer() + self.cacheable_status_codes = status_codes or (200, 203, 300, 301, 308) + + @classmethod + def _urlnorm(cls, uri: str) -> str: + """Normalize the URL to create a safe key for the cache""" + (scheme, authority, path, query, fragment) = parse_uri(uri) + if not scheme or not authority: + raise Exception("Only absolute URIs are allowed. uri = %s" % uri) + + scheme = scheme.lower() + authority = authority.lower() + + if not path: + path = "/" + + # Could do syntax based normalization of the URI before + # computing the digest. See Section 6.2.2 of Std 66. + request_uri = query and "?".join([path, query]) or path + defrag_uri = scheme + "://" + authority + request_uri + + return defrag_uri + + @classmethod + def cache_url(cls, uri: str) -> str: + return cls._urlnorm(uri) + + def parse_cache_control(self, headers: Mapping[str, str]) -> dict[str, int | None]: + known_directives = { + # https://tools.ietf.org/html/rfc7234#section-5.2 + "max-age": (int, True), + "max-stale": (int, False), + "min-fresh": (int, True), + "no-cache": (None, False), + "no-store": (None, False), + "no-transform": (None, False), + "only-if-cached": (None, False), + "must-revalidate": (None, False), + "public": (None, False), + "private": (None, False), + "proxy-revalidate": (None, False), + "s-maxage": (int, True), + } + + cc_headers = headers.get("cache-control", headers.get("Cache-Control", "")) + + retval: dict[str, int | None] = {} + + for cc_directive in cc_headers.split(","): + if not cc_directive.strip(): + continue + + parts = cc_directive.split("=", 1) + directive = parts[0].strip() + + try: + typ, required = known_directives[directive] + except KeyError: + logger.debug("Ignoring unknown cache-control directive: %s", directive) + continue + + if not typ or not required: + retval[directive] = None + if typ: + try: + retval[directive] = typ(parts[1].strip()) + except IndexError: + if required: + logger.debug( + "Missing value for cache-control " "directive: %s", + directive, + ) + except ValueError: + logger.debug( + "Invalid value for cache-control directive " "%s, must be %s", + directive, + typ.__name__, + ) + + return retval + + def _load_from_cache(self, request: PreparedRequest) -> HTTPResponse | None: + """ + Load a cached response, or return None if it's not available. + """ + # We do not support caching of partial content: so if the request contains a + # Range header then we don't want to load anything from the cache. + if "Range" in request.headers: + return None + + cache_url = request.url + assert cache_url is not None + cache_data = self.cache.get(cache_url) + if cache_data is None: + logger.debug("No cache entry available") + return None + + if isinstance(self.cache, SeparateBodyBaseCache): + body_file = self.cache.get_body(cache_url) + else: + body_file = None + + result = self.serializer.loads(request, cache_data, body_file) + if result is None: + logger.warning("Cache entry deserialization failed, entry ignored") + return result + + def cached_request(self, request: PreparedRequest) -> HTTPResponse | Literal[False]: + """ + Return a cached response if it exists in the cache, otherwise + return False. + """ + assert request.url is not None + cache_url = self.cache_url(request.url) + logger.debug('Looking up "%s" in the cache', cache_url) + cc = self.parse_cache_control(request.headers) + + # Bail out if the request insists on fresh data + if "no-cache" in cc: + logger.debug('Request header has "no-cache", cache bypassed') + return False + + if "max-age" in cc and cc["max-age"] == 0: + logger.debug('Request header has "max_age" as 0, cache bypassed') + return False + + # Check whether we can load the response from the cache: + resp = self._load_from_cache(request) + if not resp: + return False + + # If we have a cached permanent redirect, return it immediately. We + # don't need to test our response for other headers b/c it is + # intrinsically "cacheable" as it is Permanent. + # + # See: + # https://tools.ietf.org/html/rfc7231#section-6.4.2 + # + # Client can try to refresh the value by repeating the request + # with cache busting headers as usual (ie no-cache). + if int(resp.status) in PERMANENT_REDIRECT_STATUSES: + msg = ( + "Returning cached permanent redirect response " + "(ignoring date and etag information)" + ) + logger.debug(msg) + return resp + + headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(resp.headers) + if not headers or "date" not in headers: + if "etag" not in headers: + # Without date or etag, the cached response can never be used + # and should be deleted. + logger.debug("Purging cached response: no date or etag") + self.cache.delete(cache_url) + logger.debug("Ignoring cached response: no date") + return False + + now = time.time() + time_tuple = parsedate_tz(headers["date"]) + assert time_tuple is not None + date = calendar.timegm(time_tuple[:6]) + current_age = max(0, now - date) + logger.debug("Current age based on date: %i", current_age) + + # TODO: There is an assumption that the result will be a + # urllib3 response object. This may not be best since we + # could probably avoid instantiating or constructing the + # response until we know we need it. + resp_cc = self.parse_cache_control(headers) + + # determine freshness + freshness_lifetime = 0 + + # Check the max-age pragma in the cache control header + max_age = resp_cc.get("max-age") + if max_age is not None: + freshness_lifetime = max_age + logger.debug("Freshness lifetime from max-age: %i", freshness_lifetime) + + # If there isn't a max-age, check for an expires header + elif "expires" in headers: + expires = parsedate_tz(headers["expires"]) + if expires is not None: + expire_time = calendar.timegm(expires[:6]) - date + freshness_lifetime = max(0, expire_time) + logger.debug("Freshness lifetime from expires: %i", freshness_lifetime) + + # Determine if we are setting freshness limit in the + # request. Note, this overrides what was in the response. + max_age = cc.get("max-age") + if max_age is not None: + freshness_lifetime = max_age + logger.debug( + "Freshness lifetime from request max-age: %i", freshness_lifetime + ) + + min_fresh = cc.get("min-fresh") + if min_fresh is not None: + # adjust our current age by our min fresh + current_age += min_fresh + logger.debug("Adjusted current age from min-fresh: %i", current_age) + + # Return entry if it is fresh enough + if freshness_lifetime > current_age: + logger.debug('The response is "fresh", returning cached response') + logger.debug("%i > %i", freshness_lifetime, current_age) + return resp + + # we're not fresh. If we don't have an Etag, clear it out + if "etag" not in headers: + logger.debug('The cached response is "stale" with no etag, purging') + self.cache.delete(cache_url) + + # return the original handler + return False + + def conditional_headers(self, request: PreparedRequest) -> dict[str, str]: + resp = self._load_from_cache(request) + new_headers = {} + + if resp: + headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(resp.headers) + + if "etag" in headers: + new_headers["If-None-Match"] = headers["ETag"] + + if "last-modified" in headers: + new_headers["If-Modified-Since"] = headers["Last-Modified"] + + return new_headers + + def _cache_set( + self, + cache_url: str, + request: PreparedRequest, + response: HTTPResponse, + body: bytes | None = None, + expires_time: int | None = None, + ) -> None: + """ + Store the data in the cache. + """ + if isinstance(self.cache, SeparateBodyBaseCache): + # We pass in the body separately; just put a placeholder empty + # string in the metadata. + self.cache.set( + cache_url, + self.serializer.dumps(request, response, b""), + expires=expires_time, + ) + # body is None can happen when, for example, we're only updating + # headers, as is the case in update_cached_response(). + if body is not None: + self.cache.set_body(cache_url, body) + else: + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body), + expires=expires_time, + ) + + def cache_response( + self, + request: PreparedRequest, + response: HTTPResponse, + body: bytes | None = None, + status_codes: Collection[int] | None = None, + ) -> None: + """ + Algorithm for caching requests. + + This assumes a requests Response object. + """ + # From httplib2: Don't cache 206's since we aren't going to + # handle byte range requests + cacheable_status_codes = status_codes or self.cacheable_status_codes + if response.status not in cacheable_status_codes: + logger.debug( + "Status code %s not in %s", response.status, cacheable_status_codes + ) + return + + response_headers: CaseInsensitiveDict[str] = CaseInsensitiveDict( + response.headers + ) + + if "date" in response_headers: + time_tuple = parsedate_tz(response_headers["date"]) + assert time_tuple is not None + date = calendar.timegm(time_tuple[:6]) + else: + date = 0 + + # If we've been given a body, our response has a Content-Length, that + # Content-Length is valid then we can check to see if the body we've + # been given matches the expected size, and if it doesn't we'll just + # skip trying to cache it. + if ( + body is not None + and "content-length" in response_headers + and response_headers["content-length"].isdigit() + and int(response_headers["content-length"]) != len(body) + ): + return + + cc_req = self.parse_cache_control(request.headers) + cc = self.parse_cache_control(response_headers) + + assert request.url is not None + cache_url = self.cache_url(request.url) + logger.debug('Updating cache with response from "%s"', cache_url) + + # Delete it from the cache if we happen to have it stored there + no_store = False + if "no-store" in cc: + no_store = True + logger.debug('Response header has "no-store"') + if "no-store" in cc_req: + no_store = True + logger.debug('Request header has "no-store"') + if no_store and self.cache.get(cache_url): + logger.debug('Purging existing cache entry to honor "no-store"') + self.cache.delete(cache_url) + if no_store: + return + + # https://tools.ietf.org/html/rfc7234#section-4.1: + # A Vary header field-value of "*" always fails to match. + # Storing such a response leads to a deserialization warning + # during cache lookup and is not allowed to ever be served, + # so storing it can be avoided. + if "*" in response_headers.get("vary", ""): + logger.debug('Response header has "Vary: *"') + return + + # If we've been given an etag, then keep the response + if self.cache_etags and "etag" in response_headers: + expires_time = 0 + if response_headers.get("expires"): + expires = parsedate_tz(response_headers["expires"]) + if expires is not None: + expires_time = calendar.timegm(expires[:6]) - date + + expires_time = max(expires_time, 14 * 86400) + + logger.debug(f"etag object cached for {expires_time} seconds") + logger.debug("Caching due to etag") + self._cache_set(cache_url, request, response, body, expires_time) + + # Add to the cache any permanent redirects. We do this before looking + # that the Date headers. + elif int(response.status) in PERMANENT_REDIRECT_STATUSES: + logger.debug("Caching permanent redirect") + self._cache_set(cache_url, request, response, b"") + + # Add to the cache if the response headers demand it. If there + # is no date header then we can't do anything about expiring + # the cache. + elif "date" in response_headers: + time_tuple = parsedate_tz(response_headers["date"]) + assert time_tuple is not None + date = calendar.timegm(time_tuple[:6]) + # cache when there is a max-age > 0 + max_age = cc.get("max-age") + if max_age is not None and max_age > 0: + logger.debug("Caching b/c date exists and max-age > 0") + expires_time = max_age + self._cache_set( + cache_url, + request, + response, + body, + expires_time, + ) + + # If the request can expire, it means we should cache it + # in the meantime. + elif "expires" in response_headers: + if response_headers["expires"]: + expires = parsedate_tz(response_headers["expires"]) + if expires is not None: + expires_time = calendar.timegm(expires[:6]) - date + else: + expires_time = None + + logger.debug( + "Caching b/c of expires header. expires in {} seconds".format( + expires_time + ) + ) + self._cache_set( + cache_url, + request, + response, + body, + expires_time, + ) + + def update_cached_response( + self, request: PreparedRequest, response: HTTPResponse + ) -> HTTPResponse: + """On a 304 we will get a new set of headers that we want to + update our cached value with, assuming we have one. + + This should only ever be called when we've sent an ETag and + gotten a 304 as the response. + """ + assert request.url is not None + cache_url = self.cache_url(request.url) + cached_response = self._load_from_cache(request) + + if not cached_response: + # we didn't have a cached response + return response + + # Lets update our headers with the headers from the new request: + # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1 + # + # The server isn't supposed to send headers that would make + # the cached body invalid. But... just in case, we'll be sure + # to strip out ones we know that might be problmatic due to + # typical assumptions. + excluded_headers = ["content-length"] + + cached_response.headers.update( + { + k: v + for k, v in response.headers.items() + if k.lower() not in excluded_headers + } + ) + + # we want a 200 b/c we have content via the cache + cached_response.status = 200 + + # update our cache + self._cache_set(cache_url, request, cached_response) + + return cached_response diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py new file mode 100644 index 0000000..37d2fa5 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py @@ -0,0 +1,119 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import mmap +from tempfile import NamedTemporaryFile +from typing import TYPE_CHECKING, Any, Callable + +if TYPE_CHECKING: + from http.client import HTTPResponse + + +class CallbackFileWrapper: + """ + Small wrapper around a fp object which will tee everything read into a + buffer, and when that file is closed it will execute a callback with the + contents of that buffer. + + All attributes are proxied to the underlying file object. + + This class uses members with a double underscore (__) leading prefix so as + not to accidentally shadow an attribute. + + The data is stored in a temporary file until it is all available. As long + as the temporary files directory is disk-based (sometimes it's a + memory-backed-``tmpfs`` on Linux), data will be unloaded to disk if memory + pressure is high. For small files the disk usually won't be used at all, + it'll all be in the filesystem memory cache, so there should be no + performance impact. + """ + + def __init__( + self, fp: HTTPResponse, callback: Callable[[bytes], None] | None + ) -> None: + self.__buf = NamedTemporaryFile("rb+", delete=True) + self.__fp = fp + self.__callback = callback + + def __getattr__(self, name: str) -> Any: + # The vagaries of garbage collection means that self.__fp is + # not always set. By using __getattribute__ and the private + # name[0] allows looking up the attribute value and raising an + # AttributeError when it doesn't exist. This stop things from + # infinitely recursing calls to getattr in the case where + # self.__fp hasn't been set. + # + # [0] https://docs.python.org/2/reference/expressions.html#atom-identifiers + fp = self.__getattribute__("_CallbackFileWrapper__fp") + return getattr(fp, name) + + def __is_fp_closed(self) -> bool: + try: + return self.__fp.fp is None + + except AttributeError: + pass + + try: + closed: bool = self.__fp.closed + return closed + + except AttributeError: + pass + + # We just don't cache it then. + # TODO: Add some logging here... + return False + + def _close(self) -> None: + if self.__callback: + if self.__buf.tell() == 0: + # Empty file: + result = b"" + else: + # Return the data without actually loading it into memory, + # relying on Python's buffer API and mmap(). mmap() just gives + # a view directly into the filesystem's memory cache, so it + # doesn't result in duplicate memory use. + self.__buf.seek(0, 0) + result = memoryview( + mmap.mmap(self.__buf.fileno(), 0, access=mmap.ACCESS_READ) + ) + self.__callback(result) + + # We assign this to None here, because otherwise we can get into + # really tricky problems where the CPython interpreter dead locks + # because the callback is holding a reference to something which + # has a __del__ method. Setting this to None breaks the cycle + # and allows the garbage collector to do it's thing normally. + self.__callback = None + + # Closing the temporary file releases memory and frees disk space. + # Important when caching big files. + self.__buf.close() + + def read(self, amt: int | None = None) -> bytes: + data: bytes = self.__fp.read(amt) + if data: + # We may be dealing with b'', a sign that things are over: + # it's passed e.g. after we've already closed self.__buf. + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data + + def _safe_read(self, amt: int) -> bytes: + data: bytes = self.__fp._safe_read(amt) # type: ignore[attr-defined] + if amt == 2 and data == b"\r\n": + # urllib executes this read to toss the CRLF at the end + # of the chunk. + return data + + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py new file mode 100644 index 0000000..b778c4f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py @@ -0,0 +1,157 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import calendar +import time +from datetime import datetime, timedelta, timezone +from email.utils import formatdate, parsedate, parsedate_tz +from typing import TYPE_CHECKING, Any, Mapping + +if TYPE_CHECKING: + from pip._vendor.urllib3 import HTTPResponse + +TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" + + +def expire_after(delta: timedelta, date: datetime | None = None) -> datetime: + date = date or datetime.now(timezone.utc) + return date + delta + + +def datetime_to_header(dt: datetime) -> str: + return formatdate(calendar.timegm(dt.timetuple())) + + +class BaseHeuristic: + def warning(self, response: HTTPResponse) -> str | None: + """ + Return a valid 1xx warning header value describing the cache + adjustments. + + The response is provided too allow warnings like 113 + http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need + to explicitly say response is over 24 hours old. + """ + return '110 - "Response is Stale"' + + def update_headers(self, response: HTTPResponse) -> dict[str, str]: + """Update the response headers with any new headers. + + NOTE: This SHOULD always include some Warning header to + signify that the response was cached by the client, not + by way of the provided headers. + """ + return {} + + def apply(self, response: HTTPResponse) -> HTTPResponse: + updated_headers = self.update_headers(response) + + if updated_headers: + response.headers.update(updated_headers) + warning_header_value = self.warning(response) + if warning_header_value is not None: + response.headers.update({"Warning": warning_header_value}) + + return response + + +class OneDayCache(BaseHeuristic): + """ + Cache the response by providing an expires 1 day in the + future. + """ + + def update_headers(self, response: HTTPResponse) -> dict[str, str]: + headers = {} + + if "expires" not in response.headers: + date = parsedate(response.headers["date"]) + expires = expire_after( + timedelta(days=1), + date=datetime(*date[:6], tzinfo=timezone.utc), # type: ignore[index,misc] + ) + headers["expires"] = datetime_to_header(expires) + headers["cache-control"] = "public" + return headers + + +class ExpiresAfter(BaseHeuristic): + """ + Cache **all** requests for a defined time period. + """ + + def __init__(self, **kw: Any) -> None: + self.delta = timedelta(**kw) + + def update_headers(self, response: HTTPResponse) -> dict[str, str]: + expires = expire_after(self.delta) + return {"expires": datetime_to_header(expires), "cache-control": "public"} + + def warning(self, response: HTTPResponse) -> str | None: + tmpl = "110 - Automatically cached for %s. Response might be stale" + return tmpl % self.delta + + +class LastModified(BaseHeuristic): + """ + If there is no Expires header already, fall back on Last-Modified + using the heuristic from + http://tools.ietf.org/html/rfc7234#section-4.2.2 + to calculate a reasonable value. + + Firefox also does something like this per + https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ + http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 + Unlike mozilla we limit this to 24-hr. + """ + + cacheable_by_default_statuses = { + 200, + 203, + 204, + 206, + 300, + 301, + 404, + 405, + 410, + 414, + 501, + } + + def update_headers(self, resp: HTTPResponse) -> dict[str, str]: + headers: Mapping[str, str] = resp.headers + + if "expires" in headers: + return {} + + if "cache-control" in headers and headers["cache-control"] != "public": + return {} + + if resp.status not in self.cacheable_by_default_statuses: + return {} + + if "date" not in headers or "last-modified" not in headers: + return {} + + time_tuple = parsedate_tz(headers["date"]) + assert time_tuple is not None + date = calendar.timegm(time_tuple[:6]) + last_modified = parsedate(headers["last-modified"]) + if last_modified is None: + return {} + + now = time.time() + current_age = max(0, now - date) + delta = date - calendar.timegm(last_modified) + freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) + if freshness_lifetime <= current_age: + return {} + + expires = date + freshness_lifetime + return {"expires": time.strftime(TIME_FMT, time.gmtime(expires))} + + def warning(self, resp: HTTPResponse) -> str | None: + return None diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py new file mode 100644 index 0000000..a49487a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import io +from typing import IO, TYPE_CHECKING, Any, Mapping, cast + +from pip._vendor import msgpack +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.urllib3 import HTTPResponse + +if TYPE_CHECKING: + from pip._vendor.requests import PreparedRequest + + +class Serializer: + serde_version = "4" + + def dumps( + self, + request: PreparedRequest, + response: HTTPResponse, + body: bytes | None = None, + ) -> bytes: + response_headers: CaseInsensitiveDict[str] = CaseInsensitiveDict( + response.headers + ) + + if body is None: + # When a body isn't passed in, we'll read the response. We + # also update the response with a new file handler to be + # sure it acts as though it was never read. + body = response.read(decode_content=False) + response._fp = io.BytesIO(body) # type: ignore[assignment] + response.length_remaining = len(body) + + data = { + "response": { + "body": body, # Empty bytestring if body is stored separately + "headers": {str(k): str(v) for k, v in response.headers.items()}, + "status": response.status, + "version": response.version, + "reason": str(response.reason), + "decode_content": response.decode_content, + } + } + + # Construct our vary headers + data["vary"] = {} + if "vary" in response_headers: + varied_headers = response_headers["vary"].split(",") + for header in varied_headers: + header = str(header).strip() + header_value = request.headers.get(header, None) + if header_value is not None: + header_value = str(header_value) + data["vary"][header] = header_value + + return b",".join([f"cc={self.serde_version}".encode(), self.serialize(data)]) + + def serialize(self, data: dict[str, Any]) -> bytes: + return cast(bytes, msgpack.dumps(data, use_bin_type=True)) + + def loads( + self, + request: PreparedRequest, + data: bytes, + body_file: IO[bytes] | None = None, + ) -> HTTPResponse | None: + # Short circuit if we've been given an empty set of data + if not data: + return None + + # Previous versions of this library supported other serialization + # formats, but these have all been removed. + if not data.startswith(f"cc={self.serde_version},".encode()): + return None + + data = data[5:] + return self._loads_v4(request, data, body_file) + + def prepare_response( + self, + request: PreparedRequest, + cached: Mapping[str, Any], + body_file: IO[bytes] | None = None, + ) -> HTTPResponse | None: + """Verify our vary headers match and construct a real urllib3 + HTTPResponse object. + """ + # Special case the '*' Vary value as it means we cannot actually + # determine if the cached response is suitable for this request. + # This case is also handled in the controller code when creating + # a cache entry, but is left here for backwards compatibility. + if "*" in cached.get("vary", {}): + return None + + # Ensure that the Vary headers for the cached response match our + # request + for header, value in cached.get("vary", {}).items(): + if request.headers.get(header, None) != value: + return None + + body_raw = cached["response"].pop("body") + + headers: CaseInsensitiveDict[str] = CaseInsensitiveDict( + data=cached["response"]["headers"] + ) + if headers.get("transfer-encoding", "") == "chunked": + headers.pop("transfer-encoding") + + cached["response"]["headers"] = headers + + try: + body: IO[bytes] + if body_file is None: + body = io.BytesIO(body_raw) + else: + body = body_file + except TypeError: + # This can happen if cachecontrol serialized to v1 format (pickle) + # using Python 2. A Python 2 str(byte string) will be unpickled as + # a Python 3 str (unicode string), which will cause the above to + # fail with: + # + # TypeError: 'str' does not support the buffer interface + body = io.BytesIO(body_raw.encode("utf8")) + + # Discard any `strict` parameter serialized by older version of cachecontrol. + cached["response"].pop("strict", None) + + return HTTPResponse(body=body, preload_content=False, **cached["response"]) + + def _loads_v4( + self, + request: PreparedRequest, + data: bytes, + body_file: IO[bytes] | None = None, + ) -> HTTPResponse | None: + try: + cached = msgpack.loads(data, raw=False) + except ValueError: + return None + + return self.prepare_response(request, cached, body_file) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py new file mode 100644 index 0000000..f618bc3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +from typing import TYPE_CHECKING, Collection + +from pip._vendor.cachecontrol.adapter import CacheControlAdapter +from pip._vendor.cachecontrol.cache import DictCache + +if TYPE_CHECKING: + from pip._vendor import requests + + from pip._vendor.cachecontrol.cache import BaseCache + from pip._vendor.cachecontrol.controller import CacheController + from pip._vendor.cachecontrol.heuristics import BaseHeuristic + from pip._vendor.cachecontrol.serialize import Serializer + + +def CacheControl( + sess: requests.Session, + cache: BaseCache | None = None, + cache_etags: bool = True, + serializer: Serializer | None = None, + heuristic: BaseHeuristic | None = None, + controller_class: type[CacheController] | None = None, + adapter_class: type[CacheControlAdapter] | None = None, + cacheable_methods: Collection[str] | None = None, +) -> requests.Session: + cache = DictCache() if cache is None else cache + adapter_class = adapter_class or CacheControlAdapter + adapter = adapter_class( + cache, + cache_etags=cache_etags, + serializer=serializer, + heuristic=heuristic, + controller_class=controller_class, + cacheable_methods=cacheable_methods, + ) + sess.mount("http://", adapter) + sess.mount("https://", adapter) + + return sess diff --git a/backend/venv/Lib/site-packages/pip/_vendor/certifi/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__init__.py new file mode 100644 index 0000000..f61d77f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2024.08.30" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/certifi/__main__.py b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__main__.py new file mode 100644 index 0000000..0037634 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from pip._vendor.certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efc91d673607c914b319715368211fc47be80160 GIT binary patch literal 323 zcmYjMJxjzu5Z%p(cP5;j2sSEKDNMp?AtE-mVqqB;m)!0e7qh!z6BA;k|G>`QVB;UL zv6M6lR(8U5R?dNfuXywE=FKqAlSzO8+fQfm9OB2K_=EGC%r_x2xnn_v794H1Y?Jng8-I zqBJi{N{5irR@hn^P3a?=gB5+V;{#GzQ`lT7sSDB>!;DhGGC`$o;h?cSndR(CXilJR z$%&kiS~g;*f^J@jnpCn%V72DPCQR5yUdV)kT{e`)RX>ammEqT=IIYvQpA&lg=M=lt`jpm%iB#$iiaYIN-y5@ zPf#NMBVG)xq>h)02k|EK=0#`H-R9!J%=_N=y?O7O`P66xNUh5sAF#hF{?JLi>&(5|NcOD+_7wJf=W*jc&3V zbh~GCP?Q2_RKl2cuyo?2WFqSX(u*O@V<@O><}B|;+cYBrdI^P+Jz}8W2HLb-xee)< zs}c8gHArW13*@<&kVrLIXfjx^IxnQPIPDx*R=!6k+UlR=&do3fkwVNl%hGU1h(vHs zA)yh=)Nti;5^lxG6XhdR`F41ZZG{CZX*XAFoYEpxM*Ee~er2>DMLcF%6!r3n^wzl` z;}N|D=haO8nZ-kO{5CPh-_Yt$)IavyFI#iJJ@eZK{-r(V2sv}qoT29HyKis2d-@qQ v57GLO+nBqpncF&WFYZ~#ru$;!*~VAPe|2sD`WNfMcZII(Uwys_YpVG_?Qo=} literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e0b9d4d263561ed500c034ed4b99199bed83c2b GIT binary patch literal 3216 zcmbVOU2GHC6~1?V?6G5KlGt$!*%B*2!9YxxrY-b`ibdNXZJI=oMa6P=G|WuG7~A9C z83>`-Di5m)o=CM-$-}DRp)ZJ4#bY1)SgC!m@ve;SQVFRmt$6dwNR@c%IpZ0}$)*qO z8QpX4+`qZ^JKs5X{+>+63CQ6;U$%ccO31(PC6u9{()}4FWOvX zzpNMQuNQ~)lEvYwT2#NW-q65$iQanten*NUz8x)&f=yP&s;Od%5-VkmmXGi3I;`Q| z4!}!s97e>=;ovP3BQau5n5s2yj#wFU6#B-X;925k>La|?yQk9_v76*nyA z*(-LTz8?QgU*hrQ8@8LPI_9m4m1CB7i`Cqmcf-orHP_QC72UI)TCU<4y^6DvGjv?3 zP`9c%hvjU~%^6P3vud7Oh`+*9EbvHgAtO8!S{aH6rF#a{L*jw%Nf}%BhzV{t$&;Xm zl68`&3wePLX%{bCeE0IQc5(R^T+uY^j_qmMW75U>Z?ua)EY+E_%Jgd0uC12V9LI2~ zRf`#xX4h`R79F-;x~>~Ht(sYa_uHj;`+CW>J!_^8t@^6vmg;u>v<7{q!%hc~oi-e1 z0d8FNzt;mmGrT(tS&YR^gW4o7B(*JNn^JZ=z3n|({#-i2ke_+s6`tf3G8+yN)m?4H zu2@_~?HbV9mp)4WfTlr|Hm`YooID)mi%FkAkf4;KJv*pPA?yvUE_q>i5w9OQ<>cV3 zUj0eX)SpQ_H5^qQ32Qsn8w=~<3_9TBE99}b@FoS=76NPw0k&`AJABH=c_MW1(uL(q z4EM!`L2;$**tNRu-C%fjF1jA$G4MYSk7*i@=pMR;E6iH8U1;+?!w?hS11yHK`)dkbc3~nxgOAA{p|XqO@9a<Vw0JZ~p%{d&a|@C#!wvBW zM5Du8qwhIrj6m@@a0e=bTi#(n=*tb^QyMbid*nlDL)tGU!qJ8hTpa;-C>;7Qd7HR& zO`zl&q42DeJK{C6M)Se~`xbmZFLKGLTQ%QHT*45^%PbE)>;x)21v?3fOQ!DWF5;a- z@v}+~O9WJh;vNG94o;BavELv4_}HUMpC@OYrk|%K9-jN%xsQMJZ;=ca+R2$`$(c7U zCg4Aed`EmLpNsAvBKKg#V2G51V?lFY_JhMifPD#x{oz11-glLK!f6B3RPeM zj>*eha9lPG%k!vdvzlJD@Gi#73{tU#nL1B7U2!qn1t4M0_3^Dh#YJp^T#4ZabNA=` zBzmcpIC_tMsg6EayTA5eh3$=&da9wE`es)BUkT5?jbGn=8Td^1)vvG<-4^CB zBqsc9+?8*6D>G+#1nwH!@bVKps%fTUz!^n%-R*@vMm$g4wwMd?06!Tk4o}(Dy2HGR zeZ3F{g1d8*`S+KfPvhZJ5ipR-8D?Z2|GEFOwhTQy zy43q^;mYMO=5`;GD?jf2+nr|@U^05dje+inl+v#SnM&ORp+jGgWLKi}WJe)Vv@NEZ zVrpycnRw_c>CDTq%;tN*-_7}sG$FsW_1!K3(>X(BjcysQ3EEDCL}G1uyeW@wXP(JZ zUr9e5oR;lP1JjwM@=`EuiFOqt4}T$z{8M`C<#1~2-FEs&GkxTd(Mac;!zVW9o~!At zE88=T@ncQ(_~xa~7&(x8o;mb&EGkbuAI)||urJ3Bc4V-yg;b^!#hOA!(;XbsiIaG; UJA}22D9_;5!F1w-d+?q9AA8e None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + + +if sys.version_info >= (3, 11): + + from importlib.resources import as_file, files + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = as_file(files("pip._vendor.certifi").joinpath("cacert.pem")) + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return files("pip._vendor.certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +elif sys.version_info >= (3, 7): + + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the + # file in cases where we're inside of a zipimport situation until + # someone actually calls where(), but we don't want to re-extract + # the file on every call of where(), so we'll do it once then store + # it in a global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you + # to manage the cleanup of this file, so it doesn't actually + # return a path, it returns a context manager that will give + # you the path when you enter it and will do any cleanup when + # you leave it. In the common case of not needing a temporary + # file, it will just return the file system location and the + # __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("pip._vendor.certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii") + +else: + import os + import types + from typing import Union + + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + def contents() -> str: + return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/certifi/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/certifi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__init__.py new file mode 100644 index 0000000..bf0d6c6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2023 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import logging + +__version__ = '0.3.9' + + +class DistlibException(Exception): + pass + + +try: + from logging import NullHandler +except ImportError: # pragma: no cover + + class NullHandler(logging.Handler): + + def handle(self, record): + pass + + def emit(self, record): + pass + + def createLock(self): + self.lock = None + + +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6bb774caf933141d31301dc6c100d63ac7a916c GIT binary patch literal 1274 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c1eb817a5f1afb8fb44bab6392db76e83488dd5 GIT binary patch literal 65586 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a35c357d94e95be1b7bb393a39a54b98f8bec86b GIT binary patch literal 24321 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 z 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 LQu?o=i0yv^EKH0X literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28e0b2267fbfe834c2f3d6a3c1c8ee22523e7574 GIT binary patch literal 15081 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 fklw;if(0<=p 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Ś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 iE4ZJ&VC^>>e1lyGa4WL3e{934@mG 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 Xu4Q!DKR)P$Dum(tuO(0R)T#b2#Ap~{ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c581b1e93607177bafbda8cc238e34e1dbd2b00 GIT binary patch literal 88040 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�^uo>_(J1pUm0O0Eq81WU#M~Q&^gc;Bxz{HID zbW|UAEG$s?8jTvBk>42u<_KvAnxpz&3B!or1Kc5;3Rni%0r^yLh?I|E4wY6J(JBM* znK58`Pfz#{(DYbTM>v!J5}%oeRB3GkgF0!g@5|B**n$;>HF`c6>Io5mxv9rmA4=;% zpQQC5O?)P<9GJPQBZi;E|7JAr%Rsflp zZlSbx+W&s=M)14mrq3rzSI4Y(D_71ONL6l{%8uz{rxwa8X7sbI$$~90{R1a0PM4;j z2y0DVSKL~BYR0;fXsHkJ~a^l$OjvRa9&^<*xpE-2gHr$JpK5mhJo!*khs~XFzs7WzixmPVymUvOh zRsGe+t6s5i7mCWJyJoACxtks}UN^xerX2!M;;ApzY>vK%%|{-Ru`hcH2M@;V%8%mq zA}>wzP%V;w7}q>-R~ak+e!n)ySowLK)mZ*{0g}%OH1^zBW6I`D7`)5p3Ly_dYY+b# zEC->_$010@D&>IemJlJ{6pnya1P+{bRQCilCglZ6(Pgj-`lxmZV%0qsaTyq6hPMDr zR9G1a!Rf%5X#=`T+A#zEjQBH+nZfwoje?D*G6F_MEF|%DPVt-MUl8wRiP^G5Eg%U% zBxJB{mSrv12Fy_l>b0VEmVh}zwV)kptccjoG3_}Gm^mvq`Gg*nlmp9p&>FQa=|O`U z(}Dha96`YPL>y7Df!43kzo;1`$*QPT=+P{JY?26+fNfdZtO4^A`vm0z#7{;IA&6nn zJKC6*yDW{HosHXfaQ)t%}Yl2E6n`I&$xk~k*a3QCiSR`jhkJkiQ=9(2N+Ro8q*H^*&|j+ z&J$Ni?y^4oC#{fhsn|2BV<@c*j{gGbTKEF{z(BbCtCg^9ZRIVSzh7k*IKIm2dF&X` z3Q!7EmbD|`jyk$^5d4?`(>6;ZnZIlW7O0KE6IY-%OwCQkNFy;&tN1ZhHr*xOC2HYKU zigWW_?YB{0n9v|QqIxhbrl>J$j%I&Y@&VqV<2c^YviC+bzS77WSw!s}6(qDAl=!7GNfgAMGe#_}eJbJx%|hV!*pz%1mU&M9Eq~|O{+vaq$SV?85&Jz=%bikX_fcoAV*pXZ+Lj94~w9u z8>0SEFL?iDg@iD}d%AmqfmPmMAC^x0;6RXH2Vyn!D+oaI#2G4-&(_63j5u2nUrHiS zXeO{uAzBPm4xc5R)q3Rc(UxO-mdg^-xzFx7cKpDR_D)&Q$;1y_4V6pM2qMl=VW%Xm zWa5UjMQB8b2_DkgmnF`_E70fXf?**yw{!AoHMyI&&-(TJZqL0dbeWLtOEkPHBWuqdV9^jh0;ovXZCEO zVe5RuQ^|&>QVqM~j?YXQZzCQqme$Reu1c1!nn4@3$!*yC zA^`Q$Z0I9hTEHJ>U^1=seyLmKjTmb~G(}8l13}!hi3f>kn>>X=j2BDmq2El~6m|IW z(nco9PG^O}1kp!&!sj_6CU`!TWLUDyDsAZQfgplOw`gXit?ig|$B(wO?%{~cg8~>T zUTVQWFbqjEcZ6O)N(pgxTpcAuulih&lm##Hq6?CHr7a}Grq*+(=+a7zWG4x(xMOsU zhWDhkJzNuAXv5qI_S?xFr(Ych!5e+63s=e&N9X)B&RI5bxjtl$;V(1;-fvuUKTDJ2 zCaK2Tw($cbA+z#At(oIfR(8(+*WN)$KFT9d_FQ`yZ4 zOEZMrS1wIndNUHQoE#h9zd*w8>$TTv->r`~BwW?w2NqT|B@9jDdy!0>LK62(x860o zVyBoq`}pnrh6Q{6mG;T@`1)yW%3d|0U9j0FF21pm$<#O9DoU2`PUW^H?5)Tb^T)Ll z?a1OTi~FZ5uLa}X33u(hdsWiC3c|Gs>q1W6gz0X!bJ0~i@A4*H-sv1s0Ki0fn{QPn ztG1;IwkKTM7woxL4o@CNdmFAbyt`uhnQM)6_J##lPOS23?NsgC^|6MSO_UwrJ7YPM z;aKR6R|J{h+GJH*s$fsTwTHbDtBM(~+NbPqXHT>|$k#Ys;MrXT3;7VzrOmDdn>+T* z!a13RWenWc_T9EN#!tyV@|-@b(I*1sW$>7hRrs z-rJ6e77QZv75m@XKMkS&uXu#_x{_5}Qw7ZlSMyT!#k^--(z7n**)VzFfvMcF`utOK(sOF379Bzrt(H`x;s(Y$V0JI>86LcUj%G&9R)7JPavHgFMIUc<7=9Vv6-kQp7OW51k$HdRZ z4$r$AlI{k4_=NS-3KGXwY)V>6C#x%tw?Z?|&4xZW^YQuQsv~n%M-z@`CUlEfc?~n0Ze2RF~O3Y!243ZgO)bVYUZ}}&bZGp~KXvdgUQMSb7 zq3nK?odxC#J!(=DmOP>T_GR4#9g$d% z8hMAO7!Nwe98pI=PXeQ;ou&GyjfB*f2MwCb*YTG!K%)a&6GNnSFOZBk5DbN3)i25xXL%yGC4%RNG*3JQ=5_I1*$5g(Cx(ol5LD1~ILGXIdz z>O^;iUP3|RntRT?E78g5d%LgiySDH8!D|O+@>0&m2?NmTBkzB0@@w(%oU{tAX%Xhts)fQs z`glun-ND$Q>9X7I)t@;vWvf0jYKrRa8#NU*&>7l22}2<-%*SU*2Q5kl*MA8oV9=!{ zC@(yDk#YtIQ^80c*T_%RmbwgO<$M9Xe6IG6XvayyAifTtp`A!+KW00d1}D-sngha> z&j4FSe~5%ASZ<>s?rZpfv>5|Rw{F5d3)dm~9ATN6dj`my<7JM%w2sEN87JeKMRWG$ zQ0(xWx$0g{{)7o?Hhb>);m`G&-2AJ>Q^oI%d@nR}`1jWTe)DfPrz-X)bM{V{7Hm1= zhnM#yEd|z>r*V=Y?2rH>9tZ~n5u~YMM^qD*fTIWym3Ck8#+T zVApV%EZ)*tJ)s`3wElsvAV)$DjwHt1H<2j&A)DsB{1*2%p0A7#p_Zzl^LH-pDP~Hr$=#zbV6eWt70dodQIxBIB7hJcewdNDD;NxL@8QXA>O?bV71AxLi6{Sf6pWw@F(mGw4nz7so~bXJn0*QBvK#`k0Ox=H~Vrdy_?v(F}~w`!ddf*9^*>=3o!3izToLJ3!_BnGcA+yM2xa0|wEqK41a=krk#7Wrvy)Ol<#4P{xuS^HT4I&hkUxU zu4@RSX&Bf28KgUrCxK4>L8Ovh2;U`>?20Ty1lDR$G{BlIH?}VJ%ABow!Jf?w8w>8( zz4vf_VDdn$`;NVgK`vh&kLK-ygc#YpgXSOHCVl>4(PwMrIj| z8GwfLz`sR%fk_#8ENf)VkP(t^0He>Oki-|8m2)QaJjIgVXMUy!-iQ0|HoK3T%$($BYN98rw z`>yqUX8=Z6dt#dxJQdd+*Bsw*P8nj_*xGbu)s2>fyAIZ^o`xAno>s<;3x%bLLdY%~ zkS>%}#msT-TUno3HAM~g^_q&t`*w)+CLCWtYV$y&H5P-gxMG{M#adz)e_|=Rug9$~ zAD9d<+_7u23g)d zO_(M^XwA8WlCtYtu5Foa{mzcbgA;AB+H_gvjg1MHZ=z)pYKdo3?)r&63wfSIUQNPY zgY;f$<;1>N+Z%^JvuR3wgs{tCV@L>_k)fYtx2)Q|P4mNTC9OsJA9=KtZm_oQ)cj~? zi+ztn|A%%h(hRU638)%C@BB|g>oS7Y%I5#QL|!gAMDPqcN~5O#6Q2VR-xN@*9(1uz zO~@0K$O@n%gBoC0ls3-5zp*!WNrP}X?f{y1FTX!#8YoeJ0<-{HU9BvJDxfd#Em&S2 zSII~O7y$Q52wKji{*EZdB1H6U18fp>y(RKH;u#Q}Q4Li`O(OdUVcge2Xna6)X|D?6 zUIP3rJh#Ao4>fSViX^RVj_ABEaL>_=r;+$v3<7f>(T!QkK~Q&uBPS&WG`ZiVC%;8c zZ2kbS0S^GvCLUaIWAvCYr^fC+|G5won~;PkEPypu7Gy~8Q$~WBJmC8gogJs-4=8Cu zvYY{Nu$M`XLs*sjGh}*`fF7OvB0z7^ny&yJ;8CtRrX0WQoFrGawf8JpSF$IwV;AQv za1CIV#J}8u_3U($a4F%e77YETwD&4%u1DXE&Yb+{^uIoxa5qCfk4&$;@d`lSbldv} zZXB2iestmHg*!FP3HLTU1-{!mxi_{p7QEU!)jM5z$6f=`MS&Lvt~uWO1sbFI8~b0| zKk@7xgL^r@O}M=pe-Gb7a!{kqpcd3*&*Cy6>N=|VW!+UR=r@T%P^0K&Dx2sDP>f$W zw@9h}ntnvfvquI(m;FObNM-K75TFZ=4BbFz^aGERZ>TODQ1a?#$`k0}xI4)99U53N z-uzEwGyJJFXWm+rv=*hTB?RvEKn~fiH!Pn5v^yppv9ot9MPFPtN$39R3Xezfi|&m0Z7?m`B;60dWZMVf>-`h6HnkA^6I< zmk)uSNiX4>6byHbfI8|rkIsdB;5w>@hI1sKr0%!{+-1r8)bk`Q;(I>Je#JNGdvoP@ z>wTTUSg?rYVVShVaxU9`YH@rjT;+Y!@x^5wdw|n_d`Qp?y?ad*y+0&1Y35v#L^AHT+oBEn2eYE#9QXJ6$+u@v-3&Z{*#v)MCL1 zkLl_kxipIE!k=`2wqVD@V*Fgy1T`JnfTjahFt2M6_QU{3Uu}nBR0m@aC-cS*kT?kj zFX7P)Vugw!?&Tq2X^6|X>fSBx?)26|*y+EpITPKh!6Yq9*rt$G)&CuEDGjKmc z*=ap;VV3lTxIe_@5+Rehvy)h$&Pd_%o?;JvC@yhylr4K=8|3m62Nwj2zZzU1CreRDB_m^}=$?sBwNFVsR=7B+LEc!glWX$I?(&G$xVZaSGfN$ZY zC)2*n`dJv_knk(mlxf+sY#Gg|SiK>H4xy63^1Lc8ZfZ7dvIY%85tPIqy^>v?c!#DC z1y()@YRUw`Bm#~n0CVv92 z3YKs%@d}@(X;9C*yVEIbJpExWbIczZhp)r^QMPPAuW>x)J}>~a2EEx zXG4R1Fz@~O|G*I`Tb2dI@}*+rM7=6gpJvI;<|qOX7nkmXe@NwT+AMBxwR!()SAj}OIX_O z+1eQU20tz;pgXpN(@a?S9zp%L$AzT=p z98Fj}i+Heka`Tn#Fk#A1*eVi+3I_PP&}`|DFfpxK1t!h~F4h7U>wu97A8R^{2)aQ* zck%*8JTV8{0W*FrBtk|QGAq)oKo(M4z=qTwup@N@@&gX!$_`}X%EfVH^?cS=ABzQP#Rl1TQ-Uiwp_SzxX|bc1f18;PYVrmLAcZNQ~}oYAQu2}OW2Y7Mo_86 zmmD%_nrW%7!0T!ysgbUdWqyb}6Y*vIp(g2*YgMBPp75?zkJ`Hz+Q+PDYgNDp`eE`drQ^v=^92)Dxx2kGs4K1V&AI$#crXgk0` zD5jr~EanBM0$^9rtjyS+mCG<76;;pITF>JAJfbKuk2f$F3=PzWRa(-G=oqXiX9s~Y zSue6&f8J9yk}|kuf!eeXsZ_@UkI<54Ri&+yNSgCOePwm93-} zfdUBgRVo_Rj<{4*Vi*b44Z|bWv&ah634eqxU|)cgW}Xi73IIkVJwj-w)JHtC$`f)t ztwV!CUs8onsghk5A|8TWpcuG%)>m@NPCybUnOKpfIgJxXt1N8>ML{?o{2;g>s9M6E z{lxu3X+^M(cxx8*%fydVh?XUKi`R}A*;I+-W`F{A@4wLU??+x{{Nc*IGBP=G<<-eo zn8(EXA56Z0QAKXE3GKAU>#xn%Wosodui_U8#{E3<=b`jo#Fd-=_; z%{%Lp&iW6lKB~W2KU?>~>iHGBllbr4ov`fY0jUAiiigC8{$~bB)Y(tjnn6ug)T@Fy zqtY7tKv>7%2_#-ajk92(0(1(7RHL>!LvJz9QUs)ULYqiowd9c7#F@Zh>3Hjvfz~IK zq@to%lvMMCw^32T32ujwphsMsOzf-q*FVhpL)SDrg;rX)H!j zO^z>(3FsM}&lK6xIyi)-#+DcW5&8STI2Dc<+-M^x90no433P!MAsM=2A-U*H$_f_^ za1ynl_J|XwSjm3S`2BF_xDfG(H;4n^g6D?&{2Z$)QsNys--9q=BZI?z#P4{CycP%w zm@j7WG*u@k3&o-|(zA*zzIVy@8zEpzT6x{sIiTDs6$ zc8{EQV8q2QT)dBbX*0xN>;!_zVAqATzCUzsslSkwN?^L`NWosbB$A&^(tRtCT!=Ik z@VPK)td1+rN#}dI>*i}_=CNZ=dDhHX)?nnb80XH2u^Im;GiEBZ!sA-7(P)hD%fptLf^nS|!tard?Fg*vY)d zS6IzZl0ZlK*iuBfywBJkDHNA4Z$u%j;h!$lI zrUjQvNggF`N{H1-8z6NZVEQ_K;lWjlUwDuba=(iloN@tL$ZishLqAtUB~&6wTd^1g zlMlj7K%^onWo3z0AD-olkbkR~mf;NEgdR>^bQR3Is*Z=XaxX z7@LFNrN)PiFGVtZ1|{4 zCPy2YC8V16UB;p;46G)gFf+rqsNr4dt9hN)S}>|3VC_ypi3tsM2_IY*rb%2mdfAu7 z&vS_^PUZA7u!6m6 zo-)S`?>PP|EUv5Wk$iz6gzz0p&3`rGRw753nxAaT-CeK$VZCwp8gmAckf!EdH0@DS zlgJWPi!sT#LbNTDMJzgQ1v(W(I6c%L!%adpWf3Nl1|w(}$Ff-_kNd#lj)Py_-@XLM0j& zbMYeov8WzqD59G>Gd`hS z1A;slMdXNuj(7M&6`4|Ap|7wgM-33Y(LbOq$XW+O+Xs6*zLX`hKJhm863~R+#7kt7$i%L(bGL0}->Z7R{zm=G zv$w0(|DNvmEx&E~c;D?U2OpX=1tsK`S$K8(TiX}i#a9nb9ZYyP&R&Gm%BQ8}V z^6t~~rA^7wrdfBgbmJ{|vSdfBP0G9N)-xX)=G=Q0-EbqF+8=*r+Hl8R`{gOB46Re7dEd@BFSZ!>Fi9UKZ&Lsclz zXjmd{)zBxA(n=8@v(k3UHHv4Ue8mb^F;tUV#!B#r@5#SRZcDoUCC8I`iH8(`6}t9_ zt(8R5Jd3KNVL9@plnHpJ zwkPK7RZ9BSoyx15Y@2AAxJdbk)oYovmlNA}aPnZ>F=IfG);W8l2tz;?P~bfGJK01y zz)}o4_jy-k(p5R{s!h6TrvrCfD?z5ZO71%~jV;=Qt(sqO1n9&=LWn=c_hP{zI)<^jWDWYey+w9YGH{e)WOvu`j|eT88Z)5s%x-i#3uQn zO3O!n#zJ(P;RpanX6}GYo61W><`B89GJhB~$~n}mKE-y1iXWd(jcX)_5yYp{Z$~%F zyy_#QL8h;n1BPxxk0xsQp7xh8fzfwrG9iO6tL&%ICOj`!Ac|(6s1lXF%sd$UeJa{Ochl822Vb}sr?IhMD|1&+5B{W$-wi+JCR4;`**@yJj}c zm8?s+*Ck5U;r91hXH4HcIDIHlu@+vZWfc?ccb!$=8~HGj*miWT{+Y!>#Gc;xo00j= zCzG2`&J{kpxMIWniv7tI`{!4jOs+VYaMv$vIuOfFRIE$7)-O^lY|=5s!_z0>?ixti z58oQNZ9gpYsKav>czubcH5m$4i6Z#-_~L&ajzws|mM37f$1<+mFFoOHRX`z5_R!#y z#YW;%WlKj*Xq2y5ger#LOYocursP&KIzt6V!T^VKmnu)xggnZccpUi8=^GAe{4w1C zgj!>|C-f3UoR(<6$Mlng8q|T6I4Z1!NB5HoMIiK(%9F3wPmHgKlpP}r526)->;=Od zG7UzsI4~7(>Va&Tf&_tA&z74?Bt{g5rrdh7gu&p?u^&mu~mp9 z$Jpdp{KTBI>ce#(ZN9nrqn$T*-l~~fxeFpJif@xB+kPuB=W1OjEV&weD@ts{;i<#Z zHFE$Z;6k>&wGB_=;rWU+N&GKdv*0P6_xO??pAg=~eaEv2)PrX&5_bi~gej1u+BI`| z^$VWzsg`@5@>q*hVdKoj*%}DVq$&%p9+)~154>|Ev&OZ_inYnYwX8-8gg@_DoAj)m zt-0gbOf{}!HQuk(*o6?f0$G60&}fKCV;sT*oRFae3meIh5j{pEcV%w=))Rc$xO$oF zQRB(s2rQI?(pAK3B8*|-_TbX1$gS3v#|qn+%P=o1AZKlq21jp@VsIhmn7c59T(F9h z#kp+4Vn2wkE^J(rHaypP?(-Z}>3xqr#hosiL(p6S-t(F*mHwt(pQ4Z9QMMrFM?w@ zT8SACQ*DWa=~W{TBq1n7dIs((=zOsy&;>|a_*wXbZ9tUTu#YCQq(8Z#G!dKZ4Hup}QEWtQNboy>yM=MdCJ z6s3|GSuFuh3_X&C1(~d}shu`cUgF8?@Y#rL(@*DYzVnhgK`e*6A>P3R{$F?_tqTQ~ zi|M$*zCNL>Y)a4A*jYb)>M)sTRV@Rt8u zhu~gW&;$ojcQL)OGFiNG_QYIX^F-TE^NYwAwV2WWYu|OmjCb=q3nkv^Gt)u8|Uw16pW$JM{QX|nJT&Nyr4O?7#;ONd zI-~D_CCAvReOTu-Hax6y7#kjxn~k*(a<#_o4@_Ccy3ahCk~S^E>O3%H8CN~@3)2UsD`wzpqFj3 z`M&IKMFBm=K_wGz20m5|HmfkqH^}a-psWpQU<_gh^c)@1633zkzyXH>Nxa1Mkkh7| zbH#S1xZL{jg^d& zzfWUTj?yqzI`R=VO(KH_qHGiy1qWxzY^3wPrrLpb;gkXGXS6+M&mZ2l;| z6T4++7#sf~DvRVOKZLmh|A4-tkbT9c&H_kSUzvIZjp-}bxPer)(N+aKE! zCr{0v>`a~POgLXkSYF~g1#d`)G^RvoW{jyyxTBDP=dYMYn@TqT7OLDO;^&f@AC&TRg*CDtCpqV0(grl8lJNcgPJ&?Jm7Vd?V(hz)!t}S2$96 zsVz0pO4JCuTey%gVw@%x7y(|!XzJ_?Uc`XqD#jbjkM7a-m?46{q$((i*M6^L&e^zt z6}OjmB?6BF5(6B1&s5L!#`l|VG$#uh5w4Fj|? zYxHX$m`uh3#?Vo`jMw(_rBNA?A2jSbx}C7m&W0CWJpIC%)5ll%d=if&@>%>ZcA?#Y zKY9b(1ojcXy0hW*$Vy+s3(cpS&d}M4$GqEsy=eKjnHl6x?4XOCX&ZLXd%GG|;Tg_^ zOB6)cXMDRJ(UuGsLWvsrb9_>UJeB6il0!jNKob`#hLQs=uq;Rz5ET8wfKO8gwEK<%d>ThKsWaa^jL3cn)m<<-O0ia5vEs=woaC^;k@42ID_Fe5 z*fVgbDXW~`5JRX7fU|fGMfI*ji49E)Yj&WHhMlORa2M|6?7CN0dA;LW$Bh2nP6QF! z8{12P0_&%;5OK)nn%J@6%#HOYoz>H!nSN{~_?U9s1(SR3H8g%?yJ?$koom>Va&JvG zY?)pgdxj)f-#V3O*fOyv;oiEKQyM=py=i9C?8a2iR@UP2!~gApQIp@ysOKMP3tLwh z)PcqK(6uB<8K-?9p1{BeCPwQJ2o!_DA8Lpfz{9J^p@L*pfq=9DG4>m(c*6TMUzQx$ z7#TB!jtrktTEjw&E<=drLo=rzoK~z5ejbD&x zS>)r*)rY+22L=Bssi(Y+f-n1Eh{6e?%P4C@{j2ppJbFSK*=JJwAqQaXWH(MoH>ksU zhv5Q7dE_dU1Hrr6E&F~yKOX|v$e!zG9qvC1ZxZG%$DGHhL?RPKOpAVI_g{L64|@I5 zOMI_IEaIrAb%>~ESB_`IQN#S?v2!+ytEYW6($FSp3I(S=>?uW`K|MQqmieh5e;27Fcj^q`Hlddds}=*=iUb7!J`(tAtL+8!mC<@1JEj@E&curL3A~OLLNEJ9QU{+fCG1% zk~$>dT*l~}$bz(qZ_W~(B*pOH<+-$~xXY;E?+ERawFeXk@@F6E+%2lF!1PBj_`#~ei4N)&Ft)jem~qjZKhO`B4-`h=nWi_aYzSK$MV zj*1kjSuJ`>l8K-WAwG4gm>!Z25mx|* zscvSi!2c@jw7jJP*bI~qK^p=FO3CWTPl9I#6VmScp!D|)kM*$o8MNLqh z!crhYhMz|p0(2(W;_o{*h?RK0pR$n0ZF3f@p}NVd1m3j$)k`ncH`l-PlIUI<;3xtJ zRx{)#ef};PX4E$}HX+66iA61L?#Aj z5lDnUK8%r@aErth8sWR`f>i~JFT%ZzCqDXQ!8gEWztTL}9P7Hgi@1#SlOq$^X!JNQ zg~%YysW+*)4}TpA#D$PyVPATIJLlFyzNFf8c}cMaNc&}j1BZ<wjDomh`5D@|L#T!4Fn^3QY{-r6Bxr8&yd&}6 zm{Di(leQ4zXLmln)f6Wy6%@e zs@w=Gwu$|*^LNe8#k}J9mQ-HNgeBu*!Il?$KK^pTR+})?^72enEFILhY}7h%qLgQ< z33TO&29`@2O|_gdSS86KdRN!}b3zDE$X~=y+Bi&J1j}{^pxA5_w~UN2I{7T`p`M-8 zUtYWiKHA~D^8DoUd~n=FgNYB)IA?Gxc1Dm|hBqV>6Tk(tcR|=R*mOyG_vP612qS{%n-_Ua z(K$4TUyQVJWH^)yyAf!DL7yPz*u`OjsoXT0+eV$xf~=S{jvR!Nhrso+2L8nTwI%sQ7R%5%MAZlc=Jfb^&mPOh1 z**OB?Ts4w(_R&)(_G5=bVRudL6|6As6MAA~yCpJ)!4{d@HE%E~T8_d1ph?*)Wqg)0J|r8{fZZDVVpE zB`sy~^C?R`@=KyTV}O4_sr}~RIi^snaFR3m73Wx{_3K=X5PLcXO|7>LVWT`%H+}ucsh(K?L;?;yWVoMR0yrGXYmRM{9KLIBP<|)%HkEa z0xeHe?E7(Lvf^MW`%uDihzNPauXxkJ)9=qtZoRT=a#zY$I&Z5=+Nx5v8dxhCZ=6rq zXh%?<59Jfdp}SvG)ha zJH&zvq^)q~?O{4uUeu)Jz+nuG_y_QCiJ?k5i)dt4Pl)>gO8Pp@-`gmhh-25AC$W2$ zD=&87ts~R9DOb(-fy^u7GJ3EX#eyYA*z-1T&QgY58DhSq1wyKyItsw5+Uzkswl;!* z=jq9(V;8@9cmZms)03y;)pL&Wg+fm}C!QM{p4gAL5b;qUATnXko`QSL##@$T#Zz-G z1db?-Z@NvpN)=E*_xSlcuKIgUSKNx7rWCog$%?IW*t}J)>3)$WyYPN7Q+M%e2j3_i zwDf6KKP0m9ss_Gk8F9ZAP#jQLZT?GZ3^QGA#O3ut$G?!(UR2a17h~M9C0cq?NQDi-32dV=L+~ zW&(*khOm_%+gv7uop!M8BQz+q zr;Rqae8YoW7ROm^T_@XB=3~_R9a?{afh=tfc3y*M+h;12`TX5Ak<$HVO zgn7Z?zVgE43-R)lqhUfvo0`B0B~i9|&bfx9sqk%06t#YQ43bnBe9)dGWYoI)ooDCs zYm@o4)8|t8O*7$C{)UOY5C+3$1p!UtFQ@YBVA#iRI`+lqMvXlmHZ5oZ3mZ+_S|^HH zK3@N0?Y!mbgym^QTm8d*Bjxy#nYF#%lDFHg`J`wK(jVHbyEp59m|wVio&JaGj5v?f zpAUzJLd~mJkBp2o0md~3pj$x9r~cJLqeDHb1u8eRTAlWS2{_g%F)2jRsEL5Y70KI? zkNufl05bo4$CX{{6-q zjla73*Eb}xwv4wfX64M~`exRrvR325Q8BGgIch-COZ09AM=b$6-T?0x>%^#*jO@N` z0x>}VlO2k#l%!{PE_bCQ8DnUUnaHwO!x8K1Ar|B?*cdUgp5%TgcTw6b5OS=q)Vhg( zmtQmFDgE!Lo7SLB=%!j9Hqn0W{WCYt{A%Z~2YzQ?BCBm_N7>5aT`5~t!cetbfF)8^ z4{K1I(rQ(T#EUq0h^H&W;)PABIc;nua1SvZeBcB@Is-ps zw@c9tDLN#a;RX<)nqXBQ6OZ#MIb!;RxX!FhMrDVvwB;oB<@h^aTNB0?3P#YbUo?$M$QL= zeZqa7?#`G~vOEmKkiis*9m!7>mZ~90dAVi8IH0+@;(!yG{E>m;-)zpqf=sJ)RV=M>N6wu|2Y z>tspwGivY|Bg1S?kc965HcfyOn1Y5vwIgnsDsWzuLEyefmB@2dnW}mkUCa#{XQndo zhR%!gf|RqM7WpBkqJF*$O=L?rQYI^ES)_2xLQ>HVLBoT0+I=>K%L!AMPNKs(8zt)~ zk*HRtUrAdAz{8QYgo~mI(Z`C;l|ELyMRhh?YLYGWf1rimkDOq(;G@Pz{1hEAMIEJK z&R$06`zEnb*PDmu?UhM;<#b!p-Z1mbZCjJ1cO(Z*dnzm^~ltb@9lnn-;I6q zH5-yO8)i?WYMN8-ZPLyY88O8SXaa%7howlAJQyhiK9r^qz@RSDE)AccmV=H;TCnIu z+9+C8F(-tqXCoz#3sf*y(5d(#^^#y4%Nv)`{Y>!b;EN}<6ckdCJia$GZZ1%l(o{y5 zg6OE6E|`5`&e@W%v@9o|rPcohYPt%h5{MLM{Gl$#S2L6nXF8b1-y-%=v1(M{fSMRY z-7H)V-$}lpPbk$Uwp;#{iRO?}Ev(iii40eJ8&F2>6*W^T2~R@)zu^h(RDm*bI}sdC zf+=dDGUS|KZhrs(F1kYj*)X_mJCQ;@Hp; zO+c&~!pTkS;?HSH6I}?Qr$tj(G+|qWJ;aKs74Z|-PhC6plid1=-O5eS1I+0qH%Y)GJ-ms^;=)d7s*k%5Rq6(#`p{i5_Zazjas)DSBq=%=Egs{5sLkyK2r|`vs`) zyoUR^2mu5CPa>_|Wgx8`^$V^NA7S%N{d^!8h^A! zi?p3Pi;e>0@i){he@DrEBx&pm6Bz7*h4^35tv{pAOi|KCmuo3mP04?tdzAc$`h=Lb z*EOGE?(SZRB;wEN2%oNr#BV9ul>sN**DYicB71qXG>!Dlj3n zjGBGcbk-j1Tpm8$bE#(_vX;#nhy^J)b%@bR*z@Bo(AoLbq2aT%DF;ln`0XwDiIl+; zP*d;`;?_fm%A&gUkiAnX3+{_cygPWLk|#Gx!YrRt{}A2q%#L8dCj%CtYTnGF+56mi zeybSN$KN7V4iFp}fiSp~*(U$Mqbg=5Xhgd!ULdbm)?Gv~3H>Fuv>m$q1zKG+AsD<$ zXYnoQ3wDRan0H3@7HmwU?&q@_=ms2WFD}*Ma3t)DWbcudO%wVM5hgXEgQy1p%?+3G zd8aq&^ul1<=87Aj*k3HJm@b~Sr-~b~g=zj92k#+JWpJuwVmGY07KHefEAF^z@8O)J zX}xz`J|4SMGg{}T9o64ws2#K!$0dWj)0OoX4&`A=y!EK>4+Ajvf4 zU>V_7Cl4!MnGK!JHt561W~+^CZfT-y?d+ap+16BUbHd&Xwf)4&N!z@IZRmwCn|1s^ zihvpok$1KrgOm*FRMpQ;73?VD$9{mXp@UJguPFwL1zI3R1VRu$wqlZ&iagsxOQ4Oo zdX@tlwonLc@Jbv_eCM+A5cRR^Jh^Kr=2%1sH6lGNC zJlv8Fndbuq>;(mEWc$1uquO&|AAUvqYbGE!J%t>DUy!P80>rICxuEN+3`%klt=7X z%lyC+3J^xt519twDi8}(9Fm0}%_JZP$R!XWR4PL;Xv=wARxFQpq^Tp|3wf@H$O6I1 z_^cHDlq9*34wg(e+YVbQMy=diLE|gB5F90|u76@J zUgh+cKPOTpZGP?z43mwI(7Wuzc^P_pWVO%@5PCOL{UPrToUZcn%@ZylF@hC2y8y2G zj~F^8?B;p(-=WJI%ma=j;~+jI_?9+MfoT(87H^5fK;9oB_i~}PS!fDeGiAsp+$*QG zHi6dw`U+sM3v?a~mVRb&fJ< zkLF$8q|2MA+%xCeizrBM8DVnlDEl%*tXACKlB@e9*W0qu_{jz>Qh@-sE+N3VIqD-u zd^7bN<78MjQdEYeWcW|$9wmPV1RL_A9wNhaAj2(MW5q*Lu5rbKhAd0!3p zSirywd!-Axr9)h=4@tJHq{l&VL-mT(5U@RpBFFY&*f=bhMH`3_dqhWv4cFL8OuDv@ zX8G)C>v7R`Oq~YbiC0N~rli5y6~2)_WD5wfXcf16+87H4d(cwiH#FSU6=G^nTntc5 zV0H36S8AI?y*JZbB7y_ddja{_!?~XQEEW{K9fSo z+@`%>81W_`qO^g10u7jGB5VOE$385g_yqCZF8T!0&*2jgq8t_i%;67=NEzRDYOi>Z zNP?~(ZbA8IJ9PHF;xolBJkm$@T0LV-t8d0w#3Y9DW1?wdwtn53XAY#&%)GG;f9`U^@0%LJ*i|82NnlBiE8p){_ zhMrdS(xS#4n#-U!WR314zV@G9t4iOAwX$&Fh|=GN-oO@)Z1OS?_9wW({WZ;HBC5E* zq2v@LzePC(Oh9p{(#Bxm9F{1vn<1lc?njgyN3t9b*m!D}pZxjq`c>TCP4oXA-p2e# z2;U7?w@qzJ+R7;wFC0(AfSYsnn!DI>G2at+UoW{+SuB3 zp$Ev~y6u{6y5(9n;szA0`vvlUM)~jOY3w=6S2N9bwwnJOCu}t{WrY++4R@Cwsxw+A zuN-M!3J61uoKwOv%smywifS#|U$7P>yC>`bX=F1DT(PuoHgE01FeyzrQS@gZ+<;xf z2s2O*f#BlhT8v9}$P)=r^cYQ`qsW8_*SAq};{8BTP4ww~4Q4JVJnNc51q*R$OK@w!Z+p3O18H1(H6J&HW zj5yFA`~lh?u0gV%7W_KfxJv|DUzf}?mb`^1-11vd-McVMgkD(pZ7GbI{3h(yBjvRm zQw;e*y|RFaU}kuv;3)4%Cv(^QR#V*H<2msOIEHQ85`D~XwF?a~`9LjTG|&R0g@0PR)G+UL0}{=V6ZGy0t7;$ZwU*P zC0ll!aS79*WOs*R+G&e!Iu_HOX*u!4IIkydcPG<+d6T>2y!t=MyX` z)3$pu{l33*x2ocTlbJu>1)aM0+;h%7>+k%|Z+#Y;HJ()Qy*x)yqe`B7!8PKwAZQ3UODmqz(M7abX|!sW2It@wAr3-8CN8DxTY!_0<2`|F#09c+J^o`6Jt zW^Q2JYg?l6)`6w_JDJsYfzC)y21G$f*c2`o(GcboPd|4eoV(U3s&D(P#3RPnvKHHD5AMYk>;`cO`lFX~VM|EQXr3nrT=(khUF= zuG00IX|kBF6J)Lu&YHBzI`OysL)815rmLE1lOP2)jhYYxMSeCb&lj~9**5Feda+3Q z0YF*Glr!;dM_#%VX-`gL(M&^%kxr0QU(_52T#^TyHiMB4y~x+`jf=3UrUILkp&1-~+m0es`0QD=8Wi{Q%o+Ef0NWuvCJ#&3x_ z3upI)ob^A?ES;@g$gE$iteMN5uK<5K_k-Hd#{J>S1O7dMp4YmfS;e!Jx3j8oQmLvH zlVsf*4{h8VuG}XixtES2L4gCb&`&=9Onz2LT^K3Y|SZTfC@e$-X@mgTzTyH@|+ zXl8XJvoVy}I5)nKxiOmKn(erqQxnZCf;q{Y0$@5tW$>dAE^PH%?uzhg@J?FIy(~>y z!{;jnBL5q$DS0i0*xoLI=Jt+Zr(N?CyLD%Q?kD*iLI}4IItYJLzrf6AbAnIBAn*V&>anthhzv`uI<7lXk};IKUUtthmGVE4cQYY=zoGNY1HHw1av+-cxa^j zl;wju6x|W5C)kXmrqA$eeW|5(NrPaylheSo9D(=1hTD$vkJE|*@B&kgvtm|0XqM_W zwW-z&54cE0>Y7k z08TO!Hl~AhR&U(#5|8iF#CQ&cVJT;n_{l;Rog2RK2*x|%0P#s~kzddB7GAUeo6$e& z2^P2AN!#?9PLo$m6TyXvkd-H9gwQrov8!i0t~K7V)q-G=<+=+q8un?sAH?f?GMPL+ zJs!x0u3pgWVpwq(-$!f1o=lKtwCI1J#w}66Fs6S*eFe-)j|CDlL*N+F%cJ9bCM}v= z3OXo>A~5nx%1glpYA+q9$-*ErF3cHl~O zJ9wV%@ebh$3dc?l^`lnuCDTpLWBt6sy<)wp@o_%uNf-@y**vL_6Rbi*lP@){=d_HQ zT#AzrkBhZJv%vthST|OPn#!=e!@>aw6ljMJJs_RDhw=uu0Y(mtlg8n;2c$JgJ2KLm zk=BB=6%R-&8{UE!wvQ?X!#)N$+3~u~@oSen(x>z0`v^ z5EZMZJyR~FRes%RQr}HjdgVU94EBIK{bgoWal+6m>+zt@)kbN+~>MXz|k#fL*G@ zNqJgJso>J<;W<>!&C}RSr8-F+Pe%Z?={~J2?`#}un38SW7t@q_NOz+3PCCZ0i|A+Z zo8(IzO#A~q{vO_X3z>-?a^4JUYcMJ1fhqyBX-Q{gn2>!9iFl&Y#*9!H1b-|}>^ggoI{B~YsqLt#SO~>j7H#u3z~gkEDXi)4p9J`{OG;0gWPMrx&PXJAfPSb zLg;XBWacN?VS3MkqjD~NuH|OVyF1?Ne5dnvZ5tz{ZMxMLD%uv#*dDZP$G%u6xRV75 zs)!b=3qeeWEdmkbubR$ih`?^))$?tqyofHK=n^6Ngx71}+pxRvg+fFh&;NULnKw%$ zN05lgIcR5)w2?%ZxIrC9Ba@&3K{JdUOMeeHS8;HRll4W}$rn`PWcC)5xR4X5Nk-!U zl^3s36L&C^=bki6UjnObQv19%PPtC&-FWx{#OwNa(kP*Ql&k^Z^i%I5(`tMlX$~+E zhl{Y8igT3faZ=r86xS}Ol$ykxu@oh1%-YF{P{^_{LNdyeb(?bo=S~dpf{i2{l;jdf z^s#i%XvlH{&PQS`ycH_b>b_LJq1i>s2ZVs@?5h@YiX%C-p`6;es`-j=&iY{5`p;pk zCgQ9LIjcyXcGY6G>xOf-`@6Z}?7CoD-EZh>%O14P4^=MZfdiV zmkr?w{A;v;XvOd(Bnuq{=z5cw3SUpts2p!&X3&Hv+QW?g^FN?;q)jVygGX4OOy`Rh zDPK+*n`pYhpd9N7NI)_V?%=PdiOY+6hS_`ID=4K=n1&>ZgXK&yCNUwuo~mFFzE2-v zgEcse4D=1Y5`l1heTE%iDcCM7Y>V9M{AQ&3i2C;rQQ8+%nt#+A4DB3bCqz{Wa-#{m z5H&CbVNLa2e09rIM-)aQb~7ssQENfOS`o5V1S{7qSX*HvX1X(KFN)Z!LiQ>UaTn~H znBkbHGjF;h?!~4B`)2V)e%y=MXBX^^Vtn>=$EQR;Zwap79V*%#&e#)#4x_f(Pzc>N z|6`Z7EoK)5iyP;4;p`UQZn*x7=9WZqYeKm-;oLgE;giBrf5*p}aL9KjvjUiQQ5nv= zImK6pW`@X;L{B)o?W=MD#1xgmvjKhV4Ns(Gb*Nh`ETm4r3_4;=$cXHaI<#lguzP>q9-Wn=zogWLAZ}abF&Pxi{ETtMPtDuZo z+3GVbm`m@P9irskh6QuQXHdFyMr}-zGg>bf?)WM3wJbix-@^`*n;ps zy0SXg=@K?y6D9;ZL%xJ@jo*6Jlrp4!AIcl@2CUG+;=xa{7kLF7sqy8NGJq?&!39T+ zCiRny50024crwLl63dEMsJnQnZMwiFP0|JpBi7L7cWYs6$MU~Wk|nOB6wt`jR4dFA zDbm+~yFP{U@JT&@yc=ItOokEjgn;>4SV9}qa+)I=4*w|bqV9-hjDt{X9rh+yysbUv z3~z84GG=`)at`X*d(bsVZ#jZ%p%#8=2Mu?Iy!yy)nl*_0N^nG>ei`_MGI_52b>F*qS=ha(sE{p zCGTgY%^_P6B#|ou26h-;%*netHZw*}d1pK30K-?~fSjElXbG(IpY`kFU+tKBxOmt`PUBR{!0e?-frKrqeb`Q7Q>FMCY<>RQ;%_v z#JB@7Zg-69iE)Se5hY(}AG?;H#ZSC26-24*pki|nrqV%VO4R*~S8f=vkT8|Bl8&a} zIYFq3M5>P35StR0%8qAi+;i%5XXZR(Z{+T={opCSAwb;7Ll;DiKh&% zpY}x)h_~F?V;C6iJ`I_Zxd?JmFKY<}xW|AC7m;}t&nIqrN9D1L41M%sFA$$7r3?-P ztd#nv6a9!Y9dIjHXoRDhzKi7Ey^owp#Y_W3edl2oGNyNf7Ax`WjUehmuoLJ(-$nc; zAO(W{MY_~tS$?a6rWr`?m}Vre_xx=3Tac4m;lf^BhX@MNl^%dmSKHAtvZ3 zfnoNZA3S;U$=l^5Egf{M69;ZFHRHJwsKS18XixMPUnvTG*G03B1NRa#~>Luzm+|$H? ztod+1pTP09Pz=-e_GZW(B*(Qm&cyE{zAxxxR6UC)jay&&-~{=*+=8<_e*W z@`^QQMJxW1z!=e_p0mW`a>N)0Q==g~0CybaSEXyys>WsplSUo$V*N7J^; zybr;H8aZWC9~b7q2l!5kde9wDNzVjq*9x}^*h|CXa4^JM5u*0zW%Y&e_VhUbUg!f=4 zs4@)@ODE=}i=dVlHCOMghvWgq0KF2j8?{mGjSvx!lAlXO5)9xhcoHTVH(o|Xb2#L zEi=GfIuIBYm(+aAdmG-_aBK8O7vH~lyLopss{~^W(Jr`|HcsDRT55~rXJrF(7iw8PU=G}XR`gmK`b022mWWq1#tZU^rfUIIH6d@7om zJ;RZQp2C^J+4S4#WwWDiUA%r#n3uP!H$^kEW;l>NvfwNA&6;a9vpsJ;dHu;yenU93 zkp!dD{XJKooOyCq|Caf>Ih0isN~=M1R(2qL=COeL&7o^Uq0Blz7b}3jpGf(7xD&d? zEtIzf9h-t?f%cj}aUjUUpwGX<&4Z>eAd)a~ut^M8sSg@rRVI-*$S6Dc^3oO%=ern` zg;X{*z|lTSgM{<=unEvm@1-fjk=ssKDC1txo@AQ_2Hhwidg4Bz(G30)EfJo!U)c^I zgiXVnS1{-$51cgJ8;jym0J>Ak^*P(7P{RJ3hNgQnhJVOn*S-I1l5VN>?dge5c-`wlDq3l|q&c|*Z3uSHeb^aF|Z6HyQ70_Rr{5UNO zrtV^XR|n>-FDa+BV?r=DJY>{$JC$B)$=tDB%eh?qR?O@I2Sr=L4s zcWiRv*mErX1FXNkjW&UzhETZFaaako@o5CKev&SQhK7=`Y93mW z%z;*Nku06JeHW9C1bP3|(8!4sq$YUs!Z4%6gZd9HhX+Q?;1Am4s;h%?zuWcP$obK= z^$40MXr65Ju4iZXL7@b2MB1RFiIbv-j8;*huCltiGS@lsHv=_)W>l&VUd{%*P4{Iy zH|POp1clZ8- zI|QrBM3j#?#RLcTb{}Z(*}12;dsh#%#0IG@wc414IbWa$z5o+B{-nkebYa2EG({i9 z6KGkc!icFnWGbKCyI^XJrat1+Ey7!_GcbOwB%E3sG}kVg@*}2F_|%1bm8m|O+IfEp z5Q}SJwl%0193>}!N7_Tn@wZH#dLIFC@T;c~IG;#MSK_csQwzYf11)(neoDyin9)^_ zX&=x)iMBwLAx46Q=VT_;tTNpo+biNF0HXlaFcvAJa_$Fc89<&{e^SmDm!B|ls672X zca;O_)C|&TogU|EG7kwM%B*<2At@I`hm>5Pb*LT`-3FzHL@WECgbCOTPa+iB36uDw zgOf1RaM^@O4F_<`!U-g{pqj!W)ei(~nFX(An_a;t(0@;eByS_UH(ExqDG8UF(M>hs z21SY*1~=tV_=<955FmXGxRFsIb4%?&?PzpTCQ_7szI=p6=ill;u1@J<_zr&qr7*{c zjCAVN*46O?v@ejQVP?oL#vLP~^WnW%foz3-n{qG)+Boe5Rd|HN=BQg(nS3?9{u%|_ z=`~|T{}l>@ytfw-u~dGr|1@Jc_p-&y(5Jtm^pjK)sra80_=_gK58fDwP(`F^M$*2G zf>cS^JgW-@S7^y^K)PQtUUgRS)!v!j*(38@IIC%@YZ1n5w}wsmfk$tfiXpb`-x_w5 z&Gy}PR0qxL=ZeGT^+88(quHhXvT!p1!ZqGUTd6l!rX`76wNPXPnqHTM)0L7 zs>p=dT<0Gi45hjJdOy6!h~)K1PIV}!dQKnCY4Gb8^IbPGh+5BFfw<>)hf6pAEPsoC zM>N0i^*yL`!B!}&RknP=B;#J%W!sesrbf)Rr>Eyo_a1B+Ly)LVWnjJc^oWPCMPq3@ zAzC(gl5DvOEaiTTp?qNw*tLu^Dxl$j<|yaZ9EGSB=`Blyc37{`#~kb{FqTHLzTh5r z^(25+45@&5)&sJC6|YMjyF{$Y(dQ%`N(gW#U2$L;xTkQDF-`D;M3Bno5P7&)E)(U* zU_;8GND@J*O6EMN0f$jpkVMU-m$an8rz0XAyObP?vIbv1p}okR0S=seDXGuUSR`F! z(Ys&UD|6@K!M0oP*2rzHf|?0&SduQZoybv17h+vWQFxSkmLp5dL_jLLKMntATzxC< ze?Ot^C2#4wQk}mVCiFxrvChka^Rdq0>OpHNloSL&0Bz$1SMLME%Fc%+fXMv8-F+_lQRbSEJK>UCH8ezZx-ab}%# zr~JC1hoIJWB|m8aFg<`)DHp_8c7Y$NUek?ID&;p0yKYlrr8{ZHKd{6tQcC4lYCETS zNs(Bybj57FqZa^Ih8Wc9j9CvJ>g_t%+ugnY*(PWb0Ddun47j{9_V;#CWAX~`W^s2GG+#lH{gbhmZ!FaUqlsR>4J~KI0b>2o}eVeu7Gtza07%Z zh~c@gKTkaHD|&qr<^xuyS+<$X)Ae#ZwLKi&V~{;=~=Y}#;qG8%Y# z?y&_&bF>gUkfVpJwM>9iAD!(H*JW5USh|&fe(Tjr8B}1P+jRTUyRl$7_xo z&2MeHzAcp2^i79Q)>Cs83y#%z8%e7UrD22pLF&y^eA@oLoy?15$w1$PWosesKqj}acw{F3?HoB(eJESry8xy76qJdVQ#R{X*sjF`kU2!oXoPGw+@WslW6Pvilb;?WrJ&|J2Z)y2q&l z0r&3_saP!JzlEXZ={UrHkAe<*OHhlAGye+3QSe7Jp0q!Lkl@UL#swI?wq;|!C0|HQ zX%Y|%JhN-rg`YUY0>=e#@Fk-tjE@gwYsDSvh5Z%+C$l3WSdA>Msl)&+299y~E zaZ!g>A4}T-YrOG@lR$cryF;QT$q^nZL|Om>$2==OzsxniLtRyZ#F+ZF!icRhWUHKo zP1{w`!V1ic15sDKuj7tQv>zfNU`Ws0nh}Pwd=WuB4mCmhm6n;FdVr!jUk11?^*NO# zUK6@Fu>;i|11aQu6GVLF`U(({LW^Cxn2Bpx{u8YQLRvbRTFYEH!zwNhlCa0z=~h$?v$v zm?dUPTu=EF%ghHKVP2e3P1w2OT>$XIu)E>%kg=-1(S-7lua0Okb%H%BxxQlq)k8ya zPY$~t8}{^_6z1ek8O;_Nmss9u9M6QhgK~pWIX%#S7IsGo_>;A)PKb9f$Dz!kG&6(F zJRvg^TdbQBit9f;GJ^DDtW*$-;tg+!L!#Kaq8Wju!Qg_tG(eI41?C(7DJC=9Ed+K? z;+A1$8*eW;=jFY*i7SUDk?SnO*R%zFl*i1$xzlh8DPT%Kbhb68^7U* zR@I5H+eok*GAIWaI7$!=Mu`F-`7_**XfRev{HjANT@P44GWmyz2~(5U1zc(!Se|kE zD8MzatAc4YuO7bH#C;=44 zQkW|Vwsb{wKs<^zDlh&U4J+k`^sv@s&&T#5$eoF1z5ByCZNaoQNDvn+X$*MpY<#zT zzVE%$@0|YQhLCgHVt(B{4Oib1ZQV$5pXs>zZOa<2U^|ECEQG{i`OQ5mvVQ5oQAzVs zL9yoBmi9v3TWi{LbRXsza4XsjyKf6*G-am@>zvfhb#bhVYY6mulbWDG7-I|R_wr*k$+T!9)nch5QoRVJIX}H|@7$h6A^CQ_cq3jxn+GaOSTcI-9 zGl8O8nkx<>5+Tr|KD}^=hS@G5r2X^l_i&*P+57|<;5+#f-)fa`xk9l5nFl4Rvxj{ zhivt8J@cFI*tXxl?2u7_@&6q+jA1YB8hDm2MeRCn+37u6kmvO3i);e0j!0m5OA9;c z5*Me+8)4C~#aYP~C+$D%!s3*<8mi(%S~px<;+UeRV+vcK=t42CYApnJm^g62wG#t{ zl%8=sa2$M}MuNruDc$`a6ws<g4U4eQ6)9{C6_P)$!j|a+zIGq)Z~fSr7tJdG!QWN!mhHL?e1MIRq{lHh;w-=I zEGL6Wk=5HmtG9i?g;wvlUA+TF8vJ@fNXx6=&WY4+57ln}ApL`mP;K`|od|;E-SpZe zln_D*?a-MD+60@?UHpgCm>*NnK`mBL5jH(3$e}8eAdRpQwsXs7v!z-{N$(SuqBNl% zjD}dd8JY+|n2X~H7zlNy6@SY%6oT2QRYROXa+gWQOy*tsAagwV;vRL*C;?~8URBFV z@qXZ;c&r!shjD5uP@p!BLgGlcCXFEV!V1!a0pw#epDxq{+(%ji#7~ST^FEw+s7CrH zZ9z7-*%6#cC7a^s?0fiT%)qc+*vMc{mQe|_fQslCY9UN!qU;MM9NAbh(E5KNw}1wG zM0W&!VEgeGl=376G_8f)ee}qR*N^tY>-=dvd+5-?COiUR&Ql5A%(yX?;Zz;Xn`ykp zRENX){OkF1d*?^NWeS=%6SCkR10rp62Cc=P!uxOk>&Iu;!b2TSUInFZwq0wR9iHzC z7i{qDCpK8lZHH?yr(#C`X$}Z>A6M1Qt^c5Kp{grr>%t1z6tb1fmPU&pKz_N4;UMI| zIAX2}nX9m1x4rX3+FcHEb3pKD|+&z0^+$oPMNC zz67)c{-|gS;3UzlBU42XkV+xBR=0s>66Dvk0&5{|PAAL_Kr^%GsO|{=us@P6l(1`>< zvP~%wQx3d;2Dp&OHHCz@UpH-?*58HG45M#6WX{9D7FXil8#3oF!jh-f-x0Ew2Rac1 z^};Tm05xdo)3v+@fpU1!Y6f(QGB|sZRbbhZEP~+Hzo7#I(ZDoyj0lZzJz|cTc6L8b zq&LRUj&Wst4qAhwki`wf&U0iuK4$sag^|$#P*lLoq)tN|lvl`8s==G+HRlu?kqqW4*zs0jaZx<99_?M}&^a+W+ZbsEE4vwO-X>pZhF^|*8(}@yw6%+v? z<~$7W9kbvqrVFx>Nrx(StcRNU$vzkt_wZ4CiT{Lx4yuTx~VK* zHIB2Yzg8w3t0-m-XDZYj)WSfuaLd**u-)jTIwkQMnJ-SHHVHa+Y$DUfEKV&9>F(IX48MA2<_u&p3$7Q0vbWCb z-?P7C$Bkk}T$*jD1eV*s1UO*15#+&gOKcg7JB60&cvP4u%7pqh&70RK70qL&UN4b@iS^E(qF@TW zm&ifn{}xf+RAnAf+0+-FBglYF4Zd>RSI^Fz4X2m+jL>Y2SPMedf3hHM}umasen%@;~L+iVVkaX*H>)h_JtHs|LSo_*un0G29aUR*umkNaZJF4Y> zr7@;@#V{YJKJeq!K`#^t`JX8X1xKl>B*j5?m@I~EOW6R0OGYDvW8ncY^TjwoLEh=3j&eZXuJj%<^Olkij^^v=cf-Vp!^TSoBdf60IyVNYkhr zo0YL9h-kKA36lDjx}1i}GFHF>Loz-^({X@MmZ-8i$q0~O=<&bN5SfJ`8W|H;EOgLE z#@L>rwqpNZWMS}893?69b2LiNpl2~k_pehj&DZ`(ZULm*oWLD!>|Jm+Mhi;b+;nZz z>{u998#%E(P&$XpoczGD_ll))fMGJ3-nFV!x2wf>Ug zD7ZjX6ew3qdaYp_j>`st9>!iLtWarkFH@6ViCd$D-VW&1Xde<>he|p(U~n@?>Nfc_ zCvl2+*>cqA)&t)$F;v*hyzp6kIG-L(q0>T){H~uIJVlC9BYeyXWmTdbf@?Dx)8Qe3 zAVzg#6Zs@=zRAT;?5(oiBM9-Hf za>f(-4oJ)P!zy;amKkz0!04?_u{=GaB|~og+DTb#4kf@)?iHh$2d2{?w=7fc6lrD{ z{&h@%Zi3Rd2_vDeQfp6YQEHJMbQ9#nOcE|gFH3!7Cc(N1J!pMqCX!%*b?H?AeRe6W z@+-|L;49eh7`~D+X;mmN6PAe-RtKw8x+KU5K$s6eXz51lIM%{3>CQMt%0dZ<7!5ng z8!k7Zk`Fd>rl4IXWsVGAjq`v>s>a&cYHp`z$qsiJb%%Q2V)+U_{RQxh7+ z8j3W){2J1n#@WR=ZBR8kE)RoH8c4k0b)fseCz{l;8bER}ez-6cI)=Js(7w?Pi^*yO zp|ndVSL{@{7=Y&Xm)e?IoEq6a!MuuCu%uv`VEp_5j7SXjkH*r3Wet{LZ$Bg%M$R$m zFalDw#uzsuV0jGR`w4oI|0jYHzrY<6RK`B<63v;hH{QmCm7iR6oNY4!4*ouYgtt%{ zfdm*fD}BR#V^`q#f@4)Q&-F%Tpzm8b@AQRBH@wp~pMJf1uJn6#^L?Sx4dJ|vej^++ zX6E}2tT;8W4Br06=t6o0$gY94GaI8trIDg0SPGwC8!lSs?}YghN_o$!DR%igKPf5> za35E!nrolyyV>#G0|8^;Yya8;V?f0v*q>NJohHBd&BAMivwhzx!NG-u558E+(v%4d zp|>16GR*uJ)DZ)ilV0sp$JzFTotcpX#}Ub&rGPq{r^(CzhVK47?qJMgV6<-(_Pp!@ zA#jD>e2d<|&BDlek05ICKPi@VIAu~KFL;`x%;yX1Z$>G8hDJfWwhK`Be;~WJ=%Hir z4eI*4DEteuN@cU;-zy{^U;C!_`A1<9*~cw9Kz6$PoG7gqc=UA#RHR{KIAta!&^)UT zr&an4cO6+*ywl!5#jG~$DEH|qRyuZ;n?Kx^wzEe6<1`1t1ms(feqejcW!yZ71|)h6N!Ujeup@(k3V;DEz<>*A zo(z0YtavFq3sKb1NYQb>6O6wjEN1?5j3jnoHcQwlW;2P#S31pKM^+UjY-?{X*rKG* zfwOOJ!c>TR^DfPTohSikd#Jh=%oGH=L+Pb-F3a+te8at9EuYiR8*ipYYw9C4TS7Hk zZk-I*khcwA2e}Cf=%5-Ic$RF)*o8whY9?POTU9qAt#Y7{VeMhtSHYhlYuQ2OD~ zK`_Ve={wN@ zo<=Tc_c_w9j7^VSnVg;sK+w0G{B`f1*-c`vpz7pZ&zsv7&TR7SS_FW3YWk@_)~s&s z)E#^4tG53m`yi#My#OVbR$F=874CT??@;NB4yjm;(JUT_rg9-kCyR zpWU;m!b8-aX?@D+Ah#&^f<6zApY#f|X%J3=E{vYPFv@Z#8o#1yF+k{I)gnm`MLvcJ z++wZ>mrV4Inb6NCAZWKb2+1l#OcpNf;THn-dgHtpcL|!6 z1Tz6GX-@JqJISL>pPMo8Ud5}JQOL*tH69qrlZ;MW@SGNyIz|C!BicEC0~0|hhi^oj zj1x=zS|YuBvy&$}eQ|*QPc+Txn-H8#fnS=dTV}RE`aUE3YW+;T&jd4|gl#!y9O1N5 zU;D?-%qWZzIC6sI<{&qa9@q^hdOy!8UWAI|zL|ZI%!*KE#ccPT%-T;AVjd-{6mzG- zm8}bz>lf3Ugue;?SmC(lUJe}B+{+a`xqdxWeG9julFLWY+;~YvwN04Ruj008J@O@8 z4}a_C-oQbNojl`B+^CQ%fjOll6^%!nREZRnbh%-O0-LzFZs{DZMlo0BwQ^)sThR~v zGC{1Q%dJoNGN8%Bzl{3Js&z_HO3hI7EG1sLi+lf2BkoL{i-dubt`{@WrktcmJVO6l zW_t#Po;u9@-VNjGm_DhOIAV>|wV8n}bRhY;aJq zWbJcsR6v+xR2@pVP=@<9`JMElXIE(#jden}t#a~nMs*hQ*4};Qo?i|3Jx8T0j zue|&@fq)Q-!s*wR9kCS>GTj}tJ@t0}4@z#9{CWOQOFk?K*`5ma97TvDnLRsVFACX< zU~A^7>rdU{eq?^%{6S4{{UZzZ{XT8foN~oHZN8lH&rKIKTdo+VjWF(roTh2hWs7nH z6I)xRw*;*fWUx)}nbEpnt0Qhpy3Y*G3(RdDyL4>P=Abj9Sob3fw(6)O&1YtSq*mLh z!jM^@0cCVX#+WRmf#^UV2#C^Zx-(N81wWw_^V8f?0&(gM@;Q(e*HF05n~lw_Z?y8T1aguw%i`B6ghfaBKvtWiGN6jo6_+ z*P&g9T=Sf|$@%;Gt!A6jURu2uF z>gyk04IN9wBw~^B0DPN$cY>SR5(oIDT1mCUuUfZ%MGlptwIaO&6iWj4kSB=e*)trL z>c=j@?CS4eSiC0IGQJ;cozcJPC?x=dS7^e{QScPvB-EBMyeL8iwRI}}Cu6lHR9IAh ziCXQxw#9Vk)ts3evM%+;i8oJOI~6Hj6DnRa?+h2On;#FSxBGTPbMwIxvqzoTz4i>Nj)eq@C1pv+mTXb$D}ncPY~Lb)pkFbaTiB(uOgcJ zgz*efX_GFgO>RBO*n$S1^YC;aGS>){_zBY~%~`Ba-U7=l@ZGcNEnACz5NOJS? zhxAoQs2K;zHl%8cCXCoo#VHT61yhn|isUMz1C9x~$d>nPr6G8ea#DvcHi;B{*j2&z z)Qk=o;c`a&9-sZ7Iw@(e2+fR?-3Y#bbl(E9w$W{1ZFkYaRGUj~!%3p1rK!I~TZM98 z#~tH!ObD)=xyx_RI~piC=6ke4F3;hs=vlXw_4NSU_K=rN)i%O%jnqcxgW9O1fvr9= z1*y{Gpyhq_s68l!>=+0=L{|1x#?5Vi!ywq^6p8=DM@j91eKSC@|`h9|ME$t}$aY|`difG?|0J>^@9tcsAl0M{ee?iIWC}4GBA=2Y@%5e>WhenZ3wZbJ()u}45&MfbZjf7d+39gr8nh*sQZt6a@+OMpi zUVmll^j6pfY`E5N$66E3D>8o)3+T}cU@I)rCd*$+jPqjcJ1-oqZ>OT8~4Nc z;72_R8xMyI&W1J~o_jX<__4_2Cqj>(2tV!)o<0+P{7j&eT*3T7S8(HDzd2ZNHtH-0 z@ULyXn^QEK3ojqhin`ei0rNfh(jz&V<(-_Sd{w|0EvuXB43;+IuA%t{M{gdzW&9u| z-0%q4CEidj;eo3+-Rg*J?hbA44mR`zpLja>j63oSA9{ulKJJM&Y+KfG4ei{u{lHXm z?v_+WO4fu**34($axRo?i8i+U;LOc4x3WKQh8uUy8fQJJ{s>)xYDi1MHTFqcr3wovm7M)B<)yY{em4ao|~k97vWj zo#Jl|w9Q^zFt15|UbLtC%l!S9j|ch)=#ZE7^vef{^j<*U5$NqdHfHQ7)&02Cu%pfd zE^-%Gn}1Ku{s#)~QBX_Ww2Feiqelj%p8^z2KFXC+5(>1`K-y(r*4)i&3+l7sgL&$} zvR-e$2k1N))4L*s>fy)92rHH=qUIyld1y}KE; z@h|{6k;Yv#F0e{KBz9uMh|)VmR)j49(TXF?Jf0YL$y=+SL65_ncsgJ$rhC>YH#z1* zHU5xi>t%Ld=-9;f^DSuGLF$`AWWf>7tg&SWD&MTVR=Z%Wh*)bwR@giQi$O5Cnb0e= z?5Ss#pFt4cD^d&9q}I`6D&PXK1b&jP_~j(2whGOokyiHoX4E3Sh4x+u5YRa0xZKgNzyAa)!^H2P(rBVwLA7BQt>1dwT7@mE z)+{wol2Vre)#S#(yZhfP0i?74%@Ry;`3V_Gx`4o%<9b7d?1`2*AD%)$k0IA0m#x~X z7IvUXQ=qew-Yxs?@uYoKeHDpTH6o$Z|Hp7Pp9GpdDHzdI_4+BLRXYT_t#O_-p|Yr& z#_mp)rnc&PtJ@*H$3CiYr@7PfHSP>{P=Uf3%w0Rkqc0h>mft$r+Z|9N%A`YwJBw)~ z#N64F8h6g9db?3R$@*<#f*pbiF|i~yYLMNe_zqiTC^r@ z$T?|&kEl#{#ZczCtjQE$7?v|cI!wAIQXX!n4M!^d_eF5X6mZe^G~#T8$y>89&IV>7 zq+Ti<7D7zGIH(@@HaxFylYMkn_I(M^cz6KZR%{u>?h=@;umKDolfz`)1N<@CX<(#* zM}+JAP~RvquNqx0$rcZ@?n?x2nAsT}VH*_fHYn-Bpy#xlqd{be^~2ZT;E)?TlHi$& zzCa8%spQ0T0@s(y;|JlR5L=svK8?+Y*lpt^YA|#Gek)le4|a=0O%w+vuZL}fxJLt6 zwV1CwD0HE@1FjlziyVS=HrgSpM?8)2gm-SBrnb5k#%YE?EWL2*G%I-EB253pv+Y=M z;!Q;v%v*pPg1*Uh3a;Kp~`Z)hDU}Q=sfp$iOtslN(`*=Jfu?0OOAd$6s0x5*( z{Q_I*r>HaI0zha&gaG{SQrsmWou#=&qFLdjf`hVRiF$p2gL~W?tKet@r~+8mNTt!h0u zmM+`xkm|u7L5^n#Wn6(Yd2Ubj)Q_K#WeQoo5=6B40oD$MEOg--F@vjf;o_zx1 zq^X%#j!hqX_34PcJY+AQ-8q*Lw%1Q}MpLt{j7*ON`e&QNsnwCx)uGhY^Sb%&aO%dX z-FHoP-wEH>ro8?qZkr01%$kDI>(xQ#Y~Zei)O*u?`Tnun7HY76?Q~nf$-EjAgNl@0 z1i!3L%sqPj=yyxz*M?wn@YJooTPNnv23>;k7b+^>H6tZPDzUtEXm8y*@a-JF$pQ%mw$fI!n>t*j8Z(D%M2G zw};BNe~=exKN@O38g4%peA*p6c`i8eY`AB;} zz)?RYt9&7WaJrhu%|GMl0jfWrq9|oaC`b{8EknEZyx zn#GdRH@(-qZ$5wR`C#LYaLG8m$vqC;{NTAnvcpAf43Sb#oI~^K4!883eJu`hyXdnMPa`Ia# zAkoN}350D>woeJrdOMZP;Oio#{U#-Ql={m_!K)NkPjSS-=YL2+HeSRW?hEJ6jrYoe z2h5X_uxE)I2D%b%Y|ufXY9&$Ocp5|AN&y|_c%rKDsT8orrqLbI!1xRbm{55p-O3k9uHA)kb*V}c2cm7f@dfo#GLP> zV2FZ$MZxb;@Hz!=Q1BfJ{v!qdH-cEI*wv7H07IPT@6ekl1wW_YR}}m|6nsv>mlT|( z%A7+GGd;fR@Q#DsyLc}}{RzFiOm}_?UZ)^H!5b9JB8YK&`M2odyA-@l!4D{yr{Fyb zKA_;wDfkNtKBC|+Dfk%$zeEtrpcO&>FLpiIv#YCn@4>Ea=CqkPW912hU|vr6NxB=O z;35TN>z}o*v(&fY}21i0*Xh&>gL(B*I$EycsrxFANQArsxw*`X`!{ zztNO`qOp9Uv3{aSWjBb#qaC1^b9|ytT{ddC45VYP9iM0%_w+ih<`X^i|23TLZ#Big z)@r$?Uu*6UmMIQfN=kt*Ct}GDS@HuL!j_6DBb>6O=K2nk``RFOTzlPA3LJR(4_`ex zb2R8`4rjFlH5pNRj+A6w*xrgHwrt-Hk|qh}bcAiYrYuo|W9slLM_)YZw}uUcQ`)F8 zZR*4;XI?zxFAN)tr*v`#|8rqmInq1we7vxC?+QCQr)*2cCpfNjX;eGTaiiSQMO_Y; zyVPRhGL|wOT*h*RowF~w*ke87p61fHtb0`&tu4akhq(ODv<5DJS*Ourm%<&?f0Z{z zj$G%^8{ENbj`U^;&sFl9s+9~o2SNH34StqfxtwdI75mr@H+@vT){&GKO`6(y9x_xh5} z##Jp9>(B<9najABttqSuG*K>C36@kTP}*EZ!?GTXV;ORh{5y&(gs>NEu%Tu_sKFOwUl7_ws7wDpe8Gt?ed=> z(*eQKb>ZyRpvJjmG;>8u*?C;iXB#wn(|^$)3+a!o*h&off$9kGx%{;&8a%A*;1C9L zs)eT>2x~V7HqRBTXmGQVY30iOmPlH8D6M=&gNM%wQPv8~(NqU4k=)gx+|?@@Jgk(Z zahv_Mk&Nn421>%iQj?jhSjo0>g+2^9epU)|xlF%lMT4J})>N*H?(wryzmCfeI#E1+ zSI%>*xOAE%_*pu}>A2M^W&6-S)Q$AJbX2S7>X%YEZo^XMA&zUlcUnu1%&pn@4}%>} z?UZ9V)yS>;{NBMW8nYAF5a)=dr2fuMf(DM?fR!dh*8FFEHAU5Y$=q`OiT*&V=0k_R bORxE>R#O+J`)dtHq2AJ!uKVjW4&na?I0F<% literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe67caeb20c1877fead96275ec67ace195e1a525 GIT binary patch literal 30349 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e73fd480c5b2114d1829789820ae225ec2fd191c GIT binary patch literal 52550 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Ξ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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/compat.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/compat.py new file mode 100644 index 0000000..ca561dd --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/compat.py @@ -0,0 +1,1137 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import absolute_import + +import os +import re +import shutil +import sys + +try: + import ssl +except ImportError: # pragma: no cover + ssl = None + +if sys.version_info[0] < 3: # pragma: no cover + from StringIO import StringIO + string_types = basestring, + text_type = unicode + from types import FileType as file_type + import __builtin__ as builtins + import ConfigParser as configparser + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit + from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, + pathname2url, ContentTooShortError, splittype) + + def quote(s): + if isinstance(s, unicode): + s = s.encode('utf-8') + return _quote(s) + + import urllib2 + from urllib2 import (Request, urlopen, URLError, HTTPError, + HTTPBasicAuthHandler, HTTPPasswordMgr, HTTPHandler, + HTTPRedirectHandler, build_opener) + if ssl: + from urllib2 import HTTPSHandler + import httplib + import xmlrpclib + import Queue as queue + from HTMLParser import HTMLParser + import htmlentitydefs + raw_input = raw_input + from itertools import ifilter as filter + from itertools import ifilterfalse as filterfalse + + # Leaving this around for now, in case it needs resurrecting in some way + # _userprog = None + # def splituser(host): + # """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" + # global _userprog + # if _userprog is None: + # import re + # _userprog = re.compile('^(.*)@(.*)$') + + # match = _userprog.match(host) + # if match: return match.group(1, 2) + # return None, host + +else: # pragma: no cover + from io import StringIO + string_types = str, + text_type = str + from io import TextIOWrapper as file_type + import builtins + import configparser + from urllib.parse import (urlparse, urlunparse, urljoin, quote, unquote, + urlsplit, urlunsplit, splittype) + from urllib.request import (urlopen, urlretrieve, Request, url2pathname, + pathname2url, HTTPBasicAuthHandler, + HTTPPasswordMgr, HTTPHandler, + HTTPRedirectHandler, build_opener) + if ssl: + from urllib.request import HTTPSHandler + from urllib.error import HTTPError, URLError, ContentTooShortError + import http.client as httplib + import urllib.request as urllib2 + import xmlrpc.client as xmlrpclib + import queue + from html.parser import HTMLParser + import html.entities as htmlentitydefs + raw_input = input + from itertools import filterfalse + filter = filter + +try: + from ssl import match_hostname, CertificateError +except ImportError: # pragma: no cover + + class CertificateError(ValueError): + pass + + def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + parts = dn.split('.') + leftmost, remainder = parts[0], parts[1:] + + wildcards = leftmost.count('*') + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) + + def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" % + (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" % + (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") + + +try: + from types import SimpleNamespace as Container +except ImportError: # pragma: no cover + + class Container(object): + """ + A generic container for when multiple values need to be returned + """ + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +try: + from shutil import which +except ImportError: # pragma: no cover + # Implementation from Python 3.3 + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + + """ + + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)) + + # If we're given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to the + # current directory, e.g. ./script + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + # The current directory takes precedence on Windows. + if os.curdir not in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given "python.exe". + # If it does match, only test that one, otherwise we have to try + # others. + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + # On other platforms you don't have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if normdir not in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None + + +# ZipFile is a context manager in 2.7, but not in 2.6 + +from zipfile import ZipFile as BaseZipFile + +if hasattr(BaseZipFile, '__enter__'): # pragma: no cover + ZipFile = BaseZipFile +else: # pragma: no cover + from zipfile import ZipExtFile as BaseZipExtFile + + class ZipExtFile(BaseZipExtFile): + + def __init__(self, base): + self.__dict__.update(base.__dict__) + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + class ZipFile(BaseZipFile): + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + def open(self, *args, **kwargs): + base = BaseZipFile.open(self, *args, **kwargs) + return ZipExtFile(base) + + +try: + from platform import python_implementation +except ImportError: # pragma: no cover + + def python_implementation(): + """Return a string identifying the Python implementation.""" + if 'PyPy' in sys.version: + return 'PyPy' + if os.name == 'java': + return 'Jython' + if sys.version.startswith('IronPython'): + return 'IronPython' + return 'CPython' + + +import sysconfig + +try: + callable = callable +except NameError: # pragma: no cover + from collections.abc import Callable + + def callable(obj): + return isinstance(obj, Callable) + + +try: + fsencode = os.fsencode + fsdecode = os.fsdecode +except AttributeError: # pragma: no cover + # Issue #99: on some systems (e.g. containerised), + # sys.getfilesystemencoding() returns None, and we need a real value, + # so fall back to utf-8. From the CPython 2.7 docs relating to Unix and + # sys.getfilesystemencoding(): the return value is "the user’s preference + # according to the result of nl_langinfo(CODESET), or None if the + # nl_langinfo(CODESET) failed." + _fsencoding = sys.getfilesystemencoding() or 'utf-8' + if _fsencoding == 'mbcs': + _fserrors = 'strict' + else: + _fserrors = 'surrogateescape' + + def fsencode(filename): + if isinstance(filename, bytes): + return filename + elif isinstance(filename, text_type): + return filename.encode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + + def fsdecode(filename): + if isinstance(filename, text_type): + return filename + elif isinstance(filename, bytes): + return filename.decode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + + +try: + from tokenize import detect_encoding +except ImportError: # pragma: no cover + from codecs import BOM_UTF8, lookup + + cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)") + + def _get_normal_name(orig_enc): + """Imitates get_normal_name in tokenizer.c.""" + # Only care about the first 12 characters. + enc = orig_enc[:12].lower().replace("_", "-") + if enc == "utf-8" or enc.startswith("utf-8-"): + return "utf-8" + if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ + enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): + return "iso-8859-1" + return orig_enc + + def detect_encoding(readline): + """ + The detect_encoding() function is used to detect the encoding that should + be used to decode a Python source file. It requires one argument, readline, + in the same way as the tokenize() generator. + + It will call readline a maximum of twice, and return the encoding used + (as a string) and a list of any lines (left as bytes) it has read in. + + It detects the encoding from the presence of a utf-8 bom or an encoding + cookie as specified in pep-0263. If both a bom and a cookie are present, + but disagree, a SyntaxError will be raised. If the encoding cookie is an + invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, + 'utf-8-sig' is returned. + + If no encoding is specified, then the default of 'utf-8' will be returned. + """ + try: + filename = readline.__self__.name + except AttributeError: + filename = None + bom_found = False + encoding = None + default = 'utf-8' + + def read_or_stop(): + try: + return readline() + except StopIteration: + return b'' + + def find_cookie(line): + try: + # Decode as UTF-8. Either the line is an encoding declaration, + # in which case it should be pure ASCII, or it must be UTF-8 + # per default encoding. + line_string = line.decode('utf-8') + except UnicodeDecodeError: + msg = "invalid or missing encoding declaration" + if filename is not None: + msg = '{} for {!r}'.format(msg, filename) + raise SyntaxError(msg) + + matches = cookie_re.findall(line_string) + if not matches: + return None + encoding = _get_normal_name(matches[0]) + try: + codec = lookup(encoding) + except LookupError: + # This behaviour mimics the Python interpreter + if filename is None: + msg = "unknown encoding: " + encoding + else: + msg = "unknown encoding for {!r}: {}".format( + filename, encoding) + raise SyntaxError(msg) + + if bom_found: + if codec.name != 'utf-8': + # This behaviour mimics the Python interpreter + if filename is None: + msg = 'encoding problem: utf-8' + else: + msg = 'encoding problem for {!r}: utf-8'.format( + filename) + raise SyntaxError(msg) + encoding += '-sig' + return encoding + + first = read_or_stop() + if first.startswith(BOM_UTF8): + bom_found = True + first = first[3:] + default = 'utf-8-sig' + if not first: + return default, [] + + encoding = find_cookie(first) + if encoding: + return encoding, [first] + + second = read_or_stop() + if not second: + return default, [first] + + encoding = find_cookie(second) + if encoding: + return encoding, [first, second] + + return default, [first, second] + + +# For converting & <-> & etc. +try: + from html import escape +except ImportError: + from cgi import escape +if sys.version_info[:2] < (3, 4): + unescape = HTMLParser().unescape +else: + from html import unescape + +try: + from collections import ChainMap +except ImportError: # pragma: no cover + from collections import MutableMapping + + try: + from reprlib import recursive_repr as _recursive_repr + except ImportError: + + def _recursive_repr(fillvalue='...'): + ''' + Decorator to make a repr function return fillvalue for a recursive + call + ''' + + def decorating_function(user_function): + repr_running = set() + + def wrapper(self): + key = id(self), get_ident() + if key in repr_running: + return fillvalue + repr_running.add(key) + try: + result = user_function(self) + finally: + repr_running.discard(key) + return result + + # Can't use functools.wraps() here because of bootstrap issues + wrapper.__module__ = getattr(user_function, '__module__') + wrapper.__doc__ = getattr(user_function, '__doc__') + wrapper.__name__ = getattr(user_function, '__name__') + wrapper.__annotations__ = getattr(user_function, + '__annotations__', {}) + return wrapper + + return decorating_function + + class ChainMap(MutableMapping): + ''' + A ChainMap groups multiple dicts (or other mappings) together + to create a single, updateable view. + + The underlying mappings are stored in a list. That list is public and can + accessed or updated using the *maps* attribute. There is no other state. + + Lookups search the underlying mappings successively until a key is found. + In contrast, writes, updates, and deletions only operate on the first + mapping. + ''' + + def __init__(self, *maps): + '''Initialize a ChainMap by setting *maps* to the given mappings. + If no mappings are provided, a single empty dictionary is used. + + ''' + self.maps = list(maps) or [{}] # always at least one map + + def __missing__(self, key): + raise KeyError(key) + + def __getitem__(self, key): + for mapping in self.maps: + try: + return mapping[ + key] # can't use 'key in mapping' with defaultdict + except KeyError: + pass + return self.__missing__( + key) # support subclasses that define __missing__ + + def get(self, key, default=None): + return self[key] if key in self else default + + def __len__(self): + return len(set().union( + *self.maps)) # reuses stored hash values if possible + + def __iter__(self): + return iter(set().union(*self.maps)) + + def __contains__(self, key): + return any(key in m for m in self.maps) + + def __bool__(self): + return any(self.maps) + + @_recursive_repr() + def __repr__(self): + return '{0.__class__.__name__}({1})'.format( + self, ', '.join(map(repr, self.maps))) + + @classmethod + def fromkeys(cls, iterable, *args): + 'Create a ChainMap with a single dict created from the iterable.' + return cls(dict.fromkeys(iterable, *args)) + + def copy(self): + 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' + return self.__class__(self.maps[0].copy(), *self.maps[1:]) + + __copy__ = copy + + def new_child(self): # like Django's Context.push() + 'New ChainMap with a new dict followed by all previous maps.' + return self.__class__({}, *self.maps) + + @property + def parents(self): # like Django's Context.pop() + 'New ChainMap from maps[1:].' + return self.__class__(*self.maps[1:]) + + def __setitem__(self, key, value): + self.maps[0][key] = value + + def __delitem__(self, key): + try: + del self.maps[0][key] + except KeyError: + raise KeyError( + 'Key not found in the first mapping: {!r}'.format(key)) + + def popitem(self): + 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' + try: + return self.maps[0].popitem() + except KeyError: + raise KeyError('No keys found in the first mapping.') + + def pop(self, key, *args): + 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' + try: + return self.maps[0].pop(key, *args) + except KeyError: + raise KeyError( + 'Key not found in the first mapping: {!r}'.format(key)) + + def clear(self): + 'Clear maps[0], leaving maps[1:] intact.' + self.maps[0].clear() + + +try: + from importlib.util import cache_from_source # Python >= 3.4 +except ImportError: # pragma: no cover + + def cache_from_source(path, debug_override=None): + assert path.endswith('.py') + if debug_override is None: + debug_override = __debug__ + if debug_override: + suffix = 'c' + else: + suffix = 'o' + return path + suffix + + +try: + from collections import OrderedDict +except ImportError: # pragma: no cover + # {{{ http://code.activestate.com/recipes/576693/ (r9) + # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. + # Passes Python2.7's test suite and incorporates all the latest updates. + try: + from thread import get_ident as _get_ident + except ImportError: + from dummy_thread import get_ident as _get_ident + + try: + from _abcoll import KeysView, ValuesView, ItemsView + except ImportError: + pass + + class OrderedDict(dict): + 'Dictionary that remembers insertion order' + + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % + len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args), )) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running=None): + 'od.__repr__() <==> repr(od)' + if not _repr_running: + _repr_running = {} + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__, ) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items, ), inst_dict) + return self.__class__, (items, ) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self) == len( + other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + + +try: + from logging.config import BaseConfigurator, valid_ident +except ImportError: # pragma: no cover + IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) + + def valid_ident(s): + m = IDENTIFIER.match(s) + if not m: + raise ValueError('Not a valid Python identifier: %r' % s) + return True + + # The ConvertingXXX classes are wrappers around standard Python containers, + # and they serve to convert any suitable values in the container. The + # conversion converts base dicts, lists and tuples to their wrapped + # equivalents, whereas strings which match a conversion format are converted + # appropriately. + # + # Each wrapper should have a configurator attribute holding the actual + # configurator to use for conversion. + + class ConvertingDict(dict): + """A converting dictionary wrapper.""" + + def __getitem__(self, key): + value = dict.__getitem__(self, key) + result = self.configurator.convert(value) + # If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def get(self, key, default=None): + value = dict.get(self, key, default) + result = self.configurator.convert(value) + # If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, key, default=None): + value = dict.pop(self, key, default) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class ConvertingList(list): + """A converting list wrapper.""" + + def __getitem__(self, key): + value = list.__getitem__(self, key) + result = self.configurator.convert(value) + # If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, idx=-1): + value = list.pop(self, idx) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + return result + + class ConvertingTuple(tuple): + """A converting tuple wrapper.""" + + def __getitem__(self, key): + value = tuple.__getitem__(self, key) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class BaseConfigurator(object): + """ + The configurator base class which defines some useful defaults. + """ + + CONVERT_PATTERN = re.compile(r'^(?P[a-z]+)://(?P.*)$') + + WORD_PATTERN = re.compile(r'^\s*(\w+)\s*') + DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*') + INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*') + DIGIT_PATTERN = re.compile(r'^\d+$') + + value_converters = { + 'ext': 'ext_convert', + 'cfg': 'cfg_convert', + } + + # We might want to use a different one, e.g. importlib + importer = staticmethod(__import__) + + def __init__(self, config): + self.config = ConvertingDict(config) + self.config.configurator = self + + def resolve(self, s): + """ + Resolve strings to objects using standard import and attribute + syntax. + """ + name = s.split('.') + used = name.pop(0) + try: + found = self.importer(used) + for frag in name: + used += '.' + frag + try: + found = getattr(found, frag) + except AttributeError: + self.importer(used) + found = getattr(found, frag) + return found + except ImportError: + e, tb = sys.exc_info()[1:] + v = ValueError('Cannot resolve %r: %s' % (s, e)) + v.__cause__, v.__traceback__ = e, tb + raise v + + def ext_convert(self, value): + """Default converter for the ext:// protocol.""" + return self.resolve(value) + + def cfg_convert(self, value): + """Default converter for the cfg:// protocol.""" + rest = value + m = self.WORD_PATTERN.match(rest) + if m is None: + raise ValueError("Unable to convert %r" % value) + else: + rest = rest[m.end():] + d = self.config[m.groups()[0]] + while rest: + m = self.DOT_PATTERN.match(rest) + if m: + d = d[m.groups()[0]] + else: + m = self.INDEX_PATTERN.match(rest) + if m: + idx = m.groups()[0] + if not self.DIGIT_PATTERN.match(idx): + d = d[idx] + else: + try: + n = int( + idx + ) # try as number first (most likely) + d = d[n] + except TypeError: + d = d[idx] + if m: + rest = rest[m.end():] + else: + raise ValueError('Unable to convert ' + '%r at %r' % (value, rest)) + # rest should be empty + return d + + def convert(self, value): + """ + Convert values to an appropriate type. dicts, lists and tuples are + replaced by their converting alternatives. Strings are checked to + see if they have a conversion format and are converted if they do. + """ + if not isinstance(value, ConvertingDict) and isinstance( + value, dict): + value = ConvertingDict(value) + value.configurator = self + elif not isinstance(value, ConvertingList) and isinstance( + value, list): + value = ConvertingList(value) + value.configurator = self + elif not isinstance(value, ConvertingTuple) and isinstance(value, tuple): + value = ConvertingTuple(value) + value.configurator = self + elif isinstance(value, string_types): + m = self.CONVERT_PATTERN.match(value) + if m: + d = m.groupdict() + prefix = d['prefix'] + converter = self.value_converters.get(prefix, None) + if converter: + suffix = d['suffix'] + converter = getattr(self, converter) + value = converter(suffix) + return value + + def configure_custom(self, config): + """Configure an object with a user-supplied factory.""" + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) + result = c(**kwargs) + if props: + for name, value in props.items(): + setattr(result, name, value) + return result + + def as_tuple(self, value): + """Utility function which converts lists to tuples.""" + if isinstance(value, list): + value = tuple(value) + return value diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/database.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/database.py new file mode 100644 index 0000000..c0f896a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/database.py @@ -0,0 +1,1329 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2023 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""PEP 376 implementation.""" + +from __future__ import unicode_literals + +import base64 +import codecs +import contextlib +import hashlib +import logging +import os +import posixpath +import sys +import zipimport + +from . import DistlibException, resources +from .compat import StringIO +from .version import get_scheme, UnsupportedVersionError +from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME) +from .util import (parse_requirement, cached_property, parse_name_and_version, read_exports, write_exports, CSVReader, + CSVWriter) + +__all__ = [ + 'Distribution', 'BaseInstalledDistribution', 'InstalledDistribution', 'EggInfoDistribution', 'DistributionPath' +] + +logger = logging.getLogger(__name__) + +EXPORTS_FILENAME = 'pydist-exports.json' +COMMANDS_FILENAME = 'pydist-commands.json' + +DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', 'RESOURCES', EXPORTS_FILENAME, 'SHARED') + +DISTINFO_EXT = '.dist-info' + + +class _Cache(object): + """ + A simple cache mapping names and .dist-info paths to distributions + """ + + def __init__(self): + """ + Initialise an instance. There is normally one for each DistributionPath. + """ + self.name = {} + self.path = {} + self.generated = False + + def clear(self): + """ + Clear the cache, setting it to its initial state. + """ + self.name.clear() + self.path.clear() + self.generated = False + + def add(self, dist): + """ + Add a distribution to the cache. + :param dist: The distribution to add. + """ + if dist.path not in self.path: + self.path[dist.path] = dist + self.name.setdefault(dist.key, []).append(dist) + + +class DistributionPath(object): + """ + Represents a set of distributions installed on a path (typically sys.path). + """ + + def __init__(self, path=None, include_egg=False): + """ + Create an instance from a path, optionally including legacy (distutils/ + setuptools/distribute) distributions. + :param path: The path to use, as a list of directories. If not specified, + sys.path is used. + :param include_egg: If True, this instance will look for and return legacy + distributions as well as those based on PEP 376. + """ + if path is None: + path = sys.path + self.path = path + self._include_dist = True + self._include_egg = include_egg + + self._cache = _Cache() + self._cache_egg = _Cache() + self._cache_enabled = True + self._scheme = get_scheme('default') + + def _get_cache_enabled(self): + return self._cache_enabled + + def _set_cache_enabled(self, value): + self._cache_enabled = value + + cache_enabled = property(_get_cache_enabled, _set_cache_enabled) + + def clear_cache(self): + """ + Clears the internal cache. + """ + self._cache.clear() + self._cache_egg.clear() + + def _yield_distributions(self): + """ + Yield .dist-info and/or .egg(-info) distributions. + """ + # We need to check if we've seen some resources already, because on + # some Linux systems (e.g. some Debian/Ubuntu variants) there are + # symlinks which alias other files in the environment. + seen = set() + for path in self.path: + finder = resources.finder_for_path(path) + if finder is None: + continue + r = finder.find('') + if not r or not r.is_container: + continue + rset = sorted(r.resources) + for entry in rset: + r = finder.find(entry) + if not r or r.path in seen: + continue + try: + if self._include_dist and entry.endswith(DISTINFO_EXT): + possible_filenames = [METADATA_FILENAME, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME] + for metadata_filename in possible_filenames: + metadata_path = posixpath.join(entry, metadata_filename) + pydist = finder.find(metadata_path) + if pydist: + break + else: + continue + + with contextlib.closing(pydist.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + logger.debug('Found %s', r.path) + seen.add(r.path) + yield new_dist_class(r.path, metadata=metadata, env=self) + elif self._include_egg and entry.endswith(('.egg-info', '.egg')): + logger.debug('Found %s', r.path) + seen.add(r.path) + yield old_dist_class(r.path, self) + except Exception as e: + msg = 'Unable to read distribution at %s, perhaps due to bad metadata: %s' + logger.warning(msg, r.path, e) + import warnings + warnings.warn(msg % (r.path, e), stacklevel=2) + + def _generate_cache(self): + """ + Scan the path for distributions and populate the cache with + those that are found. + """ + gen_dist = not self._cache.generated + gen_egg = self._include_egg and not self._cache_egg.generated + if gen_dist or gen_egg: + for dist in self._yield_distributions(): + if isinstance(dist, InstalledDistribution): + self._cache.add(dist) + else: + self._cache_egg.add(dist) + + if gen_dist: + self._cache.generated = True + if gen_egg: + self._cache_egg.generated = True + + @classmethod + def distinfo_dirname(cls, name, version): + """ + The *name* and *version* parameters are converted into their + filename-escaped form, i.e. any ``'-'`` characters are replaced + with ``'_'`` other than the one in ``'dist-info'`` and the one + separating the name from the version number. + + :parameter name: is converted to a standard distribution name by replacing + any runs of non- alphanumeric characters with a single + ``'-'``. + :type name: string + :parameter version: is converted to a standard version string. Spaces + become dots, and all other non-alphanumeric characters + (except dots) become dashes, with runs of multiple + dashes condensed to a single dash. + :type version: string + :returns: directory name + :rtype: string""" + name = name.replace('-', '_') + return '-'.join([name, version]) + DISTINFO_EXT + + def get_distributions(self): + """ + Provides an iterator that looks for distributions and returns + :class:`InstalledDistribution` or + :class:`EggInfoDistribution` instances for each one of them. + + :rtype: iterator of :class:`InstalledDistribution` and + :class:`EggInfoDistribution` instances + """ + if not self._cache_enabled: + for dist in self._yield_distributions(): + yield dist + else: + self._generate_cache() + + for dist in self._cache.path.values(): + yield dist + + if self._include_egg: + for dist in self._cache_egg.path.values(): + yield dist + + def get_distribution(self, name): + """ + Looks for a named distribution on the path. + + This function only returns the first result found, as no more than one + value is expected. If nothing is found, ``None`` is returned. + + :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` + or ``None`` + """ + result = None + name = name.lower() + if not self._cache_enabled: + for dist in self._yield_distributions(): + if dist.key == name: + result = dist + break + else: + self._generate_cache() + + if name in self._cache.name: + result = self._cache.name[name][0] + elif self._include_egg and name in self._cache_egg.name: + result = self._cache_egg.name[name][0] + return result + + def provides_distribution(self, name, version=None): + """ + Iterates over all distributions to find which distributions provide *name*. + If a *version* is provided, it will be used to filter the results. + + This function only returns the first result found, since no more than + one values are expected. If the directory is not found, returns ``None``. + + :parameter version: a version specifier that indicates the version + required, conforming to the format in ``PEP-345`` + + :type name: string + :type version: string + """ + matcher = None + if version is not None: + try: + matcher = self._scheme.matcher('%s (%s)' % (name, version)) + except ValueError: + raise DistlibException('invalid name or version: %r, %r' % (name, version)) + + for dist in self.get_distributions(): + # We hit a problem on Travis where enum34 was installed and doesn't + # have a provides attribute ... + if not hasattr(dist, 'provides'): + logger.debug('No "provides": %s', dist) + else: + provided = dist.provides + + for p in provided: + p_name, p_ver = parse_name_and_version(p) + if matcher is None: + if p_name == name: + yield dist + break + else: + if p_name == name and matcher.match(p_ver): + yield dist + break + + def get_file_path(self, name, relative_path): + """ + Return the path to a resource file. + """ + dist = self.get_distribution(name) + if dist is None: + raise LookupError('no distribution named %r found' % name) + return dist.get_resource_path(relative_path) + + def get_exported_entries(self, category, name=None): + """ + Return all of the exported entries in a particular category. + + :param category: The category to search for entries. + :param name: If specified, only entries with that name are returned. + """ + for dist in self.get_distributions(): + r = dist.exports + if category in r: + d = r[category] + if name is not None: + if name in d: + yield d[name] + else: + for v in d.values(): + yield v + + +class Distribution(object): + """ + A base class for distributions, whether installed or from indexes. + Either way, it must have some metadata, so that's all that's needed + for construction. + """ + + build_time_dependency = False + """ + Set to True if it's known to be only a build-time dependency (i.e. + not needed after installation). + """ + + requested = False + """A boolean that indicates whether the ``REQUESTED`` metadata file is + present (in other words, whether the package was installed by user + request or it was installed as a dependency).""" + + def __init__(self, metadata): + """ + Initialise an instance. + :param metadata: The instance of :class:`Metadata` describing this + distribution. + """ + self.metadata = metadata + self.name = metadata.name + self.key = self.name.lower() # for case-insensitive comparisons + self.version = metadata.version + self.locator = None + self.digest = None + self.extras = None # additional features requested + self.context = None # environment marker overrides + self.download_urls = set() + self.digests = {} + + @property + def source_url(self): + """ + The source archive download URL for this distribution. + """ + return self.metadata.source_url + + download_url = source_url # Backward compatibility + + @property + def name_and_version(self): + """ + A utility property which displays the name and version in parentheses. + """ + return '%s (%s)' % (self.name, self.version) + + @property + def provides(self): + """ + A set of distribution names and versions provided by this distribution. + :return: A set of "name (version)" strings. + """ + plist = self.metadata.provides + s = '%s (%s)' % (self.name, self.version) + if s not in plist: + plist.append(s) + return plist + + def _get_requirements(self, req_attr): + md = self.metadata + reqts = getattr(md, req_attr) + logger.debug('%s: got requirements %r from metadata: %r', self.name, req_attr, reqts) + return set(md.get_requirements(reqts, extras=self.extras, env=self.context)) + + @property + def run_requires(self): + return self._get_requirements('run_requires') + + @property + def meta_requires(self): + return self._get_requirements('meta_requires') + + @property + def build_requires(self): + return self._get_requirements('build_requires') + + @property + def test_requires(self): + return self._get_requirements('test_requires') + + @property + def dev_requires(self): + return self._get_requirements('dev_requires') + + def matches_requirement(self, req): + """ + Say if this instance matches (fulfills) a requirement. + :param req: The requirement to match. + :rtype req: str + :return: True if it matches, else False. + """ + # Requirement may contain extras - parse to lose those + # from what's passed to the matcher + r = parse_requirement(req) + scheme = get_scheme(self.metadata.scheme) + try: + matcher = scheme.matcher(r.requirement) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + result = False + for p in self.provides: + p_name, p_ver = parse_name_and_version(p) + if p_name != name: + continue + try: + result = matcher.match(p_ver) + break + except UnsupportedVersionError: + pass + return result + + def __repr__(self): + """ + Return a textual representation of this instance, + """ + if self.source_url: + suffix = ' [%s]' % self.source_url + else: + suffix = '' + return '' % (self.name, self.version, suffix) + + def __eq__(self, other): + """ + See if this distribution is the same as another. + :param other: The distribution to compare with. To be equal to one + another. distributions must have the same type, name, + version and source_url. + :return: True if it is the same, else False. + """ + if type(other) is not type(self): + result = False + else: + result = (self.name == other.name and self.version == other.version and self.source_url == other.source_url) + return result + + def __hash__(self): + """ + Compute hash in a way which matches the equality test. + """ + return hash(self.name) + hash(self.version) + hash(self.source_url) + + +class BaseInstalledDistribution(Distribution): + """ + This is the base class for installed distributions (whether PEP 376 or + legacy). + """ + + hasher = None + + def __init__(self, metadata, path, env=None): + """ + Initialise an instance. + :param metadata: An instance of :class:`Metadata` which describes the + distribution. This will normally have been initialised + from a metadata file in the ``path``. + :param path: The path of the ``.dist-info`` or ``.egg-info`` + directory for the distribution. + :param env: This is normally the :class:`DistributionPath` + instance where this distribution was found. + """ + super(BaseInstalledDistribution, self).__init__(metadata) + self.path = path + self.dist_path = env + + def get_hash(self, data, hasher=None): + """ + Get the hash of some data, using a particular hash algorithm, if + specified. + + :param data: The data to be hashed. + :type data: bytes + :param hasher: The name of a hash implementation, supported by hashlib, + or ``None``. Examples of valid values are ``'sha1'``, + ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and + ``'sha512'``. If no hasher is specified, the ``hasher`` + attribute of the :class:`InstalledDistribution` instance + is used. If the hasher is determined to be ``None``, MD5 + is used as the hashing algorithm. + :returns: The hash of the data. If a hasher was explicitly specified, + the returned hash will be prefixed with the specified hasher + followed by '='. + :rtype: str + """ + if hasher is None: + hasher = self.hasher + if hasher is None: + hasher = hashlib.md5 + prefix = '' + else: + hasher = getattr(hashlib, hasher) + prefix = '%s=' % self.hasher + digest = hasher(data).digest() + digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') + return '%s%s' % (prefix, digest) + + +class InstalledDistribution(BaseInstalledDistribution): + """ + Created with the *path* of the ``.dist-info`` directory provided to the + constructor. It reads the metadata contained in ``pydist.json`` when it is + instantiated., or uses a passed in Metadata instance (useful for when + dry-run mode is being used). + """ + + hasher = 'sha256' + + def __init__(self, path, metadata=None, env=None): + self.modules = [] + self.finder = finder = resources.finder_for_path(path) + if finder is None: + raise ValueError('finder unavailable for %s' % path) + if env and env._cache_enabled and path in env._cache.path: + metadata = env._cache.path[path].metadata + elif metadata is None: + r = finder.find(METADATA_FILENAME) + # Temporary - for Wheel 0.23 support + if r is None: + r = finder.find(WHEEL_METADATA_FILENAME) + # Temporary - for legacy support + if r is None: + r = finder.find(LEGACY_METADATA_FILENAME) + if r is None: + raise ValueError('no %s found in %s' % (METADATA_FILENAME, path)) + with contextlib.closing(r.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + + super(InstalledDistribution, self).__init__(metadata, path, env) + + if env and env._cache_enabled: + env._cache.add(self) + + r = finder.find('REQUESTED') + self.requested = r is not None + p = os.path.join(path, 'top_level.txt') + if os.path.exists(p): + with open(p, 'rb') as f: + data = f.read().decode('utf-8') + self.modules = data.splitlines() + + def __repr__(self): + return '' % (self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def _get_records(self): + """ + Get the list of installed files for the distribution + :return: A list of tuples of path, hash and size. Note that hash and + size might be ``None`` for some entries. The path is exactly + as stored in the file (which is as in PEP 376). + """ + results = [] + r = self.get_distinfo_resource('RECORD') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as record_reader: + # Base location is parent dir of .dist-info dir + # base_location = os.path.dirname(self.path) + # base_location = os.path.abspath(base_location) + for row in record_reader: + missing = [None for i in range(len(row), 3)] + path, checksum, size = row + missing + # if not os.path.isabs(path): + # path = path.replace('/', os.sep) + # path = os.path.join(base_location, path) + results.append((path, checksum, size)) + return results + + @cached_property + def exports(self): + """ + Return the information exported by this distribution. + :return: A dictionary of exports, mapping an export category to a dict + of :class:`ExportEntry` instances describing the individual + export entries, and keyed by name. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + result = self.read_exports() + return result + + def read_exports(self): + """ + Read exports data from a file in .ini format. + + :return: A dictionary of exports, mapping an export category to a list + of :class:`ExportEntry` instances describing the individual + export entries. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + with contextlib.closing(r.as_stream()) as stream: + result = read_exports(stream) + return result + + def write_exports(self, exports): + """ + Write a dictionary of exports to a file in .ini format. + :param exports: A dictionary of exports, mapping an export category to + a list of :class:`ExportEntry` instances describing the + individual export entries. + """ + rf = self.get_distinfo_file(EXPORTS_FILENAME) + with open(rf, 'w') as f: + write_exports(exports, f) + + def get_resource_path(self, relative_path): + """ + NOTE: This API may change in the future. + + Return the absolute path to a resource file with the given relative + path. + + :param relative_path: The path, relative to .dist-info, of the resource + of interest. + :return: The absolute path where the resource is to be found. + """ + r = self.get_distinfo_resource('RESOURCES') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as resources_reader: + for relative, destination in resources_reader: + if relative == relative_path: + return destination + raise KeyError('no resource file with relative path %r ' + 'is installed' % relative_path) + + def list_installed_files(self): + """ + Iterates over the ``RECORD`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: iterator of (path, hash, size) + """ + for result in self._get_records(): + yield result + + def write_installed_files(self, paths, prefix, dry_run=False): + """ + Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any + existing ``RECORD`` file is silently overwritten. + + prefix is used to determine when to write absolute paths. + """ + prefix = os.path.join(prefix, '') + base = os.path.dirname(self.path) + base_under_prefix = base.startswith(prefix) + base = os.path.join(base, '') + record_path = self.get_distinfo_file('RECORD') + logger.info('creating %s', record_path) + if dry_run: + return None + with CSVWriter(record_path) as writer: + for path in paths: + if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')): + # do not put size and hash, as in PEP-376 + hash_value = size = '' + else: + size = '%d' % os.path.getsize(path) + with open(path, 'rb') as fp: + hash_value = self.get_hash(fp.read()) + if path.startswith(base) or (base_under_prefix and path.startswith(prefix)): + path = os.path.relpath(path, base) + writer.writerow((path, hash_value, size)) + + # add the RECORD file itself + if record_path.startswith(base): + record_path = os.path.relpath(record_path, base) + writer.writerow((record_path, '', '')) + return record_path + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + base = os.path.dirname(self.path) + record_path = self.get_distinfo_file('RECORD') + for path, hash_value, size in self.list_installed_files(): + if not os.path.isabs(path): + path = os.path.join(base, path) + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + elif os.path.isfile(path): + actual_size = str(os.path.getsize(path)) + if size and actual_size != size: + mismatches.append((path, 'size', size, actual_size)) + elif hash_value: + if '=' in hash_value: + hasher = hash_value.split('=', 1)[0] + else: + hasher = None + + with open(path, 'rb') as f: + actual_hash = self.get_hash(f.read(), hasher) + if actual_hash != hash_value: + mismatches.append((path, 'hash', hash_value, actual_hash)) + return mismatches + + @cached_property + def shared_locations(self): + """ + A dictionary of shared locations whose keys are in the set 'prefix', + 'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'. + The corresponding value is the absolute path of that category for + this distribution, and takes into account any paths selected by the + user at installation time (e.g. via command-line arguments). In the + case of the 'namespace' key, this would be a list of absolute paths + for the roots of namespace packages in this distribution. + + The first time this property is accessed, the relevant information is + read from the SHARED file in the .dist-info directory. + """ + result = {} + shared_path = os.path.join(self.path, 'SHARED') + if os.path.isfile(shared_path): + with codecs.open(shared_path, 'r', encoding='utf-8') as f: + lines = f.read().splitlines() + for line in lines: + key, value = line.split('=', 1) + if key == 'namespace': + result.setdefault(key, []).append(value) + else: + result[key] = value + return result + + def write_shared_locations(self, paths, dry_run=False): + """ + Write shared location information to the SHARED file in .dist-info. + :param paths: A dictionary as described in the documentation for + :meth:`shared_locations`. + :param dry_run: If True, the action is logged but no file is actually + written. + :return: The path of the file written to. + """ + shared_path = os.path.join(self.path, 'SHARED') + logger.info('creating %s', shared_path) + if dry_run: + return None + lines = [] + for key in ('prefix', 'lib', 'headers', 'scripts', 'data'): + path = paths[key] + if os.path.isdir(paths[key]): + lines.append('%s=%s' % (key, path)) + for ns in paths.get('namespace', ()): + lines.append('namespace=%s' % ns) + + with codecs.open(shared_path, 'w', encoding='utf-8') as f: + f.write('\n'.join(lines)) + return shared_path + + def get_distinfo_resource(self, path): + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + finder = resources.finder_for_path(self.path) + if finder is None: + raise DistlibException('Unable to get a finder for %s' % self.path) + return finder.find(path) + + def get_distinfo_file(self, path): + """ + Returns a path located under the ``.dist-info`` directory. Returns a + string representing the path. + + :parameter path: a ``'/'``-separated path relative to the + ``.dist-info`` directory or an absolute path; + If *path* is an absolute path and doesn't start + with the ``.dist-info`` directory path, + a :class:`DistlibException` is raised + :type path: str + :rtype: str + """ + # Check if it is an absolute path # XXX use relpath, add tests + if path.find(os.sep) >= 0: + # it's an absolute path? + distinfo_dirname, path = path.split(os.sep)[-2:] + if distinfo_dirname != self.path.split(os.sep)[-1]: + raise DistlibException('dist-info file %r does not belong to the %r %s ' + 'distribution' % (path, self.name, self.version)) + + # The file must be relative + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + + return os.path.join(self.path, path) + + def list_distinfo_files(self): + """ + Iterates over the ``RECORD`` entries and returns paths for each line if + the path is pointing to a file located in the ``.dist-info`` directory + or one of its subdirectories. + + :returns: iterator of paths + """ + base = os.path.dirname(self.path) + for path, checksum, size in self._get_records(): + # XXX add separator or use real relpath algo + if not os.path.isabs(path): + path = os.path.join(base, path) + if path.startswith(self.path): + yield path + + def __eq__(self, other): + return (isinstance(other, InstalledDistribution) and self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +class EggInfoDistribution(BaseInstalledDistribution): + """Created with the *path* of the ``.egg-info`` directory or file provided + to the constructor. It reads the metadata contained in the file itself, or + if the given path happens to be a directory, the metadata is read from the + file ``PKG-INFO`` under that directory.""" + + requested = True # as we have no way of knowing, assume it was + shared_locations = {} + + def __init__(self, path, env=None): + + def set_name_and_version(s, n, v): + s.name = n + s.key = n.lower() # for case-insensitive comparisons + s.version = v + + self.path = path + self.dist_path = env + if env and env._cache_enabled and path in env._cache_egg.path: + metadata = env._cache_egg.path[path].metadata + set_name_and_version(self, metadata.name, metadata.version) + else: + metadata = self._get_metadata(path) + + # Need to be set before caching + set_name_and_version(self, metadata.name, metadata.version) + + if env and env._cache_enabled: + env._cache_egg.add(self) + super(EggInfoDistribution, self).__init__(metadata, path, env) + + def _get_metadata(self, path): + requires = None + + def parse_requires_data(data): + """Create a list of dependencies from a requires.txt file. + + *data*: the contents of a setuptools-produced requires.txt file. + """ + reqs = [] + lines = data.splitlines() + for line in lines: + line = line.strip() + # sectioned files have bare newlines (separating sections) + if not line: # pragma: no cover + continue + if line.startswith('['): # pragma: no cover + logger.warning('Unexpected line: quitting requirement scan: %r', line) + break + r = parse_requirement(line) + if not r: # pragma: no cover + logger.warning('Not recognised as a requirement: %r', line) + continue + if r.extras: # pragma: no cover + logger.warning('extra requirements in requires.txt are ' + 'not supported') + if not r.constraints: + reqs.append(r.name) + else: + cons = ', '.join('%s%s' % c for c in r.constraints) + reqs.append('%s (%s)' % (r.name, cons)) + return reqs + + def parse_requires_path(req_path): + """Create a list of dependencies from a requires.txt file. + + *req_path*: the path to a setuptools-produced requires.txt file. + """ + + reqs = [] + try: + with codecs.open(req_path, 'r', 'utf-8') as fp: + reqs = parse_requires_data(fp.read()) + except IOError: + pass + return reqs + + tl_path = tl_data = None + if path.endswith('.egg'): + if os.path.isdir(path): + p = os.path.join(path, 'EGG-INFO') + meta_path = os.path.join(p, 'PKG-INFO') + metadata = Metadata(path=meta_path, scheme='legacy') + req_path = os.path.join(p, 'requires.txt') + tl_path = os.path.join(p, 'top_level.txt') + requires = parse_requires_path(req_path) + else: + # FIXME handle the case where zipfile is not available + zipf = zipimport.zipimporter(path) + fileobj = StringIO(zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) + metadata = Metadata(fileobj=fileobj, scheme='legacy') + try: + data = zipf.get_data('EGG-INFO/requires.txt') + tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode('utf-8') + requires = parse_requires_data(data.decode('utf-8')) + except IOError: + requires = None + elif path.endswith('.egg-info'): + if os.path.isdir(path): + req_path = os.path.join(path, 'requires.txt') + requires = parse_requires_path(req_path) + path = os.path.join(path, 'PKG-INFO') + tl_path = os.path.join(path, 'top_level.txt') + metadata = Metadata(path=path, scheme='legacy') + else: + raise DistlibException('path must end with .egg-info or .egg, ' + 'got %r' % path) + + if requires: + metadata.add_requirements(requires) + # look for top-level modules in top_level.txt, if present + if tl_data is None: + if tl_path is not None and os.path.exists(tl_path): + with open(tl_path, 'rb') as f: + tl_data = f.read().decode('utf-8') + if not tl_data: + tl_data = [] + else: + tl_data = tl_data.splitlines() + self.modules = tl_data + return metadata + + def __repr__(self): + return '' % (self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + for path, _, _ in self.list_installed_files(): + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + return mismatches + + def list_installed_files(self): + """ + Iterates over the ``installed-files.txt`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: a list of (path, hash, size) + """ + + def _md5(path): + f = open(path, 'rb') + try: + content = f.read() + finally: + f.close() + return hashlib.md5(content).hexdigest() + + def _size(path): + return os.stat(path).st_size + + record_path = os.path.join(self.path, 'installed-files.txt') + result = [] + if os.path.exists(record_path): + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + p = os.path.normpath(os.path.join(self.path, line)) + # "./" is present as a marker between installed files + # and installation metadata files + if not os.path.exists(p): + logger.warning('Non-existent file: %s', p) + if p.endswith(('.pyc', '.pyo')): + continue + # otherwise fall through and fail + if not os.path.isdir(p): + result.append((p, _md5(p), _size(p))) + result.append((record_path, None, None)) + return result + + def list_distinfo_files(self, absolute=False): + """ + Iterates over the ``installed-files.txt`` entries and returns paths for + each line if the path is pointing to a file located in the + ``.egg-info`` directory or one of its subdirectories. + + :parameter absolute: If *absolute* is ``True``, each returned path is + transformed into a local absolute path. Otherwise the + raw value from ``installed-files.txt`` is returned. + :type absolute: boolean + :returns: iterator of paths + """ + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + skip = True + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line == './': + skip = False + continue + if not skip: + p = os.path.normpath(os.path.join(self.path, line)) + if p.startswith(self.path): + if absolute: + yield p + else: + yield line + + def __eq__(self, other): + return (isinstance(other, EggInfoDistribution) and self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +new_dist_class = InstalledDistribution +old_dist_class = EggInfoDistribution + + +class DependencyGraph(object): + """ + Represents a dependency graph between distributions. + + The dependency relationships are stored in an ``adjacency_list`` that maps + distributions to a list of ``(other, label)`` tuples where ``other`` + is a distribution and the edge is labeled with ``label`` (i.e. the version + specifier, if such was provided). Also, for more efficient traversal, for + every distribution ``x``, a list of predecessors is kept in + ``reverse_list[x]``. An edge from distribution ``a`` to + distribution ``b`` means that ``a`` depends on ``b``. If any missing + dependencies are found, they are stored in ``missing``, which is a + dictionary that maps distributions to a list of requirements that were not + provided by any other distributions. + """ + + def __init__(self): + self.adjacency_list = {} + self.reverse_list = {} + self.missing = {} + + def add_distribution(self, distribution): + """Add the *distribution* to the graph. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + """ + self.adjacency_list[distribution] = [] + self.reverse_list[distribution] = [] + # self.missing[distribution] = [] + + def add_edge(self, x, y, label=None): + """Add an edge from distribution *x* to distribution *y* with the given + *label*. + + :type x: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type y: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type label: ``str`` or ``None`` + """ + self.adjacency_list[x].append((y, label)) + # multiple edges are allowed, so be careful + if x not in self.reverse_list[y]: + self.reverse_list[y].append(x) + + def add_missing(self, distribution, requirement): + """ + Add a missing *requirement* for the given *distribution*. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + :type requirement: ``str`` + """ + logger.debug('%s missing %r', distribution, requirement) + self.missing.setdefault(distribution, []).append(requirement) + + def _repr_dist(self, dist): + return '%s %s' % (dist.name, dist.version) + + def repr_node(self, dist, level=1): + """Prints only a subgraph""" + output = [self._repr_dist(dist)] + for other, label in self.adjacency_list[dist]: + dist = self._repr_dist(other) + if label is not None: + dist = '%s [%s]' % (dist, label) + output.append(' ' * level + str(dist)) + suboutput = self.repr_node(other, level + 1) + subs = suboutput.split('\n') + output.extend(subs[1:]) + return '\n'.join(output) + + def to_dot(self, f, skip_disconnected=True): + """Writes a DOT output for the graph to the provided file *f*. + + If *skip_disconnected* is set to ``True``, then all distributions + that are not dependent on any other distribution are skipped. + + :type f: has to support ``file``-like operations + :type skip_disconnected: ``bool`` + """ + disconnected = [] + + f.write("digraph dependencies {\n") + for dist, adjs in self.adjacency_list.items(): + if len(adjs) == 0 and not skip_disconnected: + disconnected.append(dist) + for other, label in adjs: + if label is not None: + f.write('"%s" -> "%s" [label="%s"]\n' % (dist.name, other.name, label)) + else: + f.write('"%s" -> "%s"\n' % (dist.name, other.name)) + if not skip_disconnected and len(disconnected) > 0: + f.write('subgraph disconnected {\n') + f.write('label = "Disconnected"\n') + f.write('bgcolor = red\n') + + for dist in disconnected: + f.write('"%s"' % dist.name) + f.write('\n') + f.write('}\n') + f.write('}\n') + + def topological_sort(self): + """ + Perform a topological sort of the graph. + :return: A tuple, the first element of which is a topologically sorted + list of distributions, and the second element of which is a + list of distributions that cannot be sorted because they have + circular dependencies and so form a cycle. + """ + result = [] + # Make a shallow copy of the adjacency list + alist = {} + for k, v in self.adjacency_list.items(): + alist[k] = v[:] + while True: + # See what we can remove in this run + to_remove = [] + for k, v in list(alist.items())[:]: + if not v: + to_remove.append(k) + del alist[k] + if not to_remove: + # What's left in alist (if anything) is a cycle. + break + # Remove from the adjacency list of others + for k, v in alist.items(): + alist[k] = [(d, r) for d, r in v if d not in to_remove] + logger.debug('Moving to result: %s', ['%s (%s)' % (d.name, d.version) for d in to_remove]) + result.extend(to_remove) + return result, list(alist.keys()) + + def __repr__(self): + """Representation of the graph""" + output = [] + for dist, adjs in self.adjacency_list.items(): + output.append(self.repr_node(dist)) + return '\n'.join(output) + + +def make_graph(dists, scheme='default'): + """Makes a dependency graph from the given distributions. + + :parameter dists: a list of distributions + :type dists: list of :class:`distutils2.database.InstalledDistribution` and + :class:`distutils2.database.EggInfoDistribution` instances + :rtype: a :class:`DependencyGraph` instance + """ + scheme = get_scheme(scheme) + graph = DependencyGraph() + provided = {} # maps names to lists of (version, dist) tuples + + # first, build the graph and find out what's provided + for dist in dists: + graph.add_distribution(dist) + + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + provided.setdefault(name, []).append((version, dist)) + + # now make the edges + for dist in dists: + requires = (dist.run_requires | dist.meta_requires | dist.build_requires | dist.dev_requires) + for req in requires: + try: + matcher = scheme.matcher(req) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + matched = False + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + graph.add_edge(dist, provider, req) + matched = True + break + if not matched: + graph.add_missing(dist, req) + return graph + + +def get_dependent_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + dependent on *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + dep = [dist] # dependent distributions + todo = graph.reverse_list[dist] # list of nodes we should inspect + + while todo: + d = todo.pop() + dep.append(d) + for succ in graph.reverse_list[d]: + if succ not in dep: + todo.append(succ) + + dep.pop(0) # remove dist from dep, was there to prevent infinite loops + return dep + + +def get_required_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + required by *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + in finding the dependencies. + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + req = set() # required distributions + todo = graph.adjacency_list[dist] # list of nodes we should inspect + seen = set(t[0] for t in todo) # already added to todo + + while todo: + d = todo.pop()[0] + req.add(d) + pred_list = graph.adjacency_list[d] + for pred in pred_list: + d = pred[0] + if d not in req and d not in seen: + seen.add(d) + todo.append(pred) + return req + + +def make_dist(name, version, **kwargs): + """ + A convenience method for making a dist given just a name and version. + """ + summary = kwargs.pop('summary', 'Placeholder for summary') + md = Metadata(**kwargs) + md.name = name + md.version = version + md.summary = summary or 'Placeholder for summary' + return Distribution(md) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/index.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/index.py new file mode 100644 index 0000000..56cd286 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/index.py @@ -0,0 +1,508 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2023 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import hashlib +import logging +import os +import shutil +import subprocess +import tempfile +try: + from threading import Thread +except ImportError: # pragma: no cover + from dummy_threading import Thread + +from . import DistlibException +from .compat import (HTTPBasicAuthHandler, Request, HTTPPasswordMgr, + urlparse, build_opener, string_types) +from .util import zip_dir, ServerProxy + +logger = logging.getLogger(__name__) + +DEFAULT_INDEX = 'https://pypi.org/pypi' +DEFAULT_REALM = 'pypi' + + +class PackageIndex(object): + """ + This class represents a package index compatible with PyPI, the Python + Package Index. + """ + + boundary = b'----------ThIs_Is_tHe_distlib_index_bouNdaRY_$' + + def __init__(self, url=None): + """ + Initialise an instance. + + :param url: The URL of the index. If not specified, the URL for PyPI is + used. + """ + self.url = url or DEFAULT_INDEX + self.read_configuration() + scheme, netloc, path, params, query, frag = urlparse(self.url) + if params or query or frag or scheme not in ('http', 'https'): + raise DistlibException('invalid repository: %s' % self.url) + self.password_handler = None + self.ssl_verifier = None + self.gpg = None + self.gpg_home = None + with open(os.devnull, 'w') as sink: + # Use gpg by default rather than gpg2, as gpg2 insists on + # prompting for passwords + for s in ('gpg', 'gpg2'): + try: + rc = subprocess.check_call([s, '--version'], stdout=sink, + stderr=sink) + if rc == 0: + self.gpg = s + break + except OSError: + pass + + def _get_pypirc_command(self): + """ + Get the distutils command for interacting with PyPI configurations. + :return: the command. + """ + from .util import _get_pypirc_command as cmd + return cmd() + + def read_configuration(self): + """ + Read the PyPI access configuration as supported by distutils. This populates + ``username``, ``password``, ``realm`` and ``url`` attributes from the + configuration. + """ + from .util import _load_pypirc + cfg = _load_pypirc(self) + self.username = cfg.get('username') + self.password = cfg.get('password') + self.realm = cfg.get('realm', 'pypi') + self.url = cfg.get('repository', self.url) + + def save_configuration(self): + """ + Save the PyPI access configuration. You must have set ``username`` and + ``password`` attributes before calling this method. + """ + self.check_credentials() + from .util import _store_pypirc + _store_pypirc(self) + + def check_credentials(self): + """ + Check that ``username`` and ``password`` have been set, and raise an + exception if not. + """ + if self.username is None or self.password is None: + raise DistlibException('username and password must be set') + pm = HTTPPasswordMgr() + _, netloc, _, _, _, _ = urlparse(self.url) + pm.add_password(self.realm, netloc, self.username, self.password) + self.password_handler = HTTPBasicAuthHandler(pm) + + def register(self, metadata): # pragma: no cover + """ + Register a distribution on PyPI, using the provided metadata. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the distribution to be + registered. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + metadata.validate() + d = metadata.todict() + d[':action'] = 'verify' + request = self.encode_request(d.items(), []) + self.send_request(request) + d[':action'] = 'submit' + request = self.encode_request(d.items(), []) + return self.send_request(request) + + def _reader(self, name, stream, outbuf): + """ + Thread runner for reading lines of from a subprocess into a buffer. + + :param name: The logical name of the stream (used for logging only). + :param stream: The stream to read from. This will typically a pipe + connected to the output stream of a subprocess. + :param outbuf: The list to append the read lines to. + """ + while True: + s = stream.readline() + if not s: + break + s = s.decode('utf-8').rstrip() + outbuf.append(s) + logger.debug('%s: %s' % (name, s)) + stream.close() + + def get_sign_command(self, filename, signer, sign_password, keystore=None): # pragma: no cover + """ + Return a suitable command for signing a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The signing command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + if sign_password is not None: + cmd.extend(['--batch', '--passphrase-fd', '0']) + td = tempfile.mkdtemp() + sf = os.path.join(td, os.path.basename(filename) + '.asc') + cmd.extend(['--detach-sign', '--armor', '--local-user', + signer, '--output', sf, filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd, sf + + def run_command(self, cmd, input_data=None): + """ + Run a command in a child process , passing it any input data specified. + + :param cmd: The command to run. + :param input_data: If specified, this must be a byte string containing + data to be sent to the child process. + :return: A tuple consisting of the subprocess' exit code, a list of + lines read from the subprocess' ``stdout``, and a list of + lines read from the subprocess' ``stderr``. + """ + kwargs = { + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + } + if input_data is not None: + kwargs['stdin'] = subprocess.PIPE + stdout = [] + stderr = [] + p = subprocess.Popen(cmd, **kwargs) + # We don't use communicate() here because we may need to + # get clever with interacting with the command + t1 = Thread(target=self._reader, args=('stdout', p.stdout, stdout)) + t1.start() + t2 = Thread(target=self._reader, args=('stderr', p.stderr, stderr)) + t2.start() + if input_data is not None: + p.stdin.write(input_data) + p.stdin.close() + + p.wait() + t1.join() + t2.join() + return p.returncode, stdout, stderr + + def sign_file(self, filename, signer, sign_password, keystore=None): # pragma: no cover + """ + Sign a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The absolute pathname of the file where the signature is + stored. + """ + cmd, sig_file = self.get_sign_command(filename, signer, sign_password, + keystore) + rc, stdout, stderr = self.run_command(cmd, + sign_password.encode('utf-8')) + if rc != 0: + raise DistlibException('sign command failed with error ' + 'code %s' % rc) + return sig_file + + def upload_file(self, metadata, filename, signer=None, sign_password=None, + filetype='sdist', pyversion='source', keystore=None): + """ + Upload a release file to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the file to be uploaded. + :param filename: The pathname of the file to be uploaded. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param filetype: The type of the file being uploaded. This is the + distutils command which produced that file, e.g. + ``sdist`` or ``bdist_wheel``. + :param pyversion: The version of Python which the release relates + to. For code compatible with any Python, this would + be ``source``, otherwise it would be e.g. ``3.2``. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.exists(filename): + raise DistlibException('not found: %s' % filename) + metadata.validate() + d = metadata.todict() + sig_file = None + if signer: + if not self.gpg: + logger.warning('no signing program available - not signed') + else: + sig_file = self.sign_file(filename, signer, sign_password, + keystore) + with open(filename, 'rb') as f: + file_data = f.read() + md5_digest = hashlib.md5(file_data).hexdigest() + sha256_digest = hashlib.sha256(file_data).hexdigest() + d.update({ + ':action': 'file_upload', + 'protocol_version': '1', + 'filetype': filetype, + 'pyversion': pyversion, + 'md5_digest': md5_digest, + 'sha256_digest': sha256_digest, + }) + files = [('content', os.path.basename(filename), file_data)] + if sig_file: + with open(sig_file, 'rb') as f: + sig_data = f.read() + files.append(('gpg_signature', os.path.basename(sig_file), + sig_data)) + shutil.rmtree(os.path.dirname(sig_file)) + request = self.encode_request(d.items(), files) + return self.send_request(request) + + def upload_documentation(self, metadata, doc_dir): # pragma: no cover + """ + Upload documentation to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the documentation to be + uploaded. + :param doc_dir: The pathname of the directory which contains the + documentation. This should be the directory that + contains the ``index.html`` for the documentation. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.isdir(doc_dir): + raise DistlibException('not a directory: %r' % doc_dir) + fn = os.path.join(doc_dir, 'index.html') + if not os.path.exists(fn): + raise DistlibException('not found: %r' % fn) + metadata.validate() + name, version = metadata.name, metadata.version + zip_data = zip_dir(doc_dir).getvalue() + fields = [(':action', 'doc_upload'), + ('name', name), ('version', version)] + files = [('content', name, zip_data)] + request = self.encode_request(fields, files) + return self.send_request(request) + + def get_verify_command(self, signature_filename, data_filename, + keystore=None): + """ + Return a suitable command for verifying a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The verifying command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + cmd.extend(['--verify', signature_filename, data_filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd + + def verify_signature(self, signature_filename, data_filename, + keystore=None): + """ + Verify a signature for a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: True if the signature was verified, else False. + """ + if not self.gpg: + raise DistlibException('verification unavailable because gpg ' + 'unavailable') + cmd = self.get_verify_command(signature_filename, data_filename, + keystore) + rc, stdout, stderr = self.run_command(cmd) + if rc not in (0, 1): + raise DistlibException('verify command failed with error code %s' % rc) + return rc == 0 + + def download_file(self, url, destfile, digest=None, reporthook=None): + """ + This is a convenience method for downloading a file from an URL. + Normally, this will be a file from the index, though currently + no check is made for this (i.e. a file can be downloaded from + anywhere). + + The method is just like the :func:`urlretrieve` function in the + standard library, except that it allows digest computation to be + done during download and checking that the downloaded data + matched any expected value. + + :param url: The URL of the file to be downloaded (assumed to be + available via an HTTP GET request). + :param destfile: The pathname where the downloaded file is to be + saved. + :param digest: If specified, this must be a (hasher, value) + tuple, where hasher is the algorithm used (e.g. + ``'md5'``) and ``value`` is the expected value. + :param reporthook: The same as for :func:`urlretrieve` in the + standard library. + """ + if digest is None: + digester = None + logger.debug('No digest specified') + else: + if isinstance(digest, (list, tuple)): + hasher, digest = digest + else: + hasher = 'md5' + digester = getattr(hashlib, hasher)() + logger.debug('Digest specified: %s' % digest) + # The following code is equivalent to urlretrieve. + # We need to do it this way so that we can compute the + # digest of the file as we go. + with open(destfile, 'wb') as dfp: + # addinfourl is not a context manager on 2.x + # so we have to use try/finally + sfp = self.send_request(Request(url)) + try: + headers = sfp.info() + blocksize = 8192 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + if reporthook: + reporthook(blocknum, blocksize, size) + while True: + block = sfp.read(blocksize) + if not block: + break + read += len(block) + dfp.write(block) + if digester: + digester.update(block) + blocknum += 1 + if reporthook: + reporthook(blocknum, blocksize, size) + finally: + sfp.close() + + # check that we got the whole file, if we can + if size >= 0 and read < size: + raise DistlibException( + 'retrieval incomplete: got only %d out of %d bytes' + % (read, size)) + # if we have a digest, it must match. + if digester: + actual = digester.hexdigest() + if digest != actual: + raise DistlibException('%s digest mismatch for %s: expected ' + '%s, got %s' % (hasher, destfile, + digest, actual)) + logger.debug('Digest verified: %s', digest) + + def send_request(self, req): + """ + Send a standard library :class:`Request` to PyPI and return its + response. + + :param req: The request to send. + :return: The HTTP response from PyPI (a standard library HTTPResponse). + """ + handlers = [] + if self.password_handler: + handlers.append(self.password_handler) + if self.ssl_verifier: + handlers.append(self.ssl_verifier) + opener = build_opener(*handlers) + return opener.open(req) + + def encode_request(self, fields, files): + """ + Encode fields and files for posting to an HTTP server. + + :param fields: The fields to send as a list of (fieldname, value) + tuples. + :param files: The files to send as a list of (fieldname, filename, + file_bytes) tuple. + """ + # Adapted from packaging, which in turn was adapted from + # http://code.activestate.com/recipes/146306 + + parts = [] + boundary = self.boundary + for k, values in fields: + if not isinstance(values, (list, tuple)): + values = [values] + + for v in values: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"' % + k).encode('utf-8'), + b'', + v.encode('utf-8'))) + for key, filename, value in files: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)).encode('utf-8'), + b'', + value)) + + parts.extend((b'--' + boundary + b'--', b'')) + + body = b'\r\n'.join(parts) + ct = b'multipart/form-data; boundary=' + boundary + headers = { + 'Content-type': ct, + 'Content-length': str(len(body)) + } + return Request(self.url, body, headers) + + def search(self, terms, operator=None): # pragma: no cover + if isinstance(terms, string_types): + terms = {'name': terms} + rpc_proxy = ServerProxy(self.url, timeout=3.0) + try: + return rpc_proxy.search(terms, operator or 'and') + finally: + rpc_proxy('close')() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/locators.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/locators.py new file mode 100644 index 0000000..222c1bf --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/locators.py @@ -0,0 +1,1295 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2023 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# + +import gzip +from io import BytesIO +import json +import logging +import os +import posixpath +import re +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import zlib + +from . import DistlibException +from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, queue, quote, unescape, build_opener, + HTTPRedirectHandler as BaseRedirectHandler, text_type, Request, HTTPError, URLError) +from .database import Distribution, DistributionPath, make_dist +from .metadata import Metadata, MetadataInvalidError +from .util import (cached_property, ensure_slash, split_filename, get_project_data, parse_requirement, + parse_name_and_version, ServerProxy, normalize_name) +from .version import get_scheme, UnsupportedVersionError +from .wheel import Wheel, is_compatible + +logger = logging.getLogger(__name__) + +HASHER_HASH = re.compile(r'^(\w+)=([a-f0-9]+)') +CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I) +HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml') +DEFAULT_INDEX = 'https://pypi.org/pypi' + + +def get_all_distribution_names(url=None): + """ + Return all distribution names known by an index. + :param url: The URL of the index. + :return: A list of all known distribution names. + """ + if url is None: + url = DEFAULT_INDEX + client = ServerProxy(url, timeout=3.0) + try: + return client.list_packages() + finally: + client('close')() + + +class RedirectHandler(BaseRedirectHandler): + """ + A class to work around a bug in some Python 3.2.x releases. + """ + + # There's a bug in the base version for some 3.2.x + # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header + # returns e.g. /abc, it bails because it says the scheme '' + # is bogus, when actually it should use the request's + # URL for the scheme. See Python issue #13696. + def http_error_302(self, req, fp, code, msg, headers): + # Some servers (incorrectly) return multiple Location headers + # (so probably same goes for URI). Use first header. + newurl = None + for key in ('location', 'uri'): + if key in headers: + newurl = headers[key] + break + if newurl is None: # pragma: no cover + return + urlparts = urlparse(newurl) + if urlparts.scheme == '': + newurl = urljoin(req.get_full_url(), newurl) + if hasattr(headers, 'replace_header'): + headers.replace_header(key, newurl) + else: + headers[key] = newurl + return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, headers) + + http_error_301 = http_error_303 = http_error_307 = http_error_302 + + +class Locator(object): + """ + A base class for locators - things that locate distributions. + """ + source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz') + binary_extensions = ('.egg', '.exe', '.whl') + excluded_extensions = ('.pdf', ) + + # A list of tags indicating which wheels you want to match. The default + # value of None matches against the tags compatible with the running + # Python. If you want to match other values, set wheel_tags on a locator + # instance to a list of tuples (pyver, abi, arch) which you want to match. + wheel_tags = None + + downloadable_extensions = source_extensions + ('.whl', ) + + def __init__(self, scheme='default'): + """ + Initialise an instance. + :param scheme: Because locators look for most recent versions, they + need to know the version scheme to use. This specifies + the current PEP-recommended scheme - use ``'legacy'`` + if you need to support existing distributions on PyPI. + """ + self._cache = {} + self.scheme = scheme + # Because of bugs in some of the handlers on some of the platforms, + # we use our own opener rather than just using urlopen. + self.opener = build_opener(RedirectHandler()) + # If get_project() is called from locate(), the matcher instance + # is set from the requirement passed to locate(). See issue #18 for + # why this can be useful to know. + self.matcher = None + self.errors = queue.Queue() + + def get_errors(self): + """ + Return any errors which have occurred. + """ + result = [] + while not self.errors.empty(): # pragma: no cover + try: + e = self.errors.get(False) + result.append(e) + except self.errors.Empty: + continue + self.errors.task_done() + return result + + def clear_errors(self): + """ + Clear any errors which may have been logged. + """ + # Just get the errors and throw them away + self.get_errors() + + def clear_cache(self): + self._cache.clear() + + def _get_scheme(self): + return self._scheme + + def _set_scheme(self, value): + self._scheme = value + + scheme = property(_get_scheme, _set_scheme) + + def _get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This should be implemented in subclasses. + + If called from a locate() request, self.matcher will be set to a + matcher for the requirement to satisfy, otherwise it will be None. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This calls _get_project to do all the work, and just implements a caching layer on top. + """ + if self._cache is None: # pragma: no cover + result = self._get_project(name) + elif name in self._cache: + result = self._cache[name] + else: + self.clear_errors() + result = self._get_project(name) + self._cache[name] = result + return result + + def score_url(self, url): + """ + Give an url a score which can be used to choose preferred URLs + for a given project release. + """ + t = urlparse(url) + basename = posixpath.basename(t.path) + compatible = True + is_wheel = basename.endswith('.whl') + is_downloadable = basename.endswith(self.downloadable_extensions) + if is_wheel: + compatible = is_compatible(Wheel(basename), self.wheel_tags) + return (t.scheme == 'https', 'pypi.org' in t.netloc, is_downloadable, is_wheel, compatible, basename) + + def prefer_url(self, url1, url2): + """ + Choose one of two URLs where both are candidates for distribution + archives for the same version of a distribution (for example, + .tar.gz vs. zip). + + The current implementation favours https:// URLs over http://, archives + from PyPI over those from other locations, wheel compatibility (if a + wheel) and then the archive name. + """ + result = url2 + if url1: + s1 = self.score_url(url1) + s2 = self.score_url(url2) + if s1 > s2: + result = url1 + if result != url2: + logger.debug('Not replacing %r with %r', url1, url2) + else: + logger.debug('Replacing %r with %r', url1, url2) + return result + + def split_filename(self, filename, project_name): + """ + Attempt to split a filename in project name, version and Python version. + """ + return split_filename(filename, project_name) + + def convert_url_to_download_info(self, url, project_name): + """ + See if a URL is a candidate for a download URL for a project (the URL + has typically been scraped from an HTML page). + + If it is, a dictionary is returned with keys "name", "version", + "filename" and "url"; otherwise, None is returned. + """ + + def same_project(name1, name2): + return normalize_name(name1) == normalize_name(name2) + + result = None + scheme, netloc, path, params, query, frag = urlparse(url) + if frag.lower().startswith('egg='): # pragma: no cover + logger.debug('%s: version hint in fragment: %r', project_name, frag) + m = HASHER_HASH.match(frag) + if m: + algo, digest = m.groups() + else: + algo, digest = None, None + origpath = path + if path and path[-1] == '/': # pragma: no cover + path = path[:-1] + if path.endswith('.whl'): + try: + wheel = Wheel(path) + if not is_compatible(wheel, self.wheel_tags): + logger.debug('Wheel not compatible: %s', path) + else: + if project_name is None: + include = True + else: + include = same_project(wheel.name, project_name) + if include: + result = { + 'name': wheel.name, + 'version': wheel.version, + 'filename': wheel.filename, + 'url': urlunparse((scheme, netloc, origpath, params, query, '')), + 'python-version': ', '.join(['.'.join(list(v[2:])) for v in wheel.pyver]), + } + except Exception: # pragma: no cover + logger.warning('invalid path for wheel: %s', path) + elif not path.endswith(self.downloadable_extensions): # pragma: no cover + logger.debug('Not downloadable: %s', path) + else: # downloadable extension + path = filename = posixpath.basename(path) + for ext in self.downloadable_extensions: + if path.endswith(ext): + path = path[:-len(ext)] + t = self.split_filename(path, project_name) + if not t: # pragma: no cover + logger.debug('No match for project/version: %s', path) + else: + name, version, pyver = t + if not project_name or same_project(project_name, name): + result = { + 'name': name, + 'version': version, + 'filename': filename, + 'url': urlunparse((scheme, netloc, origpath, params, query, '')), + } + if pyver: # pragma: no cover + result['python-version'] = pyver + break + if result and algo: + result['%s_digest' % algo] = digest + return result + + def _get_digest(self, info): + """ + Get a digest from a dictionary by looking at a "digests" dictionary + or keys of the form 'algo_digest'. + + Returns a 2-tuple (algo, digest) if found, else None. Currently + looks only for SHA256, then MD5. + """ + result = None + if 'digests' in info: + digests = info['digests'] + for algo in ('sha256', 'md5'): + if algo in digests: + result = (algo, digests[algo]) + break + if not result: + for algo in ('sha256', 'md5'): + key = '%s_digest' % algo + if key in info: + result = (algo, info[key]) + break + return result + + def _update_version_data(self, result, info): + """ + Update a result dictionary (the final result from _get_project) with a + dictionary for a specific version, which typically holds information + gleaned from a filename or URL for an archive for the distribution. + """ + name = info.pop('name') + version = info.pop('version') + if version in result: + dist = result[version] + md = dist.metadata + else: + dist = make_dist(name, version, scheme=self.scheme) + md = dist.metadata + dist.digest = digest = self._get_digest(info) + url = info['url'] + result['digests'][url] = digest + if md.source_url != info['url']: + md.source_url = self.prefer_url(md.source_url, url) + result['urls'].setdefault(version, set()).add(url) + dist.locator = self + result[version] = dist + + def locate(self, requirement, prereleases=False): + """ + Find the most recent distribution which matches the given + requirement. + + :param requirement: A requirement of the form 'foo (1.0)' or perhaps + 'foo (>= 1.0, < 2.0, != 1.3)' + :param prereleases: If ``True``, allow pre-release versions + to be located. Otherwise, pre-release versions + are not returned. + :return: A :class:`Distribution` instance, or ``None`` if no such + distribution could be located. + """ + result = None + r = parse_requirement(requirement) + if r is None: # pragma: no cover + raise DistlibException('Not a valid requirement: %r' % requirement) + scheme = get_scheme(self.scheme) + self.matcher = matcher = scheme.matcher(r.requirement) + logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__) + versions = self.get_project(r.name) + if len(versions) > 2: # urls and digests keys are present + # sometimes, versions are invalid + slist = [] + vcls = matcher.version_class + for k in versions: + if k in ('urls', 'digests'): + continue + try: + if not matcher.match(k): + pass # logger.debug('%s did not match %r', matcher, k) + else: + if prereleases or not vcls(k).is_prerelease: + slist.append(k) + except Exception: # pragma: no cover + logger.warning('error matching %s with %r', matcher, k) + pass # slist.append(k) + if len(slist) > 1: + slist = sorted(slist, key=scheme.key) + if slist: + logger.debug('sorted list: %s', slist) + version = slist[-1] + result = versions[version] + if result: + if r.extras: + result.extras = r.extras + result.download_urls = versions.get('urls', {}).get(version, set()) + d = {} + sd = versions.get('digests', {}) + for url in result.download_urls: + if url in sd: # pragma: no cover + d[url] = sd[url] + result.digests = d + self.matcher = None + return result + + +class PyPIRPCLocator(Locator): + """ + This locator uses XML-RPC to locate distributions. It therefore + cannot be used with simple mirrors (that only mirror file content). + """ + + def __init__(self, url, **kwargs): + """ + Initialise an instance. + + :param url: The URL to use for XML-RPC. + :param kwargs: Passed to the superclass constructor. + """ + super(PyPIRPCLocator, self).__init__(**kwargs) + self.base_url = url + self.client = ServerProxy(url, timeout=3.0) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + return set(self.client.list_packages()) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + versions = self.client.package_releases(name, True) + for v in versions: + urls = self.client.release_urls(name, v) + data = self.client.release_data(name, v) + metadata = Metadata(scheme=self.scheme) + metadata.name = data['name'] + metadata.version = data['version'] + metadata.license = data.get('license') + metadata.keywords = data.get('keywords', []) + metadata.summary = data.get('summary') + dist = Distribution(metadata) + if urls: + info = urls[0] + metadata.source_url = info['url'] + dist.digest = self._get_digest(info) + dist.locator = self + result[v] = dist + for info in urls: + url = info['url'] + digest = self._get_digest(info) + result['urls'].setdefault(v, set()).add(url) + result['digests'][url] = digest + return result + + +class PyPIJSONLocator(Locator): + """ + This locator uses PyPI's JSON interface. It's very limited in functionality + and probably not worth using. + """ + + def __init__(self, url, **kwargs): + super(PyPIJSONLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + url = urljoin(self.base_url, '%s/json' % quote(name)) + try: + resp = self.opener.open(url) + data = resp.read().decode() # for now + d = json.loads(data) + md = Metadata(scheme=self.scheme) + data = d['info'] + md.name = data['name'] + md.version = data['version'] + md.license = data.get('license') + md.keywords = data.get('keywords', []) + md.summary = data.get('summary') + dist = Distribution(md) + dist.locator = self + # urls = d['urls'] + result[md.version] = dist + for info in d['urls']: + url = info['url'] + dist.download_urls.add(url) + dist.digests[url] = self._get_digest(info) + result['urls'].setdefault(md.version, set()).add(url) + result['digests'][url] = self._get_digest(info) + # Now get other releases + for version, infos in d['releases'].items(): + if version == md.version: + continue # already done + omd = Metadata(scheme=self.scheme) + omd.name = md.name + omd.version = version + odist = Distribution(omd) + odist.locator = self + result[version] = odist + for info in infos: + url = info['url'] + odist.download_urls.add(url) + odist.digests[url] = self._get_digest(info) + result['urls'].setdefault(version, set()).add(url) + result['digests'][url] = self._get_digest(info) + + +# for info in urls: +# md.source_url = info['url'] +# dist.digest = self._get_digest(info) +# dist.locator = self +# for info in urls: +# url = info['url'] +# result['urls'].setdefault(md.version, set()).add(url) +# result['digests'][url] = self._get_digest(info) + except Exception as e: + self.errors.put(text_type(e)) + logger.exception('JSON fetch failed: %s', e) + return result + + +class Page(object): + """ + This class represents a scraped HTML page. + """ + # The following slightly hairy-looking regex just looks for the contents of + # an anchor link, which has an attribute "href" either immediately preceded + # or immediately followed by a "rel" attribute. The attribute values can be + # declared with double quotes, single quotes or no quotes - which leads to + # the length of the expression. + _href = re.compile( + """ +(rel\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*))\\s+)? +href\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*)) +(\\s+rel\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*)))? +""", re.I | re.S | re.X) + _base = re.compile(r"""]+)""", re.I | re.S) + + def __init__(self, data, url): + """ + Initialise an instance with the Unicode page contents and the URL they + came from. + """ + self.data = data + self.base_url = self.url = url + m = self._base.search(self.data) + if m: + self.base_url = m.group(1) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + @cached_property + def links(self): + """ + Return the URLs of all the links on a page together with information + about their "rel" attribute, for determining which ones to treat as + downloads and which ones to queue for further scraping. + """ + + def clean(url): + "Tidy up an URL." + scheme, netloc, path, params, query, frag = urlparse(url) + return urlunparse((scheme, netloc, quote(path), params, query, frag)) + + result = set() + for match in self._href.finditer(self.data): + d = match.groupdict('') + rel = (d['rel1'] or d['rel2'] or d['rel3'] or d['rel4'] or d['rel5'] or d['rel6']) + url = d['url1'] or d['url2'] or d['url3'] + url = urljoin(self.base_url, url) + url = unescape(url) + url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url) + result.add((url, rel)) + # We sort the result, hoping to bring the most recent versions + # to the front + result = sorted(result, key=lambda t: t[0], reverse=True) + return result + + +class SimpleScrapingLocator(Locator): + """ + A locator which scrapes HTML pages to locate downloads for a distribution. + This runs multiple threads to do the I/O; performance is at least as good + as pip's PackageFinder, which works in an analogous fashion. + """ + + # These are used to deal with various Content-Encoding schemes. + decoders = { + 'deflate': zlib.decompress, + 'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(b)).read(), + 'none': lambda b: b, + } + + def __init__(self, url, timeout=None, num_workers=10, **kwargs): + """ + Initialise an instance. + :param url: The root URL to use for scraping. + :param timeout: The timeout, in seconds, to be applied to requests. + This defaults to ``None`` (no timeout specified). + :param num_workers: The number of worker threads you want to do I/O, + This defaults to 10. + :param kwargs: Passed to the superclass. + """ + super(SimpleScrapingLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + self.timeout = timeout + self._page_cache = {} + self._seen = set() + self._to_fetch = queue.Queue() + self._bad_hosts = set() + self.skip_externals = False + self.num_workers = num_workers + self._lock = threading.RLock() + # See issue #45: we need to be resilient when the locator is used + # in a thread, e.g. with concurrent.futures. We can't use self._lock + # as it is for coordinating our internal threads - the ones created + # in _prepare_threads. + self._gplock = threading.RLock() + self.platform_check = False # See issue #112 + + def _prepare_threads(self): + """ + Threads are created only when get_project is called, and terminate + before it returns. They are there primarily to parallelise I/O (i.e. + fetching web pages). + """ + self._threads = [] + for i in range(self.num_workers): + t = threading.Thread(target=self._fetch) + t.daemon = True + t.start() + self._threads.append(t) + + def _wait_threads(self): + """ + Tell all the threads to terminate (by sending a sentinel value) and + wait for them to do so. + """ + # Note that you need two loops, since you can't say which + # thread will get each sentinel + for t in self._threads: + self._to_fetch.put(None) # sentinel + for t in self._threads: + t.join() + self._threads = [] + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + with self._gplock: + self.result = result + self.project_name = name + url = urljoin(self.base_url, '%s/' % quote(name)) + self._seen.clear() + self._page_cache.clear() + self._prepare_threads() + try: + logger.debug('Queueing %s', url) + self._to_fetch.put(url) + self._to_fetch.join() + finally: + self._wait_threads() + del self.result + return result + + platform_dependent = re.compile(r'\b(linux_(i\d86|x86_64|arm\w+)|' + r'win(32|_amd64)|macosx_?\d+)\b', re.I) + + def _is_platform_dependent(self, url): + """ + Does an URL refer to a platform-specific download? + """ + return self.platform_dependent.search(url) + + def _process_download(self, url): + """ + See if an URL is a suitable download for a project. + + If it is, register information in the result dictionary (for + _get_project) about the specific version it's for. + + Note that the return value isn't actually used other than as a boolean + value. + """ + if self.platform_check and self._is_platform_dependent(url): + info = None + else: + info = self.convert_url_to_download_info(url, self.project_name) + logger.debug('process_download: %s -> %s', url, info) + if info: + with self._lock: # needed because self.result is shared + self._update_version_data(self.result, info) + return info + + def _should_queue(self, link, referrer, rel): + """ + Determine whether a link URL from a referring page and with a + particular "rel" attribute should be queued for scraping. + """ + scheme, netloc, path, _, _, _ = urlparse(link) + if path.endswith(self.source_extensions + self.binary_extensions + self.excluded_extensions): + result = False + elif self.skip_externals and not link.startswith(self.base_url): + result = False + elif not referrer.startswith(self.base_url): + result = False + elif rel not in ('homepage', 'download'): + result = False + elif scheme not in ('http', 'https', 'ftp'): + result = False + elif self._is_platform_dependent(link): + result = False + else: + host = netloc.split(':', 1)[0] + if host.lower() == 'localhost': + result = False + else: + result = True + logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, referrer, result) + return result + + def _fetch(self): + """ + Get a URL to fetch from the work queue, get the HTML page, examine its + links for download candidates and candidates for further scraping. + + This is a handy method to run in a thread. + """ + while True: + url = self._to_fetch.get() + try: + if url: + page = self.get_page(url) + if page is None: # e.g. after an error + continue + for link, rel in page.links: + if link not in self._seen: + try: + self._seen.add(link) + if (not self._process_download(link) and self._should_queue(link, url, rel)): + logger.debug('Queueing %s from %s', link, url) + self._to_fetch.put(link) + except MetadataInvalidError: # e.g. invalid versions + pass + except Exception as e: # pragma: no cover + self.errors.put(text_type(e)) + finally: + # always do this, to avoid hangs :-) + self._to_fetch.task_done() + if not url: + # logger.debug('Sentinel seen, quitting.') + break + + def get_page(self, url): + """ + Get the HTML for an URL, possibly from an in-memory cache. + + XXX TODO Note: this cache is never actually cleared. It's assumed that + the data won't get stale over the lifetime of a locator instance (not + necessarily true for the default_locator). + """ + # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api + scheme, netloc, path, _, _, _ = urlparse(url) + if scheme == 'file' and os.path.isdir(url2pathname(path)): + url = urljoin(ensure_slash(url), 'index.html') + + if url in self._page_cache: + result = self._page_cache[url] + logger.debug('Returning %s from cache: %s', url, result) + else: + host = netloc.split(':', 1)[0] + result = None + if host in self._bad_hosts: + logger.debug('Skipping %s due to bad host %s', url, host) + else: + req = Request(url, headers={'Accept-encoding': 'identity'}) + try: + logger.debug('Fetching %s', url) + resp = self.opener.open(req, timeout=self.timeout) + logger.debug('Fetched %s', url) + headers = resp.info() + content_type = headers.get('Content-Type', '') + if HTML_CONTENT_TYPE.match(content_type): + final_url = resp.geturl() + data = resp.read() + encoding = headers.get('Content-Encoding') + if encoding: + decoder = self.decoders[encoding] # fail if not found + data = decoder(data) + encoding = 'utf-8' + m = CHARSET.search(content_type) + if m: + encoding = m.group(1) + try: + data = data.decode(encoding) + except UnicodeError: # pragma: no cover + data = data.decode('latin-1') # fallback + result = Page(data, final_url) + self._page_cache[final_url] = result + except HTTPError as e: + if e.code != 404: + logger.exception('Fetch failed: %s: %s', url, e) + except URLError as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + with self._lock: + self._bad_hosts.add(host) + except Exception as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + finally: + self._page_cache[url] = result # even if None (failure) + return result + + _distname_re = re.compile(']*>([^<]+)<') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + page = self.get_page(self.base_url) + if not page: + raise DistlibException('Unable to get %s' % self.base_url) + for match in self._distname_re.finditer(page.data): + result.add(match.group(1)) + return result + + +class DirectoryLocator(Locator): + """ + This class locates distributions in a directory tree. + """ + + def __init__(self, path, **kwargs): + """ + Initialise an instance. + :param path: The root of the directory tree to search. + :param kwargs: Passed to the superclass constructor, + except for: + * recursive - if True (the default), subdirectories are + recursed into. If False, only the top-level directory + is searched, + """ + self.recursive = kwargs.pop('recursive', True) + super(DirectoryLocator, self).__init__(**kwargs) + path = os.path.abspath(path) + if not os.path.isdir(path): # pragma: no cover + raise DistlibException('Not a directory: %r' % path) + self.base_dir = path + + def should_include(self, filename, parent): + """ + Should a filename be considered as a candidate for a distribution + archive? As well as the filename, the directory which contains it + is provided, though not used by the current implementation. + """ + return filename.endswith(self.downloadable_extensions) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', pathname2url(os.path.abspath(fn)), '', '', '')) + info = self.convert_url_to_download_info(url, name) + if info: + self._update_version_data(result, info) + if not self.recursive: + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', pathname2url(os.path.abspath(fn)), '', '', '')) + info = self.convert_url_to_download_info(url, None) + if info: + result.add(info['name']) + if not self.recursive: + break + return result + + +class JSONLocator(Locator): + """ + This locator uses special extended metadata (not available on PyPI) and is + the basis of performant dependency resolution in distlib. Other locators + require archive downloads before dependencies can be determined! As you + might imagine, that can be slow. + """ + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + data = get_project_data(name) + if data: + for info in data.get('files', []): + if info['ptype'] != 'sdist' or info['pyversion'] != 'source': + continue + # We don't store summary in project metadata as it makes + # the data bigger for no benefit during dependency + # resolution + dist = make_dist(data['name'], + info['version'], + summary=data.get('summary', 'Placeholder for summary'), + scheme=self.scheme) + md = dist.metadata + md.source_url = info['url'] + # TODO SHA256 digest + if 'digest' in info and info['digest']: + dist.digest = ('md5', info['digest']) + md.dependencies = info.get('requirements', {}) + dist.exports = info.get('exports', {}) + result[dist.version] = dist + result['urls'].setdefault(dist.version, set()).add(info['url']) + return result + + +class DistPathLocator(Locator): + """ + This locator finds installed distributions in a path. It can be useful for + adding to an :class:`AggregatingLocator`. + """ + + def __init__(self, distpath, **kwargs): + """ + Initialise an instance. + + :param distpath: A :class:`DistributionPath` instance to search. + """ + super(DistPathLocator, self).__init__(**kwargs) + assert isinstance(distpath, DistributionPath) + self.distpath = distpath + + def _get_project(self, name): + dist = self.distpath.get_distribution(name) + if dist is None: + result = {'urls': {}, 'digests': {}} + else: + result = { + dist.version: dist, + 'urls': { + dist.version: set([dist.source_url]) + }, + 'digests': { + dist.version: set([None]) + } + } + return result + + +class AggregatingLocator(Locator): + """ + This class allows you to chain and/or merge a list of locators. + """ + + def __init__(self, *locators, **kwargs): + """ + Initialise an instance. + + :param locators: The list of locators to search. + :param kwargs: Passed to the superclass constructor, + except for: + * merge - if False (the default), the first successful + search from any of the locators is returned. If True, + the results from all locators are merged (this can be + slow). + """ + self.merge = kwargs.pop('merge', False) + self.locators = locators + super(AggregatingLocator, self).__init__(**kwargs) + + def clear_cache(self): + super(AggregatingLocator, self).clear_cache() + for locator in self.locators: + locator.clear_cache() + + def _set_scheme(self, value): + self._scheme = value + for locator in self.locators: + locator.scheme = value + + scheme = property(Locator.scheme.fget, _set_scheme) + + def _get_project(self, name): + result = {} + for locator in self.locators: + d = locator.get_project(name) + if d: + if self.merge: + files = result.get('urls', {}) + digests = result.get('digests', {}) + # next line could overwrite result['urls'], result['digests'] + result.update(d) + df = result.get('urls') + if files and df: + for k, v in files.items(): + if k in df: + df[k] |= v + else: + df[k] = v + dd = result.get('digests') + if digests and dd: + dd.update(digests) + else: + # See issue #18. If any dists are found and we're looking + # for specific constraints, we only return something if + # a match is found. For example, if a DirectoryLocator + # returns just foo (1.0) while we're looking for + # foo (>= 2.0), we'll pretend there was nothing there so + # that subsequent locators can be queried. Otherwise we + # would just return foo (1.0) which would then lead to a + # failure to find foo (>= 2.0), because other locators + # weren't searched. Note that this only matters when + # merge=False. + if self.matcher is None: + found = True + else: + found = False + for k in d: + if self.matcher.match(k): + found = True + break + if found: + result = d + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for locator in self.locators: + try: + result |= locator.get_distribution_names() + except NotImplementedError: + pass + return result + + +# We use a legacy scheme simply because most of the dists on PyPI use legacy +# versions which don't conform to PEP 440. +default_locator = AggregatingLocator( + # JSONLocator(), # don't use as PEP 426 is withdrawn + SimpleScrapingLocator('https://pypi.org/simple/', timeout=3.0), + scheme='legacy') + +locate = default_locator.locate + + +class DependencyFinder(object): + """ + Locate dependencies for distributions. + """ + + def __init__(self, locator=None): + """ + Initialise an instance, using the specified locator + to locate distributions. + """ + self.locator = locator or default_locator + self.scheme = get_scheme(self.locator.scheme) + + def add_distribution(self, dist): + """ + Add a distribution to the finder. This will update internal information + about who provides what. + :param dist: The distribution to add. + """ + logger.debug('adding distribution %s', dist) + name = dist.key + self.dists_by_name[name] = dist + self.dists[(name, dist.version)] = dist + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + self.provided.setdefault(name, set()).add((version, dist)) + + def remove_distribution(self, dist): + """ + Remove a distribution from the finder. This will update internal + information about who provides what. + :param dist: The distribution to remove. + """ + logger.debug('removing distribution %s', dist) + name = dist.key + del self.dists_by_name[name] + del self.dists[(name, dist.version)] + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Remove from provided: %s, %s, %s', name, version, dist) + s = self.provided[name] + s.remove((version, dist)) + if not s: + del self.provided[name] + + def get_matcher(self, reqt): + """ + Get a version matcher for a requirement. + :param reqt: The requirement + :type reqt: str + :return: A version matcher (an instance of + :class:`distlib.version.Matcher`). + """ + try: + matcher = self.scheme.matcher(reqt) + except UnsupportedVersionError: # pragma: no cover + # XXX compat-mode if cannot read the version + name = reqt.split()[0] + matcher = self.scheme.matcher(name) + return matcher + + def find_providers(self, reqt): + """ + Find the distributions which can fulfill a requirement. + + :param reqt: The requirement. + :type reqt: str + :return: A set of distribution which can fulfill the requirement. + """ + matcher = self.get_matcher(reqt) + name = matcher.key # case-insensitive + result = set() + provided = self.provided + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + result.add(provider) + break + return result + + def try_to_replace(self, provider, other, problems): + """ + Attempt to replace one provider with another. This is typically used + when resolving dependencies from multiple sources, e.g. A requires + (B >= 1.0) while C requires (B >= 1.1). + + For successful replacement, ``provider`` must meet all the requirements + which ``other`` fulfills. + + :param provider: The provider we are trying to replace with. + :param other: The provider we're trying to replace. + :param problems: If False is returned, this will contain what + problems prevented replacement. This is currently + a tuple of the literal string 'cantreplace', + ``provider``, ``other`` and the set of requirements + that ``provider`` couldn't fulfill. + :return: True if we can replace ``other`` with ``provider``, else + False. + """ + rlist = self.reqts[other] + unmatched = set() + for s in rlist: + matcher = self.get_matcher(s) + if not matcher.match(provider.version): + unmatched.add(s) + if unmatched: + # can't replace other with provider + problems.add(('cantreplace', provider, other, frozenset(unmatched))) + result = False + else: + # can replace other with provider + self.remove_distribution(other) + del self.reqts[other] + for s in rlist: + self.reqts.setdefault(provider, set()).add(s) + self.add_distribution(provider) + result = True + return result + + def find(self, requirement, meta_extras=None, prereleases=False): + """ + Find a distribution and all distributions it depends on. + + :param requirement: The requirement specifying the distribution to + find, or a Distribution instance. + :param meta_extras: A list of meta extras such as :test:, :build: and + so on. + :param prereleases: If ``True``, allow pre-release versions to be + returned - otherwise, don't return prereleases + unless they're all that's available. + + Return a set of :class:`Distribution` instances and a set of + problems. + + The distributions returned should be such that they have the + :attr:`required` attribute set to ``True`` if they were + from the ``requirement`` passed to ``find()``, and they have the + :attr:`build_time_dependency` attribute set to ``True`` unless they + are post-installation dependencies of the ``requirement``. + + The problems should be a tuple consisting of the string + ``'unsatisfied'`` and the requirement which couldn't be satisfied + by any distribution known to the locator. + """ + + self.provided = {} + self.dists = {} + self.dists_by_name = {} + self.reqts = {} + + meta_extras = set(meta_extras or []) + if ':*:' in meta_extras: + meta_extras.remove(':*:') + # :meta: and :run: are implicitly included + meta_extras |= set([':test:', ':build:', ':dev:']) + + if isinstance(requirement, Distribution): + dist = odist = requirement + logger.debug('passed %s as requirement', odist) + else: + dist = odist = self.locator.locate(requirement, prereleases=prereleases) + if dist is None: + raise DistlibException('Unable to locate %r' % requirement) + logger.debug('located %s', odist) + dist.requested = True + problems = set() + todo = set([dist]) + install_dists = set([odist]) + while todo: + dist = todo.pop() + name = dist.key # case-insensitive + if name not in self.dists_by_name: + self.add_distribution(dist) + else: + # import pdb; pdb.set_trace() + other = self.dists_by_name[name] + if other != dist: + self.try_to_replace(dist, other, problems) + + ireqts = dist.run_requires | dist.meta_requires + sreqts = dist.build_requires + ereqts = set() + if meta_extras and dist in install_dists: + for key in ('test', 'build', 'dev'): + e = ':%s:' % key + if e in meta_extras: + ereqts |= getattr(dist, '%s_requires' % key) + all_reqts = ireqts | sreqts | ereqts + for r in all_reqts: + providers = self.find_providers(r) + if not providers: + logger.debug('No providers found for %r', r) + provider = self.locator.locate(r, prereleases=prereleases) + # If no provider is found and we didn't consider + # prereleases, consider them now. + if provider is None and not prereleases: + provider = self.locator.locate(r, prereleases=True) + if provider is None: + logger.debug('Cannot satisfy %r', r) + problems.add(('unsatisfied', r)) + else: + n, v = provider.key, provider.version + if (n, v) not in self.dists: + todo.add(provider) + providers.add(provider) + if r in ireqts and dist in install_dists: + install_dists.add(provider) + logger.debug('Adding %s to install_dists', provider.name_and_version) + for p in providers: + name = p.key + if name not in self.dists_by_name: + self.reqts.setdefault(p, set()).add(r) + else: + other = self.dists_by_name[name] + if other != p: + # see if other can be replaced by p + self.try_to_replace(p, other, problems) + + dists = set(self.dists.values()) + for dist in dists: + dist.build_time_dependency = dist not in install_dists + if dist.build_time_dependency: + logger.debug('%s is a build-time dependency only.', dist.name_and_version) + logger.debug('find done for %s', odist) + return dists, problems diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/manifest.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/manifest.py new file mode 100644 index 0000000..420dcf1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/manifest.py @@ -0,0 +1,384 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2023 Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Class representing the list of files in a distribution. + +Equivalent to distutils.filelist, but fixes some problems. +""" +import fnmatch +import logging +import os +import re +import sys + +from . import DistlibException +from .compat import fsdecode +from .util import convert_path + + +__all__ = ['Manifest'] + +logger = logging.getLogger(__name__) + +# a \ followed by some spaces + EOL +_COLLAPSE_PATTERN = re.compile('\\\\w*\n', re.M) +_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) + +# +# Due to the different results returned by fnmatch.translate, we need +# to do slightly different processing for Python 2.7 and 3.2 ... this needed +# to be brought in for Python 3.6 onwards. +# +_PYTHON_VERSION = sys.version_info[:2] + + +class Manifest(object): + """ + A list of files built by exploring the filesystem and filtered by applying various + patterns to what we find there. + """ + + def __init__(self, base=None): + """ + Initialise an instance. + + :param base: The base directory to explore under. + """ + self.base = os.path.abspath(os.path.normpath(base or os.getcwd())) + self.prefix = self.base + os.sep + self.allfiles = None + self.files = set() + + # + # Public API + # + + def findall(self): + """Find all files under the base and set ``allfiles`` to the absolute + pathnames of files found. + """ + from stat import S_ISREG, S_ISDIR, S_ISLNK + + self.allfiles = allfiles = [] + root = self.base + stack = [root] + pop = stack.pop + push = stack.append + + while stack: + root = pop() + names = os.listdir(root) + + for name in names: + fullname = os.path.join(root, name) + + # Avoid excess stat calls -- just one will do, thank you! + stat = os.stat(fullname) + mode = stat.st_mode + if S_ISREG(mode): + allfiles.append(fsdecode(fullname)) + elif S_ISDIR(mode) and not S_ISLNK(mode): + push(fullname) + + def add(self, item): + """ + Add a file to the manifest. + + :param item: The pathname to add. This can be relative to the base. + """ + if not item.startswith(self.prefix): + item = os.path.join(self.base, item) + self.files.add(os.path.normpath(item)) + + def add_many(self, items): + """ + Add a list of files to the manifest. + + :param items: The pathnames to add. These can be relative to the base. + """ + for item in items: + self.add(item) + + def sorted(self, wantdirs=False): + """ + Return sorted files in directory order + """ + + def add_dir(dirs, d): + dirs.add(d) + logger.debug('add_dir added %s', d) + if d != self.base: + parent, _ = os.path.split(d) + assert parent not in ('', '/') + add_dir(dirs, parent) + + result = set(self.files) # make a copy! + if wantdirs: + dirs = set() + for f in result: + add_dir(dirs, os.path.dirname(f)) + result |= dirs + return [os.path.join(*path_tuple) for path_tuple in + sorted(os.path.split(path) for path in result)] + + def clear(self): + """Clear all collected files.""" + self.files = set() + self.allfiles = [] + + def process_directive(self, directive): + """ + Process a directive which either adds some files from ``allfiles`` to + ``files``, or removes some files from ``files``. + + :param directive: The directive to process. This should be in a format + compatible with distutils ``MANIFEST.in`` files: + + http://docs.python.org/distutils/sourcedist.html#commands + """ + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dirpattern). + action, patterns, thedir, dirpattern = self._parse_directive(directive) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=True): + logger.warning('no files found matching %r', pattern) + + elif action == 'exclude': + for pattern in patterns: + self._exclude_pattern(pattern, anchor=True) + + elif action == 'global-include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=False): + logger.warning('no files found matching %r ' + 'anywhere in distribution', pattern) + + elif action == 'global-exclude': + for pattern in patterns: + self._exclude_pattern(pattern, anchor=False) + + elif action == 'recursive-include': + for pattern in patterns: + if not self._include_pattern(pattern, prefix=thedir): + logger.warning('no files found matching %r ' + 'under directory %r', pattern, thedir) + + elif action == 'recursive-exclude': + for pattern in patterns: + self._exclude_pattern(pattern, prefix=thedir) + + elif action == 'graft': + if not self._include_pattern(None, prefix=dirpattern): + logger.warning('no directories found matching %r', + dirpattern) + + elif action == 'prune': + if not self._exclude_pattern(None, prefix=dirpattern): + logger.warning('no previously-included directories found ' + 'matching %r', dirpattern) + else: # pragma: no cover + # This should never happen, as it should be caught in + # _parse_template_line + raise DistlibException( + 'invalid action %r' % action) + + # + # Private API + # + + def _parse_directive(self, directive): + """ + Validate a directive. + :param directive: The directive to validate. + :return: A tuple of action, patterns, thedir, dir_patterns + """ + words = directive.split() + if len(words) == 1 and words[0] not in ('include', 'exclude', + 'global-include', + 'global-exclude', + 'recursive-include', + 'recursive-exclude', + 'graft', 'prune'): + # no action given, let's use the default 'include' + words.insert(0, 'include') + + action = words[0] + patterns = thedir = dir_pattern = None + + if action in ('include', 'exclude', + 'global-include', 'global-exclude'): + if len(words) < 2: + raise DistlibException( + '%r expects ...' % action) + + patterns = [convert_path(word) for word in words[1:]] + + elif action in ('recursive-include', 'recursive-exclude'): + if len(words) < 3: + raise DistlibException( + '%r expects

        ...' % action) + + thedir = convert_path(words[1]) + patterns = [convert_path(word) for word in words[2:]] + + elif action in ('graft', 'prune'): + if len(words) != 2: + raise DistlibException( + '%r expects a single ' % action) + + dir_pattern = convert_path(words[1]) + + else: + raise DistlibException('unknown action %r' % action) + + return action, patterns, thedir, dir_pattern + + def _include_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Select strings (presumably filenames) from 'self.files' that + match 'pattern', a Unix-style wildcard (glob) pattern. + + Patterns are not quite the same as implemented by the 'fnmatch' + module: '*' and '?' match non-special characters, where "special" + is platform-dependent: slash on Unix; colon, slash, and backslash on + DOS/Windows; and colon on Mac OS. + + If 'anchor' is true (the default), then the pattern match is more + stringent: "*.py" will match "foo.py" but not "foo/bar.py". If + 'anchor' is false, both of these will match. + + If 'prefix' is supplied, then only filenames starting with 'prefix' + (itself a pattern) and ending with 'pattern', with anything in between + them, will match. 'anchor' is ignored in this case. + + If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and + 'pattern' is assumed to be either a string containing a regex or a + regex object -- no translation is done, the regex is just compiled + and used as-is. + + Selected strings will be added to self.files. + + Return True if files are found. + """ + # XXX docstring lying about what the special chars are? + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + + # delayed loading of allfiles list + if self.allfiles is None: + self.findall() + + for name in self.allfiles: + if pattern_re.search(name): + self.files.add(name) + found = True + return found + + def _exclude_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Remove strings (presumably filenames) from 'files' that match + 'pattern'. + + Other parameters are the same as for 'include_pattern()', above. + The list 'self.files' is modified in place. Return True if files are + found. + + This API is public to allow e.g. exclusion of SCM subdirs, e.g. when + packaging source distributions + """ + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + for f in list(self.files): + if pattern_re.search(f): + self.files.remove(f) + found = True + return found + + def _translate_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Translate a shell-like wildcard pattern to a compiled regular + expression. + + Return the compiled regex. If 'is_regex' true, + then 'pattern' is directly compiled to a regex (if it's a string) + or just returned as-is (assumes it's a regex object). + """ + if is_regex: + if isinstance(pattern, str): + return re.compile(pattern) + else: + return pattern + + if _PYTHON_VERSION > (3, 2): + # ditch start and end characters + start, _, end = self._glob_to_re('_').partition('_') + + if pattern: + pattern_re = self._glob_to_re(pattern) + if _PYTHON_VERSION > (3, 2): + assert pattern_re.startswith(start) and pattern_re.endswith(end) + else: + pattern_re = '' + + base = re.escape(os.path.join(self.base, '')) + if prefix is not None: + # ditch end of pattern character + if _PYTHON_VERSION <= (3, 2): + empty_pattern = self._glob_to_re('') + prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)] + else: + prefix_re = self._glob_to_re(prefix) + assert prefix_re.startswith(start) and prefix_re.endswith(end) + prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] + sep = os.sep + if os.sep == '\\': + sep = r'\\' + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + sep.join((prefix_re, + '.*' + pattern_re)) + else: + pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] + pattern_re = r'%s%s%s%s.*%s%s' % (start, base, prefix_re, sep, + pattern_re, end) + else: # no prefix -- respect anchor flag + if anchor: + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + pattern_re + else: + pattern_re = r'%s%s%s' % (start, base, pattern_re[len(start):]) + + return re.compile(pattern_re) + + def _glob_to_re(self, pattern): + """Translate a shell-like glob pattern to a regular expression. + + Return a string containing the regex. Differs from + 'fnmatch.translate()' in that '*' does not match "special characters" + (which are platform-specific). + """ + pattern_re = fnmatch.translate(pattern) + + # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which + # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, + # and by extension they shouldn't match such "special characters" under + # any OS. So change all non-escaped dots in the RE to match any + # character except the special characters (currently: just os.sep). + sep = os.sep + if os.sep == '\\': + # we're using a regex to manipulate a regex, so we need + # to escape the backslash twice + sep = r'\\\\' + escaped = r'\1[^%s]' % sep + pattern_re = re.sub(r'((? y, + '!=': lambda x, y: x != y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x == y or x < y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x == y or x > y, + 'and': lambda x, y: x and y, + 'or': lambda x, y: x or y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y, + } + + def evaluate(self, expr, context): + """ + Evaluate a marker expression returned by the :func:`parse_requirement` + function in the specified context. + """ + if isinstance(expr, string_types): + if expr[0] in '\'"': + result = expr[1:-1] + else: + if expr not in context: + raise SyntaxError('unknown variable: %s' % expr) + result = context[expr] + else: + assert isinstance(expr, dict) + op = expr['op'] + if op not in self.operations: + raise NotImplementedError('op not implemented: %s' % op) + elhs = expr['lhs'] + erhs = expr['rhs'] + if _is_literal(expr['lhs']) and _is_literal(expr['rhs']): + raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs)) + + lhs = self.evaluate(elhs, context) + rhs = self.evaluate(erhs, context) + if ((_is_version_marker(elhs) or _is_version_marker(erhs)) and + op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')): + lhs = LV(lhs) + rhs = LV(rhs) + elif _is_version_marker(elhs) and op in ('in', 'not in'): + lhs = LV(lhs) + rhs = _get_versions(rhs) + result = self.operations[op](lhs, rhs) + return result + + +_DIGITS = re.compile(r'\d+\.\d+') + + +def default_context(): + + def format_full_version(info): + version = '%s.%s.%s' % (info.major, info.minor, info.micro) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + if hasattr(sys, 'implementation'): + implementation_version = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + implementation_version = '0' + implementation_name = '' + + ppv = platform.python_version() + m = _DIGITS.match(ppv) + pv = m.group(0) + result = { + 'implementation_name': implementation_name, + 'implementation_version': implementation_version, + 'os_name': os.name, + 'platform_machine': platform.machine(), + 'platform_python_implementation': platform.python_implementation(), + 'platform_release': platform.release(), + 'platform_system': platform.system(), + 'platform_version': platform.version(), + 'platform_in_venv': str(in_venv()), + 'python_full_version': ppv, + 'python_version': pv, + 'sys_platform': sys.platform, + } + return result + + +DEFAULT_CONTEXT = default_context() +del default_context + +evaluator = Evaluator() + + +def interpret(marker, execution_context=None): + """ + Interpret a marker and return a result depending on environment. + + :param marker: The marker to interpret. + :type marker: str + :param execution_context: The context used for name lookup. + :type execution_context: mapping + """ + try: + expr, rest = parse_marker(marker) + except Exception as e: + raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e)) + if rest and rest[0] != '#': + raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest)) + context = dict(DEFAULT_CONTEXT) + if execution_context: + context.update(execution_context) + return evaluator.evaluate(expr, context) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/metadata.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/metadata.py new file mode 100644 index 0000000..ce9a34b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/metadata.py @@ -0,0 +1,1031 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Implementation of the Metadata for Python packages PEPs. + +Supports all metadata formats (1.0, 1.1, 1.2, 1.3/2.1 and 2.2). +""" +from __future__ import unicode_literals + +import codecs +from email import message_from_file +import json +import logging +import re + +from . import DistlibException, __version__ +from .compat import StringIO, string_types, text_type +from .markers import interpret +from .util import extract_by_key, get_extras +from .version import get_scheme, PEP440_VERSION_RE + +logger = logging.getLogger(__name__) + + +class MetadataMissingError(DistlibException): + """A required metadata is missing""" + + +class MetadataConflictError(DistlibException): + """Attempt to read or write metadata fields that are conflictual.""" + + +class MetadataUnrecognizedVersionError(DistlibException): + """Unknown metadata version number.""" + + +class MetadataInvalidError(DistlibException): + """A metadata value is invalid""" + + +# public API of this module +__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] + +# Encoding used for the PKG-INFO files +PKG_INFO_ENCODING = 'utf-8' + +# preferred version. Hopefully will be changed +# to 1.2 once PEP 345 is supported everywhere +PKG_INFO_PREFERRED_VERSION = '1.1' + +_LINE_PREFIX_1_2 = re.compile('\n \\|') +_LINE_PREFIX_PRE_1_2 = re.compile('\n ') +_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Summary', 'Description', 'Keywords', 'Home-page', + 'Author', 'Author-email', 'License') + +_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', 'License', 'Classifier', 'Download-URL', 'Obsoletes', + 'Provides', 'Requires') + +_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', 'Download-URL') + +_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External') + +_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', 'Obsoletes-Dist', 'Requires-External', + 'Maintainer', 'Maintainer-email', 'Project-URL') + +_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External', 'Private-Version', 'Obsoleted-By', 'Setup-Requires-Dist', + 'Extension', 'Provides-Extra') + +_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension') + +# See issue #106: Sometimes 'Requires' and 'Provides' occur wrongly in +# the metadata. Include them in the tuple literal below to allow them +# (for now). +# Ditto for Obsoletes - see issue #140. +_566_FIELDS = _426_FIELDS + ('Description-Content-Type', 'Requires', 'Provides', 'Obsoletes') + +_566_MARKERS = ('Description-Content-Type', ) + +_643_MARKERS = ('Dynamic', 'License-File') + +_643_FIELDS = _566_FIELDS + _643_MARKERS + +_ALL_FIELDS = set() +_ALL_FIELDS.update(_241_FIELDS) +_ALL_FIELDS.update(_314_FIELDS) +_ALL_FIELDS.update(_345_FIELDS) +_ALL_FIELDS.update(_426_FIELDS) +_ALL_FIELDS.update(_566_FIELDS) +_ALL_FIELDS.update(_643_FIELDS) + +EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') + + +def _version2fieldlist(version): + if version == '1.0': + return _241_FIELDS + elif version == '1.1': + return _314_FIELDS + elif version == '1.2': + return _345_FIELDS + elif version in ('1.3', '2.1'): + # avoid adding field names if already there + return _345_FIELDS + tuple(f for f in _566_FIELDS if f not in _345_FIELDS) + elif version == '2.0': + raise ValueError('Metadata 2.0 is withdrawn and not supported') + # return _426_FIELDS + elif version == '2.2': + return _643_FIELDS + raise MetadataUnrecognizedVersionError(version) + + +def _best_version(fields): + """Detect the best version depending on the fields used.""" + + def _has_marker(keys, markers): + return any(marker in keys for marker in markers) + + keys = [key for key, value in fields.items() if value not in ([], 'UNKNOWN', None)] + possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.1', '2.2'] # 2.0 removed + + # first let's try to see if a field is not part of one of the version + for key in keys: + if key not in _241_FIELDS and '1.0' in possible_versions: + possible_versions.remove('1.0') + logger.debug('Removed 1.0 due to %s', key) + if key not in _314_FIELDS and '1.1' in possible_versions: + possible_versions.remove('1.1') + logger.debug('Removed 1.1 due to %s', key) + if key not in _345_FIELDS and '1.2' in possible_versions: + possible_versions.remove('1.2') + logger.debug('Removed 1.2 due to %s', key) + if key not in _566_FIELDS and '1.3' in possible_versions: + possible_versions.remove('1.3') + logger.debug('Removed 1.3 due to %s', key) + if key not in _566_FIELDS and '2.1' in possible_versions: + if key != 'Description': # In 2.1, description allowed after headers + possible_versions.remove('2.1') + logger.debug('Removed 2.1 due to %s', key) + if key not in _643_FIELDS and '2.2' in possible_versions: + possible_versions.remove('2.2') + logger.debug('Removed 2.2 due to %s', key) + # if key not in _426_FIELDS and '2.0' in possible_versions: + # possible_versions.remove('2.0') + # logger.debug('Removed 2.0 due to %s', key) + + # possible_version contains qualified versions + if len(possible_versions) == 1: + return possible_versions[0] # found ! + elif len(possible_versions) == 0: + logger.debug('Out of options - unknown metadata set: %s', fields) + raise MetadataConflictError('Unknown metadata set') + + # let's see if one unique marker is found + is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) + is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) + is_2_1 = '2.1' in possible_versions and _has_marker(keys, _566_MARKERS) + # is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) + is_2_2 = '2.2' in possible_versions and _has_marker(keys, _643_MARKERS) + if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_2) > 1: + raise MetadataConflictError('You used incompatible 1.1/1.2/2.1/2.2 fields') + + # we have the choice, 1.0, or 1.2, 2.1 or 2.2 + # - 1.0 has a broken Summary field but works with all tools + # - 1.1 is to avoid + # - 1.2 fixes Summary but has little adoption + # - 2.1 adds more features + # - 2.2 is the latest + if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_2: + # we couldn't find any specific marker + if PKG_INFO_PREFERRED_VERSION in possible_versions: + return PKG_INFO_PREFERRED_VERSION + if is_1_1: + return '1.1' + if is_1_2: + return '1.2' + if is_2_1: + return '2.1' + # if is_2_2: + # return '2.2' + + return '2.2' + + +# This follows the rules about transforming keys as described in +# https://www.python.org/dev/peps/pep-0566/#id17 +_ATTR2FIELD = {name.lower().replace("-", "_"): name for name in _ALL_FIELDS} +_FIELD2ATTR = {field: attr for attr, field in _ATTR2FIELD.items()} + +_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') +_VERSIONS_FIELDS = ('Requires-Python', ) +_VERSION_FIELDS = ('Version', ) +_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist', + 'Requires-Dist', 'Requires-External', 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', + 'Provides-Extra', 'Extension', 'License-File') +_LISTTUPLEFIELDS = ('Project-URL', ) + +_ELEMENTSFIELD = ('Keywords', ) + +_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') + +_MISSING = object() + +_FILESAFE = re.compile('[^A-Za-z0-9.]+') + + +def _get_name_and_version(name, version, for_filename=False): + """Return the distribution name with version. + + If for_filename is true, return a filename-escaped form.""" + if for_filename: + # For both name and version any runs of non-alphanumeric or '.' + # characters are replaced with a single '-'. Additionally any + # spaces in the version string become '.' + name = _FILESAFE.sub('-', name) + version = _FILESAFE.sub('-', version.replace(' ', '.')) + return '%s-%s' % (name, version) + + +class LegacyMetadata(object): + """The legacy metadata of a release. + + Supports versions 1.0, 1.1, 1.2, 2.0 and 1.3/2.1 (auto-detected). You can + instantiate the class with one of these arguments (or none): + - *path*, the path to a metadata file + - *fileobj* give a file-like object with metadata as content + - *mapping* is a dict-like object + - *scheme* is a version scheme name + """ + + # TODO document the mapping API and UNKNOWN default key + + def __init__(self, path=None, fileobj=None, mapping=None, scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._fields = {} + self.requires_files = [] + self._dependencies = None + self.scheme = scheme + if path is not None: + self.read(path) + elif fileobj is not None: + self.read_file(fileobj) + elif mapping is not None: + self.update(mapping) + self.set_metadata_version() + + def set_metadata_version(self): + self._fields['Metadata-Version'] = _best_version(self._fields) + + def _write_field(self, fileobj, name, value): + fileobj.write('%s: %s\n' % (name, value)) + + def __getitem__(self, name): + return self.get(name) + + def __setitem__(self, name, value): + return self.set(name, value) + + def __delitem__(self, name): + field_name = self._convert_name(name) + try: + del self._fields[field_name] + except KeyError: + raise KeyError(name) + + def __contains__(self, name): + return (name in self._fields or self._convert_name(name) in self._fields) + + def _convert_name(self, name): + if name in _ALL_FIELDS: + return name + name = name.replace('-', '_').lower() + return _ATTR2FIELD.get(name, name) + + def _default_value(self, name): + if name in _LISTFIELDS or name in _ELEMENTSFIELD: + return [] + return 'UNKNOWN' + + def _remove_line_prefix(self, value): + if self.metadata_version in ('1.0', '1.1'): + return _LINE_PREFIX_PRE_1_2.sub('\n', value) + else: + return _LINE_PREFIX_1_2.sub('\n', value) + + def __getattr__(self, name): + if name in _ATTR2FIELD: + return self[name] + raise AttributeError(name) + + # + # Public API + # + + def get_fullname(self, filesafe=False): + """ + Return the distribution name with version. + + If filesafe is true, return a filename-escaped form. + """ + return _get_name_and_version(self['Name'], self['Version'], filesafe) + + def is_field(self, name): + """return True if name is a valid metadata key""" + name = self._convert_name(name) + return name in _ALL_FIELDS + + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + + def read(self, filepath): + """Read the metadata values from a file path.""" + fp = codecs.open(filepath, 'r', encoding='utf-8') + try: + self.read_file(fp) + finally: + fp.close() + + def read_file(self, fileob): + """Read the metadata values from a file object.""" + msg = message_from_file(fileob) + self._fields['Metadata-Version'] = msg['metadata-version'] + + # When reading, get all the fields we can + for field in _ALL_FIELDS: + if field not in msg: + continue + if field in _LISTFIELDS: + # we can have multiple lines + values = msg.get_all(field) + if field in _LISTTUPLEFIELDS and values is not None: + values = [tuple(value.split(',')) for value in values] + self.set(field, values) + else: + # single line + value = msg[field] + if value is not None and value != 'UNKNOWN': + self.set(field, value) + + # PEP 566 specifies that the body be used for the description, if + # available + body = msg.get_payload() + self["Description"] = body if body else self["Description"] + # logger.debug('Attempting to set metadata for %s', self) + # self.set_metadata_version() + + def write(self, filepath, skip_unknown=False): + """Write the metadata fields to filepath.""" + fp = codecs.open(filepath, 'w', encoding='utf-8') + try: + self.write_file(fp, skip_unknown) + finally: + fp.close() + + def write_file(self, fileobject, skip_unknown=False): + """Write the PKG-INFO format data to a file object.""" + self.set_metadata_version() + + for field in _version2fieldlist(self['Metadata-Version']): + values = self.get(field) + if skip_unknown and values in ('UNKNOWN', [], ['UNKNOWN']): + continue + if field in _ELEMENTSFIELD: + self._write_field(fileobject, field, ','.join(values)) + continue + if field not in _LISTFIELDS: + if field == 'Description': + if self.metadata_version in ('1.0', '1.1'): + values = values.replace('\n', '\n ') + else: + values = values.replace('\n', '\n |') + values = [values] + + if field in _LISTTUPLEFIELDS: + values = [','.join(value) for value in values] + + for value in values: + self._write_field(fileobject, field, value) + + def update(self, other=None, **kwargs): + """Set metadata values from the given iterable `other` and kwargs. + + Behavior is like `dict.update`: If `other` has a ``keys`` method, + they are looped over and ``self[key]`` is assigned ``other[key]``. + Else, ``other`` is an iterable of ``(key, value)`` iterables. + + Keys that don't match a metadata field or that have an empty value are + dropped. + """ + + def _set(key, value): + if key in _ATTR2FIELD and value: + self.set(self._convert_name(key), value) + + if not other: + # other is None or empty container + pass + elif hasattr(other, 'keys'): + for k in other.keys(): + _set(k, other[k]) + else: + for k, v in other: + _set(k, v) + + if kwargs: + for k, v in kwargs.items(): + _set(k, v) + + def set(self, name, value): + """Control then set a metadata field.""" + name = self._convert_name(name) + + if ((name in _ELEMENTSFIELD or name == 'Platform') and not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [v.strip() for v in value.split(',')] + else: + value = [] + elif (name in _LISTFIELDS and not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [value] + else: + value = [] + + if logger.isEnabledFor(logging.WARNING): + project_name = self['Name'] + + scheme = get_scheme(self.scheme) + if name in _PREDICATE_FIELDS and value is not None: + for v in value: + # check that the values are valid + if not scheme.is_valid_matcher(v.split(';')[0]): + logger.warning("'%s': '%s' is not valid (field '%s')", project_name, v, name) + # FIXME this rejects UNKNOWN, is that right? + elif name in _VERSIONS_FIELDS and value is not None: + if not scheme.is_valid_constraint_list(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", project_name, value, name) + elif name in _VERSION_FIELDS and value is not None: + if not scheme.is_valid_version(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", project_name, value, name) + + if name in _UNICODEFIELDS: + if name == 'Description': + value = self._remove_line_prefix(value) + + self._fields[name] = value + + def get(self, name, default=_MISSING): + """Get a metadata field.""" + name = self._convert_name(name) + if name not in self._fields: + if default is _MISSING: + default = self._default_value(name) + return default + if name in _UNICODEFIELDS: + value = self._fields[name] + return value + elif name in _LISTFIELDS: + value = self._fields[name] + if value is None: + return [] + res = [] + for val in value: + if name not in _LISTTUPLEFIELDS: + res.append(val) + else: + # That's for Project-URL + res.append((val[0], val[1])) + return res + + elif name in _ELEMENTSFIELD: + value = self._fields[name] + if isinstance(value, string_types): + return value.split(',') + return self._fields[name] + + def check(self, strict=False): + """Check if the metadata is compliant. If strict is True then raise if + no Name or Version are provided""" + self.set_metadata_version() + + # XXX should check the versions (if the file was loaded) + missing, warnings = [], [] + + for attr in ('Name', 'Version'): # required by PEP 345 + if attr not in self: + missing.append(attr) + + if strict and missing != []: + msg = 'missing required metadata: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + + for attr in ('Home-page', 'Author'): + if attr not in self: + missing.append(attr) + + # checking metadata 1.2 (XXX needs to check 1.1, 1.0) + if self['Metadata-Version'] != '1.2': + return missing, warnings + + scheme = get_scheme(self.scheme) + + def are_valid_constraints(value): + for v in value: + if not scheme.is_valid_matcher(v.split(';')[0]): + return False + return True + + for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints), + (_VERSIONS_FIELDS, scheme.is_valid_constraint_list), (_VERSION_FIELDS, + scheme.is_valid_version)): + for field in fields: + value = self.get(field, None) + if value is not None and not controller(value): + warnings.append("Wrong value for '%s': %s" % (field, value)) + + return missing, warnings + + def todict(self, skip_missing=False): + """Return fields as a dict. + + Field names will be converted to use the underscore-lowercase style + instead of hyphen-mixed case (i.e. home_page instead of Home-page). + This is as per https://www.python.org/dev/peps/pep-0566/#id17. + """ + self.set_metadata_version() + + fields = _version2fieldlist(self['Metadata-Version']) + + data = {} + + for field_name in fields: + if not skip_missing or field_name in self._fields: + key = _FIELD2ATTR[field_name] + if key != 'project_url': + data[key] = self[field_name] + else: + data[key] = [','.join(u) for u in self[field_name]] + + return data + + def add_requirements(self, requirements): + if self['Metadata-Version'] == '1.1': + # we can't have 1.1 metadata *and* Setuptools requires + for field in ('Obsoletes', 'Requires', 'Provides'): + if field in self: + del self[field] + self['Requires-Dist'] += requirements + + # Mapping API + # TODO could add iter* variants + + def keys(self): + return list(_version2fieldlist(self['Metadata-Version'])) + + def __iter__(self): + for key in self.keys(): + yield key + + def values(self): + return [self[key] for key in self.keys()] + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def __repr__(self): + return '<%s %s %s>' % (self.__class__.__name__, self.name, self.version) + + +METADATA_FILENAME = 'pydist.json' +WHEEL_METADATA_FILENAME = 'metadata.json' +LEGACY_METADATA_FILENAME = 'METADATA' + + +class Metadata(object): + """ + The metadata of a release. This implementation uses 2.1 + metadata where possible. If not possible, it wraps a LegacyMetadata + instance which handles the key-value metadata format. + """ + + METADATA_VERSION_MATCHER = re.compile(r'^\d+(\.\d+)*$') + + NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) + + FIELDNAME_MATCHER = re.compile('^[A-Z]([0-9A-Z-]*[0-9A-Z])?$', re.I) + + VERSION_MATCHER = PEP440_VERSION_RE + + SUMMARY_MATCHER = re.compile('.{1,2047}') + + METADATA_VERSION = '2.0' + + GENERATOR = 'distlib (%s)' % __version__ + + MANDATORY_KEYS = { + 'name': (), + 'version': (), + 'summary': ('legacy', ), + } + + INDEX_KEYS = ('name version license summary description author ' + 'author_email keywords platform home_page classifiers ' + 'download_url') + + DEPENDENCY_KEYS = ('extras run_requires test_requires build_requires ' + 'dev_requires provides meta_requires obsoleted_by ' + 'supports_environments') + + SYNTAX_VALIDATORS = { + 'metadata_version': (METADATA_VERSION_MATCHER, ()), + 'name': (NAME_MATCHER, ('legacy', )), + 'version': (VERSION_MATCHER, ('legacy', )), + 'summary': (SUMMARY_MATCHER, ('legacy', )), + 'dynamic': (FIELDNAME_MATCHER, ('legacy', )), + } + + __slots__ = ('_legacy', '_data', 'scheme') + + def __init__(self, path=None, fileobj=None, mapping=None, scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._legacy = None + self._data = None + self.scheme = scheme + # import pdb; pdb.set_trace() + if mapping is not None: + try: + self._validate_mapping(mapping, scheme) + self._data = mapping + except MetadataUnrecognizedVersionError: + self._legacy = LegacyMetadata(mapping=mapping, scheme=scheme) + self.validate() + else: + data = None + if path: + with open(path, 'rb') as f: + data = f.read() + elif fileobj: + data = fileobj.read() + if data is None: + # Initialised with no args - to be added + self._data = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + else: + if not isinstance(data, text_type): + data = data.decode('utf-8') + try: + self._data = json.loads(data) + self._validate_mapping(self._data, scheme) + except ValueError: + # Note: MetadataUnrecognizedVersionError does not + # inherit from ValueError (it's a DistlibException, + # which should not inherit from ValueError). + # The ValueError comes from the json.load - if that + # succeeds and we get a validation error, we want + # that to propagate + self._legacy = LegacyMetadata(fileobj=StringIO(data), scheme=scheme) + self.validate() + + common_keys = set(('name', 'version', 'license', 'keywords', 'summary')) + + none_list = (None, list) + none_dict = (None, dict) + + mapped_keys = { + 'run_requires': ('Requires-Dist', list), + 'build_requires': ('Setup-Requires-Dist', list), + 'dev_requires': none_list, + 'test_requires': none_list, + 'meta_requires': none_list, + 'extras': ('Provides-Extra', list), + 'modules': none_list, + 'namespaces': none_list, + 'exports': none_dict, + 'commands': none_dict, + 'classifiers': ('Classifier', list), + 'source_url': ('Download-URL', None), + 'metadata_version': ('Metadata-Version', None), + } + + del none_list, none_dict + + def __getattribute__(self, key): + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, maker = mapped[key] + if self._legacy: + if lk is None: + result = None if maker is None else maker() + else: + result = self._legacy.get(lk) + else: + value = None if maker is None else maker() + if key not in ('commands', 'exports', 'modules', 'namespaces', 'classifiers'): + result = self._data.get(key, value) + else: + # special cases for PEP 459 + sentinel = object() + result = sentinel + d = self._data.get('extensions') + if d: + if key == 'commands': + result = d.get('python.commands', value) + elif key == 'classifiers': + d = d.get('python.details') + if d: + result = d.get(key, value) + else: + d = d.get('python.exports') + if not d: + d = self._data.get('python.exports') + if d: + result = d.get(key, value) + if result is sentinel: + result = value + elif key not in common: + result = object.__getattribute__(self, key) + elif self._legacy: + result = self._legacy.get(key) + else: + result = self._data.get(key) + return result + + def _validate_value(self, key, value, scheme=None): + if key in self.SYNTAX_VALIDATORS: + pattern, exclusions = self.SYNTAX_VALIDATORS[key] + if (scheme or self.scheme) not in exclusions: + m = pattern.match(value) + if not m: + raise MetadataInvalidError("'%s' is an invalid value for " + "the '%s' property" % (value, key)) + + def __setattr__(self, key, value): + self._validate_value(key, value) + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, _ = mapped[key] + if self._legacy: + if lk is None: + raise NotImplementedError + self._legacy[lk] = value + elif key not in ('commands', 'exports', 'modules', 'namespaces', 'classifiers'): + self._data[key] = value + else: + # special cases for PEP 459 + d = self._data.setdefault('extensions', {}) + if key == 'commands': + d['python.commands'] = value + elif key == 'classifiers': + d = d.setdefault('python.details', {}) + d[key] = value + else: + d = d.setdefault('python.exports', {}) + d[key] = value + elif key not in common: + object.__setattr__(self, key, value) + else: + if key == 'keywords': + if isinstance(value, string_types): + value = value.strip() + if value: + value = value.split() + else: + value = [] + if self._legacy: + self._legacy[key] = value + else: + self._data[key] = value + + @property + def name_and_version(self): + return _get_name_and_version(self.name, self.version, True) + + @property + def provides(self): + if self._legacy: + result = self._legacy['Provides-Dist'] + else: + result = self._data.setdefault('provides', []) + s = '%s (%s)' % (self.name, self.version) + if s not in result: + result.append(s) + return result + + @provides.setter + def provides(self, value): + if self._legacy: + self._legacy['Provides-Dist'] = value + else: + self._data['provides'] = value + + def get_requirements(self, reqts, extras=None, env=None): + """ + Base method to get dependencies, given a set of extras + to satisfy and an optional environment context. + :param reqts: A list of sometimes-wanted dependencies, + perhaps dependent on extras and environment. + :param extras: A list of optional components being requested. + :param env: An optional environment for marker evaluation. + """ + if self._legacy: + result = reqts + else: + result = [] + extras = get_extras(extras or [], self.extras) + for d in reqts: + if 'extra' not in d and 'environment' not in d: + # unconditional + include = True + else: + if 'extra' not in d: + # Not extra-dependent - only environment-dependent + include = True + else: + include = d.get('extra') in extras + if include: + # Not excluded because of extras, check environment + marker = d.get('environment') + if marker: + include = interpret(marker, env) + if include: + result.extend(d['requires']) + for key in ('build', 'dev', 'test'): + e = ':%s:' % key + if e in extras: + extras.remove(e) + # A recursive call, but it should terminate since 'test' + # has been removed from the extras + reqts = self._data.get('%s_requires' % key, []) + result.extend(self.get_requirements(reqts, extras=extras, env=env)) + return result + + @property + def dictionary(self): + if self._legacy: + return self._from_legacy() + return self._data + + @property + def dependencies(self): + if self._legacy: + raise NotImplementedError + else: + return extract_by_key(self._data, self.DEPENDENCY_KEYS) + + @dependencies.setter + def dependencies(self, value): + if self._legacy: + raise NotImplementedError + else: + self._data.update(value) + + def _validate_mapping(self, mapping, scheme): + if mapping.get('metadata_version') != self.METADATA_VERSION: + raise MetadataUnrecognizedVersionError() + missing = [] + for key, exclusions in self.MANDATORY_KEYS.items(): + if key not in mapping: + if scheme not in exclusions: + missing.append(key) + if missing: + msg = 'Missing metadata items: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + for k, v in mapping.items(): + self._validate_value(k, v, scheme) + + def validate(self): + if self._legacy: + missing, warnings = self._legacy.check(True) + if missing or warnings: + logger.warning('Metadata: missing: %s, warnings: %s', missing, warnings) + else: + self._validate_mapping(self._data, self.scheme) + + def todict(self): + if self._legacy: + return self._legacy.todict(True) + else: + result = extract_by_key(self._data, self.INDEX_KEYS) + return result + + def _from_legacy(self): + assert self._legacy and not self._data + result = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + lmd = self._legacy.todict(True) # skip missing ones + for k in ('name', 'version', 'license', 'summary', 'description', 'classifier'): + if k in lmd: + if k == 'classifier': + nk = 'classifiers' + else: + nk = k + result[nk] = lmd[k] + kw = lmd.get('Keywords', []) + if kw == ['']: + kw = [] + result['keywords'] = kw + keys = (('requires_dist', 'run_requires'), ('setup_requires_dist', 'build_requires')) + for ok, nk in keys: + if ok in lmd and lmd[ok]: + result[nk] = [{'requires': lmd[ok]}] + result['provides'] = self.provides + # author = {} + # maintainer = {} + return result + + LEGACY_MAPPING = { + 'name': 'Name', + 'version': 'Version', + ('extensions', 'python.details', 'license'): 'License', + 'summary': 'Summary', + 'description': 'Description', + ('extensions', 'python.project', 'project_urls', 'Home'): 'Home-page', + ('extensions', 'python.project', 'contacts', 0, 'name'): 'Author', + ('extensions', 'python.project', 'contacts', 0, 'email'): 'Author-email', + 'source_url': 'Download-URL', + ('extensions', 'python.details', 'classifiers'): 'Classifier', + } + + def _to_legacy(self): + + def process_entries(entries): + reqts = set() + for e in entries: + extra = e.get('extra') + env = e.get('environment') + rlist = e['requires'] + for r in rlist: + if not env and not extra: + reqts.add(r) + else: + marker = '' + if extra: + marker = 'extra == "%s"' % extra + if env: + if marker: + marker = '(%s) and %s' % (env, marker) + else: + marker = env + reqts.add(';'.join((r, marker))) + return reqts + + assert self._data and not self._legacy + result = LegacyMetadata() + nmd = self._data + # import pdb; pdb.set_trace() + for nk, ok in self.LEGACY_MAPPING.items(): + if not isinstance(nk, tuple): + if nk in nmd: + result[ok] = nmd[nk] + else: + d = nmd + found = True + for k in nk: + try: + d = d[k] + except (KeyError, IndexError): + found = False + break + if found: + result[ok] = d + r1 = process_entries(self.run_requires + self.meta_requires) + r2 = process_entries(self.build_requires + self.dev_requires) + if self.extras: + result['Provides-Extra'] = sorted(self.extras) + result['Requires-Dist'] = sorted(r1) + result['Setup-Requires-Dist'] = sorted(r2) + # TODO: any other fields wanted + return result + + def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True): + if [path, fileobj].count(None) != 1: + raise ValueError('Exactly one of path and fileobj is needed') + self.validate() + if legacy: + if self._legacy: + legacy_md = self._legacy + else: + legacy_md = self._to_legacy() + if path: + legacy_md.write(path, skip_unknown=skip_unknown) + else: + legacy_md.write_file(fileobj, skip_unknown=skip_unknown) + else: + if self._legacy: + d = self._from_legacy() + else: + d = self._data + if fileobj: + json.dump(d, fileobj, ensure_ascii=True, indent=2, sort_keys=True) + else: + with codecs.open(path, 'w', 'utf-8') as f: + json.dump(d, f, ensure_ascii=True, indent=2, sort_keys=True) + + def add_requirements(self, requirements): + if self._legacy: + self._legacy.add_requirements(requirements) + else: + run_requires = self._data.setdefault('run_requires', []) + always = None + for entry in run_requires: + if 'environment' not in entry and 'extra' not in entry: + always = entry + break + if always is None: + always = {'requires': requirements} + run_requires.insert(0, always) + else: + rset = set(always['requires']) | set(requirements) + always['requires'] = sorted(rset) + + def __repr__(self): + name = self.name or '(no name)' + version = self.version or 'no version' + return '<%s %s %s (%s)>' % (self.__class__.__name__, self.metadata_version, name, version) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/resources.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/resources.py new file mode 100644 index 0000000..fef52aa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/resources.py @@ -0,0 +1,358 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import bisect +import io +import logging +import os +import pkgutil +import sys +import types +import zipimport + +from . import DistlibException +from .util import cached_property, get_cache_base, Cache + +logger = logging.getLogger(__name__) + + +cache = None # created when needed + + +class ResourceCache(Cache): + def __init__(self, base=None): + if base is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('resource-cache')) + super(ResourceCache, self).__init__(base) + + def is_stale(self, resource, path): + """ + Is the cache stale for the given resource? + + :param resource: The :class:`Resource` being cached. + :param path: The path of the resource in the cache. + :return: True if the cache is stale. + """ + # Cache invalidation is a hard problem :-) + return True + + def get(self, resource): + """ + Get a resource into the cache, + + :param resource: A :class:`Resource` instance. + :return: The pathname of the resource in the cache. + """ + prefix, path = resource.finder.get_cache_info(resource) + if prefix is None: + result = path + else: + result = os.path.join(self.base, self.prefix_to_dir(prefix), path) + dirname = os.path.dirname(result) + if not os.path.isdir(dirname): + os.makedirs(dirname) + if not os.path.exists(result): + stale = True + else: + stale = self.is_stale(resource, path) + if stale: + # write the bytes of the resource to the cache location + with open(result, 'wb') as f: + f.write(resource.bytes) + return result + + +class ResourceBase(object): + def __init__(self, finder, name): + self.finder = finder + self.name = name + + +class Resource(ResourceBase): + """ + A class representing an in-package resource, such as a data file. This is + not normally instantiated by user code, but rather by a + :class:`ResourceFinder` which manages the resource. + """ + is_container = False # Backwards compatibility + + def as_stream(self): + """ + Get the resource as a stream. + + This is not a property to make it obvious that it returns a new stream + each time. + """ + return self.finder.get_stream(self) + + @cached_property + def file_path(self): + global cache + if cache is None: + cache = ResourceCache() + return cache.get(self) + + @cached_property + def bytes(self): + return self.finder.get_bytes(self) + + @cached_property + def size(self): + return self.finder.get_size(self) + + +class ResourceContainer(ResourceBase): + is_container = True # Backwards compatibility + + @cached_property + def resources(self): + return self.finder.get_resources(self) + + +class ResourceFinder(object): + """ + Resource finder for file system resources. + """ + + if sys.platform.startswith('java'): + skipped_extensions = ('.pyc', '.pyo', '.class') + else: + skipped_extensions = ('.pyc', '.pyo') + + def __init__(self, module): + self.module = module + self.loader = getattr(module, '__loader__', None) + self.base = os.path.dirname(getattr(module, '__file__', '')) + + def _adjust_path(self, path): + return os.path.realpath(path) + + def _make_path(self, resource_name): + # Issue #50: need to preserve type of path on Python 2.x + # like os.path._get_sep + if isinstance(resource_name, bytes): # should only happen on 2.x + sep = b'/' + else: + sep = '/' + parts = resource_name.split(sep) + parts.insert(0, self.base) + result = os.path.join(*parts) + return self._adjust_path(result) + + def _find(self, path): + return os.path.exists(path) + + def get_cache_info(self, resource): + return None, resource.path + + def find(self, resource_name): + path = self._make_path(resource_name) + if not self._find(path): + result = None + else: + if self._is_directory(path): + result = ResourceContainer(self, resource_name) + else: + result = Resource(self, resource_name) + result.path = path + return result + + def get_stream(self, resource): + return open(resource.path, 'rb') + + def get_bytes(self, resource): + with open(resource.path, 'rb') as f: + return f.read() + + def get_size(self, resource): + return os.path.getsize(resource.path) + + def get_resources(self, resource): + def allowed(f): + return (f != '__pycache__' and not + f.endswith(self.skipped_extensions)) + return set([f for f in os.listdir(resource.path) if allowed(f)]) + + def is_container(self, resource): + return self._is_directory(resource.path) + + _is_directory = staticmethod(os.path.isdir) + + def iterator(self, resource_name): + resource = self.find(resource_name) + if resource is not None: + todo = [resource] + while todo: + resource = todo.pop(0) + yield resource + if resource.is_container: + rname = resource.name + for name in resource.resources: + if not rname: + new_name = name + else: + new_name = '/'.join([rname, name]) + child = self.find(new_name) + if child.is_container: + todo.append(child) + else: + yield child + + +class ZipResourceFinder(ResourceFinder): + """ + Resource finder for resources in .zip files. + """ + def __init__(self, module): + super(ZipResourceFinder, self).__init__(module) + archive = self.loader.archive + self.prefix_len = 1 + len(archive) + # PyPy doesn't have a _files attr on zipimporter, and you can't set one + if hasattr(self.loader, '_files'): + self._files = self.loader._files + else: + self._files = zipimport._zip_directory_cache[archive] + self.index = sorted(self._files) + + def _adjust_path(self, path): + return path + + def _find(self, path): + path = path[self.prefix_len:] + if path in self._files: + result = True + else: + if path and path[-1] != os.sep: + path = path + os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + if not result: + logger.debug('_find failed: %r %r', path, self.loader.prefix) + else: + logger.debug('_find worked: %r %r', path, self.loader.prefix) + return result + + def get_cache_info(self, resource): + prefix = self.loader.archive + path = resource.path[1 + len(prefix):] + return prefix, path + + def get_bytes(self, resource): + return self.loader.get_data(resource.path) + + def get_stream(self, resource): + return io.BytesIO(self.get_bytes(resource)) + + def get_size(self, resource): + path = resource.path[self.prefix_len:] + return self._files[path][3] + + def get_resources(self, resource): + path = resource.path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + plen = len(path) + result = set() + i = bisect.bisect(self.index, path) + while i < len(self.index): + if not self.index[i].startswith(path): + break + s = self.index[i][plen:] + result.add(s.split(os.sep, 1)[0]) # only immediate children + i += 1 + return result + + def _is_directory(self, path): + path = path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + return result + + +_finder_registry = { + type(None): ResourceFinder, + zipimport.zipimporter: ZipResourceFinder +} + +try: + # In Python 3.6, _frozen_importlib -> _frozen_importlib_external + try: + import _frozen_importlib_external as _fi + except ImportError: + import _frozen_importlib as _fi + _finder_registry[_fi.SourceFileLoader] = ResourceFinder + _finder_registry[_fi.FileFinder] = ResourceFinder + # See issue #146 + _finder_registry[_fi.SourcelessFileLoader] = ResourceFinder + del _fi +except (ImportError, AttributeError): + pass + + +def register_finder(loader, finder_maker): + _finder_registry[type(loader)] = finder_maker + + +_finder_cache = {} + + +def finder(package): + """ + Return a resource finder for a package. + :param package: The name of the package. + :return: A :class:`ResourceFinder` instance for the package. + """ + if package in _finder_cache: + result = _finder_cache[package] + else: + if package not in sys.modules: + __import__(package) + module = sys.modules[package] + path = getattr(module, '__path__', None) + if path is None: + raise DistlibException('You cannot get a finder for a module, ' + 'only for a package') + loader = getattr(module, '__loader__', None) + finder_maker = _finder_registry.get(type(loader)) + if finder_maker is None: + raise DistlibException('Unable to locate finder for %r' % package) + result = finder_maker(module) + _finder_cache[package] = result + return result + + +_dummy_module = types.ModuleType(str('__dummy__')) + + +def finder_for_path(path): + """ + Return a resource finder for a path, which should represent a container. + + :param path: The path. + :return: A :class:`ResourceFinder` instance for the path. + """ + result = None + # calls any path hooks, gets importer into cache + pkgutil.get_importer(path) + loader = sys.path_importer_cache.get(path) + finder = _finder_registry.get(type(loader)) + if finder: + module = _dummy_module + module.__file__ = os.path.join(path, '') + module.__loader__ = loader + result = finder(module) + return result diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/scripts.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/scripts.py new file mode 100644 index 0000000..b1fc705 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/scripts.py @@ -0,0 +1,447 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2023 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from io import BytesIO +import logging +import os +import re +import struct +import sys +import time +from zipfile import ZipInfo + +from .compat import sysconfig, detect_encoding, ZipFile +from .resources import finder +from .util import (FileOperator, get_export_entry, convert_path, get_executable, get_platform, in_venv) + +logger = logging.getLogger(__name__) + +_DEFAULT_MANIFEST = ''' + + + + + + + + + + + + +'''.strip() + +# check if Python is called on the first line with this expression +FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$') +SCRIPT_TEMPLATE = r'''# -*- coding: utf-8 -*- +import re +import sys +from %(module)s import %(import_name)s +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(%(func)s()) +''' + +# Pre-fetch the contents of all executable wrapper stubs. +# This is to address https://github.com/pypa/pip/issues/12666. +# When updating pip, we rename the old pip in place before installing the +# new version. If we try to fetch a wrapper *after* that rename, the finder +# machinery will be confused as the package is no longer available at the +# location where it was imported from. So we load everything into memory in +# advance. + +if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): + # Issue 31: don't hardcode an absolute package name, but + # determine it relative to the current package + DISTLIB_PACKAGE = __name__.rsplit('.', 1)[0] + + WRAPPERS = { + r.name: r.bytes + for r in finder(DISTLIB_PACKAGE).iterator("") + if r.name.endswith(".exe") + } + + +def enquote_executable(executable): + if ' ' in executable: + # make sure we quote only the executable in case of env + # for example /usr/bin/env "/dir with spaces/bin/jython" + # instead of "/usr/bin/env /dir with spaces/bin/jython" + # otherwise whole + if executable.startswith('/usr/bin/env '): + env, _executable = executable.split(' ', 1) + if ' ' in _executable and not _executable.startswith('"'): + executable = '%s "%s"' % (env, _executable) + else: + if not executable.startswith('"'): + executable = '"%s"' % executable + return executable + + +# Keep the old name around (for now), as there is at least one project using it! +_enquote_executable = enquote_executable + + +class ScriptMaker(object): + """ + A class to copy or create scripts from source scripts or callable + specifications. + """ + script_template = SCRIPT_TEMPLATE + + executable = None # for shebangs + + def __init__(self, source_dir, target_dir, add_launchers=True, dry_run=False, fileop=None): + self.source_dir = source_dir + self.target_dir = target_dir + self.add_launchers = add_launchers + self.force = False + self.clobber = False + # It only makes sense to set mode bits on POSIX. + self.set_mode = (os.name == 'posix') or (os.name == 'java' and os._name == 'posix') + self.variants = set(('', 'X.Y')) + self._fileop = fileop or FileOperator(dry_run) + + self._is_nt = os.name == 'nt' or (os.name == 'java' and os._name == 'nt') + self.version_info = sys.version_info + + def _get_alternate_executable(self, executable, options): + if options.get('gui', False) and self._is_nt: # pragma: no cover + dn, fn = os.path.split(executable) + fn = fn.replace('python', 'pythonw') + executable = os.path.join(dn, fn) + return executable + + if sys.platform.startswith('java'): # pragma: no cover + + def _is_shell(self, executable): + """ + Determine if the specified executable is a script + (contains a #! line) + """ + try: + with open(executable) as fp: + return fp.read(2) == '#!' + except (OSError, IOError): + logger.warning('Failed to open %s', executable) + return False + + def _fix_jython_executable(self, executable): + if self._is_shell(executable): + # Workaround for Jython is not needed on Linux systems. + import java + + if java.lang.System.getProperty('os.name') == 'Linux': + return executable + elif executable.lower().endswith('jython.exe'): + # Use wrapper exe for Jython on Windows + return executable + return '/usr/bin/env %s' % executable + + def _build_shebang(self, executable, post_interp): + """ + Build a shebang line. In the simple case (on Windows, or a shebang line + which is not too long or contains spaces) use a simple formulation for + the shebang. Otherwise, use /bin/sh as the executable, with a contrived + shebang which allows the script to run either under Python or sh, using + suitable quoting. Thanks to Harald Nordgren for his input. + + See also: http://www.in-ulm.de/~mascheck/various/shebang/#length + https://hg.mozilla.org/mozilla-central/file/tip/mach + """ + if os.name != 'posix': + simple_shebang = True + elif getattr(sys, "cross_compiling", False): + # In a cross-compiling environment, the shebang will likely be a + # script; this *must* be invoked with the "safe" version of the + # shebang, or else using os.exec() to run the entry script will + # fail, raising "OSError 8 [Errno 8] Exec format error". + simple_shebang = False + else: + # Add 3 for '#!' prefix and newline suffix. + shebang_length = len(executable) + len(post_interp) + 3 + if sys.platform == 'darwin': + max_shebang_length = 512 + else: + max_shebang_length = 127 + simple_shebang = ((b' ' not in executable) and (shebang_length <= max_shebang_length)) + + if simple_shebang: + result = b'#!' + executable + post_interp + b'\n' + else: + result = b'#!/bin/sh\n' + result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n' + result += b"' '''\n" + return result + + def _get_shebang(self, encoding, post_interp=b'', options=None): + enquote = True + if self.executable: + executable = self.executable + enquote = False # assume this will be taken care of + elif not sysconfig.is_python_build(): + executable = get_executable() + elif in_venv(): # pragma: no cover + executable = os.path.join(sysconfig.get_path('scripts'), 'python%s' % sysconfig.get_config_var('EXE')) + else: # pragma: no cover + if os.name == 'nt': + # for Python builds from source on Windows, no Python executables with + # a version suffix are created, so we use python.exe + executable = os.path.join(sysconfig.get_config_var('BINDIR'), + 'python%s' % (sysconfig.get_config_var('EXE'))) + else: + executable = os.path.join( + sysconfig.get_config_var('BINDIR'), + 'python%s%s' % (sysconfig.get_config_var('VERSION'), sysconfig.get_config_var('EXE'))) + if options: + executable = self._get_alternate_executable(executable, options) + + if sys.platform.startswith('java'): # pragma: no cover + executable = self._fix_jython_executable(executable) + + # Normalise case for Windows - COMMENTED OUT + # executable = os.path.normcase(executable) + # N.B. The normalising operation above has been commented out: See + # issue #124. Although paths in Windows are generally case-insensitive, + # they aren't always. For example, a path containing a ẞ (which is a + # LATIN CAPITAL LETTER SHARP S - U+1E9E) is normcased to ß (which is a + # LATIN SMALL LETTER SHARP S' - U+00DF). The two are not considered by + # Windows as equivalent in path names. + + # If the user didn't specify an executable, it may be necessary to + # cater for executable paths with spaces (not uncommon on Windows) + if enquote: + executable = enquote_executable(executable) + # Issue #51: don't use fsencode, since we later try to + # check that the shebang is decodable using utf-8. + executable = executable.encode('utf-8') + # in case of IronPython, play safe and enable frames support + if (sys.platform == 'cli' and '-X:Frames' not in post_interp and + '-X:FullFrames' not in post_interp): # pragma: no cover + post_interp += b' -X:Frames' + shebang = self._build_shebang(executable, post_interp) + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: # pragma: no cover + raise ValueError('The shebang (%r) is not decodable from utf-8' % shebang) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + if encoding != 'utf-8': + try: + shebang.decode(encoding) + except UnicodeDecodeError: # pragma: no cover + raise ValueError('The shebang (%r) is not decodable ' + 'from the script encoding (%r)' % (shebang, encoding)) + return shebang + + def _get_script_text(self, entry): + return self.script_template % dict( + module=entry.prefix, import_name=entry.suffix.split('.')[0], func=entry.suffix) + + manifest = _DEFAULT_MANIFEST + + def get_manifest(self, exename): + base = os.path.basename(exename) + return self.manifest % base + + def _write_script(self, names, shebang, script_bytes, filenames, ext): + use_launcher = self.add_launchers and self._is_nt + if not use_launcher: + script_bytes = shebang + script_bytes + else: # pragma: no cover + if ext == 'py': + launcher = self._get_launcher('t') + else: + launcher = self._get_launcher('w') + stream = BytesIO() + with ZipFile(stream, 'w') as zf: + source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH') + if source_date_epoch: + date_time = time.gmtime(int(source_date_epoch))[:6] + zinfo = ZipInfo(filename='__main__.py', date_time=date_time) + zf.writestr(zinfo, script_bytes) + else: + zf.writestr('__main__.py', script_bytes) + zip_data = stream.getvalue() + script_bytes = launcher + shebang + zip_data + for name in names: + outname = os.path.join(self.target_dir, name) + if use_launcher: # pragma: no cover + n, e = os.path.splitext(outname) + if e.startswith('.py'): + outname = n + outname = '%s.exe' % outname + try: + self._fileop.write_binary_file(outname, script_bytes) + except Exception: + # Failed writing an executable - it might be in use. + logger.warning('Failed to write executable - trying to ' + 'use .deleteme logic') + dfname = '%s.deleteme' % outname + if os.path.exists(dfname): + os.remove(dfname) # Not allowed to fail here + os.rename(outname, dfname) # nor here + self._fileop.write_binary_file(outname, script_bytes) + logger.debug('Able to replace executable using ' + '.deleteme logic') + try: + os.remove(dfname) + except Exception: + pass # still in use - ignore error + else: + if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover + outname = '%s.%s' % (outname, ext) + if os.path.exists(outname) and not self.clobber: + logger.warning('Skipping existing file %s', outname) + continue + self._fileop.write_binary_file(outname, script_bytes) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + + variant_separator = '-' + + def get_script_filenames(self, name): + result = set() + if '' in self.variants: + result.add(name) + if 'X' in self.variants: + result.add('%s%s' % (name, self.version_info[0])) + if 'X.Y' in self.variants: + result.add('%s%s%s.%s' % (name, self.variant_separator, self.version_info[0], self.version_info[1])) + return result + + def _make_script(self, entry, filenames, options=None): + post_interp = b'' + if options: + args = options.get('interpreter_args', []) + if args: + args = ' %s' % ' '.join(args) + post_interp = args.encode('utf-8') + shebang = self._get_shebang('utf-8', post_interp, options=options) + script = self._get_script_text(entry).encode('utf-8') + scriptnames = self.get_script_filenames(entry.name) + if options and options.get('gui', False): + ext = 'pyw' + else: + ext = 'py' + self._write_script(scriptnames, shebang, script, filenames, ext) + + def _copy_script(self, script, filenames): + adjust = False + script = os.path.join(self.source_dir, convert_path(script)) + outname = os.path.join(self.target_dir, os.path.basename(script)) + if not self.force and not self._fileop.newer(script, outname): + logger.debug('not copying %s (up-to-date)', script) + return + + # Always open the file, but ignore failures in dry-run mode -- + # that way, we'll get accurate feedback if we can read the + # script. + try: + f = open(script, 'rb') + except IOError: # pragma: no cover + if not self.dry_run: + raise + f = None + else: + first_line = f.readline() + if not first_line: # pragma: no cover + logger.warning('%s is an empty file (skipping)', script) + return + + match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n')) + if match: + adjust = True + post_interp = match.group(1) or b'' + + if not adjust: + if f: + f.close() + self._fileop.copy_file(script, outname) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + else: + logger.info('copying and adjusting %s -> %s', script, self.target_dir) + if not self._fileop.dry_run: + encoding, lines = detect_encoding(f.readline) + f.seek(0) + shebang = self._get_shebang(encoding, post_interp) + if b'pythonw' in first_line: # pragma: no cover + ext = 'pyw' + else: + ext = 'py' + n = os.path.basename(outname) + self._write_script([n], shebang, f.read(), filenames, ext) + if f: + f.close() + + @property + def dry_run(self): + return self._fileop.dry_run + + @dry_run.setter + def dry_run(self, value): + self._fileop.dry_run = value + + if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover + # Executable launcher support. + # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/ + + def _get_launcher(self, kind): + if struct.calcsize('P') == 8: # 64-bit + bits = '64' + else: + bits = '32' + platform_suffix = '-arm' if get_platform() == 'win-arm64' else '' + name = '%s%s%s.exe' % (kind, bits, platform_suffix) + if name not in WRAPPERS: + msg = ('Unable to find resource %s in package %s' % + (name, DISTLIB_PACKAGE)) + raise ValueError(msg) + return WRAPPERS[name] + + # Public API follows + + def make(self, specification, options=None): + """ + Make a script. + + :param specification: The specification, which is either a valid export + entry specification (to make a script from a + callable) or a filename (to make a script by + copying from a source location). + :param options: A dictionary of options controlling script generation. + :return: A list of all absolute pathnames written to. + """ + filenames = [] + entry = get_export_entry(specification) + if entry is None: + self._copy_script(specification, filenames) + else: + self._make_script(entry, filenames, options=options) + return filenames + + def make_multiple(self, specifications, options=None): + """ + Take a list of specifications and make scripts from them, + :param specifications: A list of specifications. + :return: A list of all absolute pathnames written to, + """ + filenames = [] + for specification in specifications: + filenames.extend(self.make(specification, options)) + return filenames diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/t32.exe b/backend/venv/Lib/site-packages/pip/_vendor/distlib/t32.exe new file mode 100644 index 0000000000000000000000000000000000000000..52154f0be32cc2bdbf98af131d477900667d0abd GIT binary patch literal 97792 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

        XMwe#*Lv$g8jIpIBEV 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 w+IyK^N3WCD*(>mhAj=irKyR>D9b+D<@QBhV6U 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

        qx{CqlSNQ_YhQ()VtG-D; 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 z zTqlq5kVRi7+$OwLt^qv^r0;n#n zpirVrmq(#)+e{mA?J464r}w|YKgY&Ytm$8P996>MchplU6=^m6w7b&Ymf=r&sCncn zOmowM3#B5s+=^cz8;l^WWBx5T1>W-N4nCyzk=dt?E zMyndXHuh#zqg1ukvrMMHB&%m(SbrN?wsnEAW~sjdtM6g;%Ieuq)!&*gjr-nKpJDZ< zTm9ZPW6#wG{S{cfT%M3G$?DHATD9}Aao^wSmDPK!e$63cKfvnOe{S@PtiI0bnfU6j z!0K%D*{9de6dVDO|_%q|y0fe5Q z@{bAaBEmDDPx;hEgu8%W85xGZV)#k^&ckJ%{gYPDm@Fpc@+af=JX%~aA7M=tami?& zeH9A@&w@jxt(0-6jH$!l<>XPun#Y@8q1(u+cGuHzBjeuVU3#Ie)HUhD!_@fqLKykO4=Fa@~Z2P(O*&IuM+EN zCDs10g*PxiP)lMb2P$;nlLM8y;Jwu~PXQgZhmJyTBWmD>CC zK7IS0(cd#*;F*I4pLO<-bIu)l-mu{#(ngLNJ?8uiE=(VL(YWywF1{qgJ25jWd(x%8 zoXMBv=3Rb8{*swb{J$uf#=N1&sD=IE2onKad&9xN^DyyomtEu$|u3xxl z@eSWuvh>EA!pZnw3q7=p$Nmjr9Ao~DH9xt|$CmRy`fE@p{vGRnndc{e}IXnEQX# zMgOzgccOTqUUv++g~FoOX7oTXu7O!}9NbZ^g=0 z!CO{;{|9Ssz3qp$-|?d#uf6jpcdh&B&wjrC7kB^io?rd?HyeI?@9*yW{U83g@%{%M zeCXjv9^JJ0vB#hI)00m%Zh3m^wr95Q*tzT3=XO8;!k)eRUVLf)%dfn8;I-G^c=N5d z-)VaHy+6PI!CyXfnm=ke`0*#7wtn{4zkUA2p~G!oe)aW{za!cGzuO_4y21ZO9m0P) z|NrUu|J(HcXC3mX?RAIzpU!_Q`A2_m9*6;5hx7 zk|@MVLe?u5e%Z#RiH4^!TR0b+4K)Hw6iB6vuF}joL6qOW{ zot+&k-}!0Gzr>*@J%3hQyt*(gZDu~Z=pK*GZhS#m0iRNfsu%Ia!fG5A<40y06#j4> zPKUdilEPw7X-(Ave3)R)93XRLFBI@m_OpP9IMBYteDO(AE%U4C+K22}$v3%bo~MYQ zg*iQ?I??UsZuOz zJxWN!iFXky{EdL0YDv)u_(f7N0y|k%41d{+s%an$2N@0_+yx6rg$FJX(n8m>hr?HA z3szfJGOrNBit@^mi#&rX+ULzDgtM@$++R{#U077&DJ=Dqqq9c@YHLQ!E3X_;QhEK^ zVb2|Wr(^HnUx^KetEKCLeZPpvqt3p{a|g2B%8& zc*^0}x;B^91=$a{Sj`R-2RJ<<8WaA)a(|idQmwzRM#uiIL>p0Gb$%^9IZJhXIY2U< zKU41`>8?{3>Atu`vqGdBPoP!^Gh_OsVP@&~y6xv(}7e)Feh7;WnI2+Pd zR8%dLfW`N5>|ls?g1=)+^tf0~5>H{x{D2gAt!GHd^|WZ^rJj-n)&9lj{PXzc!D_a# zDXZdnT26J3rZGL*`<_$w)PEduZJFWq8a-y)3T;Lvuws+qR#q`_rAApJ`nrn z$|@IG&Ae!~^slwEuY?H~&u0H$I@;RVwdD({D@x{8*min$ae1wO_QDIs46iOW4YncE zDSsvG^G1a}dYh#z{ic8J;gYE;BIv>^gz6s(Y@XI6gE_aM_kLje` zqqtbE`i7ZmL&tSJIWJ+@lj}IyJ@YjiM9Z&01C(LAVlPR04jm zsdja7sV?&{>zSZ>j&ZA=qmo*?H6`v%XpFCpE9jJ;EOBik4nMHCGjYYM-cwWdNNjSq>gRe=b!$wl?qcI^ij{ccRnKDLn%^7 zX9`5gOs9+V_(@N39O>$$dXGwJ3j6=jSfw6C`K*7P59rbx zy7Y!F(5tD(-sHw`c|ClQQg5P)tozyEf2Z@T569mp0lFrsK9o}*%Bjz7x{UH&sR=5T za!92dQlV+;R8w}zJv)(4@;4?XpU#0JZ)@BI4`ZHCA;U(+d$SJyoY_rNZtm z%!W3omq>#^7qZe4UCGMjNmQQVWaXKjq&(2XQ`5Kg^rqCkr#1GhcJ)m(JUtzrhTeUr zcJOtwlqJ06ru^MgO`Q>5DrJcJUDj(4{6$h@K380nigVqic}?7Cl@hN~DEAb~J%w^l z8I{~<_zHT%BRw$_nkS#=uAOi1f+t@?eMX+->m1`!G0-fW=Wk6>Y7R=`6PVm9fjULK z8q-zvn%bi^xv8VRi<{4;Ds|H|&b!;RC+j-aNhOTxq|08)aytXEy{KW<%?IF#GZ=%0 z{q%^T&c>-8qulL&Dy~FG8Y=APci``#!hT$xqEx3*QKp_o)=}z0n7<``A2F`oI7_KA z8<%MVO!|(```K41brq@(w*q?)>jK|TQGKT8!~0jLKCa2iaJgwyGRR!-5uMc;{)g2W z#Sf`7#yqIbaBWmcw%%9ALO)H9xORF-n%*nmMs1-|cZbs?d8vs?>)k(IC5>TirlzAE zlD12F$bVE{Burn4QlF#3VI~{;q=n1%K{g$Bq5c$(vwMu{PMLPUtxLYEZx_|qpQ`#! z?*-4Eruw?ND?>&2K)1QHH`M9g@R)6H8c)T`+pCnih&mMJWz+u9?iAbhdTL5*xO{{+ zZoUrwK>f|8D+l}?)S0$!x`aRHkq&{~fxY74$IhzPbRay_Yg7+nGyLl6+gbI!oA8^G z_qrRqRwov8NlTzClBEr!t?EO6)n`<%R+BfwYeKuaWlBAOx;PxCuBQ=guGA;|Qr|51 zceEv|>yem)3j6Jy)gVr5pOT>Z(P#9d&FD9(cT=yuDUI4K^mNm-sX4`V!FxhIympSBNh{&9wOs(=!ZvpFw+dTbHKJd*d2o zt78hH^P|#)FMUFH%V+e#+5P?9p>s0jlB9ZMcDpU1HNL6S-k8R4AFSPL+9s3sB;|gw zOSSI1{ic8EMO)fqbhn!0{iR7f+MgSL-IV(Q=+iAqbsLqC=1Pc?e5Xk{$`=WHU(iJj z9&=svU{`7M$;!gRX1Q)FPf@nLpHb>ERJd%DPtl*W;AX`3j{d}z8c*MdqQ0ckCZ~>~ zU(o#}{Ul|XN?Bs2$2x{zis6^5PRcJksU-g>jSF5<>KCYR8ha0jSKX((soULD_ZmG4 zDQF-6NIkIQq&|!X`oMei=lQ0NQ$OLg-lWftbsBY=DJS~&*6vM7drfEw`N!~I%_(`c zRr6|Wl!_h0u1aT@>MZp*g?@`LQy%D6-L)Vw-_>2xn?QPjqf87Y{EmK7*ZrIE+c{cw zrfrIXAzX=_R3iMJIMs~TdXI`x9@k3MyE;|#W*YU(n00owo3SW!l5%L0F{i74qU!HY zR{e{UsK4D*|Bmr!e(%v;)IfiUYhZD)Yv7n7*Fe{|U1k(y>U0x_K6+o+Rh{KOqRuM* zTAelKD|MFZbJgDS(*{WytcfFjX~!l~-};9+6?_nQt5UNDc9?yI+1|g>_D7hd4|b`I zn4RqVzjOG8cK>${-_YTI>pA@XuE^u=t6i)kXPWh*TxQra)zFw}C9<%XU+6EJscu9U zx%$j%o>`GrWv)pzB_+A#^J?U9!v>WpYl9{B7(HXkrQ*}47sDb}uNhCr&MYkVPpYb! z#xg`ji3u%xkvdIzYirBrSK1J!S9L_Cie0#8`P;6^68c{x-I9?^*3hgMrB08+G_R^S zP*F08rO(R?7my+Ko9HRBCK-{6j-bn<^8ywA@`;Q6CDW^BmKT>~mT~6d8VQGm_!@tp zTD;9vw}{Df)-eoO)Ezdz?IC%Uy4LtAHkoFbTlBIlR>{1;{P`s{`4l+?q|S<&>aV!69M&qVm{G}ET(MI9 z#Vog~>e@i{B(?`60un6?U8!P|Sy;{4pAw4RU$V%rJ|RbuIe#H$x?O7Qs0rJ3y*4}% zt{yE>Ih7Ehu%i5iF~5CRNl@a90*qaJJ}b(LpSu`Rn06$t+aw4&Ilrq)nq`@Wh52tLatkEtvYPY3cGyYV>wtWf43>iNdHq zkx-_W7hP-9zaxUmmOmhKow%B|xR!%%vKi*Bl^6w6Kd|kE7|c{}8mhxbO1-Y}sU@ax z*6VO>8wD*Nh|p7kaX*KW4AhoMKobL{r4$lth1|kgP+eG4(oV+`pt**|^fboW&s1y9lC-v$_EEzB7E0olV-XV00+a_ugQ_2xV6dapFZmGnbtp;m zG7E18N?us%)AkKO3FlVSIjEmm{V#x$o_kOd-)~Uj?opKF=>?S7zlsw3REQ$<5hZj9 zf37fM;qm(8tWRh=|GV!0Rsa8Ldj8e$k9U8({`mO+x9SlN(_VKq4emAfcGUkA{I?P| z>6D*|)^p15-xfE`7ik_9~f_N4tMBKZF~OSE2S z<_E5*7~Q?y!vLb-=EXM;u(bU3I|lj1uMAxF^Co>|FylsUT=H$e{gz+8{!5RsKH+!S zQDc;0;ltn1z1O;b1owOHe*f;%)dzPwcVB(#@NfKu_A!M4&y?4{{kliZef^r(N1f>Y zr2}s_eW}#Q8%@d(nH9>6aJ4bY(BnP}H&}R&h3hR`XW?24*I2m1!a579EiABbx`jRq zvn=pSw){4q6xv|9z`})5850?zFJc z!i^TLw{We6w_CWv!fFc(EbPpHG;&NZ%bMp~=(8}x!gLGMEF5BCs)g|uwkeaJCJT33 zxXHrx7Ou5$jfE>Ltg~>Dh1C|8Sy*7&Plgq&Zmu0bYkF~A2c z{tz(pEMyPhW(n|al!Si|@Lg1$#04CDwlN<9+-33I!1sng2mFc*%Oxx>X!-z0ooncc zOfiLgFde4AOq96E0{+IDZveh#@#6EiR}XVE5N1B`F4TSC_W-w}Hi7R1hSHR31Xm*o z2Xz2^1MnGC0p++8IGiDmq(2RKB}(Eg0RCdQe^1A}~32G5;T7mav8gqeFS=15CtAU*-aTXRl5qJhl((eIY zbE#4XF_&{$OAm+z{JaqUxDXYTwo1K_-zgFA=E6~Hv$i! z3c#Cy@1lyqTY;aU%D_JdE<&Vd1-QTvN@$Xruhdc0?ciz(GAK}zUxD*cjhL4Km!l*v zn}8opgXWmWOjqhcl%yvMSdJ1m6~F;A$QR)Z0&YM_m;!gB#J#}KmBfcRf*8~?l$aw+ zPwlYyPT-5PNGERg16xoM{z2fNZ<#O!&bGL~+br(kjAtS03H+`Bemt9VzTmCE(Q`~V zV}PqHehcudZ<{cO03SjLeFWZ9K-zj!r-0usRLTQh0Bl8NfeSMZy+;Exu-OWd1S5{LOa6b#U4<&8&exT<%6R*I;8uXZ_0*|7k9&uqu`TWF7I08#i zQjf}j&!KeL0h>{}EPy!y?yAr}*8yKZmEnFbaLz*V4_*ztY7u=0_-x=G7Mt{J1in;9 zyN~&P;HS%=HFzs<;myWP9q_bzgQo%yqu$3&8*oH}NlzMZ8LB5~ZUCOK+|a=TykQM| zNT0FeO}&!W<#{sPZ^kUWE*2fPyhXc&`@X;* zqdo_}51921Wlxc#iIRA;fImeI!F)Zi_&vnZSYR59krBvo&tBuu&2lkfrl$-6+g|01|RxpT4so)K7N%>~|Q@p_=#=MeV-<(`JP z7btfu#9W} z1sB-oLxaoNb2(2d<^tthwBQ2e&WNO0;AU&C{_j&Ung%f{8kk0P?gm^0OajuZ)};bB z00H_l?&B1_iE6|=3JBZRiT_rh*vHdd!~#9QPQY|v955dU(4Ps%rEip$oy5EpS9K>b zmw4Bn#9RX1D3k^wLY!%$YM)d3m`C1Olo~ zoY&RyU#HftU8{cco8PF-n>VY*#zyt(tFNk~M~^C*{)#K@7!CX;8?ZmvUB|t_9Saxk z(b_$sPmk0k9$C0>$r5q!X=wM6J)zx)vEG3`9u3bZgwQWsD0*iP(%!Wm(~yei=hM)U zQffs zh_)8@(6@PATS!}L`b!Xwu@?7Q+WrA!t;5%8lfWgs74~b?T6Ls<<4sM`b(hp}JTXE= zgS$|gHBJG=Uff0clWK_t5PeOT6|BTPaj2WX4_@<^!o2G8K z;RcA{>m$_s1H8)pq1Q8Y9SVJ2x^&kEGiJCsE%vCpqe)-hHGbFst-KsS)>;s&9SkTWZdnIqJsZNoxN5`RbZ$u2BmXEKoHy$SS1$Sh{qn`bFRp^}8D; zs0VKxr|Rctt6Q$kRJT`o)m=3i>hWb4so&S-sGlsGrygBft+xN*GPU=Y*Qy~;hSYga zht$aJA$7^NkUIa_kQ)C&NX>peq%!xj-1d4%O?fAzYEd)Z3#qF=45^}~keYWeq?RpP zrdF<8scyaXR`uf_|5)95=bdWZx^-&(`t|BpzxtIf-;EnLs)rwbShrqd3+ zXCd`)Ye+rw%rk1&u3hT+=bu;m_U%*q_wQG)zy7*<>#eucrym?pFa0&7-hKC7%@@th z&Fb?{KT?1GGNf8tTh-yihc&MVS))cUp3LVg4@?ukhH>6Tn1{;Vtrb2EbypKYBh}TR zDQa=(I<+=*t9m$ezuF(#7j92gPy7$er~j{3YQh@kx*Iunga7%hj0IQ>T!sI2`2Pd` z8}a`l{@;)Ae-{2T@|g!#Gv`@@ESrr={TBaEw=zG){{j5JjsHL6zZw6Z;{Q;D{}E@= zzj@*Hs~L0n>Bqm%-X8Ot)~!^+7n4=!z(^H(Yl;fJf1L__bgK%r-mgN3_O+*fL{Iz= z#D5z8FUEf!{t2tK9RG`xRcO^n75eEE75d|KDzxQR!n|LFKG@gcpMEVr2LGM#-x>c2 z_^178WiS--bXTE^N2<{5DJpcsbt?4ZTUF?h`&DTFz7GGY8|RpMaVBX1W2T{0+Y8hl zIKLGc?xEzXRA^+i3QhU03SGBOg>HR7h3?;}Li^r{@bAI@1^Ca!|2+IJ!vFX2e-Hj2 z#Q&4{-+_PPy!B1|e}MnicK_!ged97hC?|yP5yGzsVH+X5O9-vWA@$dhA@%u`kUDf- zNFBa4q`tgAq`ux4YWLp<|HJTq3I3DWnYK?c>D_mQt;mg{{!%U7XHt}|Ha86HEU!@T{k79Zn=)IZVjoY?hmQg_jUL` zwrQAazDUE&%!%HK-YjjDd+w0Ig9Z*f>(X`y-iecQaaq5d^D?t1UqbNNnchn#dgq=e4h9b%IKbNHSGe%{cb7uz(7lgW9L!{4MnslDb7$AN?}Xy5?PnItkt!k;`j=aR{D`}OFZ ziaid7SO;g##s4K<2_SRw+&(>e^fvZ7je`byNMufX_;XWw_ULih1RcOooy!5(lm0C6 z@12Z&&mR3QvuVpcSCWALxtDnJE}uL(d-B}VC4kh~&dZtn|Fw4};8j)E9=}nL!OEb|8Yr3&l<{f89L6LhARqy%EmF0O5hI`w zhA=*XAW%mHsn#lp5Ml``xff6YMH$p8#a0mxxLf7r^l4JKm;3^cVaYX)Tihp?7+EM*SW=&O7fs zAyIlhqup5<$?@GaL|>i1s7DWnWrNc5skN)tPOO#Cy?0u=sN5sQVR>PXuy`bOOi5{V zX6>p8Ng3%G>AkwAmp~~KQc`-Qw&|7{UnQz$-|z`&)hkWrDttbpLwubYXGKNT?I{QW zF}-(^1nJ26l=f{CTGu$U`nkPyGPRpzxlNnY)FbCJGPr|^+)pi;oHG|%Jr5zbR zBNe&p*Xf)yswHziHA&*y+uttwK_3ZN^4WE3^~*?2PwFIDD?P3AzVxh9w?lf0=-4ab zH1tn%SLplpty4QmRU%Kj{>9(kX%fU<-P?97cRHefF}hbu$Fg@zKgyQ$GM&r5+WOo> zwWlU+mvgaRb!tgH9e*xYeUz_OkuNtjkW|i}JHDUd{kbczywdq2Q?f2E^*stEbPe1& zw0q#8(W!x_r*#i3n>!`YUP=5U*}0zYT3~>D2YiMJY9D;?!N9zE^8)kd&ky9~@nvnJoVI5&L4d4x#t4-3U9A32+Wheu}r?g%P+qic>VR)oo}#nM^RwMjvaxWJ9h@Y z_~MJemtTGv_~z?9&Nn!4;6UJqAAShT`IiNj%U5{w`v^N5-%t}>drfrG%ligtqMN9R zZnh@6#eur^bfBfJ4gAtJ21eP|z#RK9u-rb;{C#Ae3B+qc>>sWBHQCjNz?eVYc{`pqvqyLwH&h_4fKezmA-ak@4>{=ynn>Hp`^XPl>_vm4c{ zQA7FU*oK$<;>-p*t6MJAvBq!F;6Iu)Y7rmbqKV+w_|03ixVS}&hAkX^4OC)P8a8x? zf!x~4=~mN)@|9hUQd?2sdw&hr>%KsYV%ciso(Ha1jS9r-|7n#obhkYAfIRlnT2-GJ z`G2Dv3;W}Z4ZLToo*xqv(@-t-V%5eqYShpQNUsTVl#&arG=}Oqs-EKd_-`rDhkmuX zsZ@c!byN}m*aZs~T&;O$&7M7bKK<&euRhbs%U^x< z)qAwRr$y(^ohA8j-#v0dKU!TmzMTyH;58HTxs4k)Zlo4k5vHz8iN5yQYm?fk=;B`} zjyPNEXj`{#oqhJ%XQuho6n7y&Wkp3rruDaRUO1T6;QuHtF8*A&{&UNgEst*4upzfw zw{ES~4}5B%dVy+PRbYXyHN%z9(3o>SSG`d60>vs?A3AjCJAKx~S!wv|iQaEW2iwp` z`}XY{1E1h>@Ne3*$rK|s!Dp*iuXb=NhGd_9`l)T+yx9~}aMy8A}zfBDtG)=ag<1s7bRnl@C8l_R_=;hXXbT9za*{ffvBeXZZioM<2P$ zXJ`(+ffrc-7vP5e$mpUk&C=e{&xvm_>!c8Td*uvTZxjwMn>7~>jbAW}d(Lduhsq5c zKKw{!fY&t+e%X5S75IJiyzuR*=m~m&yj=Z}+2z}`=l*Tc9~{JkcCVSW5)Rq#D&KKf z@$NUx64pAg+FM!p6(>cOXSQzLI!>}M13bhBhmXgD7Fr@l(7z%)pgS~&N5~EGkKNUp z%>mR;@L%yk2@c)#9A;O++EF+to@^t97w`|=YIgDSC2CPw_%&ykxBtk$<|Ctee$WEH zmviJFejr!KhQ|dRN6wIYbi=pk1?4LJSb1OJ&|C7~L-YoRE}P9d{JjK+1nGj}d5`3Ymn&N6&w1tr?#0eTmH|7Zqu}rlvtGiX zyKq>xJMxNSe%8;t+uUOyQ}5evzctM>WhyxM>hY+ECmxqbJih<_dwcWQ`S#~Yy>0HO zBztf~vIFdzPtAV)vDq)To27%pdtrT+%yjnpj7^e0W0M+7576gJB~R$|kIJ)EfP;fy z{GO@UMV##V3~<37(s~?dk$dF2JRV-Ykac9K=xgKj`I5_y@;^Io}zvg)6`J?!O z{xTnUexMH=dp!Yu**#nTryK3biJfin_%60cILsFgluX&r>x9EV+4x`WFarm#&*0$o z8JpDdRnh$=vu5BR`o}(N)=zdy<@Ji-m%VrLFI}63KZMSCJUlM&fcYSjCmt7C;Kxor zb6bi9Z|!7H2!}rlhrBT*@aOC?yZ#H|P;7R!a6q52Nxfy0ygq}2*Jp6>`ixC#y2io( zuk!GtXUs41vq~#C_*xzhuPc#w@EIH^t8zQoib)+U_+Opu@d?6VTo*gAcbB~@bq0qF z;h-FwT^*s%*d+8hMY@1ZN|a4ve)cx0$vU$}CGeNGOZ9+X{{76hZQI7lN0|X0*hN}o z20ZY2Xu*Z=m}|XX#yRF&d7l(o|m?OEaQ z%#@C{Y*Hs%Djdq|^B-lC<_u46h;@FS>8mMpO+ zpM28rOMUhHpgo?RC@yQ8AI-E4)7#tgw+RR7!c)Q_6xL^KQr_6EHh*+iduU{mJ&>Jj zvxlYFJ;LF3;V?}&OcoB5@;=7zq#G(n*&pDSEI9d>T+aZP+i$M6~9GpH22W*np=Y_IKkBm;TKaEVb`-Q_S;c&Nb_`T%lwyZP< zC^ji2!pC?@darVn{Re(8|D8H@Y77j(sa+wZIKY=kJdTIU4?i5Xe{Ps-f0>zT>!v5# zny@}&le|7ZCYuBf^TIg%L2@+fmK3{dXbBDg>U<3O+kI5$%U=Cx_F6gF=dd0;*Zez2 z`xts>XJ>B$R`d}am@;LG!y!_>%HvX=CmdrF(1jC~cV7;c`WWc*yy$Ht5qV>4&Ybb76jkFz`YLKWcx?U@^}Rro^qqpSxg=<^$k z$J*iVwBE=c=jP`~ALHS$KHn!@pi~5`|4y-r+Vb^(rDF&GrI%jXPFs7j^%Ig`$d7h> zShQ%7_3PKqw71Caz4u;IPRSm4-~k5@>wD-84$KA26UY^nH4HdlPmx3BLTL2zJ!!V3 z0Qe8urpLw|@iC+e_!#IjHfipJbihC1`b)9DyOavO4f&C*&(XTSt@gnzl@6QEnSOi6 zq!Y&R6<1v0{2uLxarP6~ffXKsgRguCy^%fEIrw()0)0TIoj!{X%+Fq*u}P8o{I^vL z@B`<0S|6|N(4oTv+SB9WAdDT>Wz!x-)1D+#Ov{=zYi9DT9W20szY$r%!B>w5E&WlE zDc?7?_3!geSf}+Q-{B)MPk>7W zMI`w4BlvZ)@gMqK`_GbMoc{!>0C%T3FOP2DqU+gXPR2gxbG-;CK12|w; z6*dPx#On$A0qnj-j#x7wSNMVO z&c`q`zgFZYce5IAmsKTAx0BoNOs4@8E~l z&>UQV8$H1O@I7k;_eF|36$@x`KIC;OQ=I?c zWf1?z(-nA%ii#XO;;qTIU{|rz2l3k^Z%zi7qo6a_Q#l3)>?kzF{;ycE!h*q|n*&3k zkh_lEKb{g*z@;uw9S1s3>@U67nQUqX2j zXIrJ~ZhphoAm7Lw@S_LlB|Je+-~sV0&ile=`h`dEgZW(e{#kHiH^~!LwmA5`oYF?h zFgW-MY~Y0qp$m81afiuf8S`{x0XAQ`2Rnl;q98x4iKxI1UJDj1AjY^*kHeoV?BM9& z_x``=Jp&xPUG%tk9B838wn=lhTPGk>%(ap91y+uMAKrK$g1ioLk1RoRbVxSiA;EDf zu$RIgDgW4rNPbkr6YwI&e%*D~nfB#6`SvuAY`G3uLe}}7IRMywene}e`KJN9gP$?{ z`d4$$EaZ|o2t3e1=!E^i)-fMN@&wwhT)EQb&YkPz8G8E)-pCHRgWtq4GDCmN1+tk1 zdS$|?(jC|-^?)aGUIcz$!NJ$#@q|9KC))LcjByXR0WY$(PPP+VJnZsM7oVcMmq2~w zzl;A!zufv)^Y;vJf&R1}4_c20Ei}cxpbJ!Z!*}oj+lijSGi(vL1aeT|0^K#nso0q# z5SRVr;P>(`U!gH{q8^VY`1klf;6+}Jifqxo^2#gD?m`3f6?q4K^g#0Xn1(-HnTf=p z9`y9_PuYpm_zyTRcjCWb|BwUbBj!$M%$gJ0!v}l;&j*gN`Pf?QnAQ|7uOXcO-LQj) zlmAHBC@<&!*z0X%i>!0ZHShwNhtA-LtV@o5l#fs>UNNt-$Kqt>Cg3|!Iae332jPFR zG6s7e*r##Y#inXM8Ei zs-j!*Z>h-hF?~gG`ZiTX!R?@GWZ{^MO8I!8x~s4-RIi>G^95NfHTu;w;N^)$(g2^egQf}uu#fIPc#({J^7{IlGes#FL)^?+$ z(}%EU@;ML4-hQsR;7i%1_vN22Qk?8&`M_zqzNKoM{Ea<>mE#~!Ml3X0@mq4<S<1^)2<*LYe zl4~Q!!~O+wROENa`;%j%91D4UAHy0zYtU@17j9<$WnN>Q%eeT_&?Jn%^PNh1Ecs8q z>>9;x$@h^fdwOr=*$O|C#EO&$H$Lk@d;}^mP_ge+Xu|xp`;+&rVEO=;mmnTaxnZ~R zUAs#1rdJ6D^1keWAhu7=*UKaMUh<5c)xKR;CS#aWw0_N$pF03JJS^}Z9~fAef7U!a z+{LuXITMrj;{(I*1Os_b^5;$-1p~P@ay-Z*IVy6UzXhFl*xCgicj3+~o~eti5O zpI>BN#ZUA8n}>xvh$|Bd%vU^d*c9KZtqH{6kAufDkL0dlW*+7P);Yj zJa!QsR7&}eZ>Bs%rk=YTfGuFXkADu{zyb|ux8x6Xc|-D5mvrYH+cXmyH=8-{_w`WKbt@vqa^AO4GPN^MXK{v|Sq9^&)U0tXd(P=NzF!H46O ztuKaL&Xio;48cIYv|KsL{xSYN_uP~D=%bGgAUA|R4jj;&bv0{h;-EwD$NqmaL4 zAAr}1isX^&!m?IT6N8Vfcty72EyJP1?Af!O-NWuO|6%`;1?Yh+GB&VK(21{hyk)z0 zyd#|`Cy&wzHCE1dsjTk*GJ7+<-Fe>_#q9MAy% zK%0HV@7wEnx7f4OQ`}wvFOQ2R_OKOy9BE(dlyh=K*2<8fYuB!=74Mx09?D~mxZ#Ey zUe)v4cFQfdxHz!(NV?dCU;99F=mGs%-ysXo1Nh4q`qXt>BwLYlZJF^oP+siU(tEcK zWUePKLvBfamTBL&!`rXFfP)G>fTKKbfRA|#+rhe2-M3T4zdK%uVGSz(V;8wZ@)CN^ z)QGCcC9Nn=8%!BmpWq`4;3tm?>PaIZWX0T*AM?TVz8k9XxCt6d*Kr7Myz9B<~ zyh4tL7`-0&H+VsQP4luF2Y&#%Gd>lc3?I$6nybDOJ#STC3zVrIXh{KY-K6uHXT7f%||3T41-anZUVj-MZNtxYmgV*LkP^%HL+{Il2Li zO`q@?81$Y1(|ZN1Z{NNSHejG~4LZPe$PIoH_JVzhiiPK?U)BnhDbD_4f3%POX8J2q zOrAL(n?r6v?<{aRX7mF1DA2*jc=4CXso=K@hetGMWyc0SH@=r==t>0+D&sL9=^Y8q zHn3L}+>tr>1+Bpwo2=N&;*%WPjn6o;HO~H51c^~{0kc}Ev3#xEr1gglr}%_r&NHYLdS5 zHCLahHnoCxuuMJbx!u^nv5NL;(RYPK@|e0{!Gfoiqd6!W^_BL8{9*Cp#bxY{asYeO z$A~AMc*1?JYpUeu=l4=Pdu?H1q2s5Y!{D=Q`a6+>kx$e9XX32itB>uHzy0VTYh&a! zs5Qt{^6S{wn54DUJgoy&R{1`-7MaF}^Ztz2DQsDW)=jLLh#_o|Thm7SI#s-X93X$d zSm+vdiHf{(FC|mU6V|}1N?bDcUHIPtwJWhr=n=5uJ0RPepMT8ej41I92Zh&ftRGpw zvQ}WNlAyKH!-9)kD{FFKNB$Z2@hQEWkF!r}uz7-+K3I#h_97O+x{q~dqSl?nsPUju_Nld~>&V_a2awnXb%J?Cw? zxw&qS2zfPliM)9FyNmU2^M+;4@1Lx-Pq={WGtf`-g0oxXF*BUVe~0Y&~`dUh3I(M^kJyy!`0JMYdwv*LpXFg(`K;PJ9&HcHN_hYAln|`2$ z&O3c#&L*D3y{xmDyOoP6b1(f&skStwj%wh{a1E$ER`u6#J+(I1Mk$aP8(T+h754_V zsDOUy#2xYewKH^%YpT1qubruLB}cq_t%}}g#8Iq!^IFyLl{(TjXN9kfb#Gm(rgy91 z?hOcB70A&4?s^Z)ReF0&zd&Cd_tO6!`b>GD${zWKQSJ|e#3$M$PO4PVpTH_pZju)n zrT)eQM(f$@?7(34HdMc;m8G7u12+Xm=<06nnuI{2!lfNl+vq(s0zS}N?nqQ1Ro4vH z+g&ns{X{{NsiQ16##QQxGxQd#_t#_w#_F0udUsrwMvD#nS}&dD6Xkb$v^A=9>@nTM%QP#G4-zJKqFn>N5_NRl~87+XaW|4h4mQqdGvR&a;8)D zU}dbhPx{A3m@oM z_WttJtcaEbx1%JznHt$cc|^hp!sBlIN@tOy9O05#hVM11EUVHvGbbl&_zlA*#!eVM zEIX%5+}P3C9diZ^$r_%SbLsG*gGP_Y8FAB?O9zb@-Z3+0_+{f-#>EcL%pQ7^e&RR$ z%c@=CT3(hA*Y%v5v9X=Uj2@fgeuK4=y|pg6Pj}{I4H~PTbDik=iB;)5I&0Kejgoa^ z|ItIo={G(HXXTWhj6B_af^Oxva{FYB%NiCtjQ?HYGIM%mj~j7I*66s{u|rb^4bl%S zcZs_xb68GRT-VO=rG1yZxwQX?D~=kyb9@5pVB`iEv;AI%LfkB z2fdmp0Ka1Mo8~9vC+7FhADF)}e{+8E(nCwD7e*I0Ele!zSvat8Na2LSI}0BwTvE8Y zaAV=N!s5b1h1G-6!KT5)U?4&78CD;Gg>@D#ELc*otYCG)`htxGn+vuTY%eG-h+UeX zUXs;MfAw^|`WmU;rmDaD)Z;?+xlFyTSHGLp^LF*USG@;<)q{03LafF}&?w2lp27aX zfx+v8LxLlN6M|EN4+R$nmjssuR|nSzHwHHcw*|Kci-UWEhk}7n^-!HqbSO5|G?WlZ z3?+wphWdvFhOQ3{35^U*2u%&$8M-g@P-tOjNoZMUb!dHPV`y_|TWEWzI3zrhk$Szu zdEtbG4=r51aNEM@yo9{OyyU!|dHwSS=B;0}QNJ~`chR9mf&A+Eb@HS0J@tAz`dyzt bB!6W7g#4-b3-g!cLzth+PZapSNrC?c%T_@< literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/wheel.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/wheel.py new file mode 100644 index 0000000..62ab10f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/wheel.py @@ -0,0 +1,1100 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2023 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import base64 +import codecs +import datetime +from email import message_from_file +import hashlib +import json +import logging +import os +import posixpath +import re +import shutil +import sys +import tempfile +import zipfile + +from . import __version__, DistlibException +from .compat import sysconfig, ZipFile, fsdecode, text_type, filter +from .database import InstalledDistribution +from .metadata import Metadata, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME +from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, cached_property, get_cache_base, + read_exports, tempdir, get_platform) +from .version import NormalizedVersion, UnsupportedVersionError + +logger = logging.getLogger(__name__) + +cache = None # created when needed + +if hasattr(sys, 'pypy_version_info'): # pragma: no cover + IMP_PREFIX = 'pp' +elif sys.platform.startswith('java'): # pragma: no cover + IMP_PREFIX = 'jy' +elif sys.platform == 'cli': # pragma: no cover + IMP_PREFIX = 'ip' +else: + IMP_PREFIX = 'cp' + +VER_SUFFIX = sysconfig.get_config_var('py_version_nodot') +if not VER_SUFFIX: # pragma: no cover + VER_SUFFIX = '%s%s' % sys.version_info[:2] +PYVER = 'py' + VER_SUFFIX +IMPVER = IMP_PREFIX + VER_SUFFIX + +ARCH = get_platform().replace('-', '_').replace('.', '_') + +ABI = sysconfig.get_config_var('SOABI') +if ABI and ABI.startswith('cpython-'): + ABI = ABI.replace('cpython-', 'cp').split('-')[0] +else: + + def _derive_abi(): + parts = ['cp', VER_SUFFIX] + if sysconfig.get_config_var('Py_DEBUG'): + parts.append('d') + if IMP_PREFIX == 'cp': + vi = sys.version_info[:2] + if vi < (3, 8): + wpm = sysconfig.get_config_var('WITH_PYMALLOC') + if wpm is None: + wpm = True + if wpm: + parts.append('m') + if vi < (3, 3): + us = sysconfig.get_config_var('Py_UNICODE_SIZE') + if us == 4 or (us is None and sys.maxunicode == 0x10FFFF): + parts.append('u') + return ''.join(parts) + + ABI = _derive_abi() + del _derive_abi + +FILENAME_RE = re.compile( + r''' +(?P[^-]+) +-(?P\d+[^-]*) +(-(?P\d+[^-]*))? +-(?P\w+\d+(\.\w+\d+)*) +-(?P\w+) +-(?P\w+(\.\w+)*) +\.whl$ +''', re.IGNORECASE | re.VERBOSE) + +NAME_VERSION_RE = re.compile(r''' +(?P[^-]+) +-(?P\d+[^-]*) +(-(?P\d+[^-]*))?$ +''', re.IGNORECASE | re.VERBOSE) + +SHEBANG_RE = re.compile(br'\s*#![^\r\n]*') +SHEBANG_DETAIL_RE = re.compile(br'^(\s*#!("[^"]+"|\S+))\s+(.*)$') +SHEBANG_PYTHON = b'#!python' +SHEBANG_PYTHONW = b'#!pythonw' + +if os.sep == '/': + to_posix = lambda o: o +else: + to_posix = lambda o: o.replace(os.sep, '/') + +if sys.version_info[0] < 3: + import imp +else: + imp = None + import importlib.machinery + import importlib.util + + +def _get_suffixes(): + if imp: + return [s[0] for s in imp.get_suffixes()] + else: + return importlib.machinery.EXTENSION_SUFFIXES + + +def _load_dynamic(name, path): + # https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly + if imp: + return imp.load_dynamic(name, path) + else: + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + +class Mounter(object): + + def __init__(self): + self.impure_wheels = {} + self.libs = {} + + def add(self, pathname, extensions): + self.impure_wheels[pathname] = extensions + self.libs.update(extensions) + + def remove(self, pathname): + extensions = self.impure_wheels.pop(pathname) + for k, v in extensions: + if k in self.libs: + del self.libs[k] + + def find_module(self, fullname, path=None): + if fullname in self.libs: + result = self + else: + result = None + return result + + def load_module(self, fullname): + if fullname in sys.modules: + result = sys.modules[fullname] + else: + if fullname not in self.libs: + raise ImportError('unable to find extension for %s' % fullname) + result = _load_dynamic(fullname, self.libs[fullname]) + result.__loader__ = self + parts = fullname.rsplit('.', 1) + if len(parts) > 1: + result.__package__ = parts[0] + return result + + +_hook = Mounter() + + +class Wheel(object): + """ + Class to build and install from Wheel files (PEP 427). + """ + + wheel_version = (1, 1) + hash_kind = 'sha256' + + def __init__(self, filename=None, sign=False, verify=False): + """ + Initialise an instance using a (valid) filename. + """ + self.sign = sign + self.should_verify = verify + self.buildver = '' + self.pyver = [PYVER] + self.abi = ['none'] + self.arch = ['any'] + self.dirname = os.getcwd() + if filename is None: + self.name = 'dummy' + self.version = '0.1' + self._filename = self.filename + else: + m = NAME_VERSION_RE.match(filename) + if m: + info = m.groupdict('') + self.name = info['nm'] + # Reinstate the local version separator + self.version = info['vn'].replace('_', '-') + self.buildver = info['bn'] + self._filename = self.filename + else: + dirname, filename = os.path.split(filename) + m = FILENAME_RE.match(filename) + if not m: + raise DistlibException('Invalid name or ' + 'filename: %r' % filename) + if dirname: + self.dirname = os.path.abspath(dirname) + self._filename = filename + info = m.groupdict('') + self.name = info['nm'] + self.version = info['vn'] + self.buildver = info['bn'] + self.pyver = info['py'].split('.') + self.abi = info['bi'].split('.') + self.arch = info['ar'].split('.') + + @property + def filename(self): + """ + Build and return a filename from the various components. + """ + if self.buildver: + buildver = '-' + self.buildver + else: + buildver = '' + pyver = '.'.join(self.pyver) + abi = '.'.join(self.abi) + arch = '.'.join(self.arch) + # replace - with _ as a local version separator + version = self.version.replace('-', '_') + return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, pyver, abi, arch) + + @property + def exists(self): + path = os.path.join(self.dirname, self.filename) + return os.path.isfile(path) + + @property + def tags(self): + for pyver in self.pyver: + for abi in self.abi: + for arch in self.arch: + yield pyver, abi, arch + + @cached_property + def metadata(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + wrapper = codecs.getreader('utf-8') + with ZipFile(pathname, 'r') as zf: + self.get_wheel_metadata(zf) + # wv = wheel_metadata['Wheel-Version'].split('.', 1) + # file_version = tuple([int(i) for i in wv]) + # if file_version < (1, 1): + # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME, + # LEGACY_METADATA_FILENAME] + # else: + # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME] + fns = [WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME] + result = None + for fn in fns: + try: + metadata_filename = posixpath.join(info_dir, fn) + with zf.open(metadata_filename) as bf: + wf = wrapper(bf) + result = Metadata(fileobj=wf) + if result: + break + except KeyError: + pass + if not result: + raise ValueError('Invalid wheel, because metadata is ' + 'missing: looked in %s' % ', '.join(fns)) + return result + + def get_wheel_metadata(self, zf): + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + metadata_filename = posixpath.join(info_dir, 'WHEEL') + with zf.open(metadata_filename) as bf: + wf = codecs.getreader('utf-8')(bf) + message = message_from_file(wf) + return dict(message) + + @cached_property + def info(self): + pathname = os.path.join(self.dirname, self.filename) + with ZipFile(pathname, 'r') as zf: + result = self.get_wheel_metadata(zf) + return result + + def process_shebang(self, data): + m = SHEBANG_RE.match(data) + if m: + end = m.end() + shebang, data_after_shebang = data[:end], data[end:] + # Preserve any arguments after the interpreter + if b'pythonw' in shebang.lower(): + shebang_python = SHEBANG_PYTHONW + else: + shebang_python = SHEBANG_PYTHON + m = SHEBANG_DETAIL_RE.match(shebang) + if m: + args = b' ' + m.groups()[-1] + else: + args = b'' + shebang = shebang_python + args + data = shebang + data_after_shebang + else: + cr = data.find(b'\r') + lf = data.find(b'\n') + if cr < 0 or cr > lf: + term = b'\n' + else: + if data[cr:cr + 2] == b'\r\n': + term = b'\r\n' + else: + term = b'\r' + data = SHEBANG_PYTHON + term + data + return data + + def get_hash(self, data, hash_kind=None): + if hash_kind is None: + hash_kind = self.hash_kind + try: + hasher = getattr(hashlib, hash_kind) + except AttributeError: + raise DistlibException('Unsupported hash algorithm: %r' % hash_kind) + result = hasher(data).digest() + result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') + return hash_kind, result + + def write_record(self, records, record_path, archive_record_path): + records = list(records) # make a copy, as mutated + records.append((archive_record_path, '', '')) + with CSVWriter(record_path) as writer: + for row in records: + writer.writerow(row) + + def write_records(self, info, libdir, archive_paths): + records = [] + distinfo, info_dir = info + # hasher = getattr(hashlib, self.hash_kind) + for ap, p in archive_paths: + with open(p, 'rb') as f: + data = f.read() + digest = '%s=%s' % self.get_hash(data) + size = os.path.getsize(p) + records.append((ap, digest, size)) + + p = os.path.join(distinfo, 'RECORD') + ap = to_posix(os.path.join(info_dir, 'RECORD')) + self.write_record(records, p, ap) + archive_paths.append((ap, p)) + + def build_zip(self, pathname, archive_paths): + with ZipFile(pathname, 'w', zipfile.ZIP_DEFLATED) as zf: + for ap, p in archive_paths: + logger.debug('Wrote %s to %s in wheel', p, ap) + zf.write(p, ap) + + def build(self, paths, tags=None, wheel_version=None): + """ + Build a wheel from files in specified paths, and use any specified tags + when determining the name of the wheel. + """ + if tags is None: + tags = {} + + libkey = list(filter(lambda o: o in paths, ('purelib', 'platlib')))[0] + if libkey == 'platlib': + is_pure = 'false' + default_pyver = [IMPVER] + default_abi = [ABI] + default_arch = [ARCH] + else: + is_pure = 'true' + default_pyver = [PYVER] + default_abi = ['none'] + default_arch = ['any'] + + self.pyver = tags.get('pyver', default_pyver) + self.abi = tags.get('abi', default_abi) + self.arch = tags.get('arch', default_arch) + + libdir = paths[libkey] + + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + archive_paths = [] + + # First, stuff which is not in site-packages + for key in ('data', 'headers', 'scripts'): + if key not in paths: + continue + path = paths[key] + if os.path.isdir(path): + for root, dirs, files in os.walk(path): + for fn in files: + p = fsdecode(os.path.join(root, fn)) + rp = os.path.relpath(p, path) + ap = to_posix(os.path.join(data_dir, key, rp)) + archive_paths.append((ap, p)) + if key == 'scripts' and not p.endswith('.exe'): + with open(p, 'rb') as f: + data = f.read() + data = self.process_shebang(data) + with open(p, 'wb') as f: + f.write(data) + + # Now, stuff which is in site-packages, other than the + # distinfo stuff. + path = libdir + distinfo = None + for root, dirs, files in os.walk(path): + if root == path: + # At the top level only, save distinfo for later + # and skip it for now + for i, dn in enumerate(dirs): + dn = fsdecode(dn) + if dn.endswith('.dist-info'): + distinfo = os.path.join(root, dn) + del dirs[i] + break + assert distinfo, '.dist-info directory expected, not found' + + for fn in files: + # comment out next suite to leave .pyc files in + if fsdecode(fn).endswith(('.pyc', '.pyo')): + continue + p = os.path.join(root, fn) + rp = to_posix(os.path.relpath(p, path)) + archive_paths.append((rp, p)) + + # Now distinfo. Assumed to be flat, i.e. os.listdir is enough. + files = os.listdir(distinfo) + for fn in files: + if fn not in ('RECORD', 'INSTALLER', 'SHARED', 'WHEEL'): + p = fsdecode(os.path.join(distinfo, fn)) + ap = to_posix(os.path.join(info_dir, fn)) + archive_paths.append((ap, p)) + + wheel_metadata = [ + 'Wheel-Version: %d.%d' % (wheel_version or self.wheel_version), + 'Generator: distlib %s' % __version__, + 'Root-Is-Purelib: %s' % is_pure, + ] + for pyver, abi, arch in self.tags: + wheel_metadata.append('Tag: %s-%s-%s' % (pyver, abi, arch)) + p = os.path.join(distinfo, 'WHEEL') + with open(p, 'w') as f: + f.write('\n'.join(wheel_metadata)) + ap = to_posix(os.path.join(info_dir, 'WHEEL')) + archive_paths.append((ap, p)) + + # sort the entries by archive path. Not needed by any spec, but it + # keeps the archive listing and RECORD tidier than they would otherwise + # be. Use the number of path segments to keep directory entries together, + # and keep the dist-info stuff at the end. + def sorter(t): + ap = t[0] + n = ap.count('/') + if '.dist-info' in ap: + n += 10000 + return (n, ap) + + archive_paths = sorted(archive_paths, key=sorter) + + # Now, at last, RECORD. + # Paths in here are archive paths - nothing else makes sense. + self.write_records((distinfo, info_dir), libdir, archive_paths) + # Now, ready to build the zip file + pathname = os.path.join(self.dirname, self.filename) + self.build_zip(pathname, archive_paths) + return pathname + + def skip_entry(self, arcname): + """ + Determine whether an archive entry should be skipped when verifying + or installing. + """ + # The signature file won't be in RECORD, + # and we don't currently don't do anything with it + # We also skip directories, as they won't be in RECORD + # either. See: + # + # https://github.com/pypa/wheel/issues/294 + # https://github.com/pypa/wheel/issues/287 + # https://github.com/pypa/wheel/pull/289 + # + return arcname.endswith(('/', '/RECORD.jws')) + + def install(self, paths, maker, **kwargs): + """ + Install a wheel to the specified paths. If kwarg ``warner`` is + specified, it should be a callable, which will be called with two + tuples indicating the wheel version of this software and the wheel + version in the file, if there is a discrepancy in the versions. + This can be used to issue any warnings to raise any exceptions. + If kwarg ``lib_only`` is True, only the purelib/platlib files are + installed, and the headers, scripts, data and dist-info metadata are + not written. If kwarg ``bytecode_hashed_invalidation`` is True, written + bytecode will try to use file-hash based invalidation (PEP-552) on + supported interpreter versions (CPython 3.7+). + + The return value is a :class:`InstalledDistribution` instance unless + ``options.lib_only`` is True, in which case the return value is ``None``. + """ + + dry_run = maker.dry_run + warner = kwargs.get('warner') + lib_only = kwargs.get('lib_only', False) + bc_hashed_invalidation = kwargs.get('bytecode_hashed_invalidation', False) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message = message_from_file(wf) + wv = message['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + if (file_version != self.wheel_version) and warner: + warner(self.wheel_version, file_version) + + if message['Root-Is-Purelib'] == 'true': + libdir = paths['purelib'] + else: + libdir = paths['platlib'] + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + data_pfx = posixpath.join(data_dir, '') + info_pfx = posixpath.join(info_dir, '') + script_pfx = posixpath.join(data_dir, 'scripts', '') + + # make a new instance rather than a copy of maker's, + # as we mutate it + fileop = FileOperator(dry_run=dry_run) + fileop.record = True # so we can rollback if needed + + bc = not sys.dont_write_bytecode # Double negatives. Lovely! + + outfiles = [] # for RECORD writing + + # for script copying/shebang processing + workdir = tempfile.mkdtemp() + # set target dir later + # we default add_launchers to False, as the + # Python Launcher should be used instead + maker.source_dir = workdir + maker.target_dir = None + try: + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if self.skip_entry(u_arcname): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + if lib_only and u_arcname.startswith((info_pfx, data_pfx)): + logger.debug('lib_only: skipping %s', u_arcname) + continue + is_script = (u_arcname.startswith(script_pfx) and not u_arcname.endswith('.exe')) + + if u_arcname.startswith(data_pfx): + _, where, rp = u_arcname.split('/', 2) + outfile = os.path.join(paths[where], convert_path(rp)) + else: + # meant for site-packages. + if u_arcname in (wheel_metadata_name, record_name): + continue + outfile = os.path.join(libdir, convert_path(u_arcname)) + if not is_script: + with zf.open(arcname) as bf: + fileop.copy_stream(bf, outfile) + # Issue #147: permission bits aren't preserved. Using + # zf.extract(zinfo, libdir) should have worked, but didn't, + # see https://www.thetopsites.net/article/53834422.shtml + # So ... manually preserve permission bits as given in zinfo + if os.name == 'posix': + # just set the normal permission bits + os.chmod(outfile, (zinfo.external_attr >> 16) & 0x1FF) + outfiles.append(outfile) + # Double check the digest of the written file + if not dry_run and row[1]: + with open(outfile, 'rb') as bf: + data = bf.read() + _, newdigest = self.get_hash(data, kind) + if newdigest != digest: + raise DistlibException('digest mismatch ' + 'on write for ' + '%s' % outfile) + if bc and outfile.endswith('.py'): + try: + pyc = fileop.byte_compile(outfile, hashed_invalidation=bc_hashed_invalidation) + outfiles.append(pyc) + except Exception: + # Don't give up if byte-compilation fails, + # but log it and perhaps warn the user + logger.warning('Byte-compilation failed', exc_info=True) + else: + fn = os.path.basename(convert_path(arcname)) + workname = os.path.join(workdir, fn) + with zf.open(arcname) as bf: + fileop.copy_stream(bf, workname) + + dn, fn = os.path.split(outfile) + maker.target_dir = dn + filenames = maker.make(fn) + fileop.set_executable_mode(filenames) + outfiles.extend(filenames) + + if lib_only: + logger.debug('lib_only: returning None') + dist = None + else: + # Generate scripts + + # Try to get pydist.json so we can see if there are + # any commands to generate. If this fails (e.g. because + # of a legacy wheel), log a warning but don't give up. + commands = None + file_version = self.info['Wheel-Version'] + if file_version == '1.0': + # Use legacy info + ep = posixpath.join(info_dir, 'entry_points.txt') + try: + with zf.open(ep) as bwf: + epdata = read_exports(bwf) + commands = {} + for key in ('console', 'gui'): + k = '%s_scripts' % key + if k in epdata: + commands['wrap_%s' % key] = d = {} + for v in epdata[k].values(): + s = '%s:%s' % (v.prefix, v.suffix) + if v.flags: + s += ' [%s]' % ','.join(v.flags) + d[v.name] = s + except Exception: + logger.warning('Unable to read legacy script ' + 'metadata, so cannot generate ' + 'scripts') + else: + try: + with zf.open(metadata_name) as bwf: + wf = wrapper(bwf) + commands = json.load(wf).get('extensions') + if commands: + commands = commands.get('python.commands') + except Exception: + logger.warning('Unable to read JSON metadata, so ' + 'cannot generate scripts') + if commands: + console_scripts = commands.get('wrap_console', {}) + gui_scripts = commands.get('wrap_gui', {}) + if console_scripts or gui_scripts: + script_dir = paths.get('scripts', '') + if not os.path.isdir(script_dir): + raise ValueError('Valid script path not ' + 'specified') + maker.target_dir = script_dir + for k, v in console_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script) + fileop.set_executable_mode(filenames) + + if gui_scripts: + options = {'gui': True} + for k, v in gui_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script, options) + fileop.set_executable_mode(filenames) + + p = os.path.join(libdir, info_dir) + dist = InstalledDistribution(p) + + # Write SHARED + paths = dict(paths) # don't change passed in dict + del paths['purelib'] + del paths['platlib'] + paths['lib'] = libdir + p = dist.write_shared_locations(paths, dry_run) + if p: + outfiles.append(p) + + # Write RECORD + dist.write_installed_files(outfiles, paths['prefix'], dry_run) + return dist + except Exception: # pragma: no cover + logger.exception('installation failed.') + fileop.rollback() + raise + finally: + shutil.rmtree(workdir) + + def _get_dylib_cache(self): + global cache + if cache is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('dylib-cache'), '%s.%s' % sys.version_info[:2]) + cache = Cache(base) + return cache + + def _get_extensions(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + arcname = posixpath.join(info_dir, 'EXTENSIONS') + wrapper = codecs.getreader('utf-8') + result = [] + with ZipFile(pathname, 'r') as zf: + try: + with zf.open(arcname) as bf: + wf = wrapper(bf) + extensions = json.load(wf) + cache = self._get_dylib_cache() + prefix = cache.prefix_to_dir(self.filename, use_abspath=False) + cache_base = os.path.join(cache.base, prefix) + if not os.path.isdir(cache_base): + os.makedirs(cache_base) + for name, relpath in extensions.items(): + dest = os.path.join(cache_base, convert_path(relpath)) + if not os.path.exists(dest): + extract = True + else: + file_time = os.stat(dest).st_mtime + file_time = datetime.datetime.fromtimestamp(file_time) + info = zf.getinfo(relpath) + wheel_time = datetime.datetime(*info.date_time) + extract = wheel_time > file_time + if extract: + zf.extract(relpath, cache_base) + result.append((name, dest)) + except KeyError: + pass + return result + + def is_compatible(self): + """ + Determine if a wheel is compatible with the running system. + """ + return is_compatible(self) + + def is_mountable(self): + """ + Determine if a wheel is asserted as mountable by its metadata. + """ + return True # for now - metadata details TBD + + def mount(self, append=False): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if not self.is_compatible(): + msg = 'Wheel %s not compatible with this Python.' % pathname + raise DistlibException(msg) + if not self.is_mountable(): + msg = 'Wheel %s is marked as not mountable.' % pathname + raise DistlibException(msg) + if pathname in sys.path: + logger.debug('%s already in path', pathname) + else: + if append: + sys.path.append(pathname) + else: + sys.path.insert(0, pathname) + extensions = self._get_extensions() + if extensions: + if _hook not in sys.meta_path: + sys.meta_path.append(_hook) + _hook.add(pathname, extensions) + + def unmount(self): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if pathname not in sys.path: + logger.debug('%s not in path', pathname) + else: + sys.path.remove(pathname) + if pathname in _hook.impure_wheels: + _hook.remove(pathname) + if not _hook.impure_wheels: + if _hook in sys.meta_path: + sys.meta_path.remove(_hook) + + def verify(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + # data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + # metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message_from_file(wf) + # wv = message['Wheel-Version'].split('.', 1) + # file_version = tuple([int(i) for i in wv]) + # TODO version verification + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + # See issue #115: some wheels have .. in their entries, but + # in the filename ... e.g. __main__..py ! So the check is + # updated to look for .. in the directory portions + p = u_arcname.split('/') + if '..' in p: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + + if self.skip_entry(u_arcname): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + def update(self, modifier, dest_dir=None, **kwargs): + """ + Update the contents of a wheel in a generic way. The modifier should + be a callable which expects a dictionary argument: its keys are + archive-entry paths, and its values are absolute filesystem paths + where the contents the corresponding archive entries can be found. The + modifier is free to change the contents of the files pointed to, add + new entries and remove entries, before returning. This method will + extract the entire contents of the wheel to a temporary location, call + the modifier, and then use the passed (and possibly updated) + dictionary to write a new wheel. If ``dest_dir`` is specified, the new + wheel is written there -- otherwise, the original wheel is overwritten. + + The modifier should return True if it updated the wheel, else False. + This method returns the same value the modifier returns. + """ + + def get_version(path_map, info_dir): + version = path = None + key = '%s/%s' % (info_dir, LEGACY_METADATA_FILENAME) + if key not in path_map: + key = '%s/PKG-INFO' % info_dir + if key in path_map: + path = path_map[key] + version = Metadata(path=path).version + return version, path + + def update_version(version, path): + updated = None + try: + NormalizedVersion(version) + i = version.find('-') + if i < 0: + updated = '%s+1' % version + else: + parts = [int(s) for s in version[i + 1:].split('.')] + parts[-1] += 1 + updated = '%s+%s' % (version[:i], '.'.join(str(i) for i in parts)) + except UnsupportedVersionError: + logger.debug('Cannot update non-compliant (PEP-440) ' + 'version %r', version) + if updated: + md = Metadata(path=path) + md.version = updated + legacy = path.endswith(LEGACY_METADATA_FILENAME) + md.write(path=path, legacy=legacy) + logger.debug('Version updated from %r to %r', version, updated) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + record_name = posixpath.join(info_dir, 'RECORD') + with tempdir() as workdir: + with ZipFile(pathname, 'r') as zf: + path_map = {} + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if u_arcname == record_name: + continue + if '..' in u_arcname: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + zf.extract(zinfo, workdir) + path = os.path.join(workdir, convert_path(u_arcname)) + path_map[u_arcname] = path + + # Remember the version. + original_version, _ = get_version(path_map, info_dir) + # Files extracted. Call the modifier. + modified = modifier(path_map, **kwargs) + if modified: + # Something changed - need to build a new wheel. + current_version, path = get_version(path_map, info_dir) + if current_version and (current_version == original_version): + # Add or update local version to signify changes. + update_version(current_version, path) + # Decide where the new wheel goes. + if dest_dir is None: + fd, newpath = tempfile.mkstemp(suffix='.whl', prefix='wheel-update-', dir=workdir) + os.close(fd) + else: + if not os.path.isdir(dest_dir): + raise DistlibException('Not a directory: %r' % dest_dir) + newpath = os.path.join(dest_dir, self.filename) + archive_paths = list(path_map.items()) + distinfo = os.path.join(workdir, info_dir) + info = distinfo, info_dir + self.write_records(info, workdir, archive_paths) + self.build_zip(newpath, archive_paths) + if dest_dir is None: + shutil.copyfile(newpath, pathname) + return modified + + +def _get_glibc_version(): + import platform + ver = platform.libc_ver() + result = [] + if ver[0] == 'glibc': + for s in ver[1].split('.'): + result.append(int(s) if s.isdigit() else 0) + result = tuple(result) + return result + + +def compatible_tags(): + """ + Return (pyver, abi, arch) tuples compatible with this Python. + """ + class _Version: + def __init__(self, major, minor): + self.major = major + self.major_minor = (major, minor) + self.string = ''.join((str(major), str(minor))) + + def __str__(self): + return self.string + + + versions = [ + _Version(sys.version_info.major, minor_version) + for minor_version in range(sys.version_info.minor, -1, -1) + ] + abis = [] + for suffix in _get_suffixes(): + if suffix.startswith('.abi'): + abis.append(suffix.split('.', 2)[1]) + abis.sort() + if ABI != 'none': + abis.insert(0, ABI) + abis.append('none') + result = [] + + arches = [ARCH] + if sys.platform == 'darwin': + m = re.match(r'(\w+)_(\d+)_(\d+)_(\w+)$', ARCH) + if m: + name, major, minor, arch = m.groups() + minor = int(minor) + matches = [arch] + if arch in ('i386', 'ppc'): + matches.append('fat') + if arch in ('i386', 'ppc', 'x86_64'): + matches.append('fat3') + if arch in ('ppc64', 'x86_64'): + matches.append('fat64') + if arch in ('i386', 'x86_64'): + matches.append('intel') + if arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): + matches.append('universal') + while minor >= 0: + for match in matches: + s = '%s_%s_%s_%s' % (name, major, minor, match) + if s != ARCH: # already there + arches.append(s) + minor -= 1 + + # Most specific - our Python version, ABI and arch + for i, version_object in enumerate(versions): + version = str(version_object) + add_abis = [] + + if i == 0: + add_abis = abis + + if IMP_PREFIX == 'cp' and version_object.major_minor >= (3, 2): + limited_api_abi = 'abi' + str(version_object.major) + if limited_api_abi not in add_abis: + add_abis.append(limited_api_abi) + + for abi in add_abis: + for arch in arches: + result.append((''.join((IMP_PREFIX, version)), abi, arch)) + # manylinux + if abi != 'none' and sys.platform.startswith('linux'): + arch = arch.replace('linux_', '') + parts = _get_glibc_version() + if len(parts) == 2: + if parts >= (2, 5): + result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux1_%s' % arch)) + if parts >= (2, 12): + result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux2010_%s' % arch)) + if parts >= (2, 17): + result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux2014_%s' % arch)) + result.append((''.join( + (IMP_PREFIX, version)), abi, 'manylinux_%s_%s_%s' % (parts[0], parts[1], arch))) + + # where no ABI / arch dependency, but IMP_PREFIX dependency + for i, version_object in enumerate(versions): + version = str(version_object) + result.append((''.join((IMP_PREFIX, version)), 'none', 'any')) + if i == 0: + result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any')) + + # no IMP_PREFIX, ABI or arch dependency + for i, version_object in enumerate(versions): + version = str(version_object) + result.append((''.join(('py', version)), 'none', 'any')) + if i == 0: + result.append((''.join(('py', version[0])), 'none', 'any')) + + return set(result) + + +COMPATIBLE_TAGS = compatible_tags() + +del compatible_tags + + +def is_compatible(wheel, tags=None): + if not isinstance(wheel, Wheel): + wheel = Wheel(wheel) # assume it's a filename + result = False + if tags is None: + tags = COMPATIBLE_TAGS + for ver, abi, arch in tags: + if ver in wheel.pyver and abi in wheel.abi and arch in wheel.arch: + result = True + break + return result diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/distro/__init__.py new file mode 100644 index 0000000..7686fe8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distro/__init__.py @@ -0,0 +1,54 @@ +from .distro import ( + NORMALIZED_DISTRO_ID, + NORMALIZED_LSB_ID, + NORMALIZED_OS_ID, + LinuxDistribution, + __version__, + build_number, + codename, + distro_release_attr, + distro_release_info, + id, + info, + like, + linux_distribution, + lsb_release_attr, + lsb_release_info, + major_version, + minor_version, + name, + os_release_attr, + os_release_info, + uname_attr, + uname_info, + version, + version_parts, +) + +__all__ = [ + "NORMALIZED_DISTRO_ID", + "NORMALIZED_LSB_ID", + "NORMALIZED_OS_ID", + "LinuxDistribution", + "build_number", + "codename", + "distro_release_attr", + "distro_release_info", + "id", + "info", + "like", + "linux_distribution", + "lsb_release_attr", + "lsb_release_info", + "major_version", + "minor_version", + "name", + "os_release_attr", + "os_release_info", + "uname_attr", + "uname_info", + "version", + "version_parts", +] + +__version__ = __version__ diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/__main__.py b/backend/venv/Lib/site-packages/pip/_vendor/distro/__main__.py new file mode 100644 index 0000000..0c01d5b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distro/__main__.py @@ -0,0 +1,4 @@ +from .distro import main + +if __name__ == "__main__": + main() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32ea4ea6b2d1e31759499110f9ac4680dfb4e349 GIT binary patch literal 965 zcmcJNzi$&U6vus+Ymz3p=4YF<143fT09{ZAgphzRL<+6cGCiGS-Q`T=_TD-2T}rdT zU%}4C!au^y;+2W5qC+Jn{H~3Z3K;S5(R*L}{j&Yl_iN0q2Vaimw-RID$yqJ;*0{Q` z#zz*j*hv^V;GhdGmY{?lc(?%@ScWoIpn_GX;wEfj4Qg12IyRtzKKQr=TiApqwxES= zXk!OD*o7|kpoiPAjXSV|edyx=1`eCC*!|?duCSSxrJ?u3vE_#Y(>pvme*JthhF2p# z8lSv5KH}q%X|Ji1lNThl)}*78;?P8&vkoSzGwS(9_qh!!%5dAh(z zXj7f4Sfn8e(~T)aaV-)NW`c)#uKy5a`c@fN#>OiwFOg@$bP}q_i}+Q^R+2?`Q{7RD zXdlB>O33vwS9Z0J;DZ| zOsEnz3G_#FozNioge^jo&?2-69YUATBWx3P2z|nUuuIspI2`Vo^3DDJwR(jP{@)f% zh4U~;IRDJ9Y&G^Pdif-nYcFK4#6m4|RRdhW-ZJ90+Ov literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dd647021216b176ba72a62ad719d0534dd2fa1f GIT binary patch literal 297 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 kR@bilGlW+bLo(JMURDL;`H%?Xw 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 r4!r(WAhx literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/distro.py b/backend/venv/Lib/site-packages/pip/_vendor/distro/distro.py new file mode 100644 index 0000000..78ccdfa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distro/distro.py @@ -0,0 +1,1403 @@ +#!/usr/bin/env python +# Copyright 2015-2021 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The ``distro`` package (``distro`` stands for Linux Distribution) provides +information about the Linux distribution it runs on, such as a reliable +machine-readable distro ID, or version information. + +It is the recommended replacement for Python's original +:py:func:`platform.linux_distribution` function, but it provides much more +functionality. An alternative implementation became necessary because Python +3.5 deprecated this function, and Python 3.8 removed it altogether. Its +predecessor function :py:func:`platform.dist` was already deprecated since +Python 2.6 and removed in Python 3.8. Still, there are many cases in which +access to OS distribution information is needed. See `Python issue 1322 +`_ for more information. +""" + +import argparse +import json +import logging +import os +import re +import shlex +import subprocess +import sys +import warnings +from typing import ( + Any, + Callable, + Dict, + Iterable, + Optional, + Sequence, + TextIO, + Tuple, + Type, +) + +try: + from typing import TypedDict +except ImportError: + # Python 3.7 + TypedDict = dict + +__version__ = "1.9.0" + + +class VersionDict(TypedDict): + major: str + minor: str + build_number: str + + +class InfoDict(TypedDict): + id: str + version: str + version_parts: VersionDict + like: str + codename: str + + +_UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc") +_UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib") +_OS_RELEASE_BASENAME = "os-release" + +#: Translation table for normalizing the "ID" attribute defined in os-release +#: files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as defined in the os-release file, translated to lower case, +#: with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_OS_ID = { + "ol": "oracle", # Oracle Linux + "opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap +} + +#: Translation table for normalizing the "Distributor ID" attribute returned by +#: the lsb_release command, for use by the :func:`distro.id` method. +#: +#: * Key: Value as returned by the lsb_release command, translated to lower +#: case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_LSB_ID = { + "enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4 + "enterpriseenterpriseserver": "oracle", # Oracle Linux 5 + "redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation + "redhatenterpriseserver": "rhel", # RHEL 6, 7 Server + "redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode +} + +#: Translation table for normalizing the distro ID derived from the file name +#: of distro release files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as derived from the file name of a distro release file, +#: translated to lower case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_DISTRO_ID = { + "redhat": "rhel", # RHEL 6.x, 7.x +} + +# Pattern for content of distro release file (reversed) +_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( + r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)" +) + +# Pattern for base file name of distro release file +_DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$") + +# Base file names to be looked up for if _UNIXCONFDIR is not readable. +_DISTRO_RELEASE_BASENAMES = [ + "SuSE-release", + "altlinux-release", + "arch-release", + "base-release", + "centos-release", + "fedora-release", + "gentoo-release", + "mageia-release", + "mandrake-release", + "mandriva-release", + "mandrivalinux-release", + "manjaro-release", + "oracle-release", + "redhat-release", + "rocky-release", + "sl-release", + "slackware-version", +] + +# Base file names to be ignored when searching for distro release file +_DISTRO_RELEASE_IGNORE_BASENAMES = ( + "debian_version", + "lsb-release", + "oem-release", + _OS_RELEASE_BASENAME, + "system-release", + "plesk-release", + "iredmail-release", + "board-release", + "ec2_version", +) + + +def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]: + """ + .. deprecated:: 1.6.0 + + :func:`distro.linux_distribution()` is deprecated. It should only be + used as a compatibility shim with Python's + :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`, + :func:`distro.version` and :func:`distro.name` instead. + + Return information about the current OS distribution as a tuple + ``(id_name, version, codename)`` with items as follows: + + * ``id_name``: If *full_distribution_name* is false, the result of + :func:`distro.id`. Otherwise, the result of :func:`distro.name`. + + * ``version``: The result of :func:`distro.version`. + + * ``codename``: The extra item (usually in parentheses) after the + os-release version number, or the result of :func:`distro.codename`. + + The interface of this function is compatible with the original + :py:func:`platform.linux_distribution` function, supporting a subset of + its parameters. + + The data it returns may not exactly be the same, because it uses more data + sources than the original function, and that may lead to different data if + the OS distribution is not consistent across multiple data sources it + provides (there are indeed such distributions ...). + + Another reason for differences is the fact that the :func:`distro.id` + method normalizes the distro ID string to a reliable machine-readable value + for a number of popular OS distributions. + """ + warnings.warn( + "distro.linux_distribution() is deprecated. It should only be used as a " + "compatibility shim with Python's platform.linux_distribution(). Please use " + "distro.id(), distro.version() and distro.name() instead.", + DeprecationWarning, + stacklevel=2, + ) + return _distro.linux_distribution(full_distribution_name) + + +def id() -> str: + """ + Return the distro ID of the current distribution, as a + machine-readable string. + + For a number of OS distributions, the returned distro ID value is + *reliable*, in the sense that it is documented and that it does not change + across releases of the distribution. + + This package maintains the following reliable distro ID values: + + ============== ========================================= + Distro ID Distribution + ============== ========================================= + "ubuntu" Ubuntu + "debian" Debian + "rhel" RedHat Enterprise Linux + "centos" CentOS + "fedora" Fedora + "sles" SUSE Linux Enterprise Server + "opensuse" openSUSE + "amzn" Amazon Linux + "arch" Arch Linux + "buildroot" Buildroot + "cloudlinux" CloudLinux OS + "exherbo" Exherbo Linux + "gentoo" GenToo Linux + "ibm_powerkvm" IBM PowerKVM + "kvmibm" KVM for IBM z Systems + "linuxmint" Linux Mint + "mageia" Mageia + "mandriva" Mandriva Linux + "parallels" Parallels + "pidora" Pidora + "raspbian" Raspbian + "oracle" Oracle Linux (and Oracle Enterprise Linux) + "scientific" Scientific Linux + "slackware" Slackware + "xenserver" XenServer + "openbsd" OpenBSD + "netbsd" NetBSD + "freebsd" FreeBSD + "midnightbsd" MidnightBSD + "rocky" Rocky Linux + "aix" AIX + "guix" Guix System + "altlinux" ALT Linux + ============== ========================================= + + If you have a need to get distros for reliable IDs added into this set, + or if you find that the :func:`distro.id` function returns a different + distro ID for one of the listed distros, please create an issue in the + `distro issue tracker`_. + + **Lookup hierarchy and transformations:** + + First, the ID is obtained from the following sources, in the specified + order. The first available and non-empty value is used: + + * the value of the "ID" attribute of the os-release file, + + * the value of the "Distributor ID" attribute returned by the lsb_release + command, + + * the first part of the file name of the distro release file, + + The so determined ID value then passes the following transformations, + before it is returned by this method: + + * it is translated to lower case, + + * blanks (which should not be there anyway) are translated to underscores, + + * a normalization of the ID is performed, based upon + `normalization tables`_. The purpose of this normalization is to ensure + that the ID is as reliable as possible, even across incompatible changes + in the OS distributions. A common reason for an incompatible change is + the addition of an os-release file, or the addition of the lsb_release + command, with ID values that differ from what was previously determined + from the distro release file name. + """ + return _distro.id() + + +def name(pretty: bool = False) -> str: + """ + Return the name of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the name is returned without version or codename. + (e.g. "CentOS Linux") + + If *pretty* is true, the version and codename are appended. + (e.g. "CentOS Linux 7.1.1503 (Core)") + + **Lookup hierarchy:** + + The name is obtained from the following sources, in the specified order. + The first available and non-empty value is used: + + * If *pretty* is false: + + - the value of the "NAME" attribute of the os-release file, + + - the value of the "Distributor ID" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file. + + * If *pretty* is true: + + - the value of the "PRETTY_NAME" attribute of the os-release file, + + - the value of the "Description" attribute returned by the lsb_release + command, + + - the value of the "" field of the distro release file, appended + with the value of the pretty version ("" and "" + fields) of the distro release file, if available. + """ + return _distro.name(pretty) + + +def version(pretty: bool = False, best: bool = False) -> str: + """ + Return the version of the current OS distribution, as a human-readable + string. + + If *pretty* is false, the version is returned without codename (e.g. + "7.0"). + + If *pretty* is true, the codename in parenthesis is appended, if the + codename is non-empty (e.g. "7.0 (Maipo)"). + + Some distributions provide version numbers with different precisions in + the different sources of distribution information. Examining the different + sources in a fixed priority order does not always yield the most precise + version (e.g. for Debian 8.2, or CentOS 7.1). + + Some other distributions may not provide this kind of information. In these + cases, an empty string would be returned. This behavior can be observed + with rolling releases distributions (e.g. Arch Linux). + + The *best* parameter can be used to control the approach for the returned + version: + + If *best* is false, the first non-empty version number in priority order of + the examined sources is returned. + + If *best* is true, the most precise version number out of all examined + sources is returned. + + **Lookup hierarchy:** + + In all cases, the version number is obtained from the following sources. + If *best* is false, this order represents the priority order: + + * the value of the "VERSION_ID" attribute of the os-release file, + * the value of the "Release" attribute returned by the lsb_release + command, + * the version number parsed from the "" field of the first line + of the distro release file, + * the version number parsed from the "PRETTY_NAME" attribute of the + os-release file, if it follows the format of the distro release files. + * the version number parsed from the "Description" attribute returned by + the lsb_release command, if it follows the format of the distro release + files. + """ + return _distro.version(pretty, best) + + +def version_parts(best: bool = False) -> Tuple[str, str, str]: + """ + Return the version of the current OS distribution as a tuple + ``(major, minor, build_number)`` with items as follows: + + * ``major``: The result of :func:`distro.major_version`. + + * ``minor``: The result of :func:`distro.minor_version`. + + * ``build_number``: The result of :func:`distro.build_number`. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.version_parts(best) + + +def major_version(best: bool = False) -> str: + """ + Return the major version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The major version is the first + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.major_version(best) + + +def minor_version(best: bool = False) -> str: + """ + Return the minor version of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The minor version is the second + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.minor_version(best) + + +def build_number(best: bool = False) -> str: + """ + Return the build number of the current OS distribution, as a string, + if provided. + Otherwise, the empty string is returned. The build number is the third part + of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.build_number(best) + + +def like() -> str: + """ + Return a space-separated list of distro IDs of distributions that are + closely related to the current OS distribution in regards to packaging + and programming interfaces, for example distributions the current + distribution is a derivative from. + + **Lookup hierarchy:** + + This information item is only provided by the os-release file. + For details, see the description of the "ID_LIKE" attribute in the + `os-release man page + `_. + """ + return _distro.like() + + +def codename() -> str: + """ + Return the codename for the release of the current OS distribution, + as a string. + + If the distribution does not have a codename, an empty string is returned. + + Note that the returned codename is not always really a codename. For + example, openSUSE returns "x86_64". This function does not handle such + cases in any special way and just returns the string it finds, if any. + + **Lookup hierarchy:** + + * the codename within the "VERSION" attribute of the os-release file, if + provided, + + * the value of the "Codename" attribute returned by the lsb_release + command, + + * the value of the "" field of the distro release file. + """ + return _distro.codename() + + +def info(pretty: bool = False, best: bool = False) -> InfoDict: + """ + Return certain machine-readable information items about the current OS + distribution in a dictionary, as shown in the following example: + + .. sourcecode:: python + + { + 'id': 'rhel', + 'version': '7.0', + 'version_parts': { + 'major': '7', + 'minor': '0', + 'build_number': '' + }, + 'like': 'fedora', + 'codename': 'Maipo' + } + + The dictionary structure and keys are always the same, regardless of which + information items are available in the underlying data sources. The values + for the various keys are as follows: + + * ``id``: The result of :func:`distro.id`. + + * ``version``: The result of :func:`distro.version`. + + * ``version_parts -> major``: The result of :func:`distro.major_version`. + + * ``version_parts -> minor``: The result of :func:`distro.minor_version`. + + * ``version_parts -> build_number``: The result of + :func:`distro.build_number`. + + * ``like``: The result of :func:`distro.like`. + + * ``codename``: The result of :func:`distro.codename`. + + For a description of the *pretty* and *best* parameters, see the + :func:`distro.version` method. + """ + return _distro.info(pretty, best) + + +def os_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the os-release file data source of the current OS distribution. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_info() + + +def lsb_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the lsb_release command data source of the current OS distribution. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_info() + + +def distro_release_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_info() + + +def uname_info() -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current OS distribution. + """ + return _distro.uname_info() + + +def os_release_attr(attribute: str) -> str: + """ + Return a single named information item from the os-release file data source + of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_attr(attribute) + + +def lsb_release_attr(attribute: str) -> str: + """ + Return a single named information item from the lsb_release command output + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_attr(attribute) + + +def distro_release_attr(attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_attr(attribute) + + +def uname_attr(attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the current OS distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + """ + return _distro.uname_attr(attribute) + + +try: + from functools import cached_property +except ImportError: + # Python < 3.8 + class cached_property: # type: ignore + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + + def __init__(self, f: Callable[[Any], Any]) -> None: + self._fname = f.__name__ + self._f = f + + def __get__(self, obj: Any, owner: Type[Any]) -> Any: + assert obj is not None, f"call {self._fname} on an instance" + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + +class LinuxDistribution: + """ + Provides information about a OS distribution. + + This package creates a private module-global instance of this class with + default initialization arguments, that is used by the + `consolidated accessor functions`_ and `single source accessor functions`_. + By using default initialization arguments, that module-global instance + returns data about the current OS distribution (i.e. the distro this + package runs on). + + Normally, it is not necessary to create additional instances of this class. + However, in situations where control is needed over the exact data sources + that are used, instances of this class can be created with a specific + distro release file, or a specific os-release file, or without invoking the + lsb_release command. + """ + + def __init__( + self, + include_lsb: Optional[bool] = None, + os_release_file: str = "", + distro_release_file: str = "", + include_uname: Optional[bool] = None, + root_dir: Optional[str] = None, + include_oslevel: Optional[bool] = None, + ) -> None: + """ + The initialization method of this class gathers information from the + available data sources, and stores that in private instance attributes. + Subsequent access to the information items uses these private instance + attributes, so that the data sources are read only once. + + Parameters: + + * ``include_lsb`` (bool): Controls whether the + `lsb_release command output`_ is included as a data source. + + If the lsb_release command is not available in the program execution + path, the data source for the lsb_release command will be empty. + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is to be used as a data source. + + An empty string (the default) will cause the default path name to + be used (see `os-release file`_ for details). + + If the specified or defaulted os-release file does not exist, the + data source for the os-release file will be empty. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is to be used as a data source. + + An empty string (the default) will cause a default search algorithm + to be used (see `distro release file`_ for details). + + If the specified distro release file does not exist, or if no default + distro release file can be found, the data source for the distro + release file will be empty. + + * ``include_uname`` (bool): Controls whether uname command output is + included as a data source. If the uname command is not available in + the program execution path the data source for the uname command will + be empty. + + * ``root_dir`` (string): The absolute path to the root directory to use + to find distro-related information files. Note that ``include_*`` + parameters must not be enabled in combination with ``root_dir``. + + * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command + output is included as a data source. If the oslevel command is not + available in the program execution path the data source will be + empty. + + Public instance attributes: + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + + * ``include_uname`` (bool): The result of the ``include_uname`` + parameter. This controls whether the uname information will + be loaded. + + * ``include_oslevel`` (bool): The result of the ``include_oslevel`` + parameter. This controls whether (AIX) oslevel information will be + loaded. + + * ``root_dir`` (string): The result of the ``root_dir`` parameter. + The absolute path to the root directory to use to find distro-related + information files. + + Raises: + + * :py:exc:`ValueError`: Initialization parameters combination is not + supported. + + * :py:exc:`OSError`: Some I/O issue with an os-release file or distro + release file. + + * :py:exc:`UnicodeError`: A data source has unexpected characters or + uses an unexpected encoding. + """ + self.root_dir = root_dir + self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR + self.usr_lib_dir = ( + os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR + ) + + if os_release_file: + self.os_release_file = os_release_file + else: + etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME) + usr_lib_os_release_file = os.path.join( + self.usr_lib_dir, _OS_RELEASE_BASENAME + ) + + # NOTE: The idea is to respect order **and** have it set + # at all times for API backwards compatibility. + if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile( + usr_lib_os_release_file + ): + self.os_release_file = etc_dir_os_release_file + else: + self.os_release_file = usr_lib_os_release_file + + self.distro_release_file = distro_release_file or "" # updated later + + is_root_dir_defined = root_dir is not None + if is_root_dir_defined and (include_lsb or include_uname or include_oslevel): + raise ValueError( + "Including subprocess data sources from specific root_dir is disallowed" + " to prevent false information" + ) + self.include_lsb = ( + include_lsb if include_lsb is not None else not is_root_dir_defined + ) + self.include_uname = ( + include_uname if include_uname is not None else not is_root_dir_defined + ) + self.include_oslevel = ( + include_oslevel if include_oslevel is not None else not is_root_dir_defined + ) + + def __repr__(self) -> str: + """Return repr of all info""" + return ( + "LinuxDistribution(" + "os_release_file={self.os_release_file!r}, " + "distro_release_file={self.distro_release_file!r}, " + "include_lsb={self.include_lsb!r}, " + "include_uname={self.include_uname!r}, " + "include_oslevel={self.include_oslevel!r}, " + "root_dir={self.root_dir!r}, " + "_os_release_info={self._os_release_info!r}, " + "_lsb_release_info={self._lsb_release_info!r}, " + "_distro_release_info={self._distro_release_info!r}, " + "_uname_info={self._uname_info!r}, " + "_oslevel_info={self._oslevel_info!r})".format(self=self) + ) + + def linux_distribution( + self, full_distribution_name: bool = True + ) -> Tuple[str, str, str]: + """ + Return information about the OS distribution that is compatible + with Python's :func:`platform.linux_distribution`, supporting a subset + of its parameters. + + For details, see :func:`distro.linux_distribution`. + """ + return ( + self.name() if full_distribution_name else self.id(), + self.version(), + self._os_release_info.get("release_codename") or self.codename(), + ) + + def id(self) -> str: + """Return the distro ID of the OS distribution, as a string. + + For details, see :func:`distro.id`. + """ + + def normalize(distro_id: str, table: Dict[str, str]) -> str: + distro_id = distro_id.lower().replace(" ", "_") + return table.get(distro_id, distro_id) + + distro_id = self.os_release_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_OS_ID) + + distro_id = self.lsb_release_attr("distributor_id") + if distro_id: + return normalize(distro_id, NORMALIZED_LSB_ID) + + distro_id = self.distro_release_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + distro_id = self.uname_attr("id") + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + return "" + + def name(self, pretty: bool = False) -> str: + """ + Return the name of the OS distribution, as a string. + + For details, see :func:`distro.name`. + """ + name = ( + self.os_release_attr("name") + or self.lsb_release_attr("distributor_id") + or self.distro_release_attr("name") + or self.uname_attr("name") + ) + if pretty: + name = self.os_release_attr("pretty_name") or self.lsb_release_attr( + "description" + ) + if not name: + name = self.distro_release_attr("name") or self.uname_attr("name") + version = self.version(pretty=True) + if version: + name = f"{name} {version}" + return name or "" + + def version(self, pretty: bool = False, best: bool = False) -> str: + """ + Return the version of the OS distribution, as a string. + + For details, see :func:`distro.version`. + """ + versions = [ + self.os_release_attr("version_id"), + self.lsb_release_attr("release"), + self.distro_release_attr("version_id"), + self._parse_distro_release_content(self.os_release_attr("pretty_name")).get( + "version_id", "" + ), + self._parse_distro_release_content( + self.lsb_release_attr("description") + ).get("version_id", ""), + self.uname_attr("release"), + ] + if self.uname_attr("id").startswith("aix"): + # On AIX platforms, prefer oslevel command output. + versions.insert(0, self.oslevel_info()) + elif self.id() == "debian" or "debian" in self.like().split(): + # On Debian-like, add debian_version file content to candidates list. + versions.append(self._debian_version) + version = "" + if best: + # This algorithm uses the last version in priority order that has + # the best precision. If the versions are not in conflict, that + # does not matter; otherwise, using the last one instead of the + # first one might be considered a surprise. + for v in versions: + if v.count(".") > version.count(".") or version == "": + version = v + else: + for v in versions: + if v != "": + version = v + break + if pretty and version and self.codename(): + version = f"{version} ({self.codename()})" + return version + + def version_parts(self, best: bool = False) -> Tuple[str, str, str]: + """ + Return the version of the OS distribution, as a tuple of version + numbers. + + For details, see :func:`distro.version_parts`. + """ + version_str = self.version(best=best) + if version_str: + version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?") + matches = version_regex.match(version_str) + if matches: + major, minor, build_number = matches.groups() + return major, minor or "", build_number or "" + return "", "", "" + + def major_version(self, best: bool = False) -> str: + """ + Return the major version number of the current distribution. + + For details, see :func:`distro.major_version`. + """ + return self.version_parts(best)[0] + + def minor_version(self, best: bool = False) -> str: + """ + Return the minor version number of the current distribution. + + For details, see :func:`distro.minor_version`. + """ + return self.version_parts(best)[1] + + def build_number(self, best: bool = False) -> str: + """ + Return the build number of the current distribution. + + For details, see :func:`distro.build_number`. + """ + return self.version_parts(best)[2] + + def like(self) -> str: + """ + Return the IDs of distributions that are like the OS distribution. + + For details, see :func:`distro.like`. + """ + return self.os_release_attr("id_like") or "" + + def codename(self) -> str: + """ + Return the codename of the OS distribution. + + For details, see :func:`distro.codename`. + """ + try: + # Handle os_release specially since distros might purposefully set + # this to empty string to have no codename + return self._os_release_info["codename"] + except KeyError: + return ( + self.lsb_release_attr("codename") + or self.distro_release_attr("codename") + or "" + ) + + def info(self, pretty: bool = False, best: bool = False) -> InfoDict: + """ + Return certain machine-readable information about the OS + distribution. + + For details, see :func:`distro.info`. + """ + return InfoDict( + id=self.id(), + version=self.version(pretty, best), + version_parts=VersionDict( + major=self.major_version(best), + minor=self.minor_version(best), + build_number=self.build_number(best), + ), + like=self.like(), + codename=self.codename(), + ) + + def os_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the os-release file data source of the OS distribution. + + For details, see :func:`distro.os_release_info`. + """ + return self._os_release_info + + def lsb_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the lsb_release command data source of the OS + distribution. + + For details, see :func:`distro.lsb_release_info`. + """ + return self._lsb_release_info + + def distro_release_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the distro release file data source of the OS + distribution. + + For details, see :func:`distro.distro_release_info`. + """ + return self._distro_release_info + + def uname_info(self) -> Dict[str, str]: + """ + Return a dictionary containing key-value pairs for the information + items from the uname command data source of the OS distribution. + + For details, see :func:`distro.uname_info`. + """ + return self._uname_info + + def oslevel_info(self) -> str: + """ + Return AIX' oslevel command output. + """ + return self._oslevel_info + + def os_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the os-release file data + source of the OS distribution. + + For details, see :func:`distro.os_release_attr`. + """ + return self._os_release_info.get(attribute, "") + + def lsb_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the lsb_release command + output data source of the OS distribution. + + For details, see :func:`distro.lsb_release_attr`. + """ + return self._lsb_release_info.get(attribute, "") + + def distro_release_attr(self, attribute: str) -> str: + """ + Return a single named information item from the distro release file + data source of the OS distribution. + + For details, see :func:`distro.distro_release_attr`. + """ + return self._distro_release_info.get(attribute, "") + + def uname_attr(self, attribute: str) -> str: + """ + Return a single named information item from the uname command + output data source of the OS distribution. + + For details, see :func:`distro.uname_attr`. + """ + return self._uname_info.get(attribute, "") + + @cached_property + def _os_release_info(self) -> Dict[str, str]: + """ + Get the information items from the specified os-release file. + + Returns: + A dictionary containing all information items. + """ + if os.path.isfile(self.os_release_file): + with open(self.os_release_file, encoding="utf-8") as release_file: + return self._parse_os_release_content(release_file) + return {} + + @staticmethod + def _parse_os_release_content(lines: TextIO) -> Dict[str, str]: + """ + Parse the lines of an os-release file. + + Parameters: + + * lines: Iterable through the lines in the os-release file. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + lexer = shlex.shlex(lines, posix=True) + lexer.whitespace_split = True + + tokens = list(lexer) + for token in tokens: + # At this point, all shell-like parsing has been done (i.e. + # comments processed, quotes and backslash escape sequences + # processed, multi-line values assembled, trailing newlines + # stripped, etc.), so the tokens are now either: + # * variable assignments: var=value + # * commands or their arguments (not allowed in os-release) + # Ignore any tokens that are not variable assignments + if "=" in token: + k, v = token.split("=", 1) + props[k.lower()] = v + + if "version" in props: + # extract release codename (if any) from version attribute + match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"]) + if match: + release_codename = match.group(1) or match.group(2) + props["codename"] = props["release_codename"] = release_codename + + if "version_codename" in props: + # os-release added a version_codename field. Use that in + # preference to anything else Note that some distros purposefully + # do not have code names. They should be setting + # version_codename="" + props["codename"] = props["version_codename"] + elif "ubuntu_codename" in props: + # Same as above but a non-standard field name used on older Ubuntus + props["codename"] = props["ubuntu_codename"] + + return props + + @cached_property + def _lsb_release_info(self) -> Dict[str, str]: + """ + Get the information items from the lsb_release command output. + + Returns: + A dictionary containing all information items. + """ + if not self.include_lsb: + return {} + try: + cmd = ("lsb_release", "-a") + stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) + # Command not found or lsb_release returned error + except (OSError, subprocess.CalledProcessError): + return {} + content = self._to_str(stdout).splitlines() + return self._parse_lsb_release_content(content) + + @staticmethod + def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]: + """ + Parse the output of the lsb_release command. + + Parameters: + + * lines: Iterable through the lines of the lsb_release output. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + for line in lines: + kv = line.strip("\n").split(":", 1) + if len(kv) != 2: + # Ignore lines without colon. + continue + k, v = kv + props.update({k.replace(" ", "_").lower(): v.strip()}) + return props + + @cached_property + def _uname_info(self) -> Dict[str, str]: + if not self.include_uname: + return {} + try: + cmd = ("uname", "-rs") + stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) + except OSError: + return {} + content = self._to_str(stdout).splitlines() + return self._parse_uname_content(content) + + @cached_property + def _oslevel_info(self) -> str: + if not self.include_oslevel: + return "" + try: + stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL) + except (OSError, subprocess.CalledProcessError): + return "" + return self._to_str(stdout).strip() + + @cached_property + def _debian_version(self) -> str: + try: + with open( + os.path.join(self.etc_dir, "debian_version"), encoding="ascii" + ) as fp: + return fp.readline().rstrip() + except FileNotFoundError: + return "" + + @staticmethod + def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]: + if not lines: + return {} + props = {} + match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip()) + if match: + name, version = match.groups() + + # This is to prevent the Linux kernel version from + # appearing as the 'best' version on otherwise + # identifiable distributions. + if name == "Linux": + return {} + props["id"] = name.lower() + props["name"] = name + props["release"] = version + return props + + @staticmethod + def _to_str(bytestring: bytes) -> str: + encoding = sys.getfilesystemencoding() + return bytestring.decode(encoding) + + @cached_property + def _distro_release_info(self) -> Dict[str, str]: + """ + Get the information items from the specified distro release file. + + Returns: + A dictionary containing all information items. + """ + if self.distro_release_file: + # If it was specified, we use it and parse what we can, even if + # its file name or content does not match the expected pattern. + distro_info = self._parse_distro_release_file(self.distro_release_file) + basename = os.path.basename(self.distro_release_file) + # The file name pattern for user-specified distro release files + # is somewhat more tolerant (compared to when searching for the + # file), because we want to use what was specified as best as + # possible. + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + else: + try: + basenames = [ + basename + for basename in os.listdir(self.etc_dir) + if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES + and os.path.isfile(os.path.join(self.etc_dir, basename)) + ] + # We sort for repeatability in cases where there are multiple + # distro specific files; e.g. CentOS, Oracle, Enterprise all + # containing `redhat-release` on top of their own. + basenames.sort() + except OSError: + # This may occur when /etc is not readable but we can't be + # sure about the *-release files. Check common entries of + # /etc for information. If they turn out to not be there the + # error is handled in `_parse_distro_release_file()`. + basenames = _DISTRO_RELEASE_BASENAMES + for basename in basenames: + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match is None: + continue + filepath = os.path.join(self.etc_dir, basename) + distro_info = self._parse_distro_release_file(filepath) + # The name is always present if the pattern matches. + if "name" not in distro_info: + continue + self.distro_release_file = filepath + break + else: # the loop didn't "break": no candidate. + return {} + + if match is not None: + distro_info["id"] = match.group(1) + + # CloudLinux < 7: manually enrich info with proper id. + if "cloudlinux" in distro_info.get("name", "").lower(): + distro_info["id"] = "cloudlinux" + + return distro_info + + def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]: + """ + Parse a distro release file. + + Parameters: + + * filepath: Path name of the distro release file. + + Returns: + A dictionary containing all information items. + """ + try: + with open(filepath, encoding="utf-8") as fp: + # Only parse the first line. For instance, on SLES there + # are multiple lines. We don't want them... + return self._parse_distro_release_content(fp.readline()) + except OSError: + # Ignore not being able to read a specific, seemingly version + # related file. + # See https://github.com/python-distro/distro/issues/162 + return {} + + @staticmethod + def _parse_distro_release_content(line: str) -> Dict[str, str]: + """ + Parse a line from a distro release file. + + Parameters: + * line: Line from the distro release file. Must be a unicode string + or a UTF-8 encoded byte string. + + Returns: + A dictionary containing all information items. + """ + matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1]) + distro_info = {} + if matches: + # regexp ensures non-None + distro_info["name"] = matches.group(3)[::-1] + if matches.group(2): + distro_info["version_id"] = matches.group(2)[::-1] + if matches.group(1): + distro_info["codename"] = matches.group(1)[::-1] + elif line: + distro_info["name"] = line.strip() + return distro_info + + +_distro = LinuxDistribution() + + +def main() -> None: + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + parser = argparse.ArgumentParser(description="OS distro info tool") + parser.add_argument( + "--json", "-j", help="Output in machine readable format", action="store_true" + ) + + parser.add_argument( + "--root-dir", + "-r", + type=str, + dest="root_dir", + help="Path to the root filesystem directory (defaults to /)", + ) + + args = parser.parse_args() + + if args.root_dir: + dist = LinuxDistribution( + include_lsb=False, + include_uname=False, + include_oslevel=False, + root_dir=args.root_dir, + ) + else: + dist = _distro + + if args.json: + logger.info(json.dumps(dist.info(), indent=4, sort_keys=True)) + else: + logger.info("Name: %s", dist.name(pretty=True)) + distribution_version = dist.version(pretty=True) + logger.info("Version: %s", distribution_version) + distribution_codename = dist.codename() + logger.info("Codename: %s", distribution_codename) + + +if __name__ == "__main__": + main() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distro/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/distro/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/__init__.py new file mode 100644 index 0000000..cfdc030 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/__init__.py @@ -0,0 +1,45 @@ +from .core import ( + IDNABidiError, + IDNAError, + InvalidCodepoint, + InvalidCodepointContext, + alabel, + check_bidi, + check_hyphen_ok, + check_initial_combiner, + check_label, + check_nfc, + decode, + encode, + ulabel, + uts46_remap, + valid_contextj, + valid_contexto, + valid_label_length, + valid_string_length, +) +from .intranges import intranges_contain +from .package_data import __version__ + +__all__ = [ + "__version__", + "IDNABidiError", + "IDNAError", + "InvalidCodepoint", + "InvalidCodepointContext", + "alabel", + "check_bidi", + "check_hyphen_ok", + "check_initial_combiner", + "check_label", + "check_nfc", + "decode", + "encode", + "intranges_contain", + "ulabel", + "uts46_remap", + "valid_contextj", + "valid_contexto", + "valid_label_length", + "valid_string_length", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..638abc7283e21236fecb816ce453412d361efd8e GIT binary patch literal 891 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 E2fTI}(f|Me literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aefb9cc367485ce7f73dc51cebc7f70862ee0b9d GIT binary patch literal 895 zcmb7Cy=xRf6rb6z`^xzhlmt0h5Q`};+}O4}fa|A)@h*?FuEv?rgdXaV(KRBoYm#q(B}}O78NzyNbgSfRP=VT>Hc#&f zu?VRUQWsU=!W1>~>*P1`n$tK{$sDcF+i_l)+i@V{Qz}RuSpxb}Kw&{#YBThE5Ed3f zc7SnT-I^|)47JB|B#u~ij=f?Z&g@Ng!d-`Bg>Ia1tddF_?CwBsQ^`5r?6}i&{no}cLJcG1ky{IYMNA&ZOjWWy0go_DX z)zwIfgAg8Jivp;Rkv=6c(mChfS?edWM;7PvgL@-J>Ud?W)TpYCwvSidJHzV>U#>2e V;HTMh(B%VNow@wj_*Lq%hd*ya%ToXV literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31f6ecda5a4a9935a5520221d55842f15fa9380a GIT binary patch literal 16126 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be645dfd25caaa0e114f335267cc3d9a51d87a94 GIT binary patch literal 222 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 mozj Tuple[bytes, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return b"", 0 + + return encode(data), len(data) + + def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return "", 0 + + return decode(data), len(data) + + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return b"", 0 + + labels = _unicode_dots_re.split(data) + trailing_dot = b"" + if labels: + if not labels[-1]: + trailing_dot = b"." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = b"." + + result = [] + size = 0 + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + # Join with U+002E + result_bytes = b".".join(result) + trailing_dot + size += len(trailing_dot) + return result_bytes, size + + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]: + if errors != "strict": + raise IDNAError('Unsupported error handling "{}"'.format(errors)) + + if not data: + return ("", 0) + + if not isinstance(data, str): + data = str(data, "ascii") + + labels = _unicode_dots_re.split(data) + trailing_dot = "" + if labels: + if not labels[-1]: + trailing_dot = "." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = "." + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result_str = ".".join(result) + trailing_dot + size += len(trailing_dot) + return (result_str, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + + +class StreamReader(Codec, codecs.StreamReader): + pass + + +def search_function(name: str) -> Optional[codecs.CodecInfo]: + if name != "idna2008": + return None + return codecs.CodecInfo( + name=name, + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) + + +codecs.register(search_function) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/compat.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/compat.py new file mode 100644 index 0000000..1df9f2a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/compat.py @@ -0,0 +1,15 @@ +from typing import Any, Union + +from .core import decode, encode + + +def ToASCII(label: str) -> bytes: + return encode(label) + + +def ToUnicode(label: Union[bytes, bytearray]) -> str: + return decode(label) + + +def nameprep(s: Any) -> None: + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/core.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/core.py new file mode 100644 index 0000000..9115f12 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/core.py @@ -0,0 +1,437 @@ +import bisect +import re +import unicodedata +from typing import Optional, Union + +from . import idnadata +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b"xn--" +_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") + + +class IDNAError(UnicodeError): + """Base exception for all IDNA-encoding related problems""" + + pass + + +class IDNABidiError(IDNAError): + """Exception when bidirectional requirements are not satisfied""" + + pass + + +class InvalidCodepoint(IDNAError): + """Exception when a disallowed or unallocated codepoint is used""" + + pass + + +class InvalidCodepointContext(IDNAError): + """Exception when the codepoint is not valid in the context it is used""" + + pass + + +def _combining_class(cp: int) -> int: + v = unicodedata.combining(chr(cp)) + if v == 0: + if not unicodedata.name(chr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + + +def _is_script(cp: str, script: str) -> bool: + return intranges_contain(ord(cp), idnadata.scripts[script]) + + +def _punycode(s: str) -> bytes: + return s.encode("punycode") + + +def _unot(s: int) -> str: + return "U+{:04X}".format(s) + + +def valid_label_length(label: Union[bytes, str]) -> bool: + if len(label) > 63: + return False + return True + + +def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool: + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label: str, check_ltr: bool = False) -> bool: + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == "": + # String likely comes from a newer version of Unicode + raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx)) + if direction in ["R", "AL", "AN"]: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ["R", "AL"]: + rtl = True + elif direction == "L": + rtl = False + else: + raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label))) + + valid_ending = False + number_type: Optional[str] = None + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if direction not in [ + "R", + "AL", + "AN", + "EN", + "ES", + "CS", + "ET", + "ON", + "BN", + "NSM", + ]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx)) + # Bidi rule 3 + if direction in ["R", "AL", "EN", "AN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + # Bidi rule 4 + if direction in ["AN", "EN"]: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError("Can not mix numeral types in a right-to-left label") + else: + # Bidi rule 5 + if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]: + raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx)) + # Bidi rule 6 + if direction in ["L", "EN"]: + valid_ending = True + elif direction != "NSM": + valid_ending = False + + if not valid_ending: + raise IDNABidiError("Label ends with illegal codepoint directionality") + + return True + + +def check_initial_combiner(label: str) -> bool: + if unicodedata.category(label[0])[0] == "M": + raise IDNAError("Label begins with an illegal combining character") + return True + + +def check_hyphen_ok(label: str) -> bool: + if label[2:4] == "--": + raise IDNAError("Label has disallowed hyphens in 3rd and 4th position") + if label[0] == "-" or label[-1] == "-": + raise IDNAError("Label must not start or end with a hyphen") + return True + + +def check_nfc(label: str) -> None: + if unicodedata.normalize("NFC", label) != label: + raise IDNAError("Label must be in Normalization Form C") + + +def valid_contextj(label: str, pos: int) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x200C: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos - 1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("L"), ord("D")]: + ok = True + break + else: + break + + if not ok: + return False + + ok = False + for i in range(pos + 1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord("T"): + continue + elif joining_type in [ord("R"), ord("D")]: + ok = True + break + else: + break + return ok + + if cp_value == 0x200D: + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + return False + + +def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: + cp_value = ord(label[pos]) + + if cp_value == 0x00B7: + if 0 < pos < len(label) - 1: + if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label) - 1 and len(label) > 1: + return _is_script(label[pos + 1], "Greek") + return False + + elif cp_value == 0x05F3 or cp_value == 0x05F4: + if pos > 0: + return _is_script(label[pos - 1], "Hebrew") + return False + + elif cp_value == 0x30FB: + for cp in label: + if cp == "\u30fb": + continue + if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): + return True + return False + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6F0 <= ord(cp) <= 0x06F9: + return False + return True + + elif 0x6F0 <= cp_value <= 0x6F9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + return False + + +def check_label(label: Union[str, bytes, bytearray]) -> None: + if isinstance(label, (bytes, bytearray)): + label = label.decode("utf-8") + if len(label) == 0: + raise IDNAError("Empty Label") + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for pos, cp in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): + try: + if not valid_contextj(label, pos): + raise InvalidCodepointContext( + "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + except ValueError: + raise IDNAError( + "Unknown codepoint adjacent to joiner {} at position {} in {}".format( + _unot(cp_value), pos + 1, repr(label) + ) + ) + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): + if not valid_contexto(label, pos): + raise InvalidCodepointContext( + "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) + ) + else: + raise InvalidCodepoint( + "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label)) + ) + + check_bidi(label) + + +def alabel(label: str) -> bytes: + try: + label_bytes = label.encode("ascii") + ulabel(label_bytes) + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + return label_bytes + except UnicodeEncodeError: + pass + + check_label(label) + label_bytes = _alabel_prefix + _punycode(label) + + if not valid_label_length(label_bytes): + raise IDNAError("Label too long") + + return label_bytes + + +def ulabel(label: Union[str, bytes, bytearray]) -> str: + if not isinstance(label, (bytes, bytearray)): + try: + label_bytes = label.encode("ascii") + except UnicodeEncodeError: + check_label(label) + return label + else: + label_bytes = label + + label_bytes = label_bytes.lower() + if label_bytes.startswith(_alabel_prefix): + label_bytes = label_bytes[len(_alabel_prefix) :] + if not label_bytes: + raise IDNAError("Malformed A-label, no Punycode eligible content found") + if label_bytes.decode("ascii")[-1] == "-": + raise IDNAError("A-label must not end with a hyphen") + else: + check_label(label_bytes) + return label_bytes.decode("ascii") + + try: + label = label_bytes.decode("punycode") + except UnicodeError: + raise IDNAError("Invalid A-label") + check_label(label) + return label + + +def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + + output = "" + + for pos, char in enumerate(domain): + code_point = ord(char) + try: + uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement: Optional[str] = None + if len(uts46row) == 3: + replacement = uts46row[2] + if ( + status == "V" + or (status == "D" and not transitional) + or (status == "3" and not std3_rules and replacement is None) + ): + output += char + elif replacement is not None and ( + status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional) + ): + output += replacement + elif status != "I": + raise IndexError() + except IndexError: + raise InvalidCodepoint( + "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain)) + ) + + return unicodedata.normalize("NFC", output) + + +def encode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, + transitional: bool = False, +) -> bytes: + if not isinstance(s, str): + try: + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("should pass a unicode string to the function rather than a byte string.") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split(".") + else: + labels = _unicode_dots_re.split(s) + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if labels[-1] == "": + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append(b"") + s = b".".join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError("Domain too long") + return s + + +def decode( + s: Union[str, bytes, bytearray], + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, +) -> str: + try: + if not isinstance(s, str): + s = str(s, "ascii") + except UnicodeDecodeError: + raise IDNAError("Invalid ASCII in A-label") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(".") + if not labels or labels == [""]: + raise IDNAError("Empty domain") + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + s = ulabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label") + if trailing_dot: + result.append("") + return ".".join(result) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/idnadata.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/idnadata.py new file mode 100644 index 0000000..4be6004 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/idnadata.py @@ -0,0 +1,4243 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "15.1.0" +scripts = { + "Greek": ( + 0x37000000374, + 0x37500000378, + 0x37A0000037E, + 0x37F00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038B, + 0x38C0000038D, + 0x38E000003A2, + 0x3A3000003E2, + 0x3F000000400, + 0x1D2600001D2B, + 0x1D5D00001D62, + 0x1D6600001D6B, + 0x1DBF00001DC0, + 0x1F0000001F16, + 0x1F1800001F1E, + 0x1F2000001F46, + 0x1F4800001F4E, + 0x1F5000001F58, + 0x1F5900001F5A, + 0x1F5B00001F5C, + 0x1F5D00001F5E, + 0x1F5F00001F7E, + 0x1F8000001FB5, + 0x1FB600001FC5, + 0x1FC600001FD4, + 0x1FD600001FDC, + 0x1FDD00001FF0, + 0x1FF200001FF5, + 0x1FF600001FFF, + 0x212600002127, + 0xAB650000AB66, + 0x101400001018F, + 0x101A0000101A1, + 0x1D2000001D246, + ), + "Han": ( + 0x2E8000002E9A, + 0x2E9B00002EF4, + 0x2F0000002FD6, + 0x300500003006, + 0x300700003008, + 0x30210000302A, + 0x30380000303C, + 0x340000004DC0, + 0x4E000000A000, + 0xF9000000FA6E, + 0xFA700000FADA, + 0x16FE200016FE4, + 0x16FF000016FF2, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x2F8000002FA1E, + 0x300000003134B, + 0x31350000323B0, + ), + "Hebrew": ( + 0x591000005C8, + 0x5D0000005EB, + 0x5EF000005F5, + 0xFB1D0000FB37, + 0xFB380000FB3D, + 0xFB3E0000FB3F, + 0xFB400000FB42, + 0xFB430000FB45, + 0xFB460000FB50, + ), + "Hiragana": ( + 0x304100003097, + 0x309D000030A0, + 0x1B0010001B120, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1F2000001F201, + ), + "Katakana": ( + 0x30A1000030FB, + 0x30FD00003100, + 0x31F000003200, + 0x32D0000032FF, + 0x330000003358, + 0xFF660000FF70, + 0xFF710000FF9E, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B001, + 0x1B1200001B123, + 0x1B1550001B156, + 0x1B1640001B168, + ), +} +joining_types = { + 0xAD: 84, + 0x300: 84, + 0x301: 84, + 0x302: 84, + 0x303: 84, + 0x304: 84, + 0x305: 84, + 0x306: 84, + 0x307: 84, + 0x308: 84, + 0x309: 84, + 0x30A: 84, + 0x30B: 84, + 0x30C: 84, + 0x30D: 84, + 0x30E: 84, + 0x30F: 84, + 0x310: 84, + 0x311: 84, + 0x312: 84, + 0x313: 84, + 0x314: 84, + 0x315: 84, + 0x316: 84, + 0x317: 84, + 0x318: 84, + 0x319: 84, + 0x31A: 84, + 0x31B: 84, + 0x31C: 84, + 0x31D: 84, + 0x31E: 84, + 0x31F: 84, + 0x320: 84, + 0x321: 84, + 0x322: 84, + 0x323: 84, + 0x324: 84, + 0x325: 84, + 0x326: 84, + 0x327: 84, + 0x328: 84, + 0x329: 84, + 0x32A: 84, + 0x32B: 84, + 0x32C: 84, + 0x32D: 84, + 0x32E: 84, + 0x32F: 84, + 0x330: 84, + 0x331: 84, + 0x332: 84, + 0x333: 84, + 0x334: 84, + 0x335: 84, + 0x336: 84, + 0x337: 84, + 0x338: 84, + 0x339: 84, + 0x33A: 84, + 0x33B: 84, + 0x33C: 84, + 0x33D: 84, + 0x33E: 84, + 0x33F: 84, + 0x340: 84, + 0x341: 84, + 0x342: 84, + 0x343: 84, + 0x344: 84, + 0x345: 84, + 0x346: 84, + 0x347: 84, + 0x348: 84, + 0x349: 84, + 0x34A: 84, + 0x34B: 84, + 0x34C: 84, + 0x34D: 84, + 0x34E: 84, + 0x34F: 84, + 0x350: 84, + 0x351: 84, + 0x352: 84, + 0x353: 84, + 0x354: 84, + 0x355: 84, + 0x356: 84, + 0x357: 84, + 0x358: 84, + 0x359: 84, + 0x35A: 84, + 0x35B: 84, + 0x35C: 84, + 0x35D: 84, + 0x35E: 84, + 0x35F: 84, + 0x360: 84, + 0x361: 84, + 0x362: 84, + 0x363: 84, + 0x364: 84, + 0x365: 84, + 0x366: 84, + 0x367: 84, + 0x368: 84, + 0x369: 84, + 0x36A: 84, + 0x36B: 84, + 0x36C: 84, + 0x36D: 84, + 0x36E: 84, + 0x36F: 84, + 0x483: 84, + 0x484: 84, + 0x485: 84, + 0x486: 84, + 0x487: 84, + 0x488: 84, + 0x489: 84, + 0x591: 84, + 0x592: 84, + 0x593: 84, + 0x594: 84, + 0x595: 84, + 0x596: 84, + 0x597: 84, + 0x598: 84, + 0x599: 84, + 0x59A: 84, + 0x59B: 84, + 0x59C: 84, + 0x59D: 84, + 0x59E: 84, + 0x59F: 84, + 0x5A0: 84, + 0x5A1: 84, + 0x5A2: 84, + 0x5A3: 84, + 0x5A4: 84, + 0x5A5: 84, + 0x5A6: 84, + 0x5A7: 84, + 0x5A8: 84, + 0x5A9: 84, + 0x5AA: 84, + 0x5AB: 84, + 0x5AC: 84, + 0x5AD: 84, + 0x5AE: 84, + 0x5AF: 84, + 0x5B0: 84, + 0x5B1: 84, + 0x5B2: 84, + 0x5B3: 84, + 0x5B4: 84, + 0x5B5: 84, + 0x5B6: 84, + 0x5B7: 84, + 0x5B8: 84, + 0x5B9: 84, + 0x5BA: 84, + 0x5BB: 84, + 0x5BC: 84, + 0x5BD: 84, + 0x5BF: 84, + 0x5C1: 84, + 0x5C2: 84, + 0x5C4: 84, + 0x5C5: 84, + 0x5C7: 84, + 0x610: 84, + 0x611: 84, + 0x612: 84, + 0x613: 84, + 0x614: 84, + 0x615: 84, + 0x616: 84, + 0x617: 84, + 0x618: 84, + 0x619: 84, + 0x61A: 84, + 0x61C: 84, + 0x620: 68, + 0x622: 82, + 0x623: 82, + 0x624: 82, + 0x625: 82, + 0x626: 68, + 0x627: 82, + 0x628: 68, + 0x629: 82, + 0x62A: 68, + 0x62B: 68, + 0x62C: 68, + 0x62D: 68, + 0x62E: 68, + 0x62F: 82, + 0x630: 82, + 0x631: 82, + 0x632: 82, + 0x633: 68, + 0x634: 68, + 0x635: 68, + 0x636: 68, + 0x637: 68, + 0x638: 68, + 0x639: 68, + 0x63A: 68, + 0x63B: 68, + 0x63C: 68, + 0x63D: 68, + 0x63E: 68, + 0x63F: 68, + 0x640: 67, + 0x641: 68, + 0x642: 68, + 0x643: 68, + 0x644: 68, + 0x645: 68, + 0x646: 68, + 0x647: 68, + 0x648: 82, + 0x649: 68, + 0x64A: 68, + 0x64B: 84, + 0x64C: 84, + 0x64D: 84, + 0x64E: 84, + 0x64F: 84, + 0x650: 84, + 0x651: 84, + 0x652: 84, + 0x653: 84, + 0x654: 84, + 0x655: 84, + 0x656: 84, + 0x657: 84, + 0x658: 84, + 0x659: 84, + 0x65A: 84, + 0x65B: 84, + 0x65C: 84, + 0x65D: 84, + 0x65E: 84, + 0x65F: 84, + 0x66E: 68, + 0x66F: 68, + 0x670: 84, + 0x671: 82, + 0x672: 82, + 0x673: 82, + 0x675: 82, + 0x676: 82, + 0x677: 82, + 0x678: 68, + 0x679: 68, + 0x67A: 68, + 0x67B: 68, + 0x67C: 68, + 0x67D: 68, + 0x67E: 68, + 0x67F: 68, + 0x680: 68, + 0x681: 68, + 0x682: 68, + 0x683: 68, + 0x684: 68, + 0x685: 68, + 0x686: 68, + 0x687: 68, + 0x688: 82, + 0x689: 82, + 0x68A: 82, + 0x68B: 82, + 0x68C: 82, + 0x68D: 82, + 0x68E: 82, + 0x68F: 82, + 0x690: 82, + 0x691: 82, + 0x692: 82, + 0x693: 82, + 0x694: 82, + 0x695: 82, + 0x696: 82, + 0x697: 82, + 0x698: 82, + 0x699: 82, + 0x69A: 68, + 0x69B: 68, + 0x69C: 68, + 0x69D: 68, + 0x69E: 68, + 0x69F: 68, + 0x6A0: 68, + 0x6A1: 68, + 0x6A2: 68, + 0x6A3: 68, + 0x6A4: 68, + 0x6A5: 68, + 0x6A6: 68, + 0x6A7: 68, + 0x6A8: 68, + 0x6A9: 68, + 0x6AA: 68, + 0x6AB: 68, + 0x6AC: 68, + 0x6AD: 68, + 0x6AE: 68, + 0x6AF: 68, + 0x6B0: 68, + 0x6B1: 68, + 0x6B2: 68, + 0x6B3: 68, + 0x6B4: 68, + 0x6B5: 68, + 0x6B6: 68, + 0x6B7: 68, + 0x6B8: 68, + 0x6B9: 68, + 0x6BA: 68, + 0x6BB: 68, + 0x6BC: 68, + 0x6BD: 68, + 0x6BE: 68, + 0x6BF: 68, + 0x6C0: 82, + 0x6C1: 68, + 0x6C2: 68, + 0x6C3: 82, + 0x6C4: 82, + 0x6C5: 82, + 0x6C6: 82, + 0x6C7: 82, + 0x6C8: 82, + 0x6C9: 82, + 0x6CA: 82, + 0x6CB: 82, + 0x6CC: 68, + 0x6CD: 82, + 0x6CE: 68, + 0x6CF: 82, + 0x6D0: 68, + 0x6D1: 68, + 0x6D2: 82, + 0x6D3: 82, + 0x6D5: 82, + 0x6D6: 84, + 0x6D7: 84, + 0x6D8: 84, + 0x6D9: 84, + 0x6DA: 84, + 0x6DB: 84, + 0x6DC: 84, + 0x6DF: 84, + 0x6E0: 84, + 0x6E1: 84, + 0x6E2: 84, + 0x6E3: 84, + 0x6E4: 84, + 0x6E7: 84, + 0x6E8: 84, + 0x6EA: 84, + 0x6EB: 84, + 0x6EC: 84, + 0x6ED: 84, + 0x6EE: 82, + 0x6EF: 82, + 0x6FA: 68, + 0x6FB: 68, + 0x6FC: 68, + 0x6FF: 68, + 0x70F: 84, + 0x710: 82, + 0x711: 84, + 0x712: 68, + 0x713: 68, + 0x714: 68, + 0x715: 82, + 0x716: 82, + 0x717: 82, + 0x718: 82, + 0x719: 82, + 0x71A: 68, + 0x71B: 68, + 0x71C: 68, + 0x71D: 68, + 0x71E: 82, + 0x71F: 68, + 0x720: 68, + 0x721: 68, + 0x722: 68, + 0x723: 68, + 0x724: 68, + 0x725: 68, + 0x726: 68, + 0x727: 68, + 0x728: 82, + 0x729: 68, + 0x72A: 82, + 0x72B: 68, + 0x72C: 82, + 0x72D: 68, + 0x72E: 68, + 0x72F: 82, + 0x730: 84, + 0x731: 84, + 0x732: 84, + 0x733: 84, + 0x734: 84, + 0x735: 84, + 0x736: 84, + 0x737: 84, + 0x738: 84, + 0x739: 84, + 0x73A: 84, + 0x73B: 84, + 0x73C: 84, + 0x73D: 84, + 0x73E: 84, + 0x73F: 84, + 0x740: 84, + 0x741: 84, + 0x742: 84, + 0x743: 84, + 0x744: 84, + 0x745: 84, + 0x746: 84, + 0x747: 84, + 0x748: 84, + 0x749: 84, + 0x74A: 84, + 0x74D: 82, + 0x74E: 68, + 0x74F: 68, + 0x750: 68, + 0x751: 68, + 0x752: 68, + 0x753: 68, + 0x754: 68, + 0x755: 68, + 0x756: 68, + 0x757: 68, + 0x758: 68, + 0x759: 82, + 0x75A: 82, + 0x75B: 82, + 0x75C: 68, + 0x75D: 68, + 0x75E: 68, + 0x75F: 68, + 0x760: 68, + 0x761: 68, + 0x762: 68, + 0x763: 68, + 0x764: 68, + 0x765: 68, + 0x766: 68, + 0x767: 68, + 0x768: 68, + 0x769: 68, + 0x76A: 68, + 0x76B: 82, + 0x76C: 82, + 0x76D: 68, + 0x76E: 68, + 0x76F: 68, + 0x770: 68, + 0x771: 82, + 0x772: 68, + 0x773: 82, + 0x774: 82, + 0x775: 68, + 0x776: 68, + 0x777: 68, + 0x778: 82, + 0x779: 82, + 0x77A: 68, + 0x77B: 68, + 0x77C: 68, + 0x77D: 68, + 0x77E: 68, + 0x77F: 68, + 0x7A6: 84, + 0x7A7: 84, + 0x7A8: 84, + 0x7A9: 84, + 0x7AA: 84, + 0x7AB: 84, + 0x7AC: 84, + 0x7AD: 84, + 0x7AE: 84, + 0x7AF: 84, + 0x7B0: 84, + 0x7CA: 68, + 0x7CB: 68, + 0x7CC: 68, + 0x7CD: 68, + 0x7CE: 68, + 0x7CF: 68, + 0x7D0: 68, + 0x7D1: 68, + 0x7D2: 68, + 0x7D3: 68, + 0x7D4: 68, + 0x7D5: 68, + 0x7D6: 68, + 0x7D7: 68, + 0x7D8: 68, + 0x7D9: 68, + 0x7DA: 68, + 0x7DB: 68, + 0x7DC: 68, + 0x7DD: 68, + 0x7DE: 68, + 0x7DF: 68, + 0x7E0: 68, + 0x7E1: 68, + 0x7E2: 68, + 0x7E3: 68, + 0x7E4: 68, + 0x7E5: 68, + 0x7E6: 68, + 0x7E7: 68, + 0x7E8: 68, + 0x7E9: 68, + 0x7EA: 68, + 0x7EB: 84, + 0x7EC: 84, + 0x7ED: 84, + 0x7EE: 84, + 0x7EF: 84, + 0x7F0: 84, + 0x7F1: 84, + 0x7F2: 84, + 0x7F3: 84, + 0x7FA: 67, + 0x7FD: 84, + 0x816: 84, + 0x817: 84, + 0x818: 84, + 0x819: 84, + 0x81B: 84, + 0x81C: 84, + 0x81D: 84, + 0x81E: 84, + 0x81F: 84, + 0x820: 84, + 0x821: 84, + 0x822: 84, + 0x823: 84, + 0x825: 84, + 0x826: 84, + 0x827: 84, + 0x829: 84, + 0x82A: 84, + 0x82B: 84, + 0x82C: 84, + 0x82D: 84, + 0x840: 82, + 0x841: 68, + 0x842: 68, + 0x843: 68, + 0x844: 68, + 0x845: 68, + 0x846: 82, + 0x847: 82, + 0x848: 68, + 0x849: 82, + 0x84A: 68, + 0x84B: 68, + 0x84C: 68, + 0x84D: 68, + 0x84E: 68, + 0x84F: 68, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 82, + 0x857: 82, + 0x858: 82, + 0x859: 84, + 0x85A: 84, + 0x85B: 84, + 0x860: 68, + 0x862: 68, + 0x863: 68, + 0x864: 68, + 0x865: 68, + 0x867: 82, + 0x868: 68, + 0x869: 82, + 0x86A: 82, + 0x870: 82, + 0x871: 82, + 0x872: 82, + 0x873: 82, + 0x874: 82, + 0x875: 82, + 0x876: 82, + 0x877: 82, + 0x878: 82, + 0x879: 82, + 0x87A: 82, + 0x87B: 82, + 0x87C: 82, + 0x87D: 82, + 0x87E: 82, + 0x87F: 82, + 0x880: 82, + 0x881: 82, + 0x882: 82, + 0x883: 67, + 0x884: 67, + 0x885: 67, + 0x886: 68, + 0x889: 68, + 0x88A: 68, + 0x88B: 68, + 0x88C: 68, + 0x88D: 68, + 0x88E: 82, + 0x898: 84, + 0x899: 84, + 0x89A: 84, + 0x89B: 84, + 0x89C: 84, + 0x89D: 84, + 0x89E: 84, + 0x89F: 84, + 0x8A0: 68, + 0x8A1: 68, + 0x8A2: 68, + 0x8A3: 68, + 0x8A4: 68, + 0x8A5: 68, + 0x8A6: 68, + 0x8A7: 68, + 0x8A8: 68, + 0x8A9: 68, + 0x8AA: 82, + 0x8AB: 82, + 0x8AC: 82, + 0x8AE: 82, + 0x8AF: 68, + 0x8B0: 68, + 0x8B1: 82, + 0x8B2: 82, + 0x8B3: 68, + 0x8B4: 68, + 0x8B5: 68, + 0x8B6: 68, + 0x8B7: 68, + 0x8B8: 68, + 0x8B9: 82, + 0x8BA: 68, + 0x8BB: 68, + 0x8BC: 68, + 0x8BD: 68, + 0x8BE: 68, + 0x8BF: 68, + 0x8C0: 68, + 0x8C1: 68, + 0x8C2: 68, + 0x8C3: 68, + 0x8C4: 68, + 0x8C5: 68, + 0x8C6: 68, + 0x8C7: 68, + 0x8C8: 68, + 0x8CA: 84, + 0x8CB: 84, + 0x8CC: 84, + 0x8CD: 84, + 0x8CE: 84, + 0x8CF: 84, + 0x8D0: 84, + 0x8D1: 84, + 0x8D2: 84, + 0x8D3: 84, + 0x8D4: 84, + 0x8D5: 84, + 0x8D6: 84, + 0x8D7: 84, + 0x8D8: 84, + 0x8D9: 84, + 0x8DA: 84, + 0x8DB: 84, + 0x8DC: 84, + 0x8DD: 84, + 0x8DE: 84, + 0x8DF: 84, + 0x8E0: 84, + 0x8E1: 84, + 0x8E3: 84, + 0x8E4: 84, + 0x8E5: 84, + 0x8E6: 84, + 0x8E7: 84, + 0x8E8: 84, + 0x8E9: 84, + 0x8EA: 84, + 0x8EB: 84, + 0x8EC: 84, + 0x8ED: 84, + 0x8EE: 84, + 0x8EF: 84, + 0x8F0: 84, + 0x8F1: 84, + 0x8F2: 84, + 0x8F3: 84, + 0x8F4: 84, + 0x8F5: 84, + 0x8F6: 84, + 0x8F7: 84, + 0x8F8: 84, + 0x8F9: 84, + 0x8FA: 84, + 0x8FB: 84, + 0x8FC: 84, + 0x8FD: 84, + 0x8FE: 84, + 0x8FF: 84, + 0x900: 84, + 0x901: 84, + 0x902: 84, + 0x93A: 84, + 0x93C: 84, + 0x941: 84, + 0x942: 84, + 0x943: 84, + 0x944: 84, + 0x945: 84, + 0x946: 84, + 0x947: 84, + 0x948: 84, + 0x94D: 84, + 0x951: 84, + 0x952: 84, + 0x953: 84, + 0x954: 84, + 0x955: 84, + 0x956: 84, + 0x957: 84, + 0x962: 84, + 0x963: 84, + 0x981: 84, + 0x9BC: 84, + 0x9C1: 84, + 0x9C2: 84, + 0x9C3: 84, + 0x9C4: 84, + 0x9CD: 84, + 0x9E2: 84, + 0x9E3: 84, + 0x9FE: 84, + 0xA01: 84, + 0xA02: 84, + 0xA3C: 84, + 0xA41: 84, + 0xA42: 84, + 0xA47: 84, + 0xA48: 84, + 0xA4B: 84, + 0xA4C: 84, + 0xA4D: 84, + 0xA51: 84, + 0xA70: 84, + 0xA71: 84, + 0xA75: 84, + 0xA81: 84, + 0xA82: 84, + 0xABC: 84, + 0xAC1: 84, + 0xAC2: 84, + 0xAC3: 84, + 0xAC4: 84, + 0xAC5: 84, + 0xAC7: 84, + 0xAC8: 84, + 0xACD: 84, + 0xAE2: 84, + 0xAE3: 84, + 0xAFA: 84, + 0xAFB: 84, + 0xAFC: 84, + 0xAFD: 84, + 0xAFE: 84, + 0xAFF: 84, + 0xB01: 84, + 0xB3C: 84, + 0xB3F: 84, + 0xB41: 84, + 0xB42: 84, + 0xB43: 84, + 0xB44: 84, + 0xB4D: 84, + 0xB55: 84, + 0xB56: 84, + 0xB62: 84, + 0xB63: 84, + 0xB82: 84, + 0xBC0: 84, + 0xBCD: 84, + 0xC00: 84, + 0xC04: 84, + 0xC3C: 84, + 0xC3E: 84, + 0xC3F: 84, + 0xC40: 84, + 0xC46: 84, + 0xC47: 84, + 0xC48: 84, + 0xC4A: 84, + 0xC4B: 84, + 0xC4C: 84, + 0xC4D: 84, + 0xC55: 84, + 0xC56: 84, + 0xC62: 84, + 0xC63: 84, + 0xC81: 84, + 0xCBC: 84, + 0xCBF: 84, + 0xCC6: 84, + 0xCCC: 84, + 0xCCD: 84, + 0xCE2: 84, + 0xCE3: 84, + 0xD00: 84, + 0xD01: 84, + 0xD3B: 84, + 0xD3C: 84, + 0xD41: 84, + 0xD42: 84, + 0xD43: 84, + 0xD44: 84, + 0xD4D: 84, + 0xD62: 84, + 0xD63: 84, + 0xD81: 84, + 0xDCA: 84, + 0xDD2: 84, + 0xDD3: 84, + 0xDD4: 84, + 0xDD6: 84, + 0xE31: 84, + 0xE34: 84, + 0xE35: 84, + 0xE36: 84, + 0xE37: 84, + 0xE38: 84, + 0xE39: 84, + 0xE3A: 84, + 0xE47: 84, + 0xE48: 84, + 0xE49: 84, + 0xE4A: 84, + 0xE4B: 84, + 0xE4C: 84, + 0xE4D: 84, + 0xE4E: 84, + 0xEB1: 84, + 0xEB4: 84, + 0xEB5: 84, + 0xEB6: 84, + 0xEB7: 84, + 0xEB8: 84, + 0xEB9: 84, + 0xEBA: 84, + 0xEBB: 84, + 0xEBC: 84, + 0xEC8: 84, + 0xEC9: 84, + 0xECA: 84, + 0xECB: 84, + 0xECC: 84, + 0xECD: 84, + 0xECE: 84, + 0xF18: 84, + 0xF19: 84, + 0xF35: 84, + 0xF37: 84, + 0xF39: 84, + 0xF71: 84, + 0xF72: 84, + 0xF73: 84, + 0xF74: 84, + 0xF75: 84, + 0xF76: 84, + 0xF77: 84, + 0xF78: 84, + 0xF79: 84, + 0xF7A: 84, + 0xF7B: 84, + 0xF7C: 84, + 0xF7D: 84, + 0xF7E: 84, + 0xF80: 84, + 0xF81: 84, + 0xF82: 84, + 0xF83: 84, + 0xF84: 84, + 0xF86: 84, + 0xF87: 84, + 0xF8D: 84, + 0xF8E: 84, + 0xF8F: 84, + 0xF90: 84, + 0xF91: 84, + 0xF92: 84, + 0xF93: 84, + 0xF94: 84, + 0xF95: 84, + 0xF96: 84, + 0xF97: 84, + 0xF99: 84, + 0xF9A: 84, + 0xF9B: 84, + 0xF9C: 84, + 0xF9D: 84, + 0xF9E: 84, + 0xF9F: 84, + 0xFA0: 84, + 0xFA1: 84, + 0xFA2: 84, + 0xFA3: 84, + 0xFA4: 84, + 0xFA5: 84, + 0xFA6: 84, + 0xFA7: 84, + 0xFA8: 84, + 0xFA9: 84, + 0xFAA: 84, + 0xFAB: 84, + 0xFAC: 84, + 0xFAD: 84, + 0xFAE: 84, + 0xFAF: 84, + 0xFB0: 84, + 0xFB1: 84, + 0xFB2: 84, + 0xFB3: 84, + 0xFB4: 84, + 0xFB5: 84, + 0xFB6: 84, + 0xFB7: 84, + 0xFB8: 84, + 0xFB9: 84, + 0xFBA: 84, + 0xFBB: 84, + 0xFBC: 84, + 0xFC6: 84, + 0x102D: 84, + 0x102E: 84, + 0x102F: 84, + 0x1030: 84, + 0x1032: 84, + 0x1033: 84, + 0x1034: 84, + 0x1035: 84, + 0x1036: 84, + 0x1037: 84, + 0x1039: 84, + 0x103A: 84, + 0x103D: 84, + 0x103E: 84, + 0x1058: 84, + 0x1059: 84, + 0x105E: 84, + 0x105F: 84, + 0x1060: 84, + 0x1071: 84, + 0x1072: 84, + 0x1073: 84, + 0x1074: 84, + 0x1082: 84, + 0x1085: 84, + 0x1086: 84, + 0x108D: 84, + 0x109D: 84, + 0x135D: 84, + 0x135E: 84, + 0x135F: 84, + 0x1712: 84, + 0x1713: 84, + 0x1714: 84, + 0x1732: 84, + 0x1733: 84, + 0x1752: 84, + 0x1753: 84, + 0x1772: 84, + 0x1773: 84, + 0x17B4: 84, + 0x17B5: 84, + 0x17B7: 84, + 0x17B8: 84, + 0x17B9: 84, + 0x17BA: 84, + 0x17BB: 84, + 0x17BC: 84, + 0x17BD: 84, + 0x17C6: 84, + 0x17C9: 84, + 0x17CA: 84, + 0x17CB: 84, + 0x17CC: 84, + 0x17CD: 84, + 0x17CE: 84, + 0x17CF: 84, + 0x17D0: 84, + 0x17D1: 84, + 0x17D2: 84, + 0x17D3: 84, + 0x17DD: 84, + 0x1807: 68, + 0x180A: 67, + 0x180B: 84, + 0x180C: 84, + 0x180D: 84, + 0x180F: 84, + 0x1820: 68, + 0x1821: 68, + 0x1822: 68, + 0x1823: 68, + 0x1824: 68, + 0x1825: 68, + 0x1826: 68, + 0x1827: 68, + 0x1828: 68, + 0x1829: 68, + 0x182A: 68, + 0x182B: 68, + 0x182C: 68, + 0x182D: 68, + 0x182E: 68, + 0x182F: 68, + 0x1830: 68, + 0x1831: 68, + 0x1832: 68, + 0x1833: 68, + 0x1834: 68, + 0x1835: 68, + 0x1836: 68, + 0x1837: 68, + 0x1838: 68, + 0x1839: 68, + 0x183A: 68, + 0x183B: 68, + 0x183C: 68, + 0x183D: 68, + 0x183E: 68, + 0x183F: 68, + 0x1840: 68, + 0x1841: 68, + 0x1842: 68, + 0x1843: 68, + 0x1844: 68, + 0x1845: 68, + 0x1846: 68, + 0x1847: 68, + 0x1848: 68, + 0x1849: 68, + 0x184A: 68, + 0x184B: 68, + 0x184C: 68, + 0x184D: 68, + 0x184E: 68, + 0x184F: 68, + 0x1850: 68, + 0x1851: 68, + 0x1852: 68, + 0x1853: 68, + 0x1854: 68, + 0x1855: 68, + 0x1856: 68, + 0x1857: 68, + 0x1858: 68, + 0x1859: 68, + 0x185A: 68, + 0x185B: 68, + 0x185C: 68, + 0x185D: 68, + 0x185E: 68, + 0x185F: 68, + 0x1860: 68, + 0x1861: 68, + 0x1862: 68, + 0x1863: 68, + 0x1864: 68, + 0x1865: 68, + 0x1866: 68, + 0x1867: 68, + 0x1868: 68, + 0x1869: 68, + 0x186A: 68, + 0x186B: 68, + 0x186C: 68, + 0x186D: 68, + 0x186E: 68, + 0x186F: 68, + 0x1870: 68, + 0x1871: 68, + 0x1872: 68, + 0x1873: 68, + 0x1874: 68, + 0x1875: 68, + 0x1876: 68, + 0x1877: 68, + 0x1878: 68, + 0x1885: 84, + 0x1886: 84, + 0x1887: 68, + 0x1888: 68, + 0x1889: 68, + 0x188A: 68, + 0x188B: 68, + 0x188C: 68, + 0x188D: 68, + 0x188E: 68, + 0x188F: 68, + 0x1890: 68, + 0x1891: 68, + 0x1892: 68, + 0x1893: 68, + 0x1894: 68, + 0x1895: 68, + 0x1896: 68, + 0x1897: 68, + 0x1898: 68, + 0x1899: 68, + 0x189A: 68, + 0x189B: 68, + 0x189C: 68, + 0x189D: 68, + 0x189E: 68, + 0x189F: 68, + 0x18A0: 68, + 0x18A1: 68, + 0x18A2: 68, + 0x18A3: 68, + 0x18A4: 68, + 0x18A5: 68, + 0x18A6: 68, + 0x18A7: 68, + 0x18A8: 68, + 0x18A9: 84, + 0x18AA: 68, + 0x1920: 84, + 0x1921: 84, + 0x1922: 84, + 0x1927: 84, + 0x1928: 84, + 0x1932: 84, + 0x1939: 84, + 0x193A: 84, + 0x193B: 84, + 0x1A17: 84, + 0x1A18: 84, + 0x1A1B: 84, + 0x1A56: 84, + 0x1A58: 84, + 0x1A59: 84, + 0x1A5A: 84, + 0x1A5B: 84, + 0x1A5C: 84, + 0x1A5D: 84, + 0x1A5E: 84, + 0x1A60: 84, + 0x1A62: 84, + 0x1A65: 84, + 0x1A66: 84, + 0x1A67: 84, + 0x1A68: 84, + 0x1A69: 84, + 0x1A6A: 84, + 0x1A6B: 84, + 0x1A6C: 84, + 0x1A73: 84, + 0x1A74: 84, + 0x1A75: 84, + 0x1A76: 84, + 0x1A77: 84, + 0x1A78: 84, + 0x1A79: 84, + 0x1A7A: 84, + 0x1A7B: 84, + 0x1A7C: 84, + 0x1A7F: 84, + 0x1AB0: 84, + 0x1AB1: 84, + 0x1AB2: 84, + 0x1AB3: 84, + 0x1AB4: 84, + 0x1AB5: 84, + 0x1AB6: 84, + 0x1AB7: 84, + 0x1AB8: 84, + 0x1AB9: 84, + 0x1ABA: 84, + 0x1ABB: 84, + 0x1ABC: 84, + 0x1ABD: 84, + 0x1ABE: 84, + 0x1ABF: 84, + 0x1AC0: 84, + 0x1AC1: 84, + 0x1AC2: 84, + 0x1AC3: 84, + 0x1AC4: 84, + 0x1AC5: 84, + 0x1AC6: 84, + 0x1AC7: 84, + 0x1AC8: 84, + 0x1AC9: 84, + 0x1ACA: 84, + 0x1ACB: 84, + 0x1ACC: 84, + 0x1ACD: 84, + 0x1ACE: 84, + 0x1B00: 84, + 0x1B01: 84, + 0x1B02: 84, + 0x1B03: 84, + 0x1B34: 84, + 0x1B36: 84, + 0x1B37: 84, + 0x1B38: 84, + 0x1B39: 84, + 0x1B3A: 84, + 0x1B3C: 84, + 0x1B42: 84, + 0x1B6B: 84, + 0x1B6C: 84, + 0x1B6D: 84, + 0x1B6E: 84, + 0x1B6F: 84, + 0x1B70: 84, + 0x1B71: 84, + 0x1B72: 84, + 0x1B73: 84, + 0x1B80: 84, + 0x1B81: 84, + 0x1BA2: 84, + 0x1BA3: 84, + 0x1BA4: 84, + 0x1BA5: 84, + 0x1BA8: 84, + 0x1BA9: 84, + 0x1BAB: 84, + 0x1BAC: 84, + 0x1BAD: 84, + 0x1BE6: 84, + 0x1BE8: 84, + 0x1BE9: 84, + 0x1BED: 84, + 0x1BEF: 84, + 0x1BF0: 84, + 0x1BF1: 84, + 0x1C2C: 84, + 0x1C2D: 84, + 0x1C2E: 84, + 0x1C2F: 84, + 0x1C30: 84, + 0x1C31: 84, + 0x1C32: 84, + 0x1C33: 84, + 0x1C36: 84, + 0x1C37: 84, + 0x1CD0: 84, + 0x1CD1: 84, + 0x1CD2: 84, + 0x1CD4: 84, + 0x1CD5: 84, + 0x1CD6: 84, + 0x1CD7: 84, + 0x1CD8: 84, + 0x1CD9: 84, + 0x1CDA: 84, + 0x1CDB: 84, + 0x1CDC: 84, + 0x1CDD: 84, + 0x1CDE: 84, + 0x1CDF: 84, + 0x1CE0: 84, + 0x1CE2: 84, + 0x1CE3: 84, + 0x1CE4: 84, + 0x1CE5: 84, + 0x1CE6: 84, + 0x1CE7: 84, + 0x1CE8: 84, + 0x1CED: 84, + 0x1CF4: 84, + 0x1CF8: 84, + 0x1CF9: 84, + 0x1DC0: 84, + 0x1DC1: 84, + 0x1DC2: 84, + 0x1DC3: 84, + 0x1DC4: 84, + 0x1DC5: 84, + 0x1DC6: 84, + 0x1DC7: 84, + 0x1DC8: 84, + 0x1DC9: 84, + 0x1DCA: 84, + 0x1DCB: 84, + 0x1DCC: 84, + 0x1DCD: 84, + 0x1DCE: 84, + 0x1DCF: 84, + 0x1DD0: 84, + 0x1DD1: 84, + 0x1DD2: 84, + 0x1DD3: 84, + 0x1DD4: 84, + 0x1DD5: 84, + 0x1DD6: 84, + 0x1DD7: 84, + 0x1DD8: 84, + 0x1DD9: 84, + 0x1DDA: 84, + 0x1DDB: 84, + 0x1DDC: 84, + 0x1DDD: 84, + 0x1DDE: 84, + 0x1DDF: 84, + 0x1DE0: 84, + 0x1DE1: 84, + 0x1DE2: 84, + 0x1DE3: 84, + 0x1DE4: 84, + 0x1DE5: 84, + 0x1DE6: 84, + 0x1DE7: 84, + 0x1DE8: 84, + 0x1DE9: 84, + 0x1DEA: 84, + 0x1DEB: 84, + 0x1DEC: 84, + 0x1DED: 84, + 0x1DEE: 84, + 0x1DEF: 84, + 0x1DF0: 84, + 0x1DF1: 84, + 0x1DF2: 84, + 0x1DF3: 84, + 0x1DF4: 84, + 0x1DF5: 84, + 0x1DF6: 84, + 0x1DF7: 84, + 0x1DF8: 84, + 0x1DF9: 84, + 0x1DFA: 84, + 0x1DFB: 84, + 0x1DFC: 84, + 0x1DFD: 84, + 0x1DFE: 84, + 0x1DFF: 84, + 0x200B: 84, + 0x200D: 67, + 0x200E: 84, + 0x200F: 84, + 0x202A: 84, + 0x202B: 84, + 0x202C: 84, + 0x202D: 84, + 0x202E: 84, + 0x2060: 84, + 0x2061: 84, + 0x2062: 84, + 0x2063: 84, + 0x2064: 84, + 0x206A: 84, + 0x206B: 84, + 0x206C: 84, + 0x206D: 84, + 0x206E: 84, + 0x206F: 84, + 0x20D0: 84, + 0x20D1: 84, + 0x20D2: 84, + 0x20D3: 84, + 0x20D4: 84, + 0x20D5: 84, + 0x20D6: 84, + 0x20D7: 84, + 0x20D8: 84, + 0x20D9: 84, + 0x20DA: 84, + 0x20DB: 84, + 0x20DC: 84, + 0x20DD: 84, + 0x20DE: 84, + 0x20DF: 84, + 0x20E0: 84, + 0x20E1: 84, + 0x20E2: 84, + 0x20E3: 84, + 0x20E4: 84, + 0x20E5: 84, + 0x20E6: 84, + 0x20E7: 84, + 0x20E8: 84, + 0x20E9: 84, + 0x20EA: 84, + 0x20EB: 84, + 0x20EC: 84, + 0x20ED: 84, + 0x20EE: 84, + 0x20EF: 84, + 0x20F0: 84, + 0x2CEF: 84, + 0x2CF0: 84, + 0x2CF1: 84, + 0x2D7F: 84, + 0x2DE0: 84, + 0x2DE1: 84, + 0x2DE2: 84, + 0x2DE3: 84, + 0x2DE4: 84, + 0x2DE5: 84, + 0x2DE6: 84, + 0x2DE7: 84, + 0x2DE8: 84, + 0x2DE9: 84, + 0x2DEA: 84, + 0x2DEB: 84, + 0x2DEC: 84, + 0x2DED: 84, + 0x2DEE: 84, + 0x2DEF: 84, + 0x2DF0: 84, + 0x2DF1: 84, + 0x2DF2: 84, + 0x2DF3: 84, + 0x2DF4: 84, + 0x2DF5: 84, + 0x2DF6: 84, + 0x2DF7: 84, + 0x2DF8: 84, + 0x2DF9: 84, + 0x2DFA: 84, + 0x2DFB: 84, + 0x2DFC: 84, + 0x2DFD: 84, + 0x2DFE: 84, + 0x2DFF: 84, + 0x302A: 84, + 0x302B: 84, + 0x302C: 84, + 0x302D: 84, + 0x3099: 84, + 0x309A: 84, + 0xA66F: 84, + 0xA670: 84, + 0xA671: 84, + 0xA672: 84, + 0xA674: 84, + 0xA675: 84, + 0xA676: 84, + 0xA677: 84, + 0xA678: 84, + 0xA679: 84, + 0xA67A: 84, + 0xA67B: 84, + 0xA67C: 84, + 0xA67D: 84, + 0xA69E: 84, + 0xA69F: 84, + 0xA6F0: 84, + 0xA6F1: 84, + 0xA802: 84, + 0xA806: 84, + 0xA80B: 84, + 0xA825: 84, + 0xA826: 84, + 0xA82C: 84, + 0xA840: 68, + 0xA841: 68, + 0xA842: 68, + 0xA843: 68, + 0xA844: 68, + 0xA845: 68, + 0xA846: 68, + 0xA847: 68, + 0xA848: 68, + 0xA849: 68, + 0xA84A: 68, + 0xA84B: 68, + 0xA84C: 68, + 0xA84D: 68, + 0xA84E: 68, + 0xA84F: 68, + 0xA850: 68, + 0xA851: 68, + 0xA852: 68, + 0xA853: 68, + 0xA854: 68, + 0xA855: 68, + 0xA856: 68, + 0xA857: 68, + 0xA858: 68, + 0xA859: 68, + 0xA85A: 68, + 0xA85B: 68, + 0xA85C: 68, + 0xA85D: 68, + 0xA85E: 68, + 0xA85F: 68, + 0xA860: 68, + 0xA861: 68, + 0xA862: 68, + 0xA863: 68, + 0xA864: 68, + 0xA865: 68, + 0xA866: 68, + 0xA867: 68, + 0xA868: 68, + 0xA869: 68, + 0xA86A: 68, + 0xA86B: 68, + 0xA86C: 68, + 0xA86D: 68, + 0xA86E: 68, + 0xA86F: 68, + 0xA870: 68, + 0xA871: 68, + 0xA872: 76, + 0xA8C4: 84, + 0xA8C5: 84, + 0xA8E0: 84, + 0xA8E1: 84, + 0xA8E2: 84, + 0xA8E3: 84, + 0xA8E4: 84, + 0xA8E5: 84, + 0xA8E6: 84, + 0xA8E7: 84, + 0xA8E8: 84, + 0xA8E9: 84, + 0xA8EA: 84, + 0xA8EB: 84, + 0xA8EC: 84, + 0xA8ED: 84, + 0xA8EE: 84, + 0xA8EF: 84, + 0xA8F0: 84, + 0xA8F1: 84, + 0xA8FF: 84, + 0xA926: 84, + 0xA927: 84, + 0xA928: 84, + 0xA929: 84, + 0xA92A: 84, + 0xA92B: 84, + 0xA92C: 84, + 0xA92D: 84, + 0xA947: 84, + 0xA948: 84, + 0xA949: 84, + 0xA94A: 84, + 0xA94B: 84, + 0xA94C: 84, + 0xA94D: 84, + 0xA94E: 84, + 0xA94F: 84, + 0xA950: 84, + 0xA951: 84, + 0xA980: 84, + 0xA981: 84, + 0xA982: 84, + 0xA9B3: 84, + 0xA9B6: 84, + 0xA9B7: 84, + 0xA9B8: 84, + 0xA9B9: 84, + 0xA9BC: 84, + 0xA9BD: 84, + 0xA9E5: 84, + 0xAA29: 84, + 0xAA2A: 84, + 0xAA2B: 84, + 0xAA2C: 84, + 0xAA2D: 84, + 0xAA2E: 84, + 0xAA31: 84, + 0xAA32: 84, + 0xAA35: 84, + 0xAA36: 84, + 0xAA43: 84, + 0xAA4C: 84, + 0xAA7C: 84, + 0xAAB0: 84, + 0xAAB2: 84, + 0xAAB3: 84, + 0xAAB4: 84, + 0xAAB7: 84, + 0xAAB8: 84, + 0xAABE: 84, + 0xAABF: 84, + 0xAAC1: 84, + 0xAAEC: 84, + 0xAAED: 84, + 0xAAF6: 84, + 0xABE5: 84, + 0xABE8: 84, + 0xABED: 84, + 0xFB1E: 84, + 0xFE00: 84, + 0xFE01: 84, + 0xFE02: 84, + 0xFE03: 84, + 0xFE04: 84, + 0xFE05: 84, + 0xFE06: 84, + 0xFE07: 84, + 0xFE08: 84, + 0xFE09: 84, + 0xFE0A: 84, + 0xFE0B: 84, + 0xFE0C: 84, + 0xFE0D: 84, + 0xFE0E: 84, + 0xFE0F: 84, + 0xFE20: 84, + 0xFE21: 84, + 0xFE22: 84, + 0xFE23: 84, + 0xFE24: 84, + 0xFE25: 84, + 0xFE26: 84, + 0xFE27: 84, + 0xFE28: 84, + 0xFE29: 84, + 0xFE2A: 84, + 0xFE2B: 84, + 0xFE2C: 84, + 0xFE2D: 84, + 0xFE2E: 84, + 0xFE2F: 84, + 0xFEFF: 84, + 0xFFF9: 84, + 0xFFFA: 84, + 0xFFFB: 84, + 0x101FD: 84, + 0x102E0: 84, + 0x10376: 84, + 0x10377: 84, + 0x10378: 84, + 0x10379: 84, + 0x1037A: 84, + 0x10A01: 84, + 0x10A02: 84, + 0x10A03: 84, + 0x10A05: 84, + 0x10A06: 84, + 0x10A0C: 84, + 0x10A0D: 84, + 0x10A0E: 84, + 0x10A0F: 84, + 0x10A38: 84, + 0x10A39: 84, + 0x10A3A: 84, + 0x10A3F: 84, + 0x10AC0: 68, + 0x10AC1: 68, + 0x10AC2: 68, + 0x10AC3: 68, + 0x10AC4: 68, + 0x10AC5: 82, + 0x10AC7: 82, + 0x10AC9: 82, + 0x10ACA: 82, + 0x10ACD: 76, + 0x10ACE: 82, + 0x10ACF: 82, + 0x10AD0: 82, + 0x10AD1: 82, + 0x10AD2: 82, + 0x10AD3: 68, + 0x10AD4: 68, + 0x10AD5: 68, + 0x10AD6: 68, + 0x10AD7: 76, + 0x10AD8: 68, + 0x10AD9: 68, + 0x10ADA: 68, + 0x10ADB: 68, + 0x10ADC: 68, + 0x10ADD: 82, + 0x10ADE: 68, + 0x10ADF: 68, + 0x10AE0: 68, + 0x10AE1: 82, + 0x10AE4: 82, + 0x10AE5: 84, + 0x10AE6: 84, + 0x10AEB: 68, + 0x10AEC: 68, + 0x10AED: 68, + 0x10AEE: 68, + 0x10AEF: 82, + 0x10B80: 68, + 0x10B81: 82, + 0x10B82: 68, + 0x10B83: 82, + 0x10B84: 82, + 0x10B85: 82, + 0x10B86: 68, + 0x10B87: 68, + 0x10B88: 68, + 0x10B89: 82, + 0x10B8A: 68, + 0x10B8B: 68, + 0x10B8C: 82, + 0x10B8D: 68, + 0x10B8E: 82, + 0x10B8F: 82, + 0x10B90: 68, + 0x10B91: 82, + 0x10BA9: 82, + 0x10BAA: 82, + 0x10BAB: 82, + 0x10BAC: 82, + 0x10BAD: 68, + 0x10BAE: 68, + 0x10D00: 76, + 0x10D01: 68, + 0x10D02: 68, + 0x10D03: 68, + 0x10D04: 68, + 0x10D05: 68, + 0x10D06: 68, + 0x10D07: 68, + 0x10D08: 68, + 0x10D09: 68, + 0x10D0A: 68, + 0x10D0B: 68, + 0x10D0C: 68, + 0x10D0D: 68, + 0x10D0E: 68, + 0x10D0F: 68, + 0x10D10: 68, + 0x10D11: 68, + 0x10D12: 68, + 0x10D13: 68, + 0x10D14: 68, + 0x10D15: 68, + 0x10D16: 68, + 0x10D17: 68, + 0x10D18: 68, + 0x10D19: 68, + 0x10D1A: 68, + 0x10D1B: 68, + 0x10D1C: 68, + 0x10D1D: 68, + 0x10D1E: 68, + 0x10D1F: 68, + 0x10D20: 68, + 0x10D21: 68, + 0x10D22: 82, + 0x10D23: 68, + 0x10D24: 84, + 0x10D25: 84, + 0x10D26: 84, + 0x10D27: 84, + 0x10EAB: 84, + 0x10EAC: 84, + 0x10EFD: 84, + 0x10EFE: 84, + 0x10EFF: 84, + 0x10F30: 68, + 0x10F31: 68, + 0x10F32: 68, + 0x10F33: 82, + 0x10F34: 68, + 0x10F35: 68, + 0x10F36: 68, + 0x10F37: 68, + 0x10F38: 68, + 0x10F39: 68, + 0x10F3A: 68, + 0x10F3B: 68, + 0x10F3C: 68, + 0x10F3D: 68, + 0x10F3E: 68, + 0x10F3F: 68, + 0x10F40: 68, + 0x10F41: 68, + 0x10F42: 68, + 0x10F43: 68, + 0x10F44: 68, + 0x10F46: 84, + 0x10F47: 84, + 0x10F48: 84, + 0x10F49: 84, + 0x10F4A: 84, + 0x10F4B: 84, + 0x10F4C: 84, + 0x10F4D: 84, + 0x10F4E: 84, + 0x10F4F: 84, + 0x10F50: 84, + 0x10F51: 68, + 0x10F52: 68, + 0x10F53: 68, + 0x10F54: 82, + 0x10F70: 68, + 0x10F71: 68, + 0x10F72: 68, + 0x10F73: 68, + 0x10F74: 82, + 0x10F75: 82, + 0x10F76: 68, + 0x10F77: 68, + 0x10F78: 68, + 0x10F79: 68, + 0x10F7A: 68, + 0x10F7B: 68, + 0x10F7C: 68, + 0x10F7D: 68, + 0x10F7E: 68, + 0x10F7F: 68, + 0x10F80: 68, + 0x10F81: 68, + 0x10F82: 84, + 0x10F83: 84, + 0x10F84: 84, + 0x10F85: 84, + 0x10FB0: 68, + 0x10FB2: 68, + 0x10FB3: 68, + 0x10FB4: 82, + 0x10FB5: 82, + 0x10FB6: 82, + 0x10FB8: 68, + 0x10FB9: 82, + 0x10FBA: 82, + 0x10FBB: 68, + 0x10FBC: 68, + 0x10FBD: 82, + 0x10FBE: 68, + 0x10FBF: 68, + 0x10FC1: 68, + 0x10FC2: 82, + 0x10FC3: 82, + 0x10FC4: 68, + 0x10FC9: 82, + 0x10FCA: 68, + 0x10FCB: 76, + 0x11001: 84, + 0x11038: 84, + 0x11039: 84, + 0x1103A: 84, + 0x1103B: 84, + 0x1103C: 84, + 0x1103D: 84, + 0x1103E: 84, + 0x1103F: 84, + 0x11040: 84, + 0x11041: 84, + 0x11042: 84, + 0x11043: 84, + 0x11044: 84, + 0x11045: 84, + 0x11046: 84, + 0x11070: 84, + 0x11073: 84, + 0x11074: 84, + 0x1107F: 84, + 0x11080: 84, + 0x11081: 84, + 0x110B3: 84, + 0x110B4: 84, + 0x110B5: 84, + 0x110B6: 84, + 0x110B9: 84, + 0x110BA: 84, + 0x110C2: 84, + 0x11100: 84, + 0x11101: 84, + 0x11102: 84, + 0x11127: 84, + 0x11128: 84, + 0x11129: 84, + 0x1112A: 84, + 0x1112B: 84, + 0x1112D: 84, + 0x1112E: 84, + 0x1112F: 84, + 0x11130: 84, + 0x11131: 84, + 0x11132: 84, + 0x11133: 84, + 0x11134: 84, + 0x11173: 84, + 0x11180: 84, + 0x11181: 84, + 0x111B6: 84, + 0x111B7: 84, + 0x111B8: 84, + 0x111B9: 84, + 0x111BA: 84, + 0x111BB: 84, + 0x111BC: 84, + 0x111BD: 84, + 0x111BE: 84, + 0x111C9: 84, + 0x111CA: 84, + 0x111CB: 84, + 0x111CC: 84, + 0x111CF: 84, + 0x1122F: 84, + 0x11230: 84, + 0x11231: 84, + 0x11234: 84, + 0x11236: 84, + 0x11237: 84, + 0x1123E: 84, + 0x11241: 84, + 0x112DF: 84, + 0x112E3: 84, + 0x112E4: 84, + 0x112E5: 84, + 0x112E6: 84, + 0x112E7: 84, + 0x112E8: 84, + 0x112E9: 84, + 0x112EA: 84, + 0x11300: 84, + 0x11301: 84, + 0x1133B: 84, + 0x1133C: 84, + 0x11340: 84, + 0x11366: 84, + 0x11367: 84, + 0x11368: 84, + 0x11369: 84, + 0x1136A: 84, + 0x1136B: 84, + 0x1136C: 84, + 0x11370: 84, + 0x11371: 84, + 0x11372: 84, + 0x11373: 84, + 0x11374: 84, + 0x11438: 84, + 0x11439: 84, + 0x1143A: 84, + 0x1143B: 84, + 0x1143C: 84, + 0x1143D: 84, + 0x1143E: 84, + 0x1143F: 84, + 0x11442: 84, + 0x11443: 84, + 0x11444: 84, + 0x11446: 84, + 0x1145E: 84, + 0x114B3: 84, + 0x114B4: 84, + 0x114B5: 84, + 0x114B6: 84, + 0x114B7: 84, + 0x114B8: 84, + 0x114BA: 84, + 0x114BF: 84, + 0x114C0: 84, + 0x114C2: 84, + 0x114C3: 84, + 0x115B2: 84, + 0x115B3: 84, + 0x115B4: 84, + 0x115B5: 84, + 0x115BC: 84, + 0x115BD: 84, + 0x115BF: 84, + 0x115C0: 84, + 0x115DC: 84, + 0x115DD: 84, + 0x11633: 84, + 0x11634: 84, + 0x11635: 84, + 0x11636: 84, + 0x11637: 84, + 0x11638: 84, + 0x11639: 84, + 0x1163A: 84, + 0x1163D: 84, + 0x1163F: 84, + 0x11640: 84, + 0x116AB: 84, + 0x116AD: 84, + 0x116B0: 84, + 0x116B1: 84, + 0x116B2: 84, + 0x116B3: 84, + 0x116B4: 84, + 0x116B5: 84, + 0x116B7: 84, + 0x1171D: 84, + 0x1171E: 84, + 0x1171F: 84, + 0x11722: 84, + 0x11723: 84, + 0x11724: 84, + 0x11725: 84, + 0x11727: 84, + 0x11728: 84, + 0x11729: 84, + 0x1172A: 84, + 0x1172B: 84, + 0x1182F: 84, + 0x11830: 84, + 0x11831: 84, + 0x11832: 84, + 0x11833: 84, + 0x11834: 84, + 0x11835: 84, + 0x11836: 84, + 0x11837: 84, + 0x11839: 84, + 0x1183A: 84, + 0x1193B: 84, + 0x1193C: 84, + 0x1193E: 84, + 0x11943: 84, + 0x119D4: 84, + 0x119D5: 84, + 0x119D6: 84, + 0x119D7: 84, + 0x119DA: 84, + 0x119DB: 84, + 0x119E0: 84, + 0x11A01: 84, + 0x11A02: 84, + 0x11A03: 84, + 0x11A04: 84, + 0x11A05: 84, + 0x11A06: 84, + 0x11A07: 84, + 0x11A08: 84, + 0x11A09: 84, + 0x11A0A: 84, + 0x11A33: 84, + 0x11A34: 84, + 0x11A35: 84, + 0x11A36: 84, + 0x11A37: 84, + 0x11A38: 84, + 0x11A3B: 84, + 0x11A3C: 84, + 0x11A3D: 84, + 0x11A3E: 84, + 0x11A47: 84, + 0x11A51: 84, + 0x11A52: 84, + 0x11A53: 84, + 0x11A54: 84, + 0x11A55: 84, + 0x11A56: 84, + 0x11A59: 84, + 0x11A5A: 84, + 0x11A5B: 84, + 0x11A8A: 84, + 0x11A8B: 84, + 0x11A8C: 84, + 0x11A8D: 84, + 0x11A8E: 84, + 0x11A8F: 84, + 0x11A90: 84, + 0x11A91: 84, + 0x11A92: 84, + 0x11A93: 84, + 0x11A94: 84, + 0x11A95: 84, + 0x11A96: 84, + 0x11A98: 84, + 0x11A99: 84, + 0x11C30: 84, + 0x11C31: 84, + 0x11C32: 84, + 0x11C33: 84, + 0x11C34: 84, + 0x11C35: 84, + 0x11C36: 84, + 0x11C38: 84, + 0x11C39: 84, + 0x11C3A: 84, + 0x11C3B: 84, + 0x11C3C: 84, + 0x11C3D: 84, + 0x11C3F: 84, + 0x11C92: 84, + 0x11C93: 84, + 0x11C94: 84, + 0x11C95: 84, + 0x11C96: 84, + 0x11C97: 84, + 0x11C98: 84, + 0x11C99: 84, + 0x11C9A: 84, + 0x11C9B: 84, + 0x11C9C: 84, + 0x11C9D: 84, + 0x11C9E: 84, + 0x11C9F: 84, + 0x11CA0: 84, + 0x11CA1: 84, + 0x11CA2: 84, + 0x11CA3: 84, + 0x11CA4: 84, + 0x11CA5: 84, + 0x11CA6: 84, + 0x11CA7: 84, + 0x11CAA: 84, + 0x11CAB: 84, + 0x11CAC: 84, + 0x11CAD: 84, + 0x11CAE: 84, + 0x11CAF: 84, + 0x11CB0: 84, + 0x11CB2: 84, + 0x11CB3: 84, + 0x11CB5: 84, + 0x11CB6: 84, + 0x11D31: 84, + 0x11D32: 84, + 0x11D33: 84, + 0x11D34: 84, + 0x11D35: 84, + 0x11D36: 84, + 0x11D3A: 84, + 0x11D3C: 84, + 0x11D3D: 84, + 0x11D3F: 84, + 0x11D40: 84, + 0x11D41: 84, + 0x11D42: 84, + 0x11D43: 84, + 0x11D44: 84, + 0x11D45: 84, + 0x11D47: 84, + 0x11D90: 84, + 0x11D91: 84, + 0x11D95: 84, + 0x11D97: 84, + 0x11EF3: 84, + 0x11EF4: 84, + 0x11F00: 84, + 0x11F01: 84, + 0x11F36: 84, + 0x11F37: 84, + 0x11F38: 84, + 0x11F39: 84, + 0x11F3A: 84, + 0x11F40: 84, + 0x11F42: 84, + 0x13430: 84, + 0x13431: 84, + 0x13432: 84, + 0x13433: 84, + 0x13434: 84, + 0x13435: 84, + 0x13436: 84, + 0x13437: 84, + 0x13438: 84, + 0x13439: 84, + 0x1343A: 84, + 0x1343B: 84, + 0x1343C: 84, + 0x1343D: 84, + 0x1343E: 84, + 0x1343F: 84, + 0x13440: 84, + 0x13447: 84, + 0x13448: 84, + 0x13449: 84, + 0x1344A: 84, + 0x1344B: 84, + 0x1344C: 84, + 0x1344D: 84, + 0x1344E: 84, + 0x1344F: 84, + 0x13450: 84, + 0x13451: 84, + 0x13452: 84, + 0x13453: 84, + 0x13454: 84, + 0x13455: 84, + 0x16AF0: 84, + 0x16AF1: 84, + 0x16AF2: 84, + 0x16AF3: 84, + 0x16AF4: 84, + 0x16B30: 84, + 0x16B31: 84, + 0x16B32: 84, + 0x16B33: 84, + 0x16B34: 84, + 0x16B35: 84, + 0x16B36: 84, + 0x16F4F: 84, + 0x16F8F: 84, + 0x16F90: 84, + 0x16F91: 84, + 0x16F92: 84, + 0x16FE4: 84, + 0x1BC9D: 84, + 0x1BC9E: 84, + 0x1BCA0: 84, + 0x1BCA1: 84, + 0x1BCA2: 84, + 0x1BCA3: 84, + 0x1CF00: 84, + 0x1CF01: 84, + 0x1CF02: 84, + 0x1CF03: 84, + 0x1CF04: 84, + 0x1CF05: 84, + 0x1CF06: 84, + 0x1CF07: 84, + 0x1CF08: 84, + 0x1CF09: 84, + 0x1CF0A: 84, + 0x1CF0B: 84, + 0x1CF0C: 84, + 0x1CF0D: 84, + 0x1CF0E: 84, + 0x1CF0F: 84, + 0x1CF10: 84, + 0x1CF11: 84, + 0x1CF12: 84, + 0x1CF13: 84, + 0x1CF14: 84, + 0x1CF15: 84, + 0x1CF16: 84, + 0x1CF17: 84, + 0x1CF18: 84, + 0x1CF19: 84, + 0x1CF1A: 84, + 0x1CF1B: 84, + 0x1CF1C: 84, + 0x1CF1D: 84, + 0x1CF1E: 84, + 0x1CF1F: 84, + 0x1CF20: 84, + 0x1CF21: 84, + 0x1CF22: 84, + 0x1CF23: 84, + 0x1CF24: 84, + 0x1CF25: 84, + 0x1CF26: 84, + 0x1CF27: 84, + 0x1CF28: 84, + 0x1CF29: 84, + 0x1CF2A: 84, + 0x1CF2B: 84, + 0x1CF2C: 84, + 0x1CF2D: 84, + 0x1CF30: 84, + 0x1CF31: 84, + 0x1CF32: 84, + 0x1CF33: 84, + 0x1CF34: 84, + 0x1CF35: 84, + 0x1CF36: 84, + 0x1CF37: 84, + 0x1CF38: 84, + 0x1CF39: 84, + 0x1CF3A: 84, + 0x1CF3B: 84, + 0x1CF3C: 84, + 0x1CF3D: 84, + 0x1CF3E: 84, + 0x1CF3F: 84, + 0x1CF40: 84, + 0x1CF41: 84, + 0x1CF42: 84, + 0x1CF43: 84, + 0x1CF44: 84, + 0x1CF45: 84, + 0x1CF46: 84, + 0x1D167: 84, + 0x1D168: 84, + 0x1D169: 84, + 0x1D173: 84, + 0x1D174: 84, + 0x1D175: 84, + 0x1D176: 84, + 0x1D177: 84, + 0x1D178: 84, + 0x1D179: 84, + 0x1D17A: 84, + 0x1D17B: 84, + 0x1D17C: 84, + 0x1D17D: 84, + 0x1D17E: 84, + 0x1D17F: 84, + 0x1D180: 84, + 0x1D181: 84, + 0x1D182: 84, + 0x1D185: 84, + 0x1D186: 84, + 0x1D187: 84, + 0x1D188: 84, + 0x1D189: 84, + 0x1D18A: 84, + 0x1D18B: 84, + 0x1D1AA: 84, + 0x1D1AB: 84, + 0x1D1AC: 84, + 0x1D1AD: 84, + 0x1D242: 84, + 0x1D243: 84, + 0x1D244: 84, + 0x1DA00: 84, + 0x1DA01: 84, + 0x1DA02: 84, + 0x1DA03: 84, + 0x1DA04: 84, + 0x1DA05: 84, + 0x1DA06: 84, + 0x1DA07: 84, + 0x1DA08: 84, + 0x1DA09: 84, + 0x1DA0A: 84, + 0x1DA0B: 84, + 0x1DA0C: 84, + 0x1DA0D: 84, + 0x1DA0E: 84, + 0x1DA0F: 84, + 0x1DA10: 84, + 0x1DA11: 84, + 0x1DA12: 84, + 0x1DA13: 84, + 0x1DA14: 84, + 0x1DA15: 84, + 0x1DA16: 84, + 0x1DA17: 84, + 0x1DA18: 84, + 0x1DA19: 84, + 0x1DA1A: 84, + 0x1DA1B: 84, + 0x1DA1C: 84, + 0x1DA1D: 84, + 0x1DA1E: 84, + 0x1DA1F: 84, + 0x1DA20: 84, + 0x1DA21: 84, + 0x1DA22: 84, + 0x1DA23: 84, + 0x1DA24: 84, + 0x1DA25: 84, + 0x1DA26: 84, + 0x1DA27: 84, + 0x1DA28: 84, + 0x1DA29: 84, + 0x1DA2A: 84, + 0x1DA2B: 84, + 0x1DA2C: 84, + 0x1DA2D: 84, + 0x1DA2E: 84, + 0x1DA2F: 84, + 0x1DA30: 84, + 0x1DA31: 84, + 0x1DA32: 84, + 0x1DA33: 84, + 0x1DA34: 84, + 0x1DA35: 84, + 0x1DA36: 84, + 0x1DA3B: 84, + 0x1DA3C: 84, + 0x1DA3D: 84, + 0x1DA3E: 84, + 0x1DA3F: 84, + 0x1DA40: 84, + 0x1DA41: 84, + 0x1DA42: 84, + 0x1DA43: 84, + 0x1DA44: 84, + 0x1DA45: 84, + 0x1DA46: 84, + 0x1DA47: 84, + 0x1DA48: 84, + 0x1DA49: 84, + 0x1DA4A: 84, + 0x1DA4B: 84, + 0x1DA4C: 84, + 0x1DA4D: 84, + 0x1DA4E: 84, + 0x1DA4F: 84, + 0x1DA50: 84, + 0x1DA51: 84, + 0x1DA52: 84, + 0x1DA53: 84, + 0x1DA54: 84, + 0x1DA55: 84, + 0x1DA56: 84, + 0x1DA57: 84, + 0x1DA58: 84, + 0x1DA59: 84, + 0x1DA5A: 84, + 0x1DA5B: 84, + 0x1DA5C: 84, + 0x1DA5D: 84, + 0x1DA5E: 84, + 0x1DA5F: 84, + 0x1DA60: 84, + 0x1DA61: 84, + 0x1DA62: 84, + 0x1DA63: 84, + 0x1DA64: 84, + 0x1DA65: 84, + 0x1DA66: 84, + 0x1DA67: 84, + 0x1DA68: 84, + 0x1DA69: 84, + 0x1DA6A: 84, + 0x1DA6B: 84, + 0x1DA6C: 84, + 0x1DA75: 84, + 0x1DA84: 84, + 0x1DA9B: 84, + 0x1DA9C: 84, + 0x1DA9D: 84, + 0x1DA9E: 84, + 0x1DA9F: 84, + 0x1DAA1: 84, + 0x1DAA2: 84, + 0x1DAA3: 84, + 0x1DAA4: 84, + 0x1DAA5: 84, + 0x1DAA6: 84, + 0x1DAA7: 84, + 0x1DAA8: 84, + 0x1DAA9: 84, + 0x1DAAA: 84, + 0x1DAAB: 84, + 0x1DAAC: 84, + 0x1DAAD: 84, + 0x1DAAE: 84, + 0x1DAAF: 84, + 0x1E000: 84, + 0x1E001: 84, + 0x1E002: 84, + 0x1E003: 84, + 0x1E004: 84, + 0x1E005: 84, + 0x1E006: 84, + 0x1E008: 84, + 0x1E009: 84, + 0x1E00A: 84, + 0x1E00B: 84, + 0x1E00C: 84, + 0x1E00D: 84, + 0x1E00E: 84, + 0x1E00F: 84, + 0x1E010: 84, + 0x1E011: 84, + 0x1E012: 84, + 0x1E013: 84, + 0x1E014: 84, + 0x1E015: 84, + 0x1E016: 84, + 0x1E017: 84, + 0x1E018: 84, + 0x1E01B: 84, + 0x1E01C: 84, + 0x1E01D: 84, + 0x1E01E: 84, + 0x1E01F: 84, + 0x1E020: 84, + 0x1E021: 84, + 0x1E023: 84, + 0x1E024: 84, + 0x1E026: 84, + 0x1E027: 84, + 0x1E028: 84, + 0x1E029: 84, + 0x1E02A: 84, + 0x1E08F: 84, + 0x1E130: 84, + 0x1E131: 84, + 0x1E132: 84, + 0x1E133: 84, + 0x1E134: 84, + 0x1E135: 84, + 0x1E136: 84, + 0x1E2AE: 84, + 0x1E2EC: 84, + 0x1E2ED: 84, + 0x1E2EE: 84, + 0x1E2EF: 84, + 0x1E4EC: 84, + 0x1E4ED: 84, + 0x1E4EE: 84, + 0x1E4EF: 84, + 0x1E8D0: 84, + 0x1E8D1: 84, + 0x1E8D2: 84, + 0x1E8D3: 84, + 0x1E8D4: 84, + 0x1E8D5: 84, + 0x1E8D6: 84, + 0x1E900: 68, + 0x1E901: 68, + 0x1E902: 68, + 0x1E903: 68, + 0x1E904: 68, + 0x1E905: 68, + 0x1E906: 68, + 0x1E907: 68, + 0x1E908: 68, + 0x1E909: 68, + 0x1E90A: 68, + 0x1E90B: 68, + 0x1E90C: 68, + 0x1E90D: 68, + 0x1E90E: 68, + 0x1E90F: 68, + 0x1E910: 68, + 0x1E911: 68, + 0x1E912: 68, + 0x1E913: 68, + 0x1E914: 68, + 0x1E915: 68, + 0x1E916: 68, + 0x1E917: 68, + 0x1E918: 68, + 0x1E919: 68, + 0x1E91A: 68, + 0x1E91B: 68, + 0x1E91C: 68, + 0x1E91D: 68, + 0x1E91E: 68, + 0x1E91F: 68, + 0x1E920: 68, + 0x1E921: 68, + 0x1E922: 68, + 0x1E923: 68, + 0x1E924: 68, + 0x1E925: 68, + 0x1E926: 68, + 0x1E927: 68, + 0x1E928: 68, + 0x1E929: 68, + 0x1E92A: 68, + 0x1E92B: 68, + 0x1E92C: 68, + 0x1E92D: 68, + 0x1E92E: 68, + 0x1E92F: 68, + 0x1E930: 68, + 0x1E931: 68, + 0x1E932: 68, + 0x1E933: 68, + 0x1E934: 68, + 0x1E935: 68, + 0x1E936: 68, + 0x1E937: 68, + 0x1E938: 68, + 0x1E939: 68, + 0x1E93A: 68, + 0x1E93B: 68, + 0x1E93C: 68, + 0x1E93D: 68, + 0x1E93E: 68, + 0x1E93F: 68, + 0x1E940: 68, + 0x1E941: 68, + 0x1E942: 68, + 0x1E943: 68, + 0x1E944: 84, + 0x1E945: 84, + 0x1E946: 84, + 0x1E947: 84, + 0x1E948: 84, + 0x1E949: 84, + 0x1E94A: 84, + 0x1E94B: 84, + 0xE0001: 84, + 0xE0020: 84, + 0xE0021: 84, + 0xE0022: 84, + 0xE0023: 84, + 0xE0024: 84, + 0xE0025: 84, + 0xE0026: 84, + 0xE0027: 84, + 0xE0028: 84, + 0xE0029: 84, + 0xE002A: 84, + 0xE002B: 84, + 0xE002C: 84, + 0xE002D: 84, + 0xE002E: 84, + 0xE002F: 84, + 0xE0030: 84, + 0xE0031: 84, + 0xE0032: 84, + 0xE0033: 84, + 0xE0034: 84, + 0xE0035: 84, + 0xE0036: 84, + 0xE0037: 84, + 0xE0038: 84, + 0xE0039: 84, + 0xE003A: 84, + 0xE003B: 84, + 0xE003C: 84, + 0xE003D: 84, + 0xE003E: 84, + 0xE003F: 84, + 0xE0040: 84, + 0xE0041: 84, + 0xE0042: 84, + 0xE0043: 84, + 0xE0044: 84, + 0xE0045: 84, + 0xE0046: 84, + 0xE0047: 84, + 0xE0048: 84, + 0xE0049: 84, + 0xE004A: 84, + 0xE004B: 84, + 0xE004C: 84, + 0xE004D: 84, + 0xE004E: 84, + 0xE004F: 84, + 0xE0050: 84, + 0xE0051: 84, + 0xE0052: 84, + 0xE0053: 84, + 0xE0054: 84, + 0xE0055: 84, + 0xE0056: 84, + 0xE0057: 84, + 0xE0058: 84, + 0xE0059: 84, + 0xE005A: 84, + 0xE005B: 84, + 0xE005C: 84, + 0xE005D: 84, + 0xE005E: 84, + 0xE005F: 84, + 0xE0060: 84, + 0xE0061: 84, + 0xE0062: 84, + 0xE0063: 84, + 0xE0064: 84, + 0xE0065: 84, + 0xE0066: 84, + 0xE0067: 84, + 0xE0068: 84, + 0xE0069: 84, + 0xE006A: 84, + 0xE006B: 84, + 0xE006C: 84, + 0xE006D: 84, + 0xE006E: 84, + 0xE006F: 84, + 0xE0070: 84, + 0xE0071: 84, + 0xE0072: 84, + 0xE0073: 84, + 0xE0074: 84, + 0xE0075: 84, + 0xE0076: 84, + 0xE0077: 84, + 0xE0078: 84, + 0xE0079: 84, + 0xE007A: 84, + 0xE007B: 84, + 0xE007C: 84, + 0xE007D: 84, + 0xE007E: 84, + 0xE007F: 84, + 0xE0100: 84, + 0xE0101: 84, + 0xE0102: 84, + 0xE0103: 84, + 0xE0104: 84, + 0xE0105: 84, + 0xE0106: 84, + 0xE0107: 84, + 0xE0108: 84, + 0xE0109: 84, + 0xE010A: 84, + 0xE010B: 84, + 0xE010C: 84, + 0xE010D: 84, + 0xE010E: 84, + 0xE010F: 84, + 0xE0110: 84, + 0xE0111: 84, + 0xE0112: 84, + 0xE0113: 84, + 0xE0114: 84, + 0xE0115: 84, + 0xE0116: 84, + 0xE0117: 84, + 0xE0118: 84, + 0xE0119: 84, + 0xE011A: 84, + 0xE011B: 84, + 0xE011C: 84, + 0xE011D: 84, + 0xE011E: 84, + 0xE011F: 84, + 0xE0120: 84, + 0xE0121: 84, + 0xE0122: 84, + 0xE0123: 84, + 0xE0124: 84, + 0xE0125: 84, + 0xE0126: 84, + 0xE0127: 84, + 0xE0128: 84, + 0xE0129: 84, + 0xE012A: 84, + 0xE012B: 84, + 0xE012C: 84, + 0xE012D: 84, + 0xE012E: 84, + 0xE012F: 84, + 0xE0130: 84, + 0xE0131: 84, + 0xE0132: 84, + 0xE0133: 84, + 0xE0134: 84, + 0xE0135: 84, + 0xE0136: 84, + 0xE0137: 84, + 0xE0138: 84, + 0xE0139: 84, + 0xE013A: 84, + 0xE013B: 84, + 0xE013C: 84, + 0xE013D: 84, + 0xE013E: 84, + 0xE013F: 84, + 0xE0140: 84, + 0xE0141: 84, + 0xE0142: 84, + 0xE0143: 84, + 0xE0144: 84, + 0xE0145: 84, + 0xE0146: 84, + 0xE0147: 84, + 0xE0148: 84, + 0xE0149: 84, + 0xE014A: 84, + 0xE014B: 84, + 0xE014C: 84, + 0xE014D: 84, + 0xE014E: 84, + 0xE014F: 84, + 0xE0150: 84, + 0xE0151: 84, + 0xE0152: 84, + 0xE0153: 84, + 0xE0154: 84, + 0xE0155: 84, + 0xE0156: 84, + 0xE0157: 84, + 0xE0158: 84, + 0xE0159: 84, + 0xE015A: 84, + 0xE015B: 84, + 0xE015C: 84, + 0xE015D: 84, + 0xE015E: 84, + 0xE015F: 84, + 0xE0160: 84, + 0xE0161: 84, + 0xE0162: 84, + 0xE0163: 84, + 0xE0164: 84, + 0xE0165: 84, + 0xE0166: 84, + 0xE0167: 84, + 0xE0168: 84, + 0xE0169: 84, + 0xE016A: 84, + 0xE016B: 84, + 0xE016C: 84, + 0xE016D: 84, + 0xE016E: 84, + 0xE016F: 84, + 0xE0170: 84, + 0xE0171: 84, + 0xE0172: 84, + 0xE0173: 84, + 0xE0174: 84, + 0xE0175: 84, + 0xE0176: 84, + 0xE0177: 84, + 0xE0178: 84, + 0xE0179: 84, + 0xE017A: 84, + 0xE017B: 84, + 0xE017C: 84, + 0xE017D: 84, + 0xE017E: 84, + 0xE017F: 84, + 0xE0180: 84, + 0xE0181: 84, + 0xE0182: 84, + 0xE0183: 84, + 0xE0184: 84, + 0xE0185: 84, + 0xE0186: 84, + 0xE0187: 84, + 0xE0188: 84, + 0xE0189: 84, + 0xE018A: 84, + 0xE018B: 84, + 0xE018C: 84, + 0xE018D: 84, + 0xE018E: 84, + 0xE018F: 84, + 0xE0190: 84, + 0xE0191: 84, + 0xE0192: 84, + 0xE0193: 84, + 0xE0194: 84, + 0xE0195: 84, + 0xE0196: 84, + 0xE0197: 84, + 0xE0198: 84, + 0xE0199: 84, + 0xE019A: 84, + 0xE019B: 84, + 0xE019C: 84, + 0xE019D: 84, + 0xE019E: 84, + 0xE019F: 84, + 0xE01A0: 84, + 0xE01A1: 84, + 0xE01A2: 84, + 0xE01A3: 84, + 0xE01A4: 84, + 0xE01A5: 84, + 0xE01A6: 84, + 0xE01A7: 84, + 0xE01A8: 84, + 0xE01A9: 84, + 0xE01AA: 84, + 0xE01AB: 84, + 0xE01AC: 84, + 0xE01AD: 84, + 0xE01AE: 84, + 0xE01AF: 84, + 0xE01B0: 84, + 0xE01B1: 84, + 0xE01B2: 84, + 0xE01B3: 84, + 0xE01B4: 84, + 0xE01B5: 84, + 0xE01B6: 84, + 0xE01B7: 84, + 0xE01B8: 84, + 0xE01B9: 84, + 0xE01BA: 84, + 0xE01BB: 84, + 0xE01BC: 84, + 0xE01BD: 84, + 0xE01BE: 84, + 0xE01BF: 84, + 0xE01C0: 84, + 0xE01C1: 84, + 0xE01C2: 84, + 0xE01C3: 84, + 0xE01C4: 84, + 0xE01C5: 84, + 0xE01C6: 84, + 0xE01C7: 84, + 0xE01C8: 84, + 0xE01C9: 84, + 0xE01CA: 84, + 0xE01CB: 84, + 0xE01CC: 84, + 0xE01CD: 84, + 0xE01CE: 84, + 0xE01CF: 84, + 0xE01D0: 84, + 0xE01D1: 84, + 0xE01D2: 84, + 0xE01D3: 84, + 0xE01D4: 84, + 0xE01D5: 84, + 0xE01D6: 84, + 0xE01D7: 84, + 0xE01D8: 84, + 0xE01D9: 84, + 0xE01DA: 84, + 0xE01DB: 84, + 0xE01DC: 84, + 0xE01DD: 84, + 0xE01DE: 84, + 0xE01DF: 84, + 0xE01E0: 84, + 0xE01E1: 84, + 0xE01E2: 84, + 0xE01E3: 84, + 0xE01E4: 84, + 0xE01E5: 84, + 0xE01E6: 84, + 0xE01E7: 84, + 0xE01E8: 84, + 0xE01E9: 84, + 0xE01EA: 84, + 0xE01EB: 84, + 0xE01EC: 84, + 0xE01ED: 84, + 0xE01EE: 84, + 0xE01EF: 84, +} +codepoint_classes = { + "PVALID": ( + 0x2D0000002E, + 0x300000003A, + 0x610000007B, + 0xDF000000F7, + 0xF800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010A, + 0x10B0000010C, + 0x10D0000010E, + 0x10F00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011A, + 0x11B0000011C, + 0x11D0000011E, + 0x11F00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012A, + 0x12B0000012C, + 0x12D0000012E, + 0x12F00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13A0000013B, + 0x13C0000013D, + 0x13E0000013F, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14B0000014C, + 0x14D0000014E, + 0x14F00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015A, + 0x15B0000015C, + 0x15D0000015E, + 0x15F00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016A, + 0x16B0000016C, + 0x16D0000016E, + 0x16F00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17A0000017B, + 0x17C0000017D, + 0x17E0000017F, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18C0000018E, + 0x19200000193, + 0x19500000196, + 0x1990000019C, + 0x19E0000019F, + 0x1A1000001A2, + 0x1A3000001A4, + 0x1A5000001A6, + 0x1A8000001A9, + 0x1AA000001AC, + 0x1AD000001AE, + 0x1B0000001B1, + 0x1B4000001B5, + 0x1B6000001B7, + 0x1B9000001BC, + 0x1BD000001C4, + 0x1CE000001CF, + 0x1D0000001D1, + 0x1D2000001D3, + 0x1D4000001D5, + 0x1D6000001D7, + 0x1D8000001D9, + 0x1DA000001DB, + 0x1DC000001DE, + 0x1DF000001E0, + 0x1E1000001E2, + 0x1E3000001E4, + 0x1E5000001E6, + 0x1E7000001E8, + 0x1E9000001EA, + 0x1EB000001EC, + 0x1ED000001EE, + 0x1EF000001F1, + 0x1F5000001F6, + 0x1F9000001FA, + 0x1FB000001FC, + 0x1FD000001FE, + 0x1FF00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020A, + 0x20B0000020C, + 0x20D0000020E, + 0x20F00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021A, + 0x21B0000021C, + 0x21D0000021E, + 0x21F00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022A, + 0x22B0000022C, + 0x22D0000022E, + 0x22F00000230, + 0x23100000232, + 0x2330000023A, + 0x23C0000023D, + 0x23F00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024A, + 0x24B0000024C, + 0x24D0000024E, + 0x24F000002B0, + 0x2B9000002C2, + 0x2C6000002D2, + 0x2EC000002ED, + 0x2EE000002EF, + 0x30000000340, + 0x34200000343, + 0x3460000034F, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37B0000037E, + 0x39000000391, + 0x3AC000003CF, + 0x3D7000003D8, + 0x3D9000003DA, + 0x3DB000003DC, + 0x3DD000003DE, + 0x3DF000003E0, + 0x3E1000003E2, + 0x3E3000003E4, + 0x3E5000003E6, + 0x3E7000003E8, + 0x3E9000003EA, + 0x3EB000003EC, + 0x3ED000003EE, + 0x3EF000003F0, + 0x3F3000003F4, + 0x3F8000003F9, + 0x3FB000003FD, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046A, + 0x46B0000046C, + 0x46D0000046E, + 0x46F00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047A, + 0x47B0000047C, + 0x47D0000047E, + 0x47F00000480, + 0x48100000482, + 0x48300000488, + 0x48B0000048C, + 0x48D0000048E, + 0x48F00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049A, + 0x49B0000049C, + 0x49D0000049E, + 0x49F000004A0, + 0x4A1000004A2, + 0x4A3000004A4, + 0x4A5000004A6, + 0x4A7000004A8, + 0x4A9000004AA, + 0x4AB000004AC, + 0x4AD000004AE, + 0x4AF000004B0, + 0x4B1000004B2, + 0x4B3000004B4, + 0x4B5000004B6, + 0x4B7000004B8, + 0x4B9000004BA, + 0x4BB000004BC, + 0x4BD000004BE, + 0x4BF000004C0, + 0x4C2000004C3, + 0x4C4000004C5, + 0x4C6000004C7, + 0x4C8000004C9, + 0x4CA000004CB, + 0x4CC000004CD, + 0x4CE000004D0, + 0x4D1000004D2, + 0x4D3000004D4, + 0x4D5000004D6, + 0x4D7000004D8, + 0x4D9000004DA, + 0x4DB000004DC, + 0x4DD000004DE, + 0x4DF000004E0, + 0x4E1000004E2, + 0x4E3000004E4, + 0x4E5000004E6, + 0x4E7000004E8, + 0x4E9000004EA, + 0x4EB000004EC, + 0x4ED000004EE, + 0x4EF000004F0, + 0x4F1000004F2, + 0x4F3000004F4, + 0x4F5000004F6, + 0x4F7000004F8, + 0x4F9000004FA, + 0x4FB000004FC, + 0x4FD000004FE, + 0x4FF00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050A, + 0x50B0000050C, + 0x50D0000050E, + 0x50F00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051A, + 0x51B0000051C, + 0x51D0000051E, + 0x51F00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052A, + 0x52B0000052C, + 0x52D0000052E, + 0x52F00000530, + 0x5590000055A, + 0x56000000587, + 0x58800000589, + 0x591000005BE, + 0x5BF000005C0, + 0x5C1000005C3, + 0x5C4000005C6, + 0x5C7000005C8, + 0x5D0000005EB, + 0x5EF000005F3, + 0x6100000061B, + 0x62000000640, + 0x64100000660, + 0x66E00000675, + 0x679000006D4, + 0x6D5000006DD, + 0x6DF000006E9, + 0x6EA000006F0, + 0x6FA00000700, + 0x7100000074B, + 0x74D000007B2, + 0x7C0000007F6, + 0x7FD000007FE, + 0x8000000082E, + 0x8400000085C, + 0x8600000086B, + 0x87000000888, + 0x8890000088F, + 0x898000008E2, + 0x8E300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098D, + 0x98F00000991, + 0x993000009A9, + 0x9AA000009B1, + 0x9B2000009B3, + 0x9B6000009BA, + 0x9BC000009C5, + 0x9C7000009C9, + 0x9CB000009CF, + 0x9D7000009D8, + 0x9E0000009E4, + 0x9E6000009F2, + 0x9FC000009FD, + 0x9FE000009FF, + 0xA0100000A04, + 0xA0500000A0B, + 0xA0F00000A11, + 0xA1300000A29, + 0xA2A00000A31, + 0xA3200000A33, + 0xA3500000A36, + 0xA3800000A3A, + 0xA3C00000A3D, + 0xA3E00000A43, + 0xA4700000A49, + 0xA4B00000A4E, + 0xA5100000A52, + 0xA5C00000A5D, + 0xA6600000A76, + 0xA8100000A84, + 0xA8500000A8E, + 0xA8F00000A92, + 0xA9300000AA9, + 0xAAA00000AB1, + 0xAB200000AB4, + 0xAB500000ABA, + 0xABC00000AC6, + 0xAC700000ACA, + 0xACB00000ACE, + 0xAD000000AD1, + 0xAE000000AE4, + 0xAE600000AF0, + 0xAF900000B00, + 0xB0100000B04, + 0xB0500000B0D, + 0xB0F00000B11, + 0xB1300000B29, + 0xB2A00000B31, + 0xB3200000B34, + 0xB3500000B3A, + 0xB3C00000B45, + 0xB4700000B49, + 0xB4B00000B4E, + 0xB5500000B58, + 0xB5F00000B64, + 0xB6600000B70, + 0xB7100000B72, + 0xB8200000B84, + 0xB8500000B8B, + 0xB8E00000B91, + 0xB9200000B96, + 0xB9900000B9B, + 0xB9C00000B9D, + 0xB9E00000BA0, + 0xBA300000BA5, + 0xBA800000BAB, + 0xBAE00000BBA, + 0xBBE00000BC3, + 0xBC600000BC9, + 0xBCA00000BCE, + 0xBD000000BD1, + 0xBD700000BD8, + 0xBE600000BF0, + 0xC0000000C0D, + 0xC0E00000C11, + 0xC1200000C29, + 0xC2A00000C3A, + 0xC3C00000C45, + 0xC4600000C49, + 0xC4A00000C4E, + 0xC5500000C57, + 0xC5800000C5B, + 0xC5D00000C5E, + 0xC6000000C64, + 0xC6600000C70, + 0xC8000000C84, + 0xC8500000C8D, + 0xC8E00000C91, + 0xC9200000CA9, + 0xCAA00000CB4, + 0xCB500000CBA, + 0xCBC00000CC5, + 0xCC600000CC9, + 0xCCA00000CCE, + 0xCD500000CD7, + 0xCDD00000CDF, + 0xCE000000CE4, + 0xCE600000CF0, + 0xCF100000CF4, + 0xD0000000D0D, + 0xD0E00000D11, + 0xD1200000D45, + 0xD4600000D49, + 0xD4A00000D4F, + 0xD5400000D58, + 0xD5F00000D64, + 0xD6600000D70, + 0xD7A00000D80, + 0xD8100000D84, + 0xD8500000D97, + 0xD9A00000DB2, + 0xDB300000DBC, + 0xDBD00000DBE, + 0xDC000000DC7, + 0xDCA00000DCB, + 0xDCF00000DD5, + 0xDD600000DD7, + 0xDD800000DE0, + 0xDE600000DF0, + 0xDF200000DF4, + 0xE0100000E33, + 0xE3400000E3B, + 0xE4000000E4F, + 0xE5000000E5A, + 0xE8100000E83, + 0xE8400000E85, + 0xE8600000E8B, + 0xE8C00000EA4, + 0xEA500000EA6, + 0xEA700000EB3, + 0xEB400000EBE, + 0xEC000000EC5, + 0xEC600000EC7, + 0xEC800000ECF, + 0xED000000EDA, + 0xEDE00000EE0, + 0xF0000000F01, + 0xF0B00000F0C, + 0xF1800000F1A, + 0xF2000000F2A, + 0xF3500000F36, + 0xF3700000F38, + 0xF3900000F3A, + 0xF3E00000F43, + 0xF4400000F48, + 0xF4900000F4D, + 0xF4E00000F52, + 0xF5300000F57, + 0xF5800000F5C, + 0xF5D00000F69, + 0xF6A00000F6D, + 0xF7100000F73, + 0xF7400000F75, + 0xF7A00000F81, + 0xF8200000F85, + 0xF8600000F93, + 0xF9400000F98, + 0xF9900000F9D, + 0xF9E00000FA2, + 0xFA300000FA7, + 0xFA800000FAC, + 0xFAD00000FB9, + 0xFBA00000FBD, + 0xFC600000FC7, + 0x10000000104A, + 0x10500000109E, + 0x10D0000010FB, + 0x10FD00001100, + 0x120000001249, + 0x124A0000124E, + 0x125000001257, + 0x125800001259, + 0x125A0000125E, + 0x126000001289, + 0x128A0000128E, + 0x1290000012B1, + 0x12B2000012B6, + 0x12B8000012BF, + 0x12C0000012C1, + 0x12C2000012C6, + 0x12C8000012D7, + 0x12D800001311, + 0x131200001316, + 0x13180000135B, + 0x135D00001360, + 0x138000001390, + 0x13A0000013F6, + 0x14010000166D, + 0x166F00001680, + 0x16810000169B, + 0x16A0000016EB, + 0x16F1000016F9, + 0x170000001716, + 0x171F00001735, + 0x174000001754, + 0x17600000176D, + 0x176E00001771, + 0x177200001774, + 0x1780000017B4, + 0x17B6000017D4, + 0x17D7000017D8, + 0x17DC000017DE, + 0x17E0000017EA, + 0x18100000181A, + 0x182000001879, + 0x1880000018AB, + 0x18B0000018F6, + 0x19000000191F, + 0x19200000192C, + 0x19300000193C, + 0x19460000196E, + 0x197000001975, + 0x1980000019AC, + 0x19B0000019CA, + 0x19D0000019DA, + 0x1A0000001A1C, + 0x1A2000001A5F, + 0x1A6000001A7D, + 0x1A7F00001A8A, + 0x1A9000001A9A, + 0x1AA700001AA8, + 0x1AB000001ABE, + 0x1ABF00001ACF, + 0x1B0000001B4D, + 0x1B5000001B5A, + 0x1B6B00001B74, + 0x1B8000001BF4, + 0x1C0000001C38, + 0x1C4000001C4A, + 0x1C4D00001C7E, + 0x1CD000001CD3, + 0x1CD400001CFB, + 0x1D0000001D2C, + 0x1D2F00001D30, + 0x1D3B00001D3C, + 0x1D4E00001D4F, + 0x1D6B00001D78, + 0x1D7900001D9B, + 0x1DC000001E00, + 0x1E0100001E02, + 0x1E0300001E04, + 0x1E0500001E06, + 0x1E0700001E08, + 0x1E0900001E0A, + 0x1E0B00001E0C, + 0x1E0D00001E0E, + 0x1E0F00001E10, + 0x1E1100001E12, + 0x1E1300001E14, + 0x1E1500001E16, + 0x1E1700001E18, + 0x1E1900001E1A, + 0x1E1B00001E1C, + 0x1E1D00001E1E, + 0x1E1F00001E20, + 0x1E2100001E22, + 0x1E2300001E24, + 0x1E2500001E26, + 0x1E2700001E28, + 0x1E2900001E2A, + 0x1E2B00001E2C, + 0x1E2D00001E2E, + 0x1E2F00001E30, + 0x1E3100001E32, + 0x1E3300001E34, + 0x1E3500001E36, + 0x1E3700001E38, + 0x1E3900001E3A, + 0x1E3B00001E3C, + 0x1E3D00001E3E, + 0x1E3F00001E40, + 0x1E4100001E42, + 0x1E4300001E44, + 0x1E4500001E46, + 0x1E4700001E48, + 0x1E4900001E4A, + 0x1E4B00001E4C, + 0x1E4D00001E4E, + 0x1E4F00001E50, + 0x1E5100001E52, + 0x1E5300001E54, + 0x1E5500001E56, + 0x1E5700001E58, + 0x1E5900001E5A, + 0x1E5B00001E5C, + 0x1E5D00001E5E, + 0x1E5F00001E60, + 0x1E6100001E62, + 0x1E6300001E64, + 0x1E6500001E66, + 0x1E6700001E68, + 0x1E6900001E6A, + 0x1E6B00001E6C, + 0x1E6D00001E6E, + 0x1E6F00001E70, + 0x1E7100001E72, + 0x1E7300001E74, + 0x1E7500001E76, + 0x1E7700001E78, + 0x1E7900001E7A, + 0x1E7B00001E7C, + 0x1E7D00001E7E, + 0x1E7F00001E80, + 0x1E8100001E82, + 0x1E8300001E84, + 0x1E8500001E86, + 0x1E8700001E88, + 0x1E8900001E8A, + 0x1E8B00001E8C, + 0x1E8D00001E8E, + 0x1E8F00001E90, + 0x1E9100001E92, + 0x1E9300001E94, + 0x1E9500001E9A, + 0x1E9C00001E9E, + 0x1E9F00001EA0, + 0x1EA100001EA2, + 0x1EA300001EA4, + 0x1EA500001EA6, + 0x1EA700001EA8, + 0x1EA900001EAA, + 0x1EAB00001EAC, + 0x1EAD00001EAE, + 0x1EAF00001EB0, + 0x1EB100001EB2, + 0x1EB300001EB4, + 0x1EB500001EB6, + 0x1EB700001EB8, + 0x1EB900001EBA, + 0x1EBB00001EBC, + 0x1EBD00001EBE, + 0x1EBF00001EC0, + 0x1EC100001EC2, + 0x1EC300001EC4, + 0x1EC500001EC6, + 0x1EC700001EC8, + 0x1EC900001ECA, + 0x1ECB00001ECC, + 0x1ECD00001ECE, + 0x1ECF00001ED0, + 0x1ED100001ED2, + 0x1ED300001ED4, + 0x1ED500001ED6, + 0x1ED700001ED8, + 0x1ED900001EDA, + 0x1EDB00001EDC, + 0x1EDD00001EDE, + 0x1EDF00001EE0, + 0x1EE100001EE2, + 0x1EE300001EE4, + 0x1EE500001EE6, + 0x1EE700001EE8, + 0x1EE900001EEA, + 0x1EEB00001EEC, + 0x1EED00001EEE, + 0x1EEF00001EF0, + 0x1EF100001EF2, + 0x1EF300001EF4, + 0x1EF500001EF6, + 0x1EF700001EF8, + 0x1EF900001EFA, + 0x1EFB00001EFC, + 0x1EFD00001EFE, + 0x1EFF00001F08, + 0x1F1000001F16, + 0x1F2000001F28, + 0x1F3000001F38, + 0x1F4000001F46, + 0x1F5000001F58, + 0x1F6000001F68, + 0x1F7000001F71, + 0x1F7200001F73, + 0x1F7400001F75, + 0x1F7600001F77, + 0x1F7800001F79, + 0x1F7A00001F7B, + 0x1F7C00001F7D, + 0x1FB000001FB2, + 0x1FB600001FB7, + 0x1FC600001FC7, + 0x1FD000001FD3, + 0x1FD600001FD8, + 0x1FE000001FE3, + 0x1FE400001FE8, + 0x1FF600001FF7, + 0x214E0000214F, + 0x218400002185, + 0x2C3000002C60, + 0x2C6100002C62, + 0x2C6500002C67, + 0x2C6800002C69, + 0x2C6A00002C6B, + 0x2C6C00002C6D, + 0x2C7100002C72, + 0x2C7300002C75, + 0x2C7600002C7C, + 0x2C8100002C82, + 0x2C8300002C84, + 0x2C8500002C86, + 0x2C8700002C88, + 0x2C8900002C8A, + 0x2C8B00002C8C, + 0x2C8D00002C8E, + 0x2C8F00002C90, + 0x2C9100002C92, + 0x2C9300002C94, + 0x2C9500002C96, + 0x2C9700002C98, + 0x2C9900002C9A, + 0x2C9B00002C9C, + 0x2C9D00002C9E, + 0x2C9F00002CA0, + 0x2CA100002CA2, + 0x2CA300002CA4, + 0x2CA500002CA6, + 0x2CA700002CA8, + 0x2CA900002CAA, + 0x2CAB00002CAC, + 0x2CAD00002CAE, + 0x2CAF00002CB0, + 0x2CB100002CB2, + 0x2CB300002CB4, + 0x2CB500002CB6, + 0x2CB700002CB8, + 0x2CB900002CBA, + 0x2CBB00002CBC, + 0x2CBD00002CBE, + 0x2CBF00002CC0, + 0x2CC100002CC2, + 0x2CC300002CC4, + 0x2CC500002CC6, + 0x2CC700002CC8, + 0x2CC900002CCA, + 0x2CCB00002CCC, + 0x2CCD00002CCE, + 0x2CCF00002CD0, + 0x2CD100002CD2, + 0x2CD300002CD4, + 0x2CD500002CD6, + 0x2CD700002CD8, + 0x2CD900002CDA, + 0x2CDB00002CDC, + 0x2CDD00002CDE, + 0x2CDF00002CE0, + 0x2CE100002CE2, + 0x2CE300002CE5, + 0x2CEC00002CED, + 0x2CEE00002CF2, + 0x2CF300002CF4, + 0x2D0000002D26, + 0x2D2700002D28, + 0x2D2D00002D2E, + 0x2D3000002D68, + 0x2D7F00002D97, + 0x2DA000002DA7, + 0x2DA800002DAF, + 0x2DB000002DB7, + 0x2DB800002DBF, + 0x2DC000002DC7, + 0x2DC800002DCF, + 0x2DD000002DD7, + 0x2DD800002DDF, + 0x2DE000002E00, + 0x2E2F00002E30, + 0x300500003008, + 0x302A0000302E, + 0x303C0000303D, + 0x304100003097, + 0x30990000309B, + 0x309D0000309F, + 0x30A1000030FB, + 0x30FC000030FF, + 0x310500003130, + 0x31A0000031C0, + 0x31F000003200, + 0x340000004DC0, + 0x4E000000A48D, + 0xA4D00000A4FE, + 0xA5000000A60D, + 0xA6100000A62C, + 0xA6410000A642, + 0xA6430000A644, + 0xA6450000A646, + 0xA6470000A648, + 0xA6490000A64A, + 0xA64B0000A64C, + 0xA64D0000A64E, + 0xA64F0000A650, + 0xA6510000A652, + 0xA6530000A654, + 0xA6550000A656, + 0xA6570000A658, + 0xA6590000A65A, + 0xA65B0000A65C, + 0xA65D0000A65E, + 0xA65F0000A660, + 0xA6610000A662, + 0xA6630000A664, + 0xA6650000A666, + 0xA6670000A668, + 0xA6690000A66A, + 0xA66B0000A66C, + 0xA66D0000A670, + 0xA6740000A67E, + 0xA67F0000A680, + 0xA6810000A682, + 0xA6830000A684, + 0xA6850000A686, + 0xA6870000A688, + 0xA6890000A68A, + 0xA68B0000A68C, + 0xA68D0000A68E, + 0xA68F0000A690, + 0xA6910000A692, + 0xA6930000A694, + 0xA6950000A696, + 0xA6970000A698, + 0xA6990000A69A, + 0xA69B0000A69C, + 0xA69E0000A6E6, + 0xA6F00000A6F2, + 0xA7170000A720, + 0xA7230000A724, + 0xA7250000A726, + 0xA7270000A728, + 0xA7290000A72A, + 0xA72B0000A72C, + 0xA72D0000A72E, + 0xA72F0000A732, + 0xA7330000A734, + 0xA7350000A736, + 0xA7370000A738, + 0xA7390000A73A, + 0xA73B0000A73C, + 0xA73D0000A73E, + 0xA73F0000A740, + 0xA7410000A742, + 0xA7430000A744, + 0xA7450000A746, + 0xA7470000A748, + 0xA7490000A74A, + 0xA74B0000A74C, + 0xA74D0000A74E, + 0xA74F0000A750, + 0xA7510000A752, + 0xA7530000A754, + 0xA7550000A756, + 0xA7570000A758, + 0xA7590000A75A, + 0xA75B0000A75C, + 0xA75D0000A75E, + 0xA75F0000A760, + 0xA7610000A762, + 0xA7630000A764, + 0xA7650000A766, + 0xA7670000A768, + 0xA7690000A76A, + 0xA76B0000A76C, + 0xA76D0000A76E, + 0xA76F0000A770, + 0xA7710000A779, + 0xA77A0000A77B, + 0xA77C0000A77D, + 0xA77F0000A780, + 0xA7810000A782, + 0xA7830000A784, + 0xA7850000A786, + 0xA7870000A789, + 0xA78C0000A78D, + 0xA78E0000A790, + 0xA7910000A792, + 0xA7930000A796, + 0xA7970000A798, + 0xA7990000A79A, + 0xA79B0000A79C, + 0xA79D0000A79E, + 0xA79F0000A7A0, + 0xA7A10000A7A2, + 0xA7A30000A7A4, + 0xA7A50000A7A6, + 0xA7A70000A7A8, + 0xA7A90000A7AA, + 0xA7AF0000A7B0, + 0xA7B50000A7B6, + 0xA7B70000A7B8, + 0xA7B90000A7BA, + 0xA7BB0000A7BC, + 0xA7BD0000A7BE, + 0xA7BF0000A7C0, + 0xA7C10000A7C2, + 0xA7C30000A7C4, + 0xA7C80000A7C9, + 0xA7CA0000A7CB, + 0xA7D10000A7D2, + 0xA7D30000A7D4, + 0xA7D50000A7D6, + 0xA7D70000A7D8, + 0xA7D90000A7DA, + 0xA7F60000A7F8, + 0xA7FA0000A828, + 0xA82C0000A82D, + 0xA8400000A874, + 0xA8800000A8C6, + 0xA8D00000A8DA, + 0xA8E00000A8F8, + 0xA8FB0000A8FC, + 0xA8FD0000A92E, + 0xA9300000A954, + 0xA9800000A9C1, + 0xA9CF0000A9DA, + 0xA9E00000A9FF, + 0xAA000000AA37, + 0xAA400000AA4E, + 0xAA500000AA5A, + 0xAA600000AA77, + 0xAA7A0000AAC3, + 0xAADB0000AADE, + 0xAAE00000AAF0, + 0xAAF20000AAF7, + 0xAB010000AB07, + 0xAB090000AB0F, + 0xAB110000AB17, + 0xAB200000AB27, + 0xAB280000AB2F, + 0xAB300000AB5B, + 0xAB600000AB69, + 0xABC00000ABEB, + 0xABEC0000ABEE, + 0xABF00000ABFA, + 0xAC000000D7A4, + 0xFA0E0000FA10, + 0xFA110000FA12, + 0xFA130000FA15, + 0xFA1F0000FA20, + 0xFA210000FA22, + 0xFA230000FA25, + 0xFA270000FA2A, + 0xFB1E0000FB1F, + 0xFE200000FE30, + 0xFE730000FE74, + 0x100000001000C, + 0x1000D00010027, + 0x100280001003B, + 0x1003C0001003E, + 0x1003F0001004E, + 0x100500001005E, + 0x10080000100FB, + 0x101FD000101FE, + 0x102800001029D, + 0x102A0000102D1, + 0x102E0000102E1, + 0x1030000010320, + 0x1032D00010341, + 0x103420001034A, + 0x103500001037B, + 0x103800001039E, + 0x103A0000103C4, + 0x103C8000103D0, + 0x104280001049E, + 0x104A0000104AA, + 0x104D8000104FC, + 0x1050000010528, + 0x1053000010564, + 0x10597000105A2, + 0x105A3000105B2, + 0x105B3000105BA, + 0x105BB000105BD, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1078000010781, + 0x1080000010806, + 0x1080800010809, + 0x1080A00010836, + 0x1083700010839, + 0x1083C0001083D, + 0x1083F00010856, + 0x1086000010877, + 0x108800001089F, + 0x108E0000108F3, + 0x108F4000108F6, + 0x1090000010916, + 0x109200001093A, + 0x10980000109B8, + 0x109BE000109C0, + 0x10A0000010A04, + 0x10A0500010A07, + 0x10A0C00010A14, + 0x10A1500010A18, + 0x10A1900010A36, + 0x10A3800010A3B, + 0x10A3F00010A40, + 0x10A6000010A7D, + 0x10A8000010A9D, + 0x10AC000010AC8, + 0x10AC900010AE7, + 0x10B0000010B36, + 0x10B4000010B56, + 0x10B6000010B73, + 0x10B8000010B92, + 0x10C0000010C49, + 0x10CC000010CF3, + 0x10D0000010D28, + 0x10D3000010D3A, + 0x10E8000010EAA, + 0x10EAB00010EAD, + 0x10EB000010EB2, + 0x10EFD00010F1D, + 0x10F2700010F28, + 0x10F3000010F51, + 0x10F7000010F86, + 0x10FB000010FC5, + 0x10FE000010FF7, + 0x1100000011047, + 0x1106600011076, + 0x1107F000110BB, + 0x110C2000110C3, + 0x110D0000110E9, + 0x110F0000110FA, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111C5, + 0x111C9000111CD, + 0x111CE000111DB, + 0x111DC000111DD, + 0x1120000011212, + 0x1121300011238, + 0x1123E00011242, + 0x1128000011287, + 0x1128800011289, + 0x1128A0001128E, + 0x1128F0001129E, + 0x1129F000112A9, + 0x112B0000112EB, + 0x112F0000112FA, + 0x1130000011304, + 0x113050001130D, + 0x1130F00011311, + 0x1131300011329, + 0x1132A00011331, + 0x1133200011334, + 0x113350001133A, + 0x1133B00011345, + 0x1134700011349, + 0x1134B0001134E, + 0x1135000011351, + 0x1135700011358, + 0x1135D00011364, + 0x113660001136D, + 0x1137000011375, + 0x114000001144B, + 0x114500001145A, + 0x1145E00011462, + 0x11480000114C6, + 0x114C7000114C8, + 0x114D0000114DA, + 0x11580000115B6, + 0x115B8000115C1, + 0x115D8000115DE, + 0x1160000011641, + 0x1164400011645, + 0x116500001165A, + 0x11680000116B9, + 0x116C0000116CA, + 0x117000001171B, + 0x1171D0001172C, + 0x117300001173A, + 0x1174000011747, + 0x118000001183B, + 0x118C0000118EA, + 0x118FF00011907, + 0x119090001190A, + 0x1190C00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193B00011944, + 0x119500001195A, + 0x119A0000119A8, + 0x119AA000119D8, + 0x119DA000119E2, + 0x119E3000119E5, + 0x11A0000011A3F, + 0x11A4700011A48, + 0x11A5000011A9A, + 0x11A9D00011A9E, + 0x11AB000011AF9, + 0x11C0000011C09, + 0x11C0A00011C37, + 0x11C3800011C41, + 0x11C5000011C5A, + 0x11C7200011C90, + 0x11C9200011CA8, + 0x11CA900011CB7, + 0x11D0000011D07, + 0x11D0800011D0A, + 0x11D0B00011D37, + 0x11D3A00011D3B, + 0x11D3C00011D3E, + 0x11D3F00011D48, + 0x11D5000011D5A, + 0x11D6000011D66, + 0x11D6700011D69, + 0x11D6A00011D8F, + 0x11D9000011D92, + 0x11D9300011D99, + 0x11DA000011DAA, + 0x11EE000011EF7, + 0x11F0000011F11, + 0x11F1200011F3B, + 0x11F3E00011F43, + 0x11F5000011F5A, + 0x11FB000011FB1, + 0x120000001239A, + 0x1248000012544, + 0x12F9000012FF1, + 0x1300000013430, + 0x1344000013456, + 0x1440000014647, + 0x1680000016A39, + 0x16A4000016A5F, + 0x16A6000016A6A, + 0x16A7000016ABF, + 0x16AC000016ACA, + 0x16AD000016AEE, + 0x16AF000016AF5, + 0x16B0000016B37, + 0x16B4000016B44, + 0x16B5000016B5A, + 0x16B6300016B78, + 0x16B7D00016B90, + 0x16E6000016E80, + 0x16F0000016F4B, + 0x16F4F00016F88, + 0x16F8F00016FA0, + 0x16FE000016FE2, + 0x16FE300016FE5, + 0x16FF000016FF2, + 0x17000000187F8, + 0x1880000018CD6, + 0x18D0000018D09, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B123, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1B1550001B156, + 0x1B1640001B168, + 0x1B1700001B2FC, + 0x1BC000001BC6B, + 0x1BC700001BC7D, + 0x1BC800001BC89, + 0x1BC900001BC9A, + 0x1BC9D0001BC9F, + 0x1CF000001CF2E, + 0x1CF300001CF47, + 0x1DA000001DA37, + 0x1DA3B0001DA6D, + 0x1DA750001DA76, + 0x1DA840001DA85, + 0x1DA9B0001DAA0, + 0x1DAA10001DAB0, + 0x1DF000001DF1F, + 0x1DF250001DF2B, + 0x1E0000001E007, + 0x1E0080001E019, + 0x1E01B0001E022, + 0x1E0230001E025, + 0x1E0260001E02B, + 0x1E08F0001E090, + 0x1E1000001E12D, + 0x1E1300001E13E, + 0x1E1400001E14A, + 0x1E14E0001E14F, + 0x1E2900001E2AF, + 0x1E2C00001E2FA, + 0x1E4D00001E4FA, + 0x1E7E00001E7E7, + 0x1E7E80001E7EC, + 0x1E7ED0001E7EF, + 0x1E7F00001E7FF, + 0x1E8000001E8C5, + 0x1E8D00001E8D7, + 0x1E9220001E94C, + 0x1E9500001E95A, + 0x200000002A6E0, + 0x2A7000002B73A, + 0x2B7400002B81E, + 0x2B8200002CEA2, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x300000003134B, + 0x31350000323B0, + ), + "CONTEXTJ": (0x200C0000200E,), + "CONTEXTO": ( + 0xB7000000B8, + 0x37500000376, + 0x5F3000005F5, + 0x6600000066A, + 0x6F0000006FA, + 0x30FB000030FC, + ), +} diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/intranges.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/intranges.py new file mode 100644 index 0000000..7bfaa8d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/intranges.py @@ -0,0 +1,57 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect +from typing import List, Tuple + + +def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i + 1 < len(sorted_list): + if sorted_list[i] == sorted_list[i + 1] - 1: + continue + current_range = sorted_list[last_write + 1 : i + 1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + + +def _encode_range(start: int, end: int) -> int: + return (start << 32) | end + + +def _decode_range(r: int) -> Tuple[int, int]: + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos - 1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/package_data.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/package_data.py new file mode 100644 index 0000000..514ff7e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/package_data.py @@ -0,0 +1 @@ +__version__ = "3.10" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/idna/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/idna/uts46data.py b/backend/venv/Lib/site-packages/pip/_vendor/idna/uts46data.py new file mode 100644 index 0000000..eb89432 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/idna/uts46data.py @@ -0,0 +1,8681 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +from typing import List, Tuple, Union + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "15.1.0" + + +def _seg_0() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x0, "3"), + (0x1, "3"), + (0x2, "3"), + (0x3, "3"), + (0x4, "3"), + (0x5, "3"), + (0x6, "3"), + (0x7, "3"), + (0x8, "3"), + (0x9, "3"), + (0xA, "3"), + (0xB, "3"), + (0xC, "3"), + (0xD, "3"), + (0xE, "3"), + (0xF, "3"), + (0x10, "3"), + (0x11, "3"), + (0x12, "3"), + (0x13, "3"), + (0x14, "3"), + (0x15, "3"), + (0x16, "3"), + (0x17, "3"), + (0x18, "3"), + (0x19, "3"), + (0x1A, "3"), + (0x1B, "3"), + (0x1C, "3"), + (0x1D, "3"), + (0x1E, "3"), + (0x1F, "3"), + (0x20, "3"), + (0x21, "3"), + (0x22, "3"), + (0x23, "3"), + (0x24, "3"), + (0x25, "3"), + (0x26, "3"), + (0x27, "3"), + (0x28, "3"), + (0x29, "3"), + (0x2A, "3"), + (0x2B, "3"), + (0x2C, "3"), + (0x2D, "V"), + (0x2E, "V"), + (0x2F, "3"), + (0x30, "V"), + (0x31, "V"), + (0x32, "V"), + (0x33, "V"), + (0x34, "V"), + (0x35, "V"), + (0x36, "V"), + (0x37, "V"), + (0x38, "V"), + (0x39, "V"), + (0x3A, "3"), + (0x3B, "3"), + (0x3C, "3"), + (0x3D, "3"), + (0x3E, "3"), + (0x3F, "3"), + (0x40, "3"), + (0x41, "M", "a"), + (0x42, "M", "b"), + (0x43, "M", "c"), + (0x44, "M", "d"), + (0x45, "M", "e"), + (0x46, "M", "f"), + (0x47, "M", "g"), + (0x48, "M", "h"), + (0x49, "M", "i"), + (0x4A, "M", "j"), + (0x4B, "M", "k"), + (0x4C, "M", "l"), + (0x4D, "M", "m"), + (0x4E, "M", "n"), + (0x4F, "M", "o"), + (0x50, "M", "p"), + (0x51, "M", "q"), + (0x52, "M", "r"), + (0x53, "M", "s"), + (0x54, "M", "t"), + (0x55, "M", "u"), + (0x56, "M", "v"), + (0x57, "M", "w"), + (0x58, "M", "x"), + (0x59, "M", "y"), + (0x5A, "M", "z"), + (0x5B, "3"), + (0x5C, "3"), + (0x5D, "3"), + (0x5E, "3"), + (0x5F, "3"), + (0x60, "3"), + (0x61, "V"), + (0x62, "V"), + (0x63, "V"), + ] + + +def _seg_1() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x64, "V"), + (0x65, "V"), + (0x66, "V"), + (0x67, "V"), + (0x68, "V"), + (0x69, "V"), + (0x6A, "V"), + (0x6B, "V"), + (0x6C, "V"), + (0x6D, "V"), + (0x6E, "V"), + (0x6F, "V"), + (0x70, "V"), + (0x71, "V"), + (0x72, "V"), + (0x73, "V"), + (0x74, "V"), + (0x75, "V"), + (0x76, "V"), + (0x77, "V"), + (0x78, "V"), + (0x79, "V"), + (0x7A, "V"), + (0x7B, "3"), + (0x7C, "3"), + (0x7D, "3"), + (0x7E, "3"), + (0x7F, "3"), + (0x80, "X"), + (0x81, "X"), + (0x82, "X"), + (0x83, "X"), + (0x84, "X"), + (0x85, "X"), + (0x86, "X"), + (0x87, "X"), + (0x88, "X"), + (0x89, "X"), + (0x8A, "X"), + (0x8B, "X"), + (0x8C, "X"), + (0x8D, "X"), + (0x8E, "X"), + (0x8F, "X"), + (0x90, "X"), + (0x91, "X"), + (0x92, "X"), + (0x93, "X"), + (0x94, "X"), + (0x95, "X"), + (0x96, "X"), + (0x97, "X"), + (0x98, "X"), + (0x99, "X"), + (0x9A, "X"), + (0x9B, "X"), + (0x9C, "X"), + (0x9D, "X"), + (0x9E, "X"), + (0x9F, "X"), + (0xA0, "3", " "), + (0xA1, "V"), + (0xA2, "V"), + (0xA3, "V"), + (0xA4, "V"), + (0xA5, "V"), + (0xA6, "V"), + (0xA7, "V"), + (0xA8, "3", " ̈"), + (0xA9, "V"), + (0xAA, "M", "a"), + (0xAB, "V"), + (0xAC, "V"), + (0xAD, "I"), + (0xAE, "V"), + (0xAF, "3", " ̄"), + (0xB0, "V"), + (0xB1, "V"), + (0xB2, "M", "2"), + (0xB3, "M", "3"), + (0xB4, "3", " ́"), + (0xB5, "M", "μ"), + (0xB6, "V"), + (0xB7, "V"), + (0xB8, "3", " ̧"), + (0xB9, "M", "1"), + (0xBA, "M", "o"), + (0xBB, "V"), + (0xBC, "M", "1⁄4"), + (0xBD, "M", "1⁄2"), + (0xBE, "M", "3⁄4"), + (0xBF, "V"), + (0xC0, "M", "à"), + (0xC1, "M", "á"), + (0xC2, "M", "â"), + (0xC3, "M", "ã"), + (0xC4, "M", "ä"), + (0xC5, "M", "å"), + (0xC6, "M", "æ"), + (0xC7, "M", "ç"), + ] + + +def _seg_2() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC8, "M", "è"), + (0xC9, "M", "é"), + (0xCA, "M", "ê"), + (0xCB, "M", "ë"), + (0xCC, "M", "ì"), + (0xCD, "M", "í"), + (0xCE, "M", "î"), + (0xCF, "M", "ï"), + (0xD0, "M", "ð"), + (0xD1, "M", "ñ"), + (0xD2, "M", "ò"), + (0xD3, "M", "ó"), + (0xD4, "M", "ô"), + (0xD5, "M", "õ"), + (0xD6, "M", "ö"), + (0xD7, "V"), + (0xD8, "M", "ø"), + (0xD9, "M", "ù"), + (0xDA, "M", "ú"), + (0xDB, "M", "û"), + (0xDC, "M", "ü"), + (0xDD, "M", "ý"), + (0xDE, "M", "þ"), + (0xDF, "D", "ss"), + (0xE0, "V"), + (0xE1, "V"), + (0xE2, "V"), + (0xE3, "V"), + (0xE4, "V"), + (0xE5, "V"), + (0xE6, "V"), + (0xE7, "V"), + (0xE8, "V"), + (0xE9, "V"), + (0xEA, "V"), + (0xEB, "V"), + (0xEC, "V"), + (0xED, "V"), + (0xEE, "V"), + (0xEF, "V"), + (0xF0, "V"), + (0xF1, "V"), + (0xF2, "V"), + (0xF3, "V"), + (0xF4, "V"), + (0xF5, "V"), + (0xF6, "V"), + (0xF7, "V"), + (0xF8, "V"), + (0xF9, "V"), + (0xFA, "V"), + (0xFB, "V"), + (0xFC, "V"), + (0xFD, "V"), + (0xFE, "V"), + (0xFF, "V"), + (0x100, "M", "ā"), + (0x101, "V"), + (0x102, "M", "ă"), + (0x103, "V"), + (0x104, "M", "ą"), + (0x105, "V"), + (0x106, "M", "ć"), + (0x107, "V"), + (0x108, "M", "ĉ"), + (0x109, "V"), + (0x10A, "M", "ċ"), + (0x10B, "V"), + (0x10C, "M", "č"), + (0x10D, "V"), + (0x10E, "M", "ď"), + (0x10F, "V"), + (0x110, "M", "đ"), + (0x111, "V"), + (0x112, "M", "ē"), + (0x113, "V"), + (0x114, "M", "ĕ"), + (0x115, "V"), + (0x116, "M", "ė"), + (0x117, "V"), + (0x118, "M", "ę"), + (0x119, "V"), + (0x11A, "M", "ě"), + (0x11B, "V"), + (0x11C, "M", "ĝ"), + (0x11D, "V"), + (0x11E, "M", "ğ"), + (0x11F, "V"), + (0x120, "M", "ġ"), + (0x121, "V"), + (0x122, "M", "ģ"), + (0x123, "V"), + (0x124, "M", "ĥ"), + (0x125, "V"), + (0x126, "M", "ħ"), + (0x127, "V"), + (0x128, "M", "ĩ"), + (0x129, "V"), + (0x12A, "M", "ī"), + (0x12B, "V"), + ] + + +def _seg_3() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x12C, "M", "ĭ"), + (0x12D, "V"), + (0x12E, "M", "į"), + (0x12F, "V"), + (0x130, "M", "i̇"), + (0x131, "V"), + (0x132, "M", "ij"), + (0x134, "M", "ĵ"), + (0x135, "V"), + (0x136, "M", "ķ"), + (0x137, "V"), + (0x139, "M", "ĺ"), + (0x13A, "V"), + (0x13B, "M", "ļ"), + (0x13C, "V"), + (0x13D, "M", "ľ"), + (0x13E, "V"), + (0x13F, "M", "l·"), + (0x141, "M", "ł"), + (0x142, "V"), + (0x143, "M", "ń"), + (0x144, "V"), + (0x145, "M", "ņ"), + (0x146, "V"), + (0x147, "M", "ň"), + (0x148, "V"), + (0x149, "M", "ʼn"), + (0x14A, "M", "ŋ"), + (0x14B, "V"), + (0x14C, "M", "ō"), + (0x14D, "V"), + (0x14E, "M", "ŏ"), + (0x14F, "V"), + (0x150, "M", "ő"), + (0x151, "V"), + (0x152, "M", "œ"), + (0x153, "V"), + (0x154, "M", "ŕ"), + (0x155, "V"), + (0x156, "M", "ŗ"), + (0x157, "V"), + (0x158, "M", "ř"), + (0x159, "V"), + (0x15A, "M", "ś"), + (0x15B, "V"), + (0x15C, "M", "ŝ"), + (0x15D, "V"), + (0x15E, "M", "ş"), + (0x15F, "V"), + (0x160, "M", "š"), + (0x161, "V"), + (0x162, "M", "ţ"), + (0x163, "V"), + (0x164, "M", "ť"), + (0x165, "V"), + (0x166, "M", "ŧ"), + (0x167, "V"), + (0x168, "M", "ũ"), + (0x169, "V"), + (0x16A, "M", "ū"), + (0x16B, "V"), + (0x16C, "M", "ŭ"), + (0x16D, "V"), + (0x16E, "M", "ů"), + (0x16F, "V"), + (0x170, "M", "ű"), + (0x171, "V"), + (0x172, "M", "ų"), + (0x173, "V"), + (0x174, "M", "ŵ"), + (0x175, "V"), + (0x176, "M", "ŷ"), + (0x177, "V"), + (0x178, "M", "ÿ"), + (0x179, "M", "ź"), + (0x17A, "V"), + (0x17B, "M", "ż"), + (0x17C, "V"), + (0x17D, "M", "ž"), + (0x17E, "V"), + (0x17F, "M", "s"), + (0x180, "V"), + (0x181, "M", "ɓ"), + (0x182, "M", "ƃ"), + (0x183, "V"), + (0x184, "M", "ƅ"), + (0x185, "V"), + (0x186, "M", "ɔ"), + (0x187, "M", "ƈ"), + (0x188, "V"), + (0x189, "M", "ɖ"), + (0x18A, "M", "ɗ"), + (0x18B, "M", "ƌ"), + (0x18C, "V"), + (0x18E, "M", "ǝ"), + (0x18F, "M", "ə"), + (0x190, "M", "ɛ"), + (0x191, "M", "ƒ"), + (0x192, "V"), + (0x193, "M", "ɠ"), + ] + + +def _seg_4() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x194, "M", "ɣ"), + (0x195, "V"), + (0x196, "M", "ɩ"), + (0x197, "M", "ɨ"), + (0x198, "M", "ƙ"), + (0x199, "V"), + (0x19C, "M", "ɯ"), + (0x19D, "M", "ɲ"), + (0x19E, "V"), + (0x19F, "M", "ɵ"), + (0x1A0, "M", "ơ"), + (0x1A1, "V"), + (0x1A2, "M", "ƣ"), + (0x1A3, "V"), + (0x1A4, "M", "ƥ"), + (0x1A5, "V"), + (0x1A6, "M", "ʀ"), + (0x1A7, "M", "ƨ"), + (0x1A8, "V"), + (0x1A9, "M", "ʃ"), + (0x1AA, "V"), + (0x1AC, "M", "ƭ"), + (0x1AD, "V"), + (0x1AE, "M", "ʈ"), + (0x1AF, "M", "ư"), + (0x1B0, "V"), + (0x1B1, "M", "ʊ"), + (0x1B2, "M", "ʋ"), + (0x1B3, "M", "ƴ"), + (0x1B4, "V"), + (0x1B5, "M", "ƶ"), + (0x1B6, "V"), + (0x1B7, "M", "ʒ"), + (0x1B8, "M", "ƹ"), + (0x1B9, "V"), + (0x1BC, "M", "ƽ"), + (0x1BD, "V"), + (0x1C4, "M", "dž"), + (0x1C7, "M", "lj"), + (0x1CA, "M", "nj"), + (0x1CD, "M", "ǎ"), + (0x1CE, "V"), + (0x1CF, "M", "ǐ"), + (0x1D0, "V"), + (0x1D1, "M", "ǒ"), + (0x1D2, "V"), + (0x1D3, "M", "ǔ"), + (0x1D4, "V"), + (0x1D5, "M", "ǖ"), + (0x1D6, "V"), + (0x1D7, "M", "ǘ"), + (0x1D8, "V"), + (0x1D9, "M", "ǚ"), + (0x1DA, "V"), + (0x1DB, "M", "ǜ"), + (0x1DC, "V"), + (0x1DE, "M", "ǟ"), + (0x1DF, "V"), + (0x1E0, "M", "ǡ"), + (0x1E1, "V"), + (0x1E2, "M", "ǣ"), + (0x1E3, "V"), + (0x1E4, "M", "ǥ"), + (0x1E5, "V"), + (0x1E6, "M", "ǧ"), + (0x1E7, "V"), + (0x1E8, "M", "ǩ"), + (0x1E9, "V"), + (0x1EA, "M", "ǫ"), + (0x1EB, "V"), + (0x1EC, "M", "ǭ"), + (0x1ED, "V"), + (0x1EE, "M", "ǯ"), + (0x1EF, "V"), + (0x1F1, "M", "dz"), + (0x1F4, "M", "ǵ"), + (0x1F5, "V"), + (0x1F6, "M", "ƕ"), + (0x1F7, "M", "ƿ"), + (0x1F8, "M", "ǹ"), + (0x1F9, "V"), + (0x1FA, "M", "ǻ"), + (0x1FB, "V"), + (0x1FC, "M", "ǽ"), + (0x1FD, "V"), + (0x1FE, "M", "ǿ"), + (0x1FF, "V"), + (0x200, "M", "ȁ"), + (0x201, "V"), + (0x202, "M", "ȃ"), + (0x203, "V"), + (0x204, "M", "ȅ"), + (0x205, "V"), + (0x206, "M", "ȇ"), + (0x207, "V"), + (0x208, "M", "ȉ"), + (0x209, "V"), + (0x20A, "M", "ȋ"), + (0x20B, "V"), + (0x20C, "M", "ȍ"), + ] + + +def _seg_5() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x20D, "V"), + (0x20E, "M", "ȏ"), + (0x20F, "V"), + (0x210, "M", "ȑ"), + (0x211, "V"), + (0x212, "M", "ȓ"), + (0x213, "V"), + (0x214, "M", "ȕ"), + (0x215, "V"), + (0x216, "M", "ȗ"), + (0x217, "V"), + (0x218, "M", "ș"), + (0x219, "V"), + (0x21A, "M", "ț"), + (0x21B, "V"), + (0x21C, "M", "ȝ"), + (0x21D, "V"), + (0x21E, "M", "ȟ"), + (0x21F, "V"), + (0x220, "M", "ƞ"), + (0x221, "V"), + (0x222, "M", "ȣ"), + (0x223, "V"), + (0x224, "M", "ȥ"), + (0x225, "V"), + (0x226, "M", "ȧ"), + (0x227, "V"), + (0x228, "M", "ȩ"), + (0x229, "V"), + (0x22A, "M", "ȫ"), + (0x22B, "V"), + (0x22C, "M", "ȭ"), + (0x22D, "V"), + (0x22E, "M", "ȯ"), + (0x22F, "V"), + (0x230, "M", "ȱ"), + (0x231, "V"), + (0x232, "M", "ȳ"), + (0x233, "V"), + (0x23A, "M", "ⱥ"), + (0x23B, "M", "ȼ"), + (0x23C, "V"), + (0x23D, "M", "ƚ"), + (0x23E, "M", "ⱦ"), + (0x23F, "V"), + (0x241, "M", "ɂ"), + (0x242, "V"), + (0x243, "M", "ƀ"), + (0x244, "M", "ʉ"), + (0x245, "M", "ʌ"), + (0x246, "M", "ɇ"), + (0x247, "V"), + (0x248, "M", "ɉ"), + (0x249, "V"), + (0x24A, "M", "ɋ"), + (0x24B, "V"), + (0x24C, "M", "ɍ"), + (0x24D, "V"), + (0x24E, "M", "ɏ"), + (0x24F, "V"), + (0x2B0, "M", "h"), + (0x2B1, "M", "ɦ"), + (0x2B2, "M", "j"), + (0x2B3, "M", "r"), + (0x2B4, "M", "ɹ"), + (0x2B5, "M", "ɻ"), + (0x2B6, "M", "ʁ"), + (0x2B7, "M", "w"), + (0x2B8, "M", "y"), + (0x2B9, "V"), + (0x2D8, "3", " ̆"), + (0x2D9, "3", " ̇"), + (0x2DA, "3", " ̊"), + (0x2DB, "3", " ̨"), + (0x2DC, "3", " ̃"), + (0x2DD, "3", " ̋"), + (0x2DE, "V"), + (0x2E0, "M", "ɣ"), + (0x2E1, "M", "l"), + (0x2E2, "M", "s"), + (0x2E3, "M", "x"), + (0x2E4, "M", "ʕ"), + (0x2E5, "V"), + (0x340, "M", "̀"), + (0x341, "M", "́"), + (0x342, "V"), + (0x343, "M", "̓"), + (0x344, "M", "̈́"), + (0x345, "M", "ι"), + (0x346, "V"), + (0x34F, "I"), + (0x350, "V"), + (0x370, "M", "ͱ"), + (0x371, "V"), + (0x372, "M", "ͳ"), + (0x373, "V"), + (0x374, "M", "ʹ"), + (0x375, "V"), + (0x376, "M", "ͷ"), + (0x377, "V"), + ] + + +def _seg_6() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x378, "X"), + (0x37A, "3", " ι"), + (0x37B, "V"), + (0x37E, "3", ";"), + (0x37F, "M", "ϳ"), + (0x380, "X"), + (0x384, "3", " ́"), + (0x385, "3", " ̈́"), + (0x386, "M", "ά"), + (0x387, "M", "·"), + (0x388, "M", "έ"), + (0x389, "M", "ή"), + (0x38A, "M", "ί"), + (0x38B, "X"), + (0x38C, "M", "ό"), + (0x38D, "X"), + (0x38E, "M", "ύ"), + (0x38F, "M", "ώ"), + (0x390, "V"), + (0x391, "M", "α"), + (0x392, "M", "β"), + (0x393, "M", "γ"), + (0x394, "M", "δ"), + (0x395, "M", "ε"), + (0x396, "M", "ζ"), + (0x397, "M", "η"), + (0x398, "M", "θ"), + (0x399, "M", "ι"), + (0x39A, "M", "κ"), + (0x39B, "M", "λ"), + (0x39C, "M", "μ"), + (0x39D, "M", "ν"), + (0x39E, "M", "ξ"), + (0x39F, "M", "ο"), + (0x3A0, "M", "π"), + (0x3A1, "M", "ρ"), + (0x3A2, "X"), + (0x3A3, "M", "σ"), + (0x3A4, "M", "τ"), + (0x3A5, "M", "υ"), + (0x3A6, "M", "φ"), + (0x3A7, "M", "χ"), + (0x3A8, "M", "ψ"), + (0x3A9, "M", "ω"), + (0x3AA, "M", "ϊ"), + (0x3AB, "M", "ϋ"), + (0x3AC, "V"), + (0x3C2, "D", "σ"), + (0x3C3, "V"), + (0x3CF, "M", "ϗ"), + (0x3D0, "M", "β"), + (0x3D1, "M", "θ"), + (0x3D2, "M", "υ"), + (0x3D3, "M", "ύ"), + (0x3D4, "M", "ϋ"), + (0x3D5, "M", "φ"), + (0x3D6, "M", "π"), + (0x3D7, "V"), + (0x3D8, "M", "ϙ"), + (0x3D9, "V"), + (0x3DA, "M", "ϛ"), + (0x3DB, "V"), + (0x3DC, "M", "ϝ"), + (0x3DD, "V"), + (0x3DE, "M", "ϟ"), + (0x3DF, "V"), + (0x3E0, "M", "ϡ"), + (0x3E1, "V"), + (0x3E2, "M", "ϣ"), + (0x3E3, "V"), + (0x3E4, "M", "ϥ"), + (0x3E5, "V"), + (0x3E6, "M", "ϧ"), + (0x3E7, "V"), + (0x3E8, "M", "ϩ"), + (0x3E9, "V"), + (0x3EA, "M", "ϫ"), + (0x3EB, "V"), + (0x3EC, "M", "ϭ"), + (0x3ED, "V"), + (0x3EE, "M", "ϯ"), + (0x3EF, "V"), + (0x3F0, "M", "κ"), + (0x3F1, "M", "ρ"), + (0x3F2, "M", "σ"), + (0x3F3, "V"), + (0x3F4, "M", "θ"), + (0x3F5, "M", "ε"), + (0x3F6, "V"), + (0x3F7, "M", "ϸ"), + (0x3F8, "V"), + (0x3F9, "M", "σ"), + (0x3FA, "M", "ϻ"), + (0x3FB, "V"), + (0x3FD, "M", "ͻ"), + (0x3FE, "M", "ͼ"), + (0x3FF, "M", "ͽ"), + (0x400, "M", "ѐ"), + (0x401, "M", "ё"), + (0x402, "M", "ђ"), + ] + + +def _seg_7() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x403, "M", "ѓ"), + (0x404, "M", "є"), + (0x405, "M", "ѕ"), + (0x406, "M", "і"), + (0x407, "M", "ї"), + (0x408, "M", "ј"), + (0x409, "M", "љ"), + (0x40A, "M", "њ"), + (0x40B, "M", "ћ"), + (0x40C, "M", "ќ"), + (0x40D, "M", "ѝ"), + (0x40E, "M", "ў"), + (0x40F, "M", "џ"), + (0x410, "M", "а"), + (0x411, "M", "б"), + (0x412, "M", "в"), + (0x413, "M", "г"), + (0x414, "M", "д"), + (0x415, "M", "е"), + (0x416, "M", "ж"), + (0x417, "M", "з"), + (0x418, "M", "и"), + (0x419, "M", "й"), + (0x41A, "M", "к"), + (0x41B, "M", "л"), + (0x41C, "M", "м"), + (0x41D, "M", "н"), + (0x41E, "M", "о"), + (0x41F, "M", "п"), + (0x420, "M", "р"), + (0x421, "M", "с"), + (0x422, "M", "т"), + (0x423, "M", "у"), + (0x424, "M", "ф"), + (0x425, "M", "х"), + (0x426, "M", "ц"), + (0x427, "M", "ч"), + (0x428, "M", "ш"), + (0x429, "M", "щ"), + (0x42A, "M", "ъ"), + (0x42B, "M", "ы"), + (0x42C, "M", "ь"), + (0x42D, "M", "э"), + (0x42E, "M", "ю"), + (0x42F, "M", "я"), + (0x430, "V"), + (0x460, "M", "ѡ"), + (0x461, "V"), + (0x462, "M", "ѣ"), + (0x463, "V"), + (0x464, "M", "ѥ"), + (0x465, "V"), + (0x466, "M", "ѧ"), + (0x467, "V"), + (0x468, "M", "ѩ"), + (0x469, "V"), + (0x46A, "M", "ѫ"), + (0x46B, "V"), + (0x46C, "M", "ѭ"), + (0x46D, "V"), + (0x46E, "M", "ѯ"), + (0x46F, "V"), + (0x470, "M", "ѱ"), + (0x471, "V"), + (0x472, "M", "ѳ"), + (0x473, "V"), + (0x474, "M", "ѵ"), + (0x475, "V"), + (0x476, "M", "ѷ"), + (0x477, "V"), + (0x478, "M", "ѹ"), + (0x479, "V"), + (0x47A, "M", "ѻ"), + (0x47B, "V"), + (0x47C, "M", "ѽ"), + (0x47D, "V"), + (0x47E, "M", "ѿ"), + (0x47F, "V"), + (0x480, "M", "ҁ"), + (0x481, "V"), + (0x48A, "M", "ҋ"), + (0x48B, "V"), + (0x48C, "M", "ҍ"), + (0x48D, "V"), + (0x48E, "M", "ҏ"), + (0x48F, "V"), + (0x490, "M", "ґ"), + (0x491, "V"), + (0x492, "M", "ғ"), + (0x493, "V"), + (0x494, "M", "ҕ"), + (0x495, "V"), + (0x496, "M", "җ"), + (0x497, "V"), + (0x498, "M", "ҙ"), + (0x499, "V"), + (0x49A, "M", "қ"), + (0x49B, "V"), + (0x49C, "M", "ҝ"), + (0x49D, "V"), + ] + + +def _seg_8() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x49E, "M", "ҟ"), + (0x49F, "V"), + (0x4A0, "M", "ҡ"), + (0x4A1, "V"), + (0x4A2, "M", "ң"), + (0x4A3, "V"), + (0x4A4, "M", "ҥ"), + (0x4A5, "V"), + (0x4A6, "M", "ҧ"), + (0x4A7, "V"), + (0x4A8, "M", "ҩ"), + (0x4A9, "V"), + (0x4AA, "M", "ҫ"), + (0x4AB, "V"), + (0x4AC, "M", "ҭ"), + (0x4AD, "V"), + (0x4AE, "M", "ү"), + (0x4AF, "V"), + (0x4B0, "M", "ұ"), + (0x4B1, "V"), + (0x4B2, "M", "ҳ"), + (0x4B3, "V"), + (0x4B4, "M", "ҵ"), + (0x4B5, "V"), + (0x4B6, "M", "ҷ"), + (0x4B7, "V"), + (0x4B8, "M", "ҹ"), + (0x4B9, "V"), + (0x4BA, "M", "һ"), + (0x4BB, "V"), + (0x4BC, "M", "ҽ"), + (0x4BD, "V"), + (0x4BE, "M", "ҿ"), + (0x4BF, "V"), + (0x4C0, "X"), + (0x4C1, "M", "ӂ"), + (0x4C2, "V"), + (0x4C3, "M", "ӄ"), + (0x4C4, "V"), + (0x4C5, "M", "ӆ"), + (0x4C6, "V"), + (0x4C7, "M", "ӈ"), + (0x4C8, "V"), + (0x4C9, "M", "ӊ"), + (0x4CA, "V"), + (0x4CB, "M", "ӌ"), + (0x4CC, "V"), + (0x4CD, "M", "ӎ"), + (0x4CE, "V"), + (0x4D0, "M", "ӑ"), + (0x4D1, "V"), + (0x4D2, "M", "ӓ"), + (0x4D3, "V"), + (0x4D4, "M", "ӕ"), + (0x4D5, "V"), + (0x4D6, "M", "ӗ"), + (0x4D7, "V"), + (0x4D8, "M", "ә"), + (0x4D9, "V"), + (0x4DA, "M", "ӛ"), + (0x4DB, "V"), + (0x4DC, "M", "ӝ"), + (0x4DD, "V"), + (0x4DE, "M", "ӟ"), + (0x4DF, "V"), + (0x4E0, "M", "ӡ"), + (0x4E1, "V"), + (0x4E2, "M", "ӣ"), + (0x4E3, "V"), + (0x4E4, "M", "ӥ"), + (0x4E5, "V"), + (0x4E6, "M", "ӧ"), + (0x4E7, "V"), + (0x4E8, "M", "ө"), + (0x4E9, "V"), + (0x4EA, "M", "ӫ"), + (0x4EB, "V"), + (0x4EC, "M", "ӭ"), + (0x4ED, "V"), + (0x4EE, "M", "ӯ"), + (0x4EF, "V"), + (0x4F0, "M", "ӱ"), + (0x4F1, "V"), + (0x4F2, "M", "ӳ"), + (0x4F3, "V"), + (0x4F4, "M", "ӵ"), + (0x4F5, "V"), + (0x4F6, "M", "ӷ"), + (0x4F7, "V"), + (0x4F8, "M", "ӹ"), + (0x4F9, "V"), + (0x4FA, "M", "ӻ"), + (0x4FB, "V"), + (0x4FC, "M", "ӽ"), + (0x4FD, "V"), + (0x4FE, "M", "ӿ"), + (0x4FF, "V"), + (0x500, "M", "ԁ"), + (0x501, "V"), + (0x502, "M", "ԃ"), + ] + + +def _seg_9() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x503, "V"), + (0x504, "M", "ԅ"), + (0x505, "V"), + (0x506, "M", "ԇ"), + (0x507, "V"), + (0x508, "M", "ԉ"), + (0x509, "V"), + (0x50A, "M", "ԋ"), + (0x50B, "V"), + (0x50C, "M", "ԍ"), + (0x50D, "V"), + (0x50E, "M", "ԏ"), + (0x50F, "V"), + (0x510, "M", "ԑ"), + (0x511, "V"), + (0x512, "M", "ԓ"), + (0x513, "V"), + (0x514, "M", "ԕ"), + (0x515, "V"), + (0x516, "M", "ԗ"), + (0x517, "V"), + (0x518, "M", "ԙ"), + (0x519, "V"), + (0x51A, "M", "ԛ"), + (0x51B, "V"), + (0x51C, "M", "ԝ"), + (0x51D, "V"), + (0x51E, "M", "ԟ"), + (0x51F, "V"), + (0x520, "M", "ԡ"), + (0x521, "V"), + (0x522, "M", "ԣ"), + (0x523, "V"), + (0x524, "M", "ԥ"), + (0x525, "V"), + (0x526, "M", "ԧ"), + (0x527, "V"), + (0x528, "M", "ԩ"), + (0x529, "V"), + (0x52A, "M", "ԫ"), + (0x52B, "V"), + (0x52C, "M", "ԭ"), + (0x52D, "V"), + (0x52E, "M", "ԯ"), + (0x52F, "V"), + (0x530, "X"), + (0x531, "M", "ա"), + (0x532, "M", "բ"), + (0x533, "M", "գ"), + (0x534, "M", "դ"), + (0x535, "M", "ե"), + (0x536, "M", "զ"), + (0x537, "M", "է"), + (0x538, "M", "ը"), + (0x539, "M", "թ"), + (0x53A, "M", "ժ"), + (0x53B, "M", "ի"), + (0x53C, "M", "լ"), + (0x53D, "M", "խ"), + (0x53E, "M", "ծ"), + (0x53F, "M", "կ"), + (0x540, "M", "հ"), + (0x541, "M", "ձ"), + (0x542, "M", "ղ"), + (0x543, "M", "ճ"), + (0x544, "M", "մ"), + (0x545, "M", "յ"), + (0x546, "M", "ն"), + (0x547, "M", "շ"), + (0x548, "M", "ո"), + (0x549, "M", "չ"), + (0x54A, "M", "պ"), + (0x54B, "M", "ջ"), + (0x54C, "M", "ռ"), + (0x54D, "M", "ս"), + (0x54E, "M", "վ"), + (0x54F, "M", "տ"), + (0x550, "M", "ր"), + (0x551, "M", "ց"), + (0x552, "M", "ւ"), + (0x553, "M", "փ"), + (0x554, "M", "ք"), + (0x555, "M", "օ"), + (0x556, "M", "ֆ"), + (0x557, "X"), + (0x559, "V"), + (0x587, "M", "եւ"), + (0x588, "V"), + (0x58B, "X"), + (0x58D, "V"), + (0x590, "X"), + (0x591, "V"), + (0x5C8, "X"), + (0x5D0, "V"), + (0x5EB, "X"), + (0x5EF, "V"), + (0x5F5, "X"), + (0x606, "V"), + (0x61C, "X"), + (0x61D, "V"), + ] + + +def _seg_10() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x675, "M", "اٴ"), + (0x676, "M", "وٴ"), + (0x677, "M", "ۇٴ"), + (0x678, "M", "يٴ"), + (0x679, "V"), + (0x6DD, "X"), + (0x6DE, "V"), + (0x70E, "X"), + (0x710, "V"), + (0x74B, "X"), + (0x74D, "V"), + (0x7B2, "X"), + (0x7C0, "V"), + (0x7FB, "X"), + (0x7FD, "V"), + (0x82E, "X"), + (0x830, "V"), + (0x83F, "X"), + (0x840, "V"), + (0x85C, "X"), + (0x85E, "V"), + (0x85F, "X"), + (0x860, "V"), + (0x86B, "X"), + (0x870, "V"), + (0x88F, "X"), + (0x898, "V"), + (0x8E2, "X"), + (0x8E3, "V"), + (0x958, "M", "क़"), + (0x959, "M", "ख़"), + (0x95A, "M", "ग़"), + (0x95B, "M", "ज़"), + (0x95C, "M", "ड़"), + (0x95D, "M", "ढ़"), + (0x95E, "M", "फ़"), + (0x95F, "M", "य़"), + (0x960, "V"), + (0x984, "X"), + (0x985, "V"), + (0x98D, "X"), + (0x98F, "V"), + (0x991, "X"), + (0x993, "V"), + (0x9A9, "X"), + (0x9AA, "V"), + (0x9B1, "X"), + (0x9B2, "V"), + (0x9B3, "X"), + (0x9B6, "V"), + (0x9BA, "X"), + (0x9BC, "V"), + (0x9C5, "X"), + (0x9C7, "V"), + (0x9C9, "X"), + (0x9CB, "V"), + (0x9CF, "X"), + (0x9D7, "V"), + (0x9D8, "X"), + (0x9DC, "M", "ড়"), + (0x9DD, "M", "ঢ়"), + (0x9DE, "X"), + (0x9DF, "M", "য়"), + (0x9E0, "V"), + (0x9E4, "X"), + (0x9E6, "V"), + (0x9FF, "X"), + (0xA01, "V"), + (0xA04, "X"), + (0xA05, "V"), + (0xA0B, "X"), + (0xA0F, "V"), + (0xA11, "X"), + (0xA13, "V"), + (0xA29, "X"), + (0xA2A, "V"), + (0xA31, "X"), + (0xA32, "V"), + (0xA33, "M", "ਲ਼"), + (0xA34, "X"), + (0xA35, "V"), + (0xA36, "M", "ਸ਼"), + (0xA37, "X"), + (0xA38, "V"), + (0xA3A, "X"), + (0xA3C, "V"), + (0xA3D, "X"), + (0xA3E, "V"), + (0xA43, "X"), + (0xA47, "V"), + (0xA49, "X"), + (0xA4B, "V"), + (0xA4E, "X"), + (0xA51, "V"), + (0xA52, "X"), + (0xA59, "M", "ਖ਼"), + (0xA5A, "M", "ਗ਼"), + (0xA5B, "M", "ਜ਼"), + (0xA5C, "V"), + (0xA5D, "X"), + ] + + +def _seg_11() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA5E, "M", "ਫ਼"), + (0xA5F, "X"), + (0xA66, "V"), + (0xA77, "X"), + (0xA81, "V"), + (0xA84, "X"), + (0xA85, "V"), + (0xA8E, "X"), + (0xA8F, "V"), + (0xA92, "X"), + (0xA93, "V"), + (0xAA9, "X"), + (0xAAA, "V"), + (0xAB1, "X"), + (0xAB2, "V"), + (0xAB4, "X"), + (0xAB5, "V"), + (0xABA, "X"), + (0xABC, "V"), + (0xAC6, "X"), + (0xAC7, "V"), + (0xACA, "X"), + (0xACB, "V"), + (0xACE, "X"), + (0xAD0, "V"), + (0xAD1, "X"), + (0xAE0, "V"), + (0xAE4, "X"), + (0xAE6, "V"), + (0xAF2, "X"), + (0xAF9, "V"), + (0xB00, "X"), + (0xB01, "V"), + (0xB04, "X"), + (0xB05, "V"), + (0xB0D, "X"), + (0xB0F, "V"), + (0xB11, "X"), + (0xB13, "V"), + (0xB29, "X"), + (0xB2A, "V"), + (0xB31, "X"), + (0xB32, "V"), + (0xB34, "X"), + (0xB35, "V"), + (0xB3A, "X"), + (0xB3C, "V"), + (0xB45, "X"), + (0xB47, "V"), + (0xB49, "X"), + (0xB4B, "V"), + (0xB4E, "X"), + (0xB55, "V"), + (0xB58, "X"), + (0xB5C, "M", "ଡ଼"), + (0xB5D, "M", "ଢ଼"), + (0xB5E, "X"), + (0xB5F, "V"), + (0xB64, "X"), + (0xB66, "V"), + (0xB78, "X"), + (0xB82, "V"), + (0xB84, "X"), + (0xB85, "V"), + (0xB8B, "X"), + (0xB8E, "V"), + (0xB91, "X"), + (0xB92, "V"), + (0xB96, "X"), + (0xB99, "V"), + (0xB9B, "X"), + (0xB9C, "V"), + (0xB9D, "X"), + (0xB9E, "V"), + (0xBA0, "X"), + (0xBA3, "V"), + (0xBA5, "X"), + (0xBA8, "V"), + (0xBAB, "X"), + (0xBAE, "V"), + (0xBBA, "X"), + (0xBBE, "V"), + (0xBC3, "X"), + (0xBC6, "V"), + (0xBC9, "X"), + (0xBCA, "V"), + (0xBCE, "X"), + (0xBD0, "V"), + (0xBD1, "X"), + (0xBD7, "V"), + (0xBD8, "X"), + (0xBE6, "V"), + (0xBFB, "X"), + (0xC00, "V"), + (0xC0D, "X"), + (0xC0E, "V"), + (0xC11, "X"), + (0xC12, "V"), + (0xC29, "X"), + (0xC2A, "V"), + ] + + +def _seg_12() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xC3A, "X"), + (0xC3C, "V"), + (0xC45, "X"), + (0xC46, "V"), + (0xC49, "X"), + (0xC4A, "V"), + (0xC4E, "X"), + (0xC55, "V"), + (0xC57, "X"), + (0xC58, "V"), + (0xC5B, "X"), + (0xC5D, "V"), + (0xC5E, "X"), + (0xC60, "V"), + (0xC64, "X"), + (0xC66, "V"), + (0xC70, "X"), + (0xC77, "V"), + (0xC8D, "X"), + (0xC8E, "V"), + (0xC91, "X"), + (0xC92, "V"), + (0xCA9, "X"), + (0xCAA, "V"), + (0xCB4, "X"), + (0xCB5, "V"), + (0xCBA, "X"), + (0xCBC, "V"), + (0xCC5, "X"), + (0xCC6, "V"), + (0xCC9, "X"), + (0xCCA, "V"), + (0xCCE, "X"), + (0xCD5, "V"), + (0xCD7, "X"), + (0xCDD, "V"), + (0xCDF, "X"), + (0xCE0, "V"), + (0xCE4, "X"), + (0xCE6, "V"), + (0xCF0, "X"), + (0xCF1, "V"), + (0xCF4, "X"), + (0xD00, "V"), + (0xD0D, "X"), + (0xD0E, "V"), + (0xD11, "X"), + (0xD12, "V"), + (0xD45, "X"), + (0xD46, "V"), + (0xD49, "X"), + (0xD4A, "V"), + (0xD50, "X"), + (0xD54, "V"), + (0xD64, "X"), + (0xD66, "V"), + (0xD80, "X"), + (0xD81, "V"), + (0xD84, "X"), + (0xD85, "V"), + (0xD97, "X"), + (0xD9A, "V"), + (0xDB2, "X"), + (0xDB3, "V"), + (0xDBC, "X"), + (0xDBD, "V"), + (0xDBE, "X"), + (0xDC0, "V"), + (0xDC7, "X"), + (0xDCA, "V"), + (0xDCB, "X"), + (0xDCF, "V"), + (0xDD5, "X"), + (0xDD6, "V"), + (0xDD7, "X"), + (0xDD8, "V"), + (0xDE0, "X"), + (0xDE6, "V"), + (0xDF0, "X"), + (0xDF2, "V"), + (0xDF5, "X"), + (0xE01, "V"), + (0xE33, "M", "ํา"), + (0xE34, "V"), + (0xE3B, "X"), + (0xE3F, "V"), + (0xE5C, "X"), + (0xE81, "V"), + (0xE83, "X"), + (0xE84, "V"), + (0xE85, "X"), + (0xE86, "V"), + (0xE8B, "X"), + (0xE8C, "V"), + (0xEA4, "X"), + (0xEA5, "V"), + (0xEA6, "X"), + (0xEA7, "V"), + (0xEB3, "M", "ໍາ"), + (0xEB4, "V"), + ] + + +def _seg_13() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xEBE, "X"), + (0xEC0, "V"), + (0xEC5, "X"), + (0xEC6, "V"), + (0xEC7, "X"), + (0xEC8, "V"), + (0xECF, "X"), + (0xED0, "V"), + (0xEDA, "X"), + (0xEDC, "M", "ຫນ"), + (0xEDD, "M", "ຫມ"), + (0xEDE, "V"), + (0xEE0, "X"), + (0xF00, "V"), + (0xF0C, "M", "་"), + (0xF0D, "V"), + (0xF43, "M", "གྷ"), + (0xF44, "V"), + (0xF48, "X"), + (0xF49, "V"), + (0xF4D, "M", "ཌྷ"), + (0xF4E, "V"), + (0xF52, "M", "དྷ"), + (0xF53, "V"), + (0xF57, "M", "བྷ"), + (0xF58, "V"), + (0xF5C, "M", "ཛྷ"), + (0xF5D, "V"), + (0xF69, "M", "ཀྵ"), + (0xF6A, "V"), + (0xF6D, "X"), + (0xF71, "V"), + (0xF73, "M", "ཱི"), + (0xF74, "V"), + (0xF75, "M", "ཱུ"), + (0xF76, "M", "ྲྀ"), + (0xF77, "M", "ྲཱྀ"), + (0xF78, "M", "ླྀ"), + (0xF79, "M", "ླཱྀ"), + (0xF7A, "V"), + (0xF81, "M", "ཱྀ"), + (0xF82, "V"), + (0xF93, "M", "ྒྷ"), + (0xF94, "V"), + (0xF98, "X"), + (0xF99, "V"), + (0xF9D, "M", "ྜྷ"), + (0xF9E, "V"), + (0xFA2, "M", "ྡྷ"), + (0xFA3, "V"), + (0xFA7, "M", "ྦྷ"), + (0xFA8, "V"), + (0xFAC, "M", "ྫྷ"), + (0xFAD, "V"), + (0xFB9, "M", "ྐྵ"), + (0xFBA, "V"), + (0xFBD, "X"), + (0xFBE, "V"), + (0xFCD, "X"), + (0xFCE, "V"), + (0xFDB, "X"), + (0x1000, "V"), + (0x10A0, "X"), + (0x10C7, "M", "ⴧ"), + (0x10C8, "X"), + (0x10CD, "M", "ⴭ"), + (0x10CE, "X"), + (0x10D0, "V"), + (0x10FC, "M", "ნ"), + (0x10FD, "V"), + (0x115F, "X"), + (0x1161, "V"), + (0x1249, "X"), + (0x124A, "V"), + (0x124E, "X"), + (0x1250, "V"), + (0x1257, "X"), + (0x1258, "V"), + (0x1259, "X"), + (0x125A, "V"), + (0x125E, "X"), + (0x1260, "V"), + (0x1289, "X"), + (0x128A, "V"), + (0x128E, "X"), + (0x1290, "V"), + (0x12B1, "X"), + (0x12B2, "V"), + (0x12B6, "X"), + (0x12B8, "V"), + (0x12BF, "X"), + (0x12C0, "V"), + (0x12C1, "X"), + (0x12C2, "V"), + (0x12C6, "X"), + (0x12C8, "V"), + (0x12D7, "X"), + (0x12D8, "V"), + (0x1311, "X"), + (0x1312, "V"), + ] + + +def _seg_14() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1316, "X"), + (0x1318, "V"), + (0x135B, "X"), + (0x135D, "V"), + (0x137D, "X"), + (0x1380, "V"), + (0x139A, "X"), + (0x13A0, "V"), + (0x13F6, "X"), + (0x13F8, "M", "Ᏸ"), + (0x13F9, "M", "Ᏹ"), + (0x13FA, "M", "Ᏺ"), + (0x13FB, "M", "Ᏻ"), + (0x13FC, "M", "Ᏼ"), + (0x13FD, "M", "Ᏽ"), + (0x13FE, "X"), + (0x1400, "V"), + (0x1680, "X"), + (0x1681, "V"), + (0x169D, "X"), + (0x16A0, "V"), + (0x16F9, "X"), + (0x1700, "V"), + (0x1716, "X"), + (0x171F, "V"), + (0x1737, "X"), + (0x1740, "V"), + (0x1754, "X"), + (0x1760, "V"), + (0x176D, "X"), + (0x176E, "V"), + (0x1771, "X"), + (0x1772, "V"), + (0x1774, "X"), + (0x1780, "V"), + (0x17B4, "X"), + (0x17B6, "V"), + (0x17DE, "X"), + (0x17E0, "V"), + (0x17EA, "X"), + (0x17F0, "V"), + (0x17FA, "X"), + (0x1800, "V"), + (0x1806, "X"), + (0x1807, "V"), + (0x180B, "I"), + (0x180E, "X"), + (0x180F, "I"), + (0x1810, "V"), + (0x181A, "X"), + (0x1820, "V"), + (0x1879, "X"), + (0x1880, "V"), + (0x18AB, "X"), + (0x18B0, "V"), + (0x18F6, "X"), + (0x1900, "V"), + (0x191F, "X"), + (0x1920, "V"), + (0x192C, "X"), + (0x1930, "V"), + (0x193C, "X"), + (0x1940, "V"), + (0x1941, "X"), + (0x1944, "V"), + (0x196E, "X"), + (0x1970, "V"), + (0x1975, "X"), + (0x1980, "V"), + (0x19AC, "X"), + (0x19B0, "V"), + (0x19CA, "X"), + (0x19D0, "V"), + (0x19DB, "X"), + (0x19DE, "V"), + (0x1A1C, "X"), + (0x1A1E, "V"), + (0x1A5F, "X"), + (0x1A60, "V"), + (0x1A7D, "X"), + (0x1A7F, "V"), + (0x1A8A, "X"), + (0x1A90, "V"), + (0x1A9A, "X"), + (0x1AA0, "V"), + (0x1AAE, "X"), + (0x1AB0, "V"), + (0x1ACF, "X"), + (0x1B00, "V"), + (0x1B4D, "X"), + (0x1B50, "V"), + (0x1B7F, "X"), + (0x1B80, "V"), + (0x1BF4, "X"), + (0x1BFC, "V"), + (0x1C38, "X"), + (0x1C3B, "V"), + (0x1C4A, "X"), + (0x1C4D, "V"), + (0x1C80, "M", "в"), + ] + + +def _seg_15() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1C81, "M", "д"), + (0x1C82, "M", "о"), + (0x1C83, "M", "с"), + (0x1C84, "M", "т"), + (0x1C86, "M", "ъ"), + (0x1C87, "M", "ѣ"), + (0x1C88, "M", "ꙋ"), + (0x1C89, "X"), + (0x1C90, "M", "ა"), + (0x1C91, "M", "ბ"), + (0x1C92, "M", "გ"), + (0x1C93, "M", "დ"), + (0x1C94, "M", "ე"), + (0x1C95, "M", "ვ"), + (0x1C96, "M", "ზ"), + (0x1C97, "M", "თ"), + (0x1C98, "M", "ი"), + (0x1C99, "M", "კ"), + (0x1C9A, "M", "ლ"), + (0x1C9B, "M", "მ"), + (0x1C9C, "M", "ნ"), + (0x1C9D, "M", "ო"), + (0x1C9E, "M", "პ"), + (0x1C9F, "M", "ჟ"), + (0x1CA0, "M", "რ"), + (0x1CA1, "M", "ს"), + (0x1CA2, "M", "ტ"), + (0x1CA3, "M", "უ"), + (0x1CA4, "M", "ფ"), + (0x1CA5, "M", "ქ"), + (0x1CA6, "M", "ღ"), + (0x1CA7, "M", "ყ"), + (0x1CA8, "M", "შ"), + (0x1CA9, "M", "ჩ"), + (0x1CAA, "M", "ც"), + (0x1CAB, "M", "ძ"), + (0x1CAC, "M", "წ"), + (0x1CAD, "M", "ჭ"), + (0x1CAE, "M", "ხ"), + (0x1CAF, "M", "ჯ"), + (0x1CB0, "M", "ჰ"), + (0x1CB1, "M", "ჱ"), + (0x1CB2, "M", "ჲ"), + (0x1CB3, "M", "ჳ"), + (0x1CB4, "M", "ჴ"), + (0x1CB5, "M", "ჵ"), + (0x1CB6, "M", "ჶ"), + (0x1CB7, "M", "ჷ"), + (0x1CB8, "M", "ჸ"), + (0x1CB9, "M", "ჹ"), + (0x1CBA, "M", "ჺ"), + (0x1CBB, "X"), + (0x1CBD, "M", "ჽ"), + (0x1CBE, "M", "ჾ"), + (0x1CBF, "M", "ჿ"), + (0x1CC0, "V"), + (0x1CC8, "X"), + (0x1CD0, "V"), + (0x1CFB, "X"), + (0x1D00, "V"), + (0x1D2C, "M", "a"), + (0x1D2D, "M", "æ"), + (0x1D2E, "M", "b"), + (0x1D2F, "V"), + (0x1D30, "M", "d"), + (0x1D31, "M", "e"), + (0x1D32, "M", "ǝ"), + (0x1D33, "M", "g"), + (0x1D34, "M", "h"), + (0x1D35, "M", "i"), + (0x1D36, "M", "j"), + (0x1D37, "M", "k"), + (0x1D38, "M", "l"), + (0x1D39, "M", "m"), + (0x1D3A, "M", "n"), + (0x1D3B, "V"), + (0x1D3C, "M", "o"), + (0x1D3D, "M", "ȣ"), + (0x1D3E, "M", "p"), + (0x1D3F, "M", "r"), + (0x1D40, "M", "t"), + (0x1D41, "M", "u"), + (0x1D42, "M", "w"), + (0x1D43, "M", "a"), + (0x1D44, "M", "ɐ"), + (0x1D45, "M", "ɑ"), + (0x1D46, "M", "ᴂ"), + (0x1D47, "M", "b"), + (0x1D48, "M", "d"), + (0x1D49, "M", "e"), + (0x1D4A, "M", "ə"), + (0x1D4B, "M", "ɛ"), + (0x1D4C, "M", "ɜ"), + (0x1D4D, "M", "g"), + (0x1D4E, "V"), + (0x1D4F, "M", "k"), + (0x1D50, "M", "m"), + (0x1D51, "M", "ŋ"), + (0x1D52, "M", "o"), + (0x1D53, "M", "ɔ"), + ] + + +def _seg_16() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D54, "M", "ᴖ"), + (0x1D55, "M", "ᴗ"), + (0x1D56, "M", "p"), + (0x1D57, "M", "t"), + (0x1D58, "M", "u"), + (0x1D59, "M", "ᴝ"), + (0x1D5A, "M", "ɯ"), + (0x1D5B, "M", "v"), + (0x1D5C, "M", "ᴥ"), + (0x1D5D, "M", "β"), + (0x1D5E, "M", "γ"), + (0x1D5F, "M", "δ"), + (0x1D60, "M", "φ"), + (0x1D61, "M", "χ"), + (0x1D62, "M", "i"), + (0x1D63, "M", "r"), + (0x1D64, "M", "u"), + (0x1D65, "M", "v"), + (0x1D66, "M", "β"), + (0x1D67, "M", "γ"), + (0x1D68, "M", "ρ"), + (0x1D69, "M", "φ"), + (0x1D6A, "M", "χ"), + (0x1D6B, "V"), + (0x1D78, "M", "н"), + (0x1D79, "V"), + (0x1D9B, "M", "ɒ"), + (0x1D9C, "M", "c"), + (0x1D9D, "M", "ɕ"), + (0x1D9E, "M", "ð"), + (0x1D9F, "M", "ɜ"), + (0x1DA0, "M", "f"), + (0x1DA1, "M", "ɟ"), + (0x1DA2, "M", "ɡ"), + (0x1DA3, "M", "ɥ"), + (0x1DA4, "M", "ɨ"), + (0x1DA5, "M", "ɩ"), + (0x1DA6, "M", "ɪ"), + (0x1DA7, "M", "ᵻ"), + (0x1DA8, "M", "ʝ"), + (0x1DA9, "M", "ɭ"), + (0x1DAA, "M", "ᶅ"), + (0x1DAB, "M", "ʟ"), + (0x1DAC, "M", "ɱ"), + (0x1DAD, "M", "ɰ"), + (0x1DAE, "M", "ɲ"), + (0x1DAF, "M", "ɳ"), + (0x1DB0, "M", "ɴ"), + (0x1DB1, "M", "ɵ"), + (0x1DB2, "M", "ɸ"), + (0x1DB3, "M", "ʂ"), + (0x1DB4, "M", "ʃ"), + (0x1DB5, "M", "ƫ"), + (0x1DB6, "M", "ʉ"), + (0x1DB7, "M", "ʊ"), + (0x1DB8, "M", "ᴜ"), + (0x1DB9, "M", "ʋ"), + (0x1DBA, "M", "ʌ"), + (0x1DBB, "M", "z"), + (0x1DBC, "M", "ʐ"), + (0x1DBD, "M", "ʑ"), + (0x1DBE, "M", "ʒ"), + (0x1DBF, "M", "θ"), + (0x1DC0, "V"), + (0x1E00, "M", "ḁ"), + (0x1E01, "V"), + (0x1E02, "M", "ḃ"), + (0x1E03, "V"), + (0x1E04, "M", "ḅ"), + (0x1E05, "V"), + (0x1E06, "M", "ḇ"), + (0x1E07, "V"), + (0x1E08, "M", "ḉ"), + (0x1E09, "V"), + (0x1E0A, "M", "ḋ"), + (0x1E0B, "V"), + (0x1E0C, "M", "ḍ"), + (0x1E0D, "V"), + (0x1E0E, "M", "ḏ"), + (0x1E0F, "V"), + (0x1E10, "M", "ḑ"), + (0x1E11, "V"), + (0x1E12, "M", "ḓ"), + (0x1E13, "V"), + (0x1E14, "M", "ḕ"), + (0x1E15, "V"), + (0x1E16, "M", "ḗ"), + (0x1E17, "V"), + (0x1E18, "M", "ḙ"), + (0x1E19, "V"), + (0x1E1A, "M", "ḛ"), + (0x1E1B, "V"), + (0x1E1C, "M", "ḝ"), + (0x1E1D, "V"), + (0x1E1E, "M", "ḟ"), + (0x1E1F, "V"), + (0x1E20, "M", "ḡ"), + (0x1E21, "V"), + (0x1E22, "M", "ḣ"), + (0x1E23, "V"), + ] + + +def _seg_17() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E24, "M", "ḥ"), + (0x1E25, "V"), + (0x1E26, "M", "ḧ"), + (0x1E27, "V"), + (0x1E28, "M", "ḩ"), + (0x1E29, "V"), + (0x1E2A, "M", "ḫ"), + (0x1E2B, "V"), + (0x1E2C, "M", "ḭ"), + (0x1E2D, "V"), + (0x1E2E, "M", "ḯ"), + (0x1E2F, "V"), + (0x1E30, "M", "ḱ"), + (0x1E31, "V"), + (0x1E32, "M", "ḳ"), + (0x1E33, "V"), + (0x1E34, "M", "ḵ"), + (0x1E35, "V"), + (0x1E36, "M", "ḷ"), + (0x1E37, "V"), + (0x1E38, "M", "ḹ"), + (0x1E39, "V"), + (0x1E3A, "M", "ḻ"), + (0x1E3B, "V"), + (0x1E3C, "M", "ḽ"), + (0x1E3D, "V"), + (0x1E3E, "M", "ḿ"), + (0x1E3F, "V"), + (0x1E40, "M", "ṁ"), + (0x1E41, "V"), + (0x1E42, "M", "ṃ"), + (0x1E43, "V"), + (0x1E44, "M", "ṅ"), + (0x1E45, "V"), + (0x1E46, "M", "ṇ"), + (0x1E47, "V"), + (0x1E48, "M", "ṉ"), + (0x1E49, "V"), + (0x1E4A, "M", "ṋ"), + (0x1E4B, "V"), + (0x1E4C, "M", "ṍ"), + (0x1E4D, "V"), + (0x1E4E, "M", "ṏ"), + (0x1E4F, "V"), + (0x1E50, "M", "ṑ"), + (0x1E51, "V"), + (0x1E52, "M", "ṓ"), + (0x1E53, "V"), + (0x1E54, "M", "ṕ"), + (0x1E55, "V"), + (0x1E56, "M", "ṗ"), + (0x1E57, "V"), + (0x1E58, "M", "ṙ"), + (0x1E59, "V"), + (0x1E5A, "M", "ṛ"), + (0x1E5B, "V"), + (0x1E5C, "M", "ṝ"), + (0x1E5D, "V"), + (0x1E5E, "M", "ṟ"), + (0x1E5F, "V"), + (0x1E60, "M", "ṡ"), + (0x1E61, "V"), + (0x1E62, "M", "ṣ"), + (0x1E63, "V"), + (0x1E64, "M", "ṥ"), + (0x1E65, "V"), + (0x1E66, "M", "ṧ"), + (0x1E67, "V"), + (0x1E68, "M", "ṩ"), + (0x1E69, "V"), + (0x1E6A, "M", "ṫ"), + (0x1E6B, "V"), + (0x1E6C, "M", "ṭ"), + (0x1E6D, "V"), + (0x1E6E, "M", "ṯ"), + (0x1E6F, "V"), + (0x1E70, "M", "ṱ"), + (0x1E71, "V"), + (0x1E72, "M", "ṳ"), + (0x1E73, "V"), + (0x1E74, "M", "ṵ"), + (0x1E75, "V"), + (0x1E76, "M", "ṷ"), + (0x1E77, "V"), + (0x1E78, "M", "ṹ"), + (0x1E79, "V"), + (0x1E7A, "M", "ṻ"), + (0x1E7B, "V"), + (0x1E7C, "M", "ṽ"), + (0x1E7D, "V"), + (0x1E7E, "M", "ṿ"), + (0x1E7F, "V"), + (0x1E80, "M", "ẁ"), + (0x1E81, "V"), + (0x1E82, "M", "ẃ"), + (0x1E83, "V"), + (0x1E84, "M", "ẅ"), + (0x1E85, "V"), + (0x1E86, "M", "ẇ"), + (0x1E87, "V"), + ] + + +def _seg_18() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E88, "M", "ẉ"), + (0x1E89, "V"), + (0x1E8A, "M", "ẋ"), + (0x1E8B, "V"), + (0x1E8C, "M", "ẍ"), + (0x1E8D, "V"), + (0x1E8E, "M", "ẏ"), + (0x1E8F, "V"), + (0x1E90, "M", "ẑ"), + (0x1E91, "V"), + (0x1E92, "M", "ẓ"), + (0x1E93, "V"), + (0x1E94, "M", "ẕ"), + (0x1E95, "V"), + (0x1E9A, "M", "aʾ"), + (0x1E9B, "M", "ṡ"), + (0x1E9C, "V"), + (0x1E9E, "M", "ß"), + (0x1E9F, "V"), + (0x1EA0, "M", "ạ"), + (0x1EA1, "V"), + (0x1EA2, "M", "ả"), + (0x1EA3, "V"), + (0x1EA4, "M", "ấ"), + (0x1EA5, "V"), + (0x1EA6, "M", "ầ"), + (0x1EA7, "V"), + (0x1EA8, "M", "ẩ"), + (0x1EA9, "V"), + (0x1EAA, "M", "ẫ"), + (0x1EAB, "V"), + (0x1EAC, "M", "ậ"), + (0x1EAD, "V"), + (0x1EAE, "M", "ắ"), + (0x1EAF, "V"), + (0x1EB0, "M", "ằ"), + (0x1EB1, "V"), + (0x1EB2, "M", "ẳ"), + (0x1EB3, "V"), + (0x1EB4, "M", "ẵ"), + (0x1EB5, "V"), + (0x1EB6, "M", "ặ"), + (0x1EB7, "V"), + (0x1EB8, "M", "ẹ"), + (0x1EB9, "V"), + (0x1EBA, "M", "ẻ"), + (0x1EBB, "V"), + (0x1EBC, "M", "ẽ"), + (0x1EBD, "V"), + (0x1EBE, "M", "ế"), + (0x1EBF, "V"), + (0x1EC0, "M", "ề"), + (0x1EC1, "V"), + (0x1EC2, "M", "ể"), + (0x1EC3, "V"), + (0x1EC4, "M", "ễ"), + (0x1EC5, "V"), + (0x1EC6, "M", "ệ"), + (0x1EC7, "V"), + (0x1EC8, "M", "ỉ"), + (0x1EC9, "V"), + (0x1ECA, "M", "ị"), + (0x1ECB, "V"), + (0x1ECC, "M", "ọ"), + (0x1ECD, "V"), + (0x1ECE, "M", "ỏ"), + (0x1ECF, "V"), + (0x1ED0, "M", "ố"), + (0x1ED1, "V"), + (0x1ED2, "M", "ồ"), + (0x1ED3, "V"), + (0x1ED4, "M", "ổ"), + (0x1ED5, "V"), + (0x1ED6, "M", "ỗ"), + (0x1ED7, "V"), + (0x1ED8, "M", "ộ"), + (0x1ED9, "V"), + (0x1EDA, "M", "ớ"), + (0x1EDB, "V"), + (0x1EDC, "M", "ờ"), + (0x1EDD, "V"), + (0x1EDE, "M", "ở"), + (0x1EDF, "V"), + (0x1EE0, "M", "ỡ"), + (0x1EE1, "V"), + (0x1EE2, "M", "ợ"), + (0x1EE3, "V"), + (0x1EE4, "M", "ụ"), + (0x1EE5, "V"), + (0x1EE6, "M", "ủ"), + (0x1EE7, "V"), + (0x1EE8, "M", "ứ"), + (0x1EE9, "V"), + (0x1EEA, "M", "ừ"), + (0x1EEB, "V"), + (0x1EEC, "M", "ử"), + (0x1EED, "V"), + (0x1EEE, "M", "ữ"), + (0x1EEF, "V"), + (0x1EF0, "M", "ự"), + ] + + +def _seg_19() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EF1, "V"), + (0x1EF2, "M", "ỳ"), + (0x1EF3, "V"), + (0x1EF4, "M", "ỵ"), + (0x1EF5, "V"), + (0x1EF6, "M", "ỷ"), + (0x1EF7, "V"), + (0x1EF8, "M", "ỹ"), + (0x1EF9, "V"), + (0x1EFA, "M", "ỻ"), + (0x1EFB, "V"), + (0x1EFC, "M", "ỽ"), + (0x1EFD, "V"), + (0x1EFE, "M", "ỿ"), + (0x1EFF, "V"), + (0x1F08, "M", "ἀ"), + (0x1F09, "M", "ἁ"), + (0x1F0A, "M", "ἂ"), + (0x1F0B, "M", "ἃ"), + (0x1F0C, "M", "ἄ"), + (0x1F0D, "M", "ἅ"), + (0x1F0E, "M", "ἆ"), + (0x1F0F, "M", "ἇ"), + (0x1F10, "V"), + (0x1F16, "X"), + (0x1F18, "M", "ἐ"), + (0x1F19, "M", "ἑ"), + (0x1F1A, "M", "ἒ"), + (0x1F1B, "M", "ἓ"), + (0x1F1C, "M", "ἔ"), + (0x1F1D, "M", "ἕ"), + (0x1F1E, "X"), + (0x1F20, "V"), + (0x1F28, "M", "ἠ"), + (0x1F29, "M", "ἡ"), + (0x1F2A, "M", "ἢ"), + (0x1F2B, "M", "ἣ"), + (0x1F2C, "M", "ἤ"), + (0x1F2D, "M", "ἥ"), + (0x1F2E, "M", "ἦ"), + (0x1F2F, "M", "ἧ"), + (0x1F30, "V"), + (0x1F38, "M", "ἰ"), + (0x1F39, "M", "ἱ"), + (0x1F3A, "M", "ἲ"), + (0x1F3B, "M", "ἳ"), + (0x1F3C, "M", "ἴ"), + (0x1F3D, "M", "ἵ"), + (0x1F3E, "M", "ἶ"), + (0x1F3F, "M", "ἷ"), + (0x1F40, "V"), + (0x1F46, "X"), + (0x1F48, "M", "ὀ"), + (0x1F49, "M", "ὁ"), + (0x1F4A, "M", "ὂ"), + (0x1F4B, "M", "ὃ"), + (0x1F4C, "M", "ὄ"), + (0x1F4D, "M", "ὅ"), + (0x1F4E, "X"), + (0x1F50, "V"), + (0x1F58, "X"), + (0x1F59, "M", "ὑ"), + (0x1F5A, "X"), + (0x1F5B, "M", "ὓ"), + (0x1F5C, "X"), + (0x1F5D, "M", "ὕ"), + (0x1F5E, "X"), + (0x1F5F, "M", "ὗ"), + (0x1F60, "V"), + (0x1F68, "M", "ὠ"), + (0x1F69, "M", "ὡ"), + (0x1F6A, "M", "ὢ"), + (0x1F6B, "M", "ὣ"), + (0x1F6C, "M", "ὤ"), + (0x1F6D, "M", "ὥ"), + (0x1F6E, "M", "ὦ"), + (0x1F6F, "M", "ὧ"), + (0x1F70, "V"), + (0x1F71, "M", "ά"), + (0x1F72, "V"), + (0x1F73, "M", "έ"), + (0x1F74, "V"), + (0x1F75, "M", "ή"), + (0x1F76, "V"), + (0x1F77, "M", "ί"), + (0x1F78, "V"), + (0x1F79, "M", "ό"), + (0x1F7A, "V"), + (0x1F7B, "M", "ύ"), + (0x1F7C, "V"), + (0x1F7D, "M", "ώ"), + (0x1F7E, "X"), + (0x1F80, "M", "ἀι"), + (0x1F81, "M", "ἁι"), + (0x1F82, "M", "ἂι"), + (0x1F83, "M", "ἃι"), + (0x1F84, "M", "ἄι"), + (0x1F85, "M", "ἅι"), + (0x1F86, "M", "ἆι"), + (0x1F87, "M", "ἇι"), + ] + + +def _seg_20() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F88, "M", "ἀι"), + (0x1F89, "M", "ἁι"), + (0x1F8A, "M", "ἂι"), + (0x1F8B, "M", "ἃι"), + (0x1F8C, "M", "ἄι"), + (0x1F8D, "M", "ἅι"), + (0x1F8E, "M", "ἆι"), + (0x1F8F, "M", "ἇι"), + (0x1F90, "M", "ἠι"), + (0x1F91, "M", "ἡι"), + (0x1F92, "M", "ἢι"), + (0x1F93, "M", "ἣι"), + (0x1F94, "M", "ἤι"), + (0x1F95, "M", "ἥι"), + (0x1F96, "M", "ἦι"), + (0x1F97, "M", "ἧι"), + (0x1F98, "M", "ἠι"), + (0x1F99, "M", "ἡι"), + (0x1F9A, "M", "ἢι"), + (0x1F9B, "M", "ἣι"), + (0x1F9C, "M", "ἤι"), + (0x1F9D, "M", "ἥι"), + (0x1F9E, "M", "ἦι"), + (0x1F9F, "M", "ἧι"), + (0x1FA0, "M", "ὠι"), + (0x1FA1, "M", "ὡι"), + (0x1FA2, "M", "ὢι"), + (0x1FA3, "M", "ὣι"), + (0x1FA4, "M", "ὤι"), + (0x1FA5, "M", "ὥι"), + (0x1FA6, "M", "ὦι"), + (0x1FA7, "M", "ὧι"), + (0x1FA8, "M", "ὠι"), + (0x1FA9, "M", "ὡι"), + (0x1FAA, "M", "ὢι"), + (0x1FAB, "M", "ὣι"), + (0x1FAC, "M", "ὤι"), + (0x1FAD, "M", "ὥι"), + (0x1FAE, "M", "ὦι"), + (0x1FAF, "M", "ὧι"), + (0x1FB0, "V"), + (0x1FB2, "M", "ὰι"), + (0x1FB3, "M", "αι"), + (0x1FB4, "M", "άι"), + (0x1FB5, "X"), + (0x1FB6, "V"), + (0x1FB7, "M", "ᾶι"), + (0x1FB8, "M", "ᾰ"), + (0x1FB9, "M", "ᾱ"), + (0x1FBA, "M", "ὰ"), + (0x1FBB, "M", "ά"), + (0x1FBC, "M", "αι"), + (0x1FBD, "3", " ̓"), + (0x1FBE, "M", "ι"), + (0x1FBF, "3", " ̓"), + (0x1FC0, "3", " ͂"), + (0x1FC1, "3", " ̈͂"), + (0x1FC2, "M", "ὴι"), + (0x1FC3, "M", "ηι"), + (0x1FC4, "M", "ήι"), + (0x1FC5, "X"), + (0x1FC6, "V"), + (0x1FC7, "M", "ῆι"), + (0x1FC8, "M", "ὲ"), + (0x1FC9, "M", "έ"), + (0x1FCA, "M", "ὴ"), + (0x1FCB, "M", "ή"), + (0x1FCC, "M", "ηι"), + (0x1FCD, "3", " ̓̀"), + (0x1FCE, "3", " ̓́"), + (0x1FCF, "3", " ̓͂"), + (0x1FD0, "V"), + (0x1FD3, "M", "ΐ"), + (0x1FD4, "X"), + (0x1FD6, "V"), + (0x1FD8, "M", "ῐ"), + (0x1FD9, "M", "ῑ"), + (0x1FDA, "M", "ὶ"), + (0x1FDB, "M", "ί"), + (0x1FDC, "X"), + (0x1FDD, "3", " ̔̀"), + (0x1FDE, "3", " ̔́"), + (0x1FDF, "3", " ̔͂"), + (0x1FE0, "V"), + (0x1FE3, "M", "ΰ"), + (0x1FE4, "V"), + (0x1FE8, "M", "ῠ"), + (0x1FE9, "M", "ῡ"), + (0x1FEA, "M", "ὺ"), + (0x1FEB, "M", "ύ"), + (0x1FEC, "M", "ῥ"), + (0x1FED, "3", " ̈̀"), + (0x1FEE, "3", " ̈́"), + (0x1FEF, "3", "`"), + (0x1FF0, "X"), + (0x1FF2, "M", "ὼι"), + (0x1FF3, "M", "ωι"), + (0x1FF4, "M", "ώι"), + (0x1FF5, "X"), + (0x1FF6, "V"), + ] + + +def _seg_21() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1FF7, "M", "ῶι"), + (0x1FF8, "M", "ὸ"), + (0x1FF9, "M", "ό"), + (0x1FFA, "M", "ὼ"), + (0x1FFB, "M", "ώ"), + (0x1FFC, "M", "ωι"), + (0x1FFD, "3", " ́"), + (0x1FFE, "3", " ̔"), + (0x1FFF, "X"), + (0x2000, "3", " "), + (0x200B, "I"), + (0x200C, "D", ""), + (0x200E, "X"), + (0x2010, "V"), + (0x2011, "M", "‐"), + (0x2012, "V"), + (0x2017, "3", " ̳"), + (0x2018, "V"), + (0x2024, "X"), + (0x2027, "V"), + (0x2028, "X"), + (0x202F, "3", " "), + (0x2030, "V"), + (0x2033, "M", "′′"), + (0x2034, "M", "′′′"), + (0x2035, "V"), + (0x2036, "M", "‵‵"), + (0x2037, "M", "‵‵‵"), + (0x2038, "V"), + (0x203C, "3", "!!"), + (0x203D, "V"), + (0x203E, "3", " ̅"), + (0x203F, "V"), + (0x2047, "3", "??"), + (0x2048, "3", "?!"), + (0x2049, "3", "!?"), + (0x204A, "V"), + (0x2057, "M", "′′′′"), + (0x2058, "V"), + (0x205F, "3", " "), + (0x2060, "I"), + (0x2061, "X"), + (0x2064, "I"), + (0x2065, "X"), + (0x2070, "M", "0"), + (0x2071, "M", "i"), + (0x2072, "X"), + (0x2074, "M", "4"), + (0x2075, "M", "5"), + (0x2076, "M", "6"), + (0x2077, "M", "7"), + (0x2078, "M", "8"), + (0x2079, "M", "9"), + (0x207A, "3", "+"), + (0x207B, "M", "−"), + (0x207C, "3", "="), + (0x207D, "3", "("), + (0x207E, "3", ")"), + (0x207F, "M", "n"), + (0x2080, "M", "0"), + (0x2081, "M", "1"), + (0x2082, "M", "2"), + (0x2083, "M", "3"), + (0x2084, "M", "4"), + (0x2085, "M", "5"), + (0x2086, "M", "6"), + (0x2087, "M", "7"), + (0x2088, "M", "8"), + (0x2089, "M", "9"), + (0x208A, "3", "+"), + (0x208B, "M", "−"), + (0x208C, "3", "="), + (0x208D, "3", "("), + (0x208E, "3", ")"), + (0x208F, "X"), + (0x2090, "M", "a"), + (0x2091, "M", "e"), + (0x2092, "M", "o"), + (0x2093, "M", "x"), + (0x2094, "M", "ə"), + (0x2095, "M", "h"), + (0x2096, "M", "k"), + (0x2097, "M", "l"), + (0x2098, "M", "m"), + (0x2099, "M", "n"), + (0x209A, "M", "p"), + (0x209B, "M", "s"), + (0x209C, "M", "t"), + (0x209D, "X"), + (0x20A0, "V"), + (0x20A8, "M", "rs"), + (0x20A9, "V"), + (0x20C1, "X"), + (0x20D0, "V"), + (0x20F1, "X"), + (0x2100, "3", "a/c"), + (0x2101, "3", "a/s"), + (0x2102, "M", "c"), + (0x2103, "M", "°c"), + (0x2104, "V"), + ] + + +def _seg_22() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2105, "3", "c/o"), + (0x2106, "3", "c/u"), + (0x2107, "M", "ɛ"), + (0x2108, "V"), + (0x2109, "M", "°f"), + (0x210A, "M", "g"), + (0x210B, "M", "h"), + (0x210F, "M", "ħ"), + (0x2110, "M", "i"), + (0x2112, "M", "l"), + (0x2114, "V"), + (0x2115, "M", "n"), + (0x2116, "M", "no"), + (0x2117, "V"), + (0x2119, "M", "p"), + (0x211A, "M", "q"), + (0x211B, "M", "r"), + (0x211E, "V"), + (0x2120, "M", "sm"), + (0x2121, "M", "tel"), + (0x2122, "M", "tm"), + (0x2123, "V"), + (0x2124, "M", "z"), + (0x2125, "V"), + (0x2126, "M", "ω"), + (0x2127, "V"), + (0x2128, "M", "z"), + (0x2129, "V"), + (0x212A, "M", "k"), + (0x212B, "M", "å"), + (0x212C, "M", "b"), + (0x212D, "M", "c"), + (0x212E, "V"), + (0x212F, "M", "e"), + (0x2131, "M", "f"), + (0x2132, "X"), + (0x2133, "M", "m"), + (0x2134, "M", "o"), + (0x2135, "M", "א"), + (0x2136, "M", "ב"), + (0x2137, "M", "ג"), + (0x2138, "M", "ד"), + (0x2139, "M", "i"), + (0x213A, "V"), + (0x213B, "M", "fax"), + (0x213C, "M", "π"), + (0x213D, "M", "γ"), + (0x213F, "M", "π"), + (0x2140, "M", "∑"), + (0x2141, "V"), + (0x2145, "M", "d"), + (0x2147, "M", "e"), + (0x2148, "M", "i"), + (0x2149, "M", "j"), + (0x214A, "V"), + (0x2150, "M", "1⁄7"), + (0x2151, "M", "1⁄9"), + (0x2152, "M", "1⁄10"), + (0x2153, "M", "1⁄3"), + (0x2154, "M", "2⁄3"), + (0x2155, "M", "1⁄5"), + (0x2156, "M", "2⁄5"), + (0x2157, "M", "3⁄5"), + (0x2158, "M", "4⁄5"), + (0x2159, "M", "1⁄6"), + (0x215A, "M", "5⁄6"), + (0x215B, "M", "1⁄8"), + (0x215C, "M", "3⁄8"), + (0x215D, "M", "5⁄8"), + (0x215E, "M", "7⁄8"), + (0x215F, "M", "1⁄"), + (0x2160, "M", "i"), + (0x2161, "M", "ii"), + (0x2162, "M", "iii"), + (0x2163, "M", "iv"), + (0x2164, "M", "v"), + (0x2165, "M", "vi"), + (0x2166, "M", "vii"), + (0x2167, "M", "viii"), + (0x2168, "M", "ix"), + (0x2169, "M", "x"), + (0x216A, "M", "xi"), + (0x216B, "M", "xii"), + (0x216C, "M", "l"), + (0x216D, "M", "c"), + (0x216E, "M", "d"), + (0x216F, "M", "m"), + (0x2170, "M", "i"), + (0x2171, "M", "ii"), + (0x2172, "M", "iii"), + (0x2173, "M", "iv"), + (0x2174, "M", "v"), + (0x2175, "M", "vi"), + (0x2176, "M", "vii"), + (0x2177, "M", "viii"), + (0x2178, "M", "ix"), + (0x2179, "M", "x"), + (0x217A, "M", "xi"), + (0x217B, "M", "xii"), + (0x217C, "M", "l"), + ] + + +def _seg_23() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x217D, "M", "c"), + (0x217E, "M", "d"), + (0x217F, "M", "m"), + (0x2180, "V"), + (0x2183, "X"), + (0x2184, "V"), + (0x2189, "M", "0⁄3"), + (0x218A, "V"), + (0x218C, "X"), + (0x2190, "V"), + (0x222C, "M", "∫∫"), + (0x222D, "M", "∫∫∫"), + (0x222E, "V"), + (0x222F, "M", "∮∮"), + (0x2230, "M", "∮∮∮"), + (0x2231, "V"), + (0x2329, "M", "〈"), + (0x232A, "M", "〉"), + (0x232B, "V"), + (0x2427, "X"), + (0x2440, "V"), + (0x244B, "X"), + (0x2460, "M", "1"), + (0x2461, "M", "2"), + (0x2462, "M", "3"), + (0x2463, "M", "4"), + (0x2464, "M", "5"), + (0x2465, "M", "6"), + (0x2466, "M", "7"), + (0x2467, "M", "8"), + (0x2468, "M", "9"), + (0x2469, "M", "10"), + (0x246A, "M", "11"), + (0x246B, "M", "12"), + (0x246C, "M", "13"), + (0x246D, "M", "14"), + (0x246E, "M", "15"), + (0x246F, "M", "16"), + (0x2470, "M", "17"), + (0x2471, "M", "18"), + (0x2472, "M", "19"), + (0x2473, "M", "20"), + (0x2474, "3", "(1)"), + (0x2475, "3", "(2)"), + (0x2476, "3", "(3)"), + (0x2477, "3", "(4)"), + (0x2478, "3", "(5)"), + (0x2479, "3", "(6)"), + (0x247A, "3", "(7)"), + (0x247B, "3", "(8)"), + (0x247C, "3", "(9)"), + (0x247D, "3", "(10)"), + (0x247E, "3", "(11)"), + (0x247F, "3", "(12)"), + (0x2480, "3", "(13)"), + (0x2481, "3", "(14)"), + (0x2482, "3", "(15)"), + (0x2483, "3", "(16)"), + (0x2484, "3", "(17)"), + (0x2485, "3", "(18)"), + (0x2486, "3", "(19)"), + (0x2487, "3", "(20)"), + (0x2488, "X"), + (0x249C, "3", "(a)"), + (0x249D, "3", "(b)"), + (0x249E, "3", "(c)"), + (0x249F, "3", "(d)"), + (0x24A0, "3", "(e)"), + (0x24A1, "3", "(f)"), + (0x24A2, "3", "(g)"), + (0x24A3, "3", "(h)"), + (0x24A4, "3", "(i)"), + (0x24A5, "3", "(j)"), + (0x24A6, "3", "(k)"), + (0x24A7, "3", "(l)"), + (0x24A8, "3", "(m)"), + (0x24A9, "3", "(n)"), + (0x24AA, "3", "(o)"), + (0x24AB, "3", "(p)"), + (0x24AC, "3", "(q)"), + (0x24AD, "3", "(r)"), + (0x24AE, "3", "(s)"), + (0x24AF, "3", "(t)"), + (0x24B0, "3", "(u)"), + (0x24B1, "3", "(v)"), + (0x24B2, "3", "(w)"), + (0x24B3, "3", "(x)"), + (0x24B4, "3", "(y)"), + (0x24B5, "3", "(z)"), + (0x24B6, "M", "a"), + (0x24B7, "M", "b"), + (0x24B8, "M", "c"), + (0x24B9, "M", "d"), + (0x24BA, "M", "e"), + (0x24BB, "M", "f"), + (0x24BC, "M", "g"), + (0x24BD, "M", "h"), + (0x24BE, "M", "i"), + (0x24BF, "M", "j"), + (0x24C0, "M", "k"), + ] + + +def _seg_24() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x24C1, "M", "l"), + (0x24C2, "M", "m"), + (0x24C3, "M", "n"), + (0x24C4, "M", "o"), + (0x24C5, "M", "p"), + (0x24C6, "M", "q"), + (0x24C7, "M", "r"), + (0x24C8, "M", "s"), + (0x24C9, "M", "t"), + (0x24CA, "M", "u"), + (0x24CB, "M", "v"), + (0x24CC, "M", "w"), + (0x24CD, "M", "x"), + (0x24CE, "M", "y"), + (0x24CF, "M", "z"), + (0x24D0, "M", "a"), + (0x24D1, "M", "b"), + (0x24D2, "M", "c"), + (0x24D3, "M", "d"), + (0x24D4, "M", "e"), + (0x24D5, "M", "f"), + (0x24D6, "M", "g"), + (0x24D7, "M", "h"), + (0x24D8, "M", "i"), + (0x24D9, "M", "j"), + (0x24DA, "M", "k"), + (0x24DB, "M", "l"), + (0x24DC, "M", "m"), + (0x24DD, "M", "n"), + (0x24DE, "M", "o"), + (0x24DF, "M", "p"), + (0x24E0, "M", "q"), + (0x24E1, "M", "r"), + (0x24E2, "M", "s"), + (0x24E3, "M", "t"), + (0x24E4, "M", "u"), + (0x24E5, "M", "v"), + (0x24E6, "M", "w"), + (0x24E7, "M", "x"), + (0x24E8, "M", "y"), + (0x24E9, "M", "z"), + (0x24EA, "M", "0"), + (0x24EB, "V"), + (0x2A0C, "M", "∫∫∫∫"), + (0x2A0D, "V"), + (0x2A74, "3", "::="), + (0x2A75, "3", "=="), + (0x2A76, "3", "==="), + (0x2A77, "V"), + (0x2ADC, "M", "⫝̸"), + (0x2ADD, "V"), + (0x2B74, "X"), + (0x2B76, "V"), + (0x2B96, "X"), + (0x2B97, "V"), + (0x2C00, "M", "ⰰ"), + (0x2C01, "M", "ⰱ"), + (0x2C02, "M", "ⰲ"), + (0x2C03, "M", "ⰳ"), + (0x2C04, "M", "ⰴ"), + (0x2C05, "M", "ⰵ"), + (0x2C06, "M", "ⰶ"), + (0x2C07, "M", "ⰷ"), + (0x2C08, "M", "ⰸ"), + (0x2C09, "M", "ⰹ"), + (0x2C0A, "M", "ⰺ"), + (0x2C0B, "M", "ⰻ"), + (0x2C0C, "M", "ⰼ"), + (0x2C0D, "M", "ⰽ"), + (0x2C0E, "M", "ⰾ"), + (0x2C0F, "M", "ⰿ"), + (0x2C10, "M", "ⱀ"), + (0x2C11, "M", "ⱁ"), + (0x2C12, "M", "ⱂ"), + (0x2C13, "M", "ⱃ"), + (0x2C14, "M", "ⱄ"), + (0x2C15, "M", "ⱅ"), + (0x2C16, "M", "ⱆ"), + (0x2C17, "M", "ⱇ"), + (0x2C18, "M", "ⱈ"), + (0x2C19, "M", "ⱉ"), + (0x2C1A, "M", "ⱊ"), + (0x2C1B, "M", "ⱋ"), + (0x2C1C, "M", "ⱌ"), + (0x2C1D, "M", "ⱍ"), + (0x2C1E, "M", "ⱎ"), + (0x2C1F, "M", "ⱏ"), + (0x2C20, "M", "ⱐ"), + (0x2C21, "M", "ⱑ"), + (0x2C22, "M", "ⱒ"), + (0x2C23, "M", "ⱓ"), + (0x2C24, "M", "ⱔ"), + (0x2C25, "M", "ⱕ"), + (0x2C26, "M", "ⱖ"), + (0x2C27, "M", "ⱗ"), + (0x2C28, "M", "ⱘ"), + (0x2C29, "M", "ⱙ"), + (0x2C2A, "M", "ⱚ"), + (0x2C2B, "M", "ⱛ"), + (0x2C2C, "M", "ⱜ"), + ] + + +def _seg_25() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2C2D, "M", "ⱝ"), + (0x2C2E, "M", "ⱞ"), + (0x2C2F, "M", "ⱟ"), + (0x2C30, "V"), + (0x2C60, "M", "ⱡ"), + (0x2C61, "V"), + (0x2C62, "M", "ɫ"), + (0x2C63, "M", "ᵽ"), + (0x2C64, "M", "ɽ"), + (0x2C65, "V"), + (0x2C67, "M", "ⱨ"), + (0x2C68, "V"), + (0x2C69, "M", "ⱪ"), + (0x2C6A, "V"), + (0x2C6B, "M", "ⱬ"), + (0x2C6C, "V"), + (0x2C6D, "M", "ɑ"), + (0x2C6E, "M", "ɱ"), + (0x2C6F, "M", "ɐ"), + (0x2C70, "M", "ɒ"), + (0x2C71, "V"), + (0x2C72, "M", "ⱳ"), + (0x2C73, "V"), + (0x2C75, "M", "ⱶ"), + (0x2C76, "V"), + (0x2C7C, "M", "j"), + (0x2C7D, "M", "v"), + (0x2C7E, "M", "ȿ"), + (0x2C7F, "M", "ɀ"), + (0x2C80, "M", "ⲁ"), + (0x2C81, "V"), + (0x2C82, "M", "ⲃ"), + (0x2C83, "V"), + (0x2C84, "M", "ⲅ"), + (0x2C85, "V"), + (0x2C86, "M", "ⲇ"), + (0x2C87, "V"), + (0x2C88, "M", "ⲉ"), + (0x2C89, "V"), + (0x2C8A, "M", "ⲋ"), + (0x2C8B, "V"), + (0x2C8C, "M", "ⲍ"), + (0x2C8D, "V"), + (0x2C8E, "M", "ⲏ"), + (0x2C8F, "V"), + (0x2C90, "M", "ⲑ"), + (0x2C91, "V"), + (0x2C92, "M", "ⲓ"), + (0x2C93, "V"), + (0x2C94, "M", "ⲕ"), + (0x2C95, "V"), + (0x2C96, "M", "ⲗ"), + (0x2C97, "V"), + (0x2C98, "M", "ⲙ"), + (0x2C99, "V"), + (0x2C9A, "M", "ⲛ"), + (0x2C9B, "V"), + (0x2C9C, "M", "ⲝ"), + (0x2C9D, "V"), + (0x2C9E, "M", "ⲟ"), + (0x2C9F, "V"), + (0x2CA0, "M", "ⲡ"), + (0x2CA1, "V"), + (0x2CA2, "M", "ⲣ"), + (0x2CA3, "V"), + (0x2CA4, "M", "ⲥ"), + (0x2CA5, "V"), + (0x2CA6, "M", "ⲧ"), + (0x2CA7, "V"), + (0x2CA8, "M", "ⲩ"), + (0x2CA9, "V"), + (0x2CAA, "M", "ⲫ"), + (0x2CAB, "V"), + (0x2CAC, "M", "ⲭ"), + (0x2CAD, "V"), + (0x2CAE, "M", "ⲯ"), + (0x2CAF, "V"), + (0x2CB0, "M", "ⲱ"), + (0x2CB1, "V"), + (0x2CB2, "M", "ⲳ"), + (0x2CB3, "V"), + (0x2CB4, "M", "ⲵ"), + (0x2CB5, "V"), + (0x2CB6, "M", "ⲷ"), + (0x2CB7, "V"), + (0x2CB8, "M", "ⲹ"), + (0x2CB9, "V"), + (0x2CBA, "M", "ⲻ"), + (0x2CBB, "V"), + (0x2CBC, "M", "ⲽ"), + (0x2CBD, "V"), + (0x2CBE, "M", "ⲿ"), + (0x2CBF, "V"), + (0x2CC0, "M", "ⳁ"), + (0x2CC1, "V"), + (0x2CC2, "M", "ⳃ"), + (0x2CC3, "V"), + (0x2CC4, "M", "ⳅ"), + (0x2CC5, "V"), + (0x2CC6, "M", "ⳇ"), + ] + + +def _seg_26() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2CC7, "V"), + (0x2CC8, "M", "ⳉ"), + (0x2CC9, "V"), + (0x2CCA, "M", "ⳋ"), + (0x2CCB, "V"), + (0x2CCC, "M", "ⳍ"), + (0x2CCD, "V"), + (0x2CCE, "M", "ⳏ"), + (0x2CCF, "V"), + (0x2CD0, "M", "ⳑ"), + (0x2CD1, "V"), + (0x2CD2, "M", "ⳓ"), + (0x2CD3, "V"), + (0x2CD4, "M", "ⳕ"), + (0x2CD5, "V"), + (0x2CD6, "M", "ⳗ"), + (0x2CD7, "V"), + (0x2CD8, "M", "ⳙ"), + (0x2CD9, "V"), + (0x2CDA, "M", "ⳛ"), + (0x2CDB, "V"), + (0x2CDC, "M", "ⳝ"), + (0x2CDD, "V"), + (0x2CDE, "M", "ⳟ"), + (0x2CDF, "V"), + (0x2CE0, "M", "ⳡ"), + (0x2CE1, "V"), + (0x2CE2, "M", "ⳣ"), + (0x2CE3, "V"), + (0x2CEB, "M", "ⳬ"), + (0x2CEC, "V"), + (0x2CED, "M", "ⳮ"), + (0x2CEE, "V"), + (0x2CF2, "M", "ⳳ"), + (0x2CF3, "V"), + (0x2CF4, "X"), + (0x2CF9, "V"), + (0x2D26, "X"), + (0x2D27, "V"), + (0x2D28, "X"), + (0x2D2D, "V"), + (0x2D2E, "X"), + (0x2D30, "V"), + (0x2D68, "X"), + (0x2D6F, "M", "ⵡ"), + (0x2D70, "V"), + (0x2D71, "X"), + (0x2D7F, "V"), + (0x2D97, "X"), + (0x2DA0, "V"), + (0x2DA7, "X"), + (0x2DA8, "V"), + (0x2DAF, "X"), + (0x2DB0, "V"), + (0x2DB7, "X"), + (0x2DB8, "V"), + (0x2DBF, "X"), + (0x2DC0, "V"), + (0x2DC7, "X"), + (0x2DC8, "V"), + (0x2DCF, "X"), + (0x2DD0, "V"), + (0x2DD7, "X"), + (0x2DD8, "V"), + (0x2DDF, "X"), + (0x2DE0, "V"), + (0x2E5E, "X"), + (0x2E80, "V"), + (0x2E9A, "X"), + (0x2E9B, "V"), + (0x2E9F, "M", "母"), + (0x2EA0, "V"), + (0x2EF3, "M", "龟"), + (0x2EF4, "X"), + (0x2F00, "M", "一"), + (0x2F01, "M", "丨"), + (0x2F02, "M", "丶"), + (0x2F03, "M", "丿"), + (0x2F04, "M", "乙"), + (0x2F05, "M", "亅"), + (0x2F06, "M", "二"), + (0x2F07, "M", "亠"), + (0x2F08, "M", "人"), + (0x2F09, "M", "儿"), + (0x2F0A, "M", "入"), + (0x2F0B, "M", "八"), + (0x2F0C, "M", "冂"), + (0x2F0D, "M", "冖"), + (0x2F0E, "M", "冫"), + (0x2F0F, "M", "几"), + (0x2F10, "M", "凵"), + (0x2F11, "M", "刀"), + (0x2F12, "M", "力"), + (0x2F13, "M", "勹"), + (0x2F14, "M", "匕"), + (0x2F15, "M", "匚"), + (0x2F16, "M", "匸"), + (0x2F17, "M", "十"), + (0x2F18, "M", "卜"), + (0x2F19, "M", "卩"), + ] + + +def _seg_27() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F1A, "M", "厂"), + (0x2F1B, "M", "厶"), + (0x2F1C, "M", "又"), + (0x2F1D, "M", "口"), + (0x2F1E, "M", "囗"), + (0x2F1F, "M", "土"), + (0x2F20, "M", "士"), + (0x2F21, "M", "夂"), + (0x2F22, "M", "夊"), + (0x2F23, "M", "夕"), + (0x2F24, "M", "大"), + (0x2F25, "M", "女"), + (0x2F26, "M", "子"), + (0x2F27, "M", "宀"), + (0x2F28, "M", "寸"), + (0x2F29, "M", "小"), + (0x2F2A, "M", "尢"), + (0x2F2B, "M", "尸"), + (0x2F2C, "M", "屮"), + (0x2F2D, "M", "山"), + (0x2F2E, "M", "巛"), + (0x2F2F, "M", "工"), + (0x2F30, "M", "己"), + (0x2F31, "M", "巾"), + (0x2F32, "M", "干"), + (0x2F33, "M", "幺"), + (0x2F34, "M", "广"), + (0x2F35, "M", "廴"), + (0x2F36, "M", "廾"), + (0x2F37, "M", "弋"), + (0x2F38, "M", "弓"), + (0x2F39, "M", "彐"), + (0x2F3A, "M", "彡"), + (0x2F3B, "M", "彳"), + (0x2F3C, "M", "心"), + (0x2F3D, "M", "戈"), + (0x2F3E, "M", "戶"), + (0x2F3F, "M", "手"), + (0x2F40, "M", "支"), + (0x2F41, "M", "攴"), + (0x2F42, "M", "文"), + (0x2F43, "M", "斗"), + (0x2F44, "M", "斤"), + (0x2F45, "M", "方"), + (0x2F46, "M", "无"), + (0x2F47, "M", "日"), + (0x2F48, "M", "曰"), + (0x2F49, "M", "月"), + (0x2F4A, "M", "木"), + (0x2F4B, "M", "欠"), + (0x2F4C, "M", "止"), + (0x2F4D, "M", "歹"), + (0x2F4E, "M", "殳"), + (0x2F4F, "M", "毋"), + (0x2F50, "M", "比"), + (0x2F51, "M", "毛"), + (0x2F52, "M", "氏"), + (0x2F53, "M", "气"), + (0x2F54, "M", "水"), + (0x2F55, "M", "火"), + (0x2F56, "M", "爪"), + (0x2F57, "M", "父"), + (0x2F58, "M", "爻"), + (0x2F59, "M", "爿"), + (0x2F5A, "M", "片"), + (0x2F5B, "M", "牙"), + (0x2F5C, "M", "牛"), + (0x2F5D, "M", "犬"), + (0x2F5E, "M", "玄"), + (0x2F5F, "M", "玉"), + (0x2F60, "M", "瓜"), + (0x2F61, "M", "瓦"), + (0x2F62, "M", "甘"), + (0x2F63, "M", "生"), + (0x2F64, "M", "用"), + (0x2F65, "M", "田"), + (0x2F66, "M", "疋"), + (0x2F67, "M", "疒"), + (0x2F68, "M", "癶"), + (0x2F69, "M", "白"), + (0x2F6A, "M", "皮"), + (0x2F6B, "M", "皿"), + (0x2F6C, "M", "目"), + (0x2F6D, "M", "矛"), + (0x2F6E, "M", "矢"), + (0x2F6F, "M", "石"), + (0x2F70, "M", "示"), + (0x2F71, "M", "禸"), + (0x2F72, "M", "禾"), + (0x2F73, "M", "穴"), + (0x2F74, "M", "立"), + (0x2F75, "M", "竹"), + (0x2F76, "M", "米"), + (0x2F77, "M", "糸"), + (0x2F78, "M", "缶"), + (0x2F79, "M", "网"), + (0x2F7A, "M", "羊"), + (0x2F7B, "M", "羽"), + (0x2F7C, "M", "老"), + (0x2F7D, "M", "而"), + ] + + +def _seg_28() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F7E, "M", "耒"), + (0x2F7F, "M", "耳"), + (0x2F80, "M", "聿"), + (0x2F81, "M", "肉"), + (0x2F82, "M", "臣"), + (0x2F83, "M", "自"), + (0x2F84, "M", "至"), + (0x2F85, "M", "臼"), + (0x2F86, "M", "舌"), + (0x2F87, "M", "舛"), + (0x2F88, "M", "舟"), + (0x2F89, "M", "艮"), + (0x2F8A, "M", "色"), + (0x2F8B, "M", "艸"), + (0x2F8C, "M", "虍"), + (0x2F8D, "M", "虫"), + (0x2F8E, "M", "血"), + (0x2F8F, "M", "行"), + (0x2F90, "M", "衣"), + (0x2F91, "M", "襾"), + (0x2F92, "M", "見"), + (0x2F93, "M", "角"), + (0x2F94, "M", "言"), + (0x2F95, "M", "谷"), + (0x2F96, "M", "豆"), + (0x2F97, "M", "豕"), + (0x2F98, "M", "豸"), + (0x2F99, "M", "貝"), + (0x2F9A, "M", "赤"), + (0x2F9B, "M", "走"), + (0x2F9C, "M", "足"), + (0x2F9D, "M", "身"), + (0x2F9E, "M", "車"), + (0x2F9F, "M", "辛"), + (0x2FA0, "M", "辰"), + (0x2FA1, "M", "辵"), + (0x2FA2, "M", "邑"), + (0x2FA3, "M", "酉"), + (0x2FA4, "M", "釆"), + (0x2FA5, "M", "里"), + (0x2FA6, "M", "金"), + (0x2FA7, "M", "長"), + (0x2FA8, "M", "門"), + (0x2FA9, "M", "阜"), + (0x2FAA, "M", "隶"), + (0x2FAB, "M", "隹"), + (0x2FAC, "M", "雨"), + (0x2FAD, "M", "靑"), + (0x2FAE, "M", "非"), + (0x2FAF, "M", "面"), + (0x2FB0, "M", "革"), + (0x2FB1, "M", "韋"), + (0x2FB2, "M", "韭"), + (0x2FB3, "M", "音"), + (0x2FB4, "M", "頁"), + (0x2FB5, "M", "風"), + (0x2FB6, "M", "飛"), + (0x2FB7, "M", "食"), + (0x2FB8, "M", "首"), + (0x2FB9, "M", "香"), + (0x2FBA, "M", "馬"), + (0x2FBB, "M", "骨"), + (0x2FBC, "M", "高"), + (0x2FBD, "M", "髟"), + (0x2FBE, "M", "鬥"), + (0x2FBF, "M", "鬯"), + (0x2FC0, "M", "鬲"), + (0x2FC1, "M", "鬼"), + (0x2FC2, "M", "魚"), + (0x2FC3, "M", "鳥"), + (0x2FC4, "M", "鹵"), + (0x2FC5, "M", "鹿"), + (0x2FC6, "M", "麥"), + (0x2FC7, "M", "麻"), + (0x2FC8, "M", "黃"), + (0x2FC9, "M", "黍"), + (0x2FCA, "M", "黑"), + (0x2FCB, "M", "黹"), + (0x2FCC, "M", "黽"), + (0x2FCD, "M", "鼎"), + (0x2FCE, "M", "鼓"), + (0x2FCF, "M", "鼠"), + (0x2FD0, "M", "鼻"), + (0x2FD1, "M", "齊"), + (0x2FD2, "M", "齒"), + (0x2FD3, "M", "龍"), + (0x2FD4, "M", "龜"), + (0x2FD5, "M", "龠"), + (0x2FD6, "X"), + (0x3000, "3", " "), + (0x3001, "V"), + (0x3002, "M", "."), + (0x3003, "V"), + (0x3036, "M", "〒"), + (0x3037, "V"), + (0x3038, "M", "十"), + (0x3039, "M", "卄"), + (0x303A, "M", "卅"), + (0x303B, "V"), + (0x3040, "X"), + ] + + +def _seg_29() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3041, "V"), + (0x3097, "X"), + (0x3099, "V"), + (0x309B, "3", " ゙"), + (0x309C, "3", " ゚"), + (0x309D, "V"), + (0x309F, "M", "より"), + (0x30A0, "V"), + (0x30FF, "M", "コト"), + (0x3100, "X"), + (0x3105, "V"), + (0x3130, "X"), + (0x3131, "M", "ᄀ"), + (0x3132, "M", "ᄁ"), + (0x3133, "M", "ᆪ"), + (0x3134, "M", "ᄂ"), + (0x3135, "M", "ᆬ"), + (0x3136, "M", "ᆭ"), + (0x3137, "M", "ᄃ"), + (0x3138, "M", "ᄄ"), + (0x3139, "M", "ᄅ"), + (0x313A, "M", "ᆰ"), + (0x313B, "M", "ᆱ"), + (0x313C, "M", "ᆲ"), + (0x313D, "M", "ᆳ"), + (0x313E, "M", "ᆴ"), + (0x313F, "M", "ᆵ"), + (0x3140, "M", "ᄚ"), + (0x3141, "M", "ᄆ"), + (0x3142, "M", "ᄇ"), + (0x3143, "M", "ᄈ"), + (0x3144, "M", "ᄡ"), + (0x3145, "M", "ᄉ"), + (0x3146, "M", "ᄊ"), + (0x3147, "M", "ᄋ"), + (0x3148, "M", "ᄌ"), + (0x3149, "M", "ᄍ"), + (0x314A, "M", "ᄎ"), + (0x314B, "M", "ᄏ"), + (0x314C, "M", "ᄐ"), + (0x314D, "M", "ᄑ"), + (0x314E, "M", "ᄒ"), + (0x314F, "M", "ᅡ"), + (0x3150, "M", "ᅢ"), + (0x3151, "M", "ᅣ"), + (0x3152, "M", "ᅤ"), + (0x3153, "M", "ᅥ"), + (0x3154, "M", "ᅦ"), + (0x3155, "M", "ᅧ"), + (0x3156, "M", "ᅨ"), + (0x3157, "M", "ᅩ"), + (0x3158, "M", "ᅪ"), + (0x3159, "M", "ᅫ"), + (0x315A, "M", "ᅬ"), + (0x315B, "M", "ᅭ"), + (0x315C, "M", "ᅮ"), + (0x315D, "M", "ᅯ"), + (0x315E, "M", "ᅰ"), + (0x315F, "M", "ᅱ"), + (0x3160, "M", "ᅲ"), + (0x3161, "M", "ᅳ"), + (0x3162, "M", "ᅴ"), + (0x3163, "M", "ᅵ"), + (0x3164, "X"), + (0x3165, "M", "ᄔ"), + (0x3166, "M", "ᄕ"), + (0x3167, "M", "ᇇ"), + (0x3168, "M", "ᇈ"), + (0x3169, "M", "ᇌ"), + (0x316A, "M", "ᇎ"), + (0x316B, "M", "ᇓ"), + (0x316C, "M", "ᇗ"), + (0x316D, "M", "ᇙ"), + (0x316E, "M", "ᄜ"), + (0x316F, "M", "ᇝ"), + (0x3170, "M", "ᇟ"), + (0x3171, "M", "ᄝ"), + (0x3172, "M", "ᄞ"), + (0x3173, "M", "ᄠ"), + (0x3174, "M", "ᄢ"), + (0x3175, "M", "ᄣ"), + (0x3176, "M", "ᄧ"), + (0x3177, "M", "ᄩ"), + (0x3178, "M", "ᄫ"), + (0x3179, "M", "ᄬ"), + (0x317A, "M", "ᄭ"), + (0x317B, "M", "ᄮ"), + (0x317C, "M", "ᄯ"), + (0x317D, "M", "ᄲ"), + (0x317E, "M", "ᄶ"), + (0x317F, "M", "ᅀ"), + (0x3180, "M", "ᅇ"), + (0x3181, "M", "ᅌ"), + (0x3182, "M", "ᇱ"), + (0x3183, "M", "ᇲ"), + (0x3184, "M", "ᅗ"), + (0x3185, "M", "ᅘ"), + (0x3186, "M", "ᅙ"), + (0x3187, "M", "ᆄ"), + (0x3188, "M", "ᆅ"), + ] + + +def _seg_30() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3189, "M", "ᆈ"), + (0x318A, "M", "ᆑ"), + (0x318B, "M", "ᆒ"), + (0x318C, "M", "ᆔ"), + (0x318D, "M", "ᆞ"), + (0x318E, "M", "ᆡ"), + (0x318F, "X"), + (0x3190, "V"), + (0x3192, "M", "一"), + (0x3193, "M", "二"), + (0x3194, "M", "三"), + (0x3195, "M", "四"), + (0x3196, "M", "上"), + (0x3197, "M", "中"), + (0x3198, "M", "下"), + (0x3199, "M", "甲"), + (0x319A, "M", "乙"), + (0x319B, "M", "丙"), + (0x319C, "M", "丁"), + (0x319D, "M", "天"), + (0x319E, "M", "地"), + (0x319F, "M", "人"), + (0x31A0, "V"), + (0x31E4, "X"), + (0x31F0, "V"), + (0x3200, "3", "(ᄀ)"), + (0x3201, "3", "(ᄂ)"), + (0x3202, "3", "(ᄃ)"), + (0x3203, "3", "(ᄅ)"), + (0x3204, "3", "(ᄆ)"), + (0x3205, "3", "(ᄇ)"), + (0x3206, "3", "(ᄉ)"), + (0x3207, "3", "(ᄋ)"), + (0x3208, "3", "(ᄌ)"), + (0x3209, "3", "(ᄎ)"), + (0x320A, "3", "(ᄏ)"), + (0x320B, "3", "(ᄐ)"), + (0x320C, "3", "(ᄑ)"), + (0x320D, "3", "(ᄒ)"), + (0x320E, "3", "(가)"), + (0x320F, "3", "(나)"), + (0x3210, "3", "(다)"), + (0x3211, "3", "(라)"), + (0x3212, "3", "(마)"), + (0x3213, "3", "(바)"), + (0x3214, "3", "(사)"), + (0x3215, "3", "(아)"), + (0x3216, "3", "(자)"), + (0x3217, "3", "(차)"), + (0x3218, "3", "(카)"), + (0x3219, "3", "(타)"), + (0x321A, "3", "(파)"), + (0x321B, "3", "(하)"), + (0x321C, "3", "(주)"), + (0x321D, "3", "(오전)"), + (0x321E, "3", "(오후)"), + (0x321F, "X"), + (0x3220, "3", "(一)"), + (0x3221, "3", "(二)"), + (0x3222, "3", "(三)"), + (0x3223, "3", "(四)"), + (0x3224, "3", "(五)"), + (0x3225, "3", "(六)"), + (0x3226, "3", "(七)"), + (0x3227, "3", "(八)"), + (0x3228, "3", "(九)"), + (0x3229, "3", "(十)"), + (0x322A, "3", "(月)"), + (0x322B, "3", "(火)"), + (0x322C, "3", "(水)"), + (0x322D, "3", "(木)"), + (0x322E, "3", "(金)"), + (0x322F, "3", "(土)"), + (0x3230, "3", "(日)"), + (0x3231, "3", "(株)"), + (0x3232, "3", "(有)"), + (0x3233, "3", "(社)"), + (0x3234, "3", "(名)"), + (0x3235, "3", "(特)"), + (0x3236, "3", "(財)"), + (0x3237, "3", "(祝)"), + (0x3238, "3", "(労)"), + (0x3239, "3", "(代)"), + (0x323A, "3", "(呼)"), + (0x323B, "3", "(学)"), + (0x323C, "3", "(監)"), + (0x323D, "3", "(企)"), + (0x323E, "3", "(資)"), + (0x323F, "3", "(協)"), + (0x3240, "3", "(祭)"), + (0x3241, "3", "(休)"), + (0x3242, "3", "(自)"), + (0x3243, "3", "(至)"), + (0x3244, "M", "問"), + (0x3245, "M", "幼"), + (0x3246, "M", "文"), + (0x3247, "M", "箏"), + (0x3248, "V"), + (0x3250, "M", "pte"), + (0x3251, "M", "21"), + ] + + +def _seg_31() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x3252, "M", "22"), + (0x3253, "M", "23"), + (0x3254, "M", "24"), + (0x3255, "M", "25"), + (0x3256, "M", "26"), + (0x3257, "M", "27"), + (0x3258, "M", "28"), + (0x3259, "M", "29"), + (0x325A, "M", "30"), + (0x325B, "M", "31"), + (0x325C, "M", "32"), + (0x325D, "M", "33"), + (0x325E, "M", "34"), + (0x325F, "M", "35"), + (0x3260, "M", "ᄀ"), + (0x3261, "M", "ᄂ"), + (0x3262, "M", "ᄃ"), + (0x3263, "M", "ᄅ"), + (0x3264, "M", "ᄆ"), + (0x3265, "M", "ᄇ"), + (0x3266, "M", "ᄉ"), + (0x3267, "M", "ᄋ"), + (0x3268, "M", "ᄌ"), + (0x3269, "M", "ᄎ"), + (0x326A, "M", "ᄏ"), + (0x326B, "M", "ᄐ"), + (0x326C, "M", "ᄑ"), + (0x326D, "M", "ᄒ"), + (0x326E, "M", "가"), + (0x326F, "M", "나"), + (0x3270, "M", "다"), + (0x3271, "M", "라"), + (0x3272, "M", "마"), + (0x3273, "M", "바"), + (0x3274, "M", "사"), + (0x3275, "M", "아"), + (0x3276, "M", "자"), + (0x3277, "M", "차"), + (0x3278, "M", "카"), + (0x3279, "M", "타"), + (0x327A, "M", "파"), + (0x327B, "M", "하"), + (0x327C, "M", "참고"), + (0x327D, "M", "주의"), + (0x327E, "M", "우"), + (0x327F, "V"), + (0x3280, "M", "一"), + (0x3281, "M", "二"), + (0x3282, "M", "三"), + (0x3283, "M", "四"), + (0x3284, "M", "五"), + (0x3285, "M", "六"), + (0x3286, "M", "七"), + (0x3287, "M", "八"), + (0x3288, "M", "九"), + (0x3289, "M", "十"), + (0x328A, "M", "月"), + (0x328B, "M", "火"), + (0x328C, "M", "水"), + (0x328D, "M", "木"), + (0x328E, "M", "金"), + (0x328F, "M", "土"), + (0x3290, "M", "日"), + (0x3291, "M", "株"), + (0x3292, "M", "有"), + (0x3293, "M", "社"), + (0x3294, "M", "名"), + (0x3295, "M", "特"), + (0x3296, "M", "財"), + (0x3297, "M", "祝"), + (0x3298, "M", "労"), + (0x3299, "M", "秘"), + (0x329A, "M", "男"), + (0x329B, "M", "女"), + (0x329C, "M", "適"), + (0x329D, "M", "優"), + (0x329E, "M", "印"), + (0x329F, "M", "注"), + (0x32A0, "M", "項"), + (0x32A1, "M", "休"), + (0x32A2, "M", "写"), + (0x32A3, "M", "正"), + (0x32A4, "M", "上"), + (0x32A5, "M", "中"), + (0x32A6, "M", "下"), + (0x32A7, "M", "左"), + (0x32A8, "M", "右"), + (0x32A9, "M", "医"), + (0x32AA, "M", "宗"), + (0x32AB, "M", "学"), + (0x32AC, "M", "監"), + (0x32AD, "M", "企"), + (0x32AE, "M", "資"), + (0x32AF, "M", "協"), + (0x32B0, "M", "夜"), + (0x32B1, "M", "36"), + (0x32B2, "M", "37"), + (0x32B3, "M", "38"), + (0x32B4, "M", "39"), + (0x32B5, "M", "40"), + ] + + +def _seg_32() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x32B6, "M", "41"), + (0x32B7, "M", "42"), + (0x32B8, "M", "43"), + (0x32B9, "M", "44"), + (0x32BA, "M", "45"), + (0x32BB, "M", "46"), + (0x32BC, "M", "47"), + (0x32BD, "M", "48"), + (0x32BE, "M", "49"), + (0x32BF, "M", "50"), + (0x32C0, "M", "1月"), + (0x32C1, "M", "2月"), + (0x32C2, "M", "3月"), + (0x32C3, "M", "4月"), + (0x32C4, "M", "5月"), + (0x32C5, "M", "6月"), + (0x32C6, "M", "7月"), + (0x32C7, "M", "8月"), + (0x32C8, "M", "9月"), + (0x32C9, "M", "10月"), + (0x32CA, "M", "11月"), + (0x32CB, "M", "12月"), + (0x32CC, "M", "hg"), + (0x32CD, "M", "erg"), + (0x32CE, "M", "ev"), + (0x32CF, "M", "ltd"), + (0x32D0, "M", "ア"), + (0x32D1, "M", "イ"), + (0x32D2, "M", "ウ"), + (0x32D3, "M", "エ"), + (0x32D4, "M", "オ"), + (0x32D5, "M", "カ"), + (0x32D6, "M", "キ"), + (0x32D7, "M", "ク"), + (0x32D8, "M", "ケ"), + (0x32D9, "M", "コ"), + (0x32DA, "M", "サ"), + (0x32DB, "M", "シ"), + (0x32DC, "M", "ス"), + (0x32DD, "M", "セ"), + (0x32DE, "M", "ソ"), + (0x32DF, "M", "タ"), + (0x32E0, "M", "チ"), + (0x32E1, "M", "ツ"), + (0x32E2, "M", "テ"), + (0x32E3, "M", "ト"), + (0x32E4, "M", "ナ"), + (0x32E5, "M", "ニ"), + (0x32E6, "M", "ヌ"), + (0x32E7, "M", "ネ"), + (0x32E8, "M", "ノ"), + (0x32E9, "M", "ハ"), + (0x32EA, "M", "ヒ"), + (0x32EB, "M", "フ"), + (0x32EC, "M", "ヘ"), + (0x32ED, "M", "ホ"), + (0x32EE, "M", "マ"), + (0x32EF, "M", "ミ"), + (0x32F0, "M", "ム"), + (0x32F1, "M", "メ"), + (0x32F2, "M", "モ"), + (0x32F3, "M", "ヤ"), + (0x32F4, "M", "ユ"), + (0x32F5, "M", "ヨ"), + (0x32F6, "M", "ラ"), + (0x32F7, "M", "リ"), + (0x32F8, "M", "ル"), + (0x32F9, "M", "レ"), + (0x32FA, "M", "ロ"), + (0x32FB, "M", "ワ"), + (0x32FC, "M", "ヰ"), + (0x32FD, "M", "ヱ"), + (0x32FE, "M", "ヲ"), + (0x32FF, "M", "令和"), + (0x3300, "M", "アパート"), + (0x3301, "M", "アルファ"), + (0x3302, "M", "アンペア"), + (0x3303, "M", "アール"), + (0x3304, "M", "イニング"), + (0x3305, "M", "インチ"), + (0x3306, "M", "ウォン"), + (0x3307, "M", "エスクード"), + (0x3308, "M", "エーカー"), + (0x3309, "M", "オンス"), + (0x330A, "M", "オーム"), + (0x330B, "M", "カイリ"), + (0x330C, "M", "カラット"), + (0x330D, "M", "カロリー"), + (0x330E, "M", "ガロン"), + (0x330F, "M", "ガンマ"), + (0x3310, "M", "ギガ"), + (0x3311, "M", "ギニー"), + (0x3312, "M", "キュリー"), + (0x3313, "M", "ギルダー"), + (0x3314, "M", "キロ"), + (0x3315, "M", "キログラム"), + (0x3316, "M", "キロメートル"), + (0x3317, "M", "キロワット"), + (0x3318, "M", "グラム"), + (0x3319, "M", "グラムトン"), + ] + + +def _seg_33() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x331A, "M", "クルゼイロ"), + (0x331B, "M", "クローネ"), + (0x331C, "M", "ケース"), + (0x331D, "M", "コルナ"), + (0x331E, "M", "コーポ"), + (0x331F, "M", "サイクル"), + (0x3320, "M", "サンチーム"), + (0x3321, "M", "シリング"), + (0x3322, "M", "センチ"), + (0x3323, "M", "セント"), + (0x3324, "M", "ダース"), + (0x3325, "M", "デシ"), + (0x3326, "M", "ドル"), + (0x3327, "M", "トン"), + (0x3328, "M", "ナノ"), + (0x3329, "M", "ノット"), + (0x332A, "M", "ハイツ"), + (0x332B, "M", "パーセント"), + (0x332C, "M", "パーツ"), + (0x332D, "M", "バーレル"), + (0x332E, "M", "ピアストル"), + (0x332F, "M", "ピクル"), + (0x3330, "M", "ピコ"), + (0x3331, "M", "ビル"), + (0x3332, "M", "ファラッド"), + (0x3333, "M", "フィート"), + (0x3334, "M", "ブッシェル"), + (0x3335, "M", "フラン"), + (0x3336, "M", "ヘクタール"), + (0x3337, "M", "ペソ"), + (0x3338, "M", "ペニヒ"), + (0x3339, "M", "ヘルツ"), + (0x333A, "M", "ペンス"), + (0x333B, "M", "ページ"), + (0x333C, "M", "ベータ"), + (0x333D, "M", "ポイント"), + (0x333E, "M", "ボルト"), + (0x333F, "M", "ホン"), + (0x3340, "M", "ポンド"), + (0x3341, "M", "ホール"), + (0x3342, "M", "ホーン"), + (0x3343, "M", "マイクロ"), + (0x3344, "M", "マイル"), + (0x3345, "M", "マッハ"), + (0x3346, "M", "マルク"), + (0x3347, "M", "マンション"), + (0x3348, "M", "ミクロン"), + (0x3349, "M", "ミリ"), + (0x334A, "M", "ミリバール"), + (0x334B, "M", "メガ"), + (0x334C, "M", "メガトン"), + (0x334D, "M", "メートル"), + (0x334E, "M", "ヤード"), + (0x334F, "M", "ヤール"), + (0x3350, "M", "ユアン"), + (0x3351, "M", "リットル"), + (0x3352, "M", "リラ"), + (0x3353, "M", "ルピー"), + (0x3354, "M", "ルーブル"), + (0x3355, "M", "レム"), + (0x3356, "M", "レントゲン"), + (0x3357, "M", "ワット"), + (0x3358, "M", "0点"), + (0x3359, "M", "1点"), + (0x335A, "M", "2点"), + (0x335B, "M", "3点"), + (0x335C, "M", "4点"), + (0x335D, "M", "5点"), + (0x335E, "M", "6点"), + (0x335F, "M", "7点"), + (0x3360, "M", "8点"), + (0x3361, "M", "9点"), + (0x3362, "M", "10点"), + (0x3363, "M", "11点"), + (0x3364, "M", "12点"), + (0x3365, "M", "13点"), + (0x3366, "M", "14点"), + (0x3367, "M", "15点"), + (0x3368, "M", "16点"), + (0x3369, "M", "17点"), + (0x336A, "M", "18点"), + (0x336B, "M", "19点"), + (0x336C, "M", "20点"), + (0x336D, "M", "21点"), + (0x336E, "M", "22点"), + (0x336F, "M", "23点"), + (0x3370, "M", "24点"), + (0x3371, "M", "hpa"), + (0x3372, "M", "da"), + (0x3373, "M", "au"), + (0x3374, "M", "bar"), + (0x3375, "M", "ov"), + (0x3376, "M", "pc"), + (0x3377, "M", "dm"), + (0x3378, "M", "dm2"), + (0x3379, "M", "dm3"), + (0x337A, "M", "iu"), + (0x337B, "M", "平成"), + (0x337C, "M", "昭和"), + (0x337D, "M", "大正"), + ] + + +def _seg_34() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x337E, "M", "明治"), + (0x337F, "M", "株式会社"), + (0x3380, "M", "pa"), + (0x3381, "M", "na"), + (0x3382, "M", "μa"), + (0x3383, "M", "ma"), + (0x3384, "M", "ka"), + (0x3385, "M", "kb"), + (0x3386, "M", "mb"), + (0x3387, "M", "gb"), + (0x3388, "M", "cal"), + (0x3389, "M", "kcal"), + (0x338A, "M", "pf"), + (0x338B, "M", "nf"), + (0x338C, "M", "μf"), + (0x338D, "M", "μg"), + (0x338E, "M", "mg"), + (0x338F, "M", "kg"), + (0x3390, "M", "hz"), + (0x3391, "M", "khz"), + (0x3392, "M", "mhz"), + (0x3393, "M", "ghz"), + (0x3394, "M", "thz"), + (0x3395, "M", "μl"), + (0x3396, "M", "ml"), + (0x3397, "M", "dl"), + (0x3398, "M", "kl"), + (0x3399, "M", "fm"), + (0x339A, "M", "nm"), + (0x339B, "M", "μm"), + (0x339C, "M", "mm"), + (0x339D, "M", "cm"), + (0x339E, "M", "km"), + (0x339F, "M", "mm2"), + (0x33A0, "M", "cm2"), + (0x33A1, "M", "m2"), + (0x33A2, "M", "km2"), + (0x33A3, "M", "mm3"), + (0x33A4, "M", "cm3"), + (0x33A5, "M", "m3"), + (0x33A6, "M", "km3"), + (0x33A7, "M", "m∕s"), + (0x33A8, "M", "m∕s2"), + (0x33A9, "M", "pa"), + (0x33AA, "M", "kpa"), + (0x33AB, "M", "mpa"), + (0x33AC, "M", "gpa"), + (0x33AD, "M", "rad"), + (0x33AE, "M", "rad∕s"), + (0x33AF, "M", "rad∕s2"), + (0x33B0, "M", "ps"), + (0x33B1, "M", "ns"), + (0x33B2, "M", "μs"), + (0x33B3, "M", "ms"), + (0x33B4, "M", "pv"), + (0x33B5, "M", "nv"), + (0x33B6, "M", "μv"), + (0x33B7, "M", "mv"), + (0x33B8, "M", "kv"), + (0x33B9, "M", "mv"), + (0x33BA, "M", "pw"), + (0x33BB, "M", "nw"), + (0x33BC, "M", "μw"), + (0x33BD, "M", "mw"), + (0x33BE, "M", "kw"), + (0x33BF, "M", "mw"), + (0x33C0, "M", "kω"), + (0x33C1, "M", "mω"), + (0x33C2, "X"), + (0x33C3, "M", "bq"), + (0x33C4, "M", "cc"), + (0x33C5, "M", "cd"), + (0x33C6, "M", "c∕kg"), + (0x33C7, "X"), + (0x33C8, "M", "db"), + (0x33C9, "M", "gy"), + (0x33CA, "M", "ha"), + (0x33CB, "M", "hp"), + (0x33CC, "M", "in"), + (0x33CD, "M", "kk"), + (0x33CE, "M", "km"), + (0x33CF, "M", "kt"), + (0x33D0, "M", "lm"), + (0x33D1, "M", "ln"), + (0x33D2, "M", "log"), + (0x33D3, "M", "lx"), + (0x33D4, "M", "mb"), + (0x33D5, "M", "mil"), + (0x33D6, "M", "mol"), + (0x33D7, "M", "ph"), + (0x33D8, "X"), + (0x33D9, "M", "ppm"), + (0x33DA, "M", "pr"), + (0x33DB, "M", "sr"), + (0x33DC, "M", "sv"), + (0x33DD, "M", "wb"), + (0x33DE, "M", "v∕m"), + (0x33DF, "M", "a∕m"), + (0x33E0, "M", "1日"), + (0x33E1, "M", "2日"), + ] + + +def _seg_35() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x33E2, "M", "3日"), + (0x33E3, "M", "4日"), + (0x33E4, "M", "5日"), + (0x33E5, "M", "6日"), + (0x33E6, "M", "7日"), + (0x33E7, "M", "8日"), + (0x33E8, "M", "9日"), + (0x33E9, "M", "10日"), + (0x33EA, "M", "11日"), + (0x33EB, "M", "12日"), + (0x33EC, "M", "13日"), + (0x33ED, "M", "14日"), + (0x33EE, "M", "15日"), + (0x33EF, "M", "16日"), + (0x33F0, "M", "17日"), + (0x33F1, "M", "18日"), + (0x33F2, "M", "19日"), + (0x33F3, "M", "20日"), + (0x33F4, "M", "21日"), + (0x33F5, "M", "22日"), + (0x33F6, "M", "23日"), + (0x33F7, "M", "24日"), + (0x33F8, "M", "25日"), + (0x33F9, "M", "26日"), + (0x33FA, "M", "27日"), + (0x33FB, "M", "28日"), + (0x33FC, "M", "29日"), + (0x33FD, "M", "30日"), + (0x33FE, "M", "31日"), + (0x33FF, "M", "gal"), + (0x3400, "V"), + (0xA48D, "X"), + (0xA490, "V"), + (0xA4C7, "X"), + (0xA4D0, "V"), + (0xA62C, "X"), + (0xA640, "M", "ꙁ"), + (0xA641, "V"), + (0xA642, "M", "ꙃ"), + (0xA643, "V"), + (0xA644, "M", "ꙅ"), + (0xA645, "V"), + (0xA646, "M", "ꙇ"), + (0xA647, "V"), + (0xA648, "M", "ꙉ"), + (0xA649, "V"), + (0xA64A, "M", "ꙋ"), + (0xA64B, "V"), + (0xA64C, "M", "ꙍ"), + (0xA64D, "V"), + (0xA64E, "M", "ꙏ"), + (0xA64F, "V"), + (0xA650, "M", "ꙑ"), + (0xA651, "V"), + (0xA652, "M", "ꙓ"), + (0xA653, "V"), + (0xA654, "M", "ꙕ"), + (0xA655, "V"), + (0xA656, "M", "ꙗ"), + (0xA657, "V"), + (0xA658, "M", "ꙙ"), + (0xA659, "V"), + (0xA65A, "M", "ꙛ"), + (0xA65B, "V"), + (0xA65C, "M", "ꙝ"), + (0xA65D, "V"), + (0xA65E, "M", "ꙟ"), + (0xA65F, "V"), + (0xA660, "M", "ꙡ"), + (0xA661, "V"), + (0xA662, "M", "ꙣ"), + (0xA663, "V"), + (0xA664, "M", "ꙥ"), + (0xA665, "V"), + (0xA666, "M", "ꙧ"), + (0xA667, "V"), + (0xA668, "M", "ꙩ"), + (0xA669, "V"), + (0xA66A, "M", "ꙫ"), + (0xA66B, "V"), + (0xA66C, "M", "ꙭ"), + (0xA66D, "V"), + (0xA680, "M", "ꚁ"), + (0xA681, "V"), + (0xA682, "M", "ꚃ"), + (0xA683, "V"), + (0xA684, "M", "ꚅ"), + (0xA685, "V"), + (0xA686, "M", "ꚇ"), + (0xA687, "V"), + (0xA688, "M", "ꚉ"), + (0xA689, "V"), + (0xA68A, "M", "ꚋ"), + (0xA68B, "V"), + (0xA68C, "M", "ꚍ"), + (0xA68D, "V"), + (0xA68E, "M", "ꚏ"), + (0xA68F, "V"), + (0xA690, "M", "ꚑ"), + (0xA691, "V"), + ] + + +def _seg_36() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA692, "M", "ꚓ"), + (0xA693, "V"), + (0xA694, "M", "ꚕ"), + (0xA695, "V"), + (0xA696, "M", "ꚗ"), + (0xA697, "V"), + (0xA698, "M", "ꚙ"), + (0xA699, "V"), + (0xA69A, "M", "ꚛ"), + (0xA69B, "V"), + (0xA69C, "M", "ъ"), + (0xA69D, "M", "ь"), + (0xA69E, "V"), + (0xA6F8, "X"), + (0xA700, "V"), + (0xA722, "M", "ꜣ"), + (0xA723, "V"), + (0xA724, "M", "ꜥ"), + (0xA725, "V"), + (0xA726, "M", "ꜧ"), + (0xA727, "V"), + (0xA728, "M", "ꜩ"), + (0xA729, "V"), + (0xA72A, "M", "ꜫ"), + (0xA72B, "V"), + (0xA72C, "M", "ꜭ"), + (0xA72D, "V"), + (0xA72E, "M", "ꜯ"), + (0xA72F, "V"), + (0xA732, "M", "ꜳ"), + (0xA733, "V"), + (0xA734, "M", "ꜵ"), + (0xA735, "V"), + (0xA736, "M", "ꜷ"), + (0xA737, "V"), + (0xA738, "M", "ꜹ"), + (0xA739, "V"), + (0xA73A, "M", "ꜻ"), + (0xA73B, "V"), + (0xA73C, "M", "ꜽ"), + (0xA73D, "V"), + (0xA73E, "M", "ꜿ"), + (0xA73F, "V"), + (0xA740, "M", "ꝁ"), + (0xA741, "V"), + (0xA742, "M", "ꝃ"), + (0xA743, "V"), + (0xA744, "M", "ꝅ"), + (0xA745, "V"), + (0xA746, "M", "ꝇ"), + (0xA747, "V"), + (0xA748, "M", "ꝉ"), + (0xA749, "V"), + (0xA74A, "M", "ꝋ"), + (0xA74B, "V"), + (0xA74C, "M", "ꝍ"), + (0xA74D, "V"), + (0xA74E, "M", "ꝏ"), + (0xA74F, "V"), + (0xA750, "M", "ꝑ"), + (0xA751, "V"), + (0xA752, "M", "ꝓ"), + (0xA753, "V"), + (0xA754, "M", "ꝕ"), + (0xA755, "V"), + (0xA756, "M", "ꝗ"), + (0xA757, "V"), + (0xA758, "M", "ꝙ"), + (0xA759, "V"), + (0xA75A, "M", "ꝛ"), + (0xA75B, "V"), + (0xA75C, "M", "ꝝ"), + (0xA75D, "V"), + (0xA75E, "M", "ꝟ"), + (0xA75F, "V"), + (0xA760, "M", "ꝡ"), + (0xA761, "V"), + (0xA762, "M", "ꝣ"), + (0xA763, "V"), + (0xA764, "M", "ꝥ"), + (0xA765, "V"), + (0xA766, "M", "ꝧ"), + (0xA767, "V"), + (0xA768, "M", "ꝩ"), + (0xA769, "V"), + (0xA76A, "M", "ꝫ"), + (0xA76B, "V"), + (0xA76C, "M", "ꝭ"), + (0xA76D, "V"), + (0xA76E, "M", "ꝯ"), + (0xA76F, "V"), + (0xA770, "M", "ꝯ"), + (0xA771, "V"), + (0xA779, "M", "ꝺ"), + (0xA77A, "V"), + (0xA77B, "M", "ꝼ"), + (0xA77C, "V"), + (0xA77D, "M", "ᵹ"), + (0xA77E, "M", "ꝿ"), + (0xA77F, "V"), + ] + + +def _seg_37() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA780, "M", "ꞁ"), + (0xA781, "V"), + (0xA782, "M", "ꞃ"), + (0xA783, "V"), + (0xA784, "M", "ꞅ"), + (0xA785, "V"), + (0xA786, "M", "ꞇ"), + (0xA787, "V"), + (0xA78B, "M", "ꞌ"), + (0xA78C, "V"), + (0xA78D, "M", "ɥ"), + (0xA78E, "V"), + (0xA790, "M", "ꞑ"), + (0xA791, "V"), + (0xA792, "M", "ꞓ"), + (0xA793, "V"), + (0xA796, "M", "ꞗ"), + (0xA797, "V"), + (0xA798, "M", "ꞙ"), + (0xA799, "V"), + (0xA79A, "M", "ꞛ"), + (0xA79B, "V"), + (0xA79C, "M", "ꞝ"), + (0xA79D, "V"), + (0xA79E, "M", "ꞟ"), + (0xA79F, "V"), + (0xA7A0, "M", "ꞡ"), + (0xA7A1, "V"), + (0xA7A2, "M", "ꞣ"), + (0xA7A3, "V"), + (0xA7A4, "M", "ꞥ"), + (0xA7A5, "V"), + (0xA7A6, "M", "ꞧ"), + (0xA7A7, "V"), + (0xA7A8, "M", "ꞩ"), + (0xA7A9, "V"), + (0xA7AA, "M", "ɦ"), + (0xA7AB, "M", "ɜ"), + (0xA7AC, "M", "ɡ"), + (0xA7AD, "M", "ɬ"), + (0xA7AE, "M", "ɪ"), + (0xA7AF, "V"), + (0xA7B0, "M", "ʞ"), + (0xA7B1, "M", "ʇ"), + (0xA7B2, "M", "ʝ"), + (0xA7B3, "M", "ꭓ"), + (0xA7B4, "M", "ꞵ"), + (0xA7B5, "V"), + (0xA7B6, "M", "ꞷ"), + (0xA7B7, "V"), + (0xA7B8, "M", "ꞹ"), + (0xA7B9, "V"), + (0xA7BA, "M", "ꞻ"), + (0xA7BB, "V"), + (0xA7BC, "M", "ꞽ"), + (0xA7BD, "V"), + (0xA7BE, "M", "ꞿ"), + (0xA7BF, "V"), + (0xA7C0, "M", "ꟁ"), + (0xA7C1, "V"), + (0xA7C2, "M", "ꟃ"), + (0xA7C3, "V"), + (0xA7C4, "M", "ꞔ"), + (0xA7C5, "M", "ʂ"), + (0xA7C6, "M", "ᶎ"), + (0xA7C7, "M", "ꟈ"), + (0xA7C8, "V"), + (0xA7C9, "M", "ꟊ"), + (0xA7CA, "V"), + (0xA7CB, "X"), + (0xA7D0, "M", "ꟑ"), + (0xA7D1, "V"), + (0xA7D2, "X"), + (0xA7D3, "V"), + (0xA7D4, "X"), + (0xA7D5, "V"), + (0xA7D6, "M", "ꟗ"), + (0xA7D7, "V"), + (0xA7D8, "M", "ꟙ"), + (0xA7D9, "V"), + (0xA7DA, "X"), + (0xA7F2, "M", "c"), + (0xA7F3, "M", "f"), + (0xA7F4, "M", "q"), + (0xA7F5, "M", "ꟶ"), + (0xA7F6, "V"), + (0xA7F8, "M", "ħ"), + (0xA7F9, "M", "œ"), + (0xA7FA, "V"), + (0xA82D, "X"), + (0xA830, "V"), + (0xA83A, "X"), + (0xA840, "V"), + (0xA878, "X"), + (0xA880, "V"), + (0xA8C6, "X"), + (0xA8CE, "V"), + (0xA8DA, "X"), + (0xA8E0, "V"), + (0xA954, "X"), + ] + + +def _seg_38() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xA95F, "V"), + (0xA97D, "X"), + (0xA980, "V"), + (0xA9CE, "X"), + (0xA9CF, "V"), + (0xA9DA, "X"), + (0xA9DE, "V"), + (0xA9FF, "X"), + (0xAA00, "V"), + (0xAA37, "X"), + (0xAA40, "V"), + (0xAA4E, "X"), + (0xAA50, "V"), + (0xAA5A, "X"), + (0xAA5C, "V"), + (0xAAC3, "X"), + (0xAADB, "V"), + (0xAAF7, "X"), + (0xAB01, "V"), + (0xAB07, "X"), + (0xAB09, "V"), + (0xAB0F, "X"), + (0xAB11, "V"), + (0xAB17, "X"), + (0xAB20, "V"), + (0xAB27, "X"), + (0xAB28, "V"), + (0xAB2F, "X"), + (0xAB30, "V"), + (0xAB5C, "M", "ꜧ"), + (0xAB5D, "M", "ꬷ"), + (0xAB5E, "M", "ɫ"), + (0xAB5F, "M", "ꭒ"), + (0xAB60, "V"), + (0xAB69, "M", "ʍ"), + (0xAB6A, "V"), + (0xAB6C, "X"), + (0xAB70, "M", "Ꭰ"), + (0xAB71, "M", "Ꭱ"), + (0xAB72, "M", "Ꭲ"), + (0xAB73, "M", "Ꭳ"), + (0xAB74, "M", "Ꭴ"), + (0xAB75, "M", "Ꭵ"), + (0xAB76, "M", "Ꭶ"), + (0xAB77, "M", "Ꭷ"), + (0xAB78, "M", "Ꭸ"), + (0xAB79, "M", "Ꭹ"), + (0xAB7A, "M", "Ꭺ"), + (0xAB7B, "M", "Ꭻ"), + (0xAB7C, "M", "Ꭼ"), + (0xAB7D, "M", "Ꭽ"), + (0xAB7E, "M", "Ꭾ"), + (0xAB7F, "M", "Ꭿ"), + (0xAB80, "M", "Ꮀ"), + (0xAB81, "M", "Ꮁ"), + (0xAB82, "M", "Ꮂ"), + (0xAB83, "M", "Ꮃ"), + (0xAB84, "M", "Ꮄ"), + (0xAB85, "M", "Ꮅ"), + (0xAB86, "M", "Ꮆ"), + (0xAB87, "M", "Ꮇ"), + (0xAB88, "M", "Ꮈ"), + (0xAB89, "M", "Ꮉ"), + (0xAB8A, "M", "Ꮊ"), + (0xAB8B, "M", "Ꮋ"), + (0xAB8C, "M", "Ꮌ"), + (0xAB8D, "M", "Ꮍ"), + (0xAB8E, "M", "Ꮎ"), + (0xAB8F, "M", "Ꮏ"), + (0xAB90, "M", "Ꮐ"), + (0xAB91, "M", "Ꮑ"), + (0xAB92, "M", "Ꮒ"), + (0xAB93, "M", "Ꮓ"), + (0xAB94, "M", "Ꮔ"), + (0xAB95, "M", "Ꮕ"), + (0xAB96, "M", "Ꮖ"), + (0xAB97, "M", "Ꮗ"), + (0xAB98, "M", "Ꮘ"), + (0xAB99, "M", "Ꮙ"), + (0xAB9A, "M", "Ꮚ"), + (0xAB9B, "M", "Ꮛ"), + (0xAB9C, "M", "Ꮜ"), + (0xAB9D, "M", "Ꮝ"), + (0xAB9E, "M", "Ꮞ"), + (0xAB9F, "M", "Ꮟ"), + (0xABA0, "M", "Ꮠ"), + (0xABA1, "M", "Ꮡ"), + (0xABA2, "M", "Ꮢ"), + (0xABA3, "M", "Ꮣ"), + (0xABA4, "M", "Ꮤ"), + (0xABA5, "M", "Ꮥ"), + (0xABA6, "M", "Ꮦ"), + (0xABA7, "M", "Ꮧ"), + (0xABA8, "M", "Ꮨ"), + (0xABA9, "M", "Ꮩ"), + (0xABAA, "M", "Ꮪ"), + (0xABAB, "M", "Ꮫ"), + (0xABAC, "M", "Ꮬ"), + (0xABAD, "M", "Ꮭ"), + (0xABAE, "M", "Ꮮ"), + ] + + +def _seg_39() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xABAF, "M", "Ꮯ"), + (0xABB0, "M", "Ꮰ"), + (0xABB1, "M", "Ꮱ"), + (0xABB2, "M", "Ꮲ"), + (0xABB3, "M", "Ꮳ"), + (0xABB4, "M", "Ꮴ"), + (0xABB5, "M", "Ꮵ"), + (0xABB6, "M", "Ꮶ"), + (0xABB7, "M", "Ꮷ"), + (0xABB8, "M", "Ꮸ"), + (0xABB9, "M", "Ꮹ"), + (0xABBA, "M", "Ꮺ"), + (0xABBB, "M", "Ꮻ"), + (0xABBC, "M", "Ꮼ"), + (0xABBD, "M", "Ꮽ"), + (0xABBE, "M", "Ꮾ"), + (0xABBF, "M", "Ꮿ"), + (0xABC0, "V"), + (0xABEE, "X"), + (0xABF0, "V"), + (0xABFA, "X"), + (0xAC00, "V"), + (0xD7A4, "X"), + (0xD7B0, "V"), + (0xD7C7, "X"), + (0xD7CB, "V"), + (0xD7FC, "X"), + (0xF900, "M", "豈"), + (0xF901, "M", "更"), + (0xF902, "M", "車"), + (0xF903, "M", "賈"), + (0xF904, "M", "滑"), + (0xF905, "M", "串"), + (0xF906, "M", "句"), + (0xF907, "M", "龜"), + (0xF909, "M", "契"), + (0xF90A, "M", "金"), + (0xF90B, "M", "喇"), + (0xF90C, "M", "奈"), + (0xF90D, "M", "懶"), + (0xF90E, "M", "癩"), + (0xF90F, "M", "羅"), + (0xF910, "M", "蘿"), + (0xF911, "M", "螺"), + (0xF912, "M", "裸"), + (0xF913, "M", "邏"), + (0xF914, "M", "樂"), + (0xF915, "M", "洛"), + (0xF916, "M", "烙"), + (0xF917, "M", "珞"), + (0xF918, "M", "落"), + (0xF919, "M", "酪"), + (0xF91A, "M", "駱"), + (0xF91B, "M", "亂"), + (0xF91C, "M", "卵"), + (0xF91D, "M", "欄"), + (0xF91E, "M", "爛"), + (0xF91F, "M", "蘭"), + (0xF920, "M", "鸞"), + (0xF921, "M", "嵐"), + (0xF922, "M", "濫"), + (0xF923, "M", "藍"), + (0xF924, "M", "襤"), + (0xF925, "M", "拉"), + (0xF926, "M", "臘"), + (0xF927, "M", "蠟"), + (0xF928, "M", "廊"), + (0xF929, "M", "朗"), + (0xF92A, "M", "浪"), + (0xF92B, "M", "狼"), + (0xF92C, "M", "郎"), + (0xF92D, "M", "來"), + (0xF92E, "M", "冷"), + (0xF92F, "M", "勞"), + (0xF930, "M", "擄"), + (0xF931, "M", "櫓"), + (0xF932, "M", "爐"), + (0xF933, "M", "盧"), + (0xF934, "M", "老"), + (0xF935, "M", "蘆"), + (0xF936, "M", "虜"), + (0xF937, "M", "路"), + (0xF938, "M", "露"), + (0xF939, "M", "魯"), + (0xF93A, "M", "鷺"), + (0xF93B, "M", "碌"), + (0xF93C, "M", "祿"), + (0xF93D, "M", "綠"), + (0xF93E, "M", "菉"), + (0xF93F, "M", "錄"), + (0xF940, "M", "鹿"), + (0xF941, "M", "論"), + (0xF942, "M", "壟"), + (0xF943, "M", "弄"), + (0xF944, "M", "籠"), + (0xF945, "M", "聾"), + (0xF946, "M", "牢"), + (0xF947, "M", "磊"), + (0xF948, "M", "賂"), + (0xF949, "M", "雷"), + ] + + +def _seg_40() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF94A, "M", "壘"), + (0xF94B, "M", "屢"), + (0xF94C, "M", "樓"), + (0xF94D, "M", "淚"), + (0xF94E, "M", "漏"), + (0xF94F, "M", "累"), + (0xF950, "M", "縷"), + (0xF951, "M", "陋"), + (0xF952, "M", "勒"), + (0xF953, "M", "肋"), + (0xF954, "M", "凜"), + (0xF955, "M", "凌"), + (0xF956, "M", "稜"), + (0xF957, "M", "綾"), + (0xF958, "M", "菱"), + (0xF959, "M", "陵"), + (0xF95A, "M", "讀"), + (0xF95B, "M", "拏"), + (0xF95C, "M", "樂"), + (0xF95D, "M", "諾"), + (0xF95E, "M", "丹"), + (0xF95F, "M", "寧"), + (0xF960, "M", "怒"), + (0xF961, "M", "率"), + (0xF962, "M", "異"), + (0xF963, "M", "北"), + (0xF964, "M", "磻"), + (0xF965, "M", "便"), + (0xF966, "M", "復"), + (0xF967, "M", "不"), + (0xF968, "M", "泌"), + (0xF969, "M", "數"), + (0xF96A, "M", "索"), + (0xF96B, "M", "參"), + (0xF96C, "M", "塞"), + (0xF96D, "M", "省"), + (0xF96E, "M", "葉"), + (0xF96F, "M", "說"), + (0xF970, "M", "殺"), + (0xF971, "M", "辰"), + (0xF972, "M", "沈"), + (0xF973, "M", "拾"), + (0xF974, "M", "若"), + (0xF975, "M", "掠"), + (0xF976, "M", "略"), + (0xF977, "M", "亮"), + (0xF978, "M", "兩"), + (0xF979, "M", "凉"), + (0xF97A, "M", "梁"), + (0xF97B, "M", "糧"), + (0xF97C, "M", "良"), + (0xF97D, "M", "諒"), + (0xF97E, "M", "量"), + (0xF97F, "M", "勵"), + (0xF980, "M", "呂"), + (0xF981, "M", "女"), + (0xF982, "M", "廬"), + (0xF983, "M", "旅"), + (0xF984, "M", "濾"), + (0xF985, "M", "礪"), + (0xF986, "M", "閭"), + (0xF987, "M", "驪"), + (0xF988, "M", "麗"), + (0xF989, "M", "黎"), + (0xF98A, "M", "力"), + (0xF98B, "M", "曆"), + (0xF98C, "M", "歷"), + (0xF98D, "M", "轢"), + (0xF98E, "M", "年"), + (0xF98F, "M", "憐"), + (0xF990, "M", "戀"), + (0xF991, "M", "撚"), + (0xF992, "M", "漣"), + (0xF993, "M", "煉"), + (0xF994, "M", "璉"), + (0xF995, "M", "秊"), + (0xF996, "M", "練"), + (0xF997, "M", "聯"), + (0xF998, "M", "輦"), + (0xF999, "M", "蓮"), + (0xF99A, "M", "連"), + (0xF99B, "M", "鍊"), + (0xF99C, "M", "列"), + (0xF99D, "M", "劣"), + (0xF99E, "M", "咽"), + (0xF99F, "M", "烈"), + (0xF9A0, "M", "裂"), + (0xF9A1, "M", "說"), + (0xF9A2, "M", "廉"), + (0xF9A3, "M", "念"), + (0xF9A4, "M", "捻"), + (0xF9A5, "M", "殮"), + (0xF9A6, "M", "簾"), + (0xF9A7, "M", "獵"), + (0xF9A8, "M", "令"), + (0xF9A9, "M", "囹"), + (0xF9AA, "M", "寧"), + (0xF9AB, "M", "嶺"), + (0xF9AC, "M", "怜"), + (0xF9AD, "M", "玲"), + ] + + +def _seg_41() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xF9AE, "M", "瑩"), + (0xF9AF, "M", "羚"), + (0xF9B0, "M", "聆"), + (0xF9B1, "M", "鈴"), + (0xF9B2, "M", "零"), + (0xF9B3, "M", "靈"), + (0xF9B4, "M", "領"), + (0xF9B5, "M", "例"), + (0xF9B6, "M", "禮"), + (0xF9B7, "M", "醴"), + (0xF9B8, "M", "隸"), + (0xF9B9, "M", "惡"), + (0xF9BA, "M", "了"), + (0xF9BB, "M", "僚"), + (0xF9BC, "M", "寮"), + (0xF9BD, "M", "尿"), + (0xF9BE, "M", "料"), + (0xF9BF, "M", "樂"), + (0xF9C0, "M", "燎"), + (0xF9C1, "M", "療"), + (0xF9C2, "M", "蓼"), + (0xF9C3, "M", "遼"), + (0xF9C4, "M", "龍"), + (0xF9C5, "M", "暈"), + (0xF9C6, "M", "阮"), + (0xF9C7, "M", "劉"), + (0xF9C8, "M", "杻"), + (0xF9C9, "M", "柳"), + (0xF9CA, "M", "流"), + (0xF9CB, "M", "溜"), + (0xF9CC, "M", "琉"), + (0xF9CD, "M", "留"), + (0xF9CE, "M", "硫"), + (0xF9CF, "M", "紐"), + (0xF9D0, "M", "類"), + (0xF9D1, "M", "六"), + (0xF9D2, "M", "戮"), + (0xF9D3, "M", "陸"), + (0xF9D4, "M", "倫"), + (0xF9D5, "M", "崙"), + (0xF9D6, "M", "淪"), + (0xF9D7, "M", "輪"), + (0xF9D8, "M", "律"), + (0xF9D9, "M", "慄"), + (0xF9DA, "M", "栗"), + (0xF9DB, "M", "率"), + (0xF9DC, "M", "隆"), + (0xF9DD, "M", "利"), + (0xF9DE, "M", "吏"), + (0xF9DF, "M", "履"), + (0xF9E0, "M", "易"), + (0xF9E1, "M", "李"), + (0xF9E2, "M", "梨"), + (0xF9E3, "M", "泥"), + (0xF9E4, "M", "理"), + (0xF9E5, "M", "痢"), + (0xF9E6, "M", "罹"), + (0xF9E7, "M", "裏"), + (0xF9E8, "M", "裡"), + (0xF9E9, "M", "里"), + (0xF9EA, "M", "離"), + (0xF9EB, "M", "匿"), + (0xF9EC, "M", "溺"), + (0xF9ED, "M", "吝"), + (0xF9EE, "M", "燐"), + (0xF9EF, "M", "璘"), + (0xF9F0, "M", "藺"), + (0xF9F1, "M", "隣"), + (0xF9F2, "M", "鱗"), + (0xF9F3, "M", "麟"), + (0xF9F4, "M", "林"), + (0xF9F5, "M", "淋"), + (0xF9F6, "M", "臨"), + (0xF9F7, "M", "立"), + (0xF9F8, "M", "笠"), + (0xF9F9, "M", "粒"), + (0xF9FA, "M", "狀"), + (0xF9FB, "M", "炙"), + (0xF9FC, "M", "識"), + (0xF9FD, "M", "什"), + (0xF9FE, "M", "茶"), + (0xF9FF, "M", "刺"), + (0xFA00, "M", "切"), + (0xFA01, "M", "度"), + (0xFA02, "M", "拓"), + (0xFA03, "M", "糖"), + (0xFA04, "M", "宅"), + (0xFA05, "M", "洞"), + (0xFA06, "M", "暴"), + (0xFA07, "M", "輻"), + (0xFA08, "M", "行"), + (0xFA09, "M", "降"), + (0xFA0A, "M", "見"), + (0xFA0B, "M", "廓"), + (0xFA0C, "M", "兀"), + (0xFA0D, "M", "嗀"), + (0xFA0E, "V"), + (0xFA10, "M", "塚"), + (0xFA11, "V"), + (0xFA12, "M", "晴"), + ] + + +def _seg_42() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFA13, "V"), + (0xFA15, "M", "凞"), + (0xFA16, "M", "猪"), + (0xFA17, "M", "益"), + (0xFA18, "M", "礼"), + (0xFA19, "M", "神"), + (0xFA1A, "M", "祥"), + (0xFA1B, "M", "福"), + (0xFA1C, "M", "靖"), + (0xFA1D, "M", "精"), + (0xFA1E, "M", "羽"), + (0xFA1F, "V"), + (0xFA20, "M", "蘒"), + (0xFA21, "V"), + (0xFA22, "M", "諸"), + (0xFA23, "V"), + (0xFA25, "M", "逸"), + (0xFA26, "M", "都"), + (0xFA27, "V"), + (0xFA2A, "M", "飯"), + (0xFA2B, "M", "飼"), + (0xFA2C, "M", "館"), + (0xFA2D, "M", "鶴"), + (0xFA2E, "M", "郞"), + (0xFA2F, "M", "隷"), + (0xFA30, "M", "侮"), + (0xFA31, "M", "僧"), + (0xFA32, "M", "免"), + (0xFA33, "M", "勉"), + (0xFA34, "M", "勤"), + (0xFA35, "M", "卑"), + (0xFA36, "M", "喝"), + (0xFA37, "M", "嘆"), + (0xFA38, "M", "器"), + (0xFA39, "M", "塀"), + (0xFA3A, "M", "墨"), + (0xFA3B, "M", "層"), + (0xFA3C, "M", "屮"), + (0xFA3D, "M", "悔"), + (0xFA3E, "M", "慨"), + (0xFA3F, "M", "憎"), + (0xFA40, "M", "懲"), + (0xFA41, "M", "敏"), + (0xFA42, "M", "既"), + (0xFA43, "M", "暑"), + (0xFA44, "M", "梅"), + (0xFA45, "M", "海"), + (0xFA46, "M", "渚"), + (0xFA47, "M", "漢"), + (0xFA48, "M", "煮"), + (0xFA49, "M", "爫"), + (0xFA4A, "M", "琢"), + (0xFA4B, "M", "碑"), + (0xFA4C, "M", "社"), + (0xFA4D, "M", "祉"), + (0xFA4E, "M", "祈"), + (0xFA4F, "M", "祐"), + (0xFA50, "M", "祖"), + (0xFA51, "M", "祝"), + (0xFA52, "M", "禍"), + (0xFA53, "M", "禎"), + (0xFA54, "M", "穀"), + (0xFA55, "M", "突"), + (0xFA56, "M", "節"), + (0xFA57, "M", "練"), + (0xFA58, "M", "縉"), + (0xFA59, "M", "繁"), + (0xFA5A, "M", "署"), + (0xFA5B, "M", "者"), + (0xFA5C, "M", "臭"), + (0xFA5D, "M", "艹"), + (0xFA5F, "M", "著"), + (0xFA60, "M", "褐"), + (0xFA61, "M", "視"), + (0xFA62, "M", "謁"), + (0xFA63, "M", "謹"), + (0xFA64, "M", "賓"), + (0xFA65, "M", "贈"), + (0xFA66, "M", "辶"), + (0xFA67, "M", "逸"), + (0xFA68, "M", "難"), + (0xFA69, "M", "響"), + (0xFA6A, "M", "頻"), + (0xFA6B, "M", "恵"), + (0xFA6C, "M", "𤋮"), + (0xFA6D, "M", "舘"), + (0xFA6E, "X"), + (0xFA70, "M", "並"), + (0xFA71, "M", "况"), + (0xFA72, "M", "全"), + (0xFA73, "M", "侀"), + (0xFA74, "M", "充"), + (0xFA75, "M", "冀"), + (0xFA76, "M", "勇"), + (0xFA77, "M", "勺"), + (0xFA78, "M", "喝"), + (0xFA79, "M", "啕"), + (0xFA7A, "M", "喙"), + (0xFA7B, "M", "嗢"), + (0xFA7C, "M", "塚"), + ] + + +def _seg_43() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFA7D, "M", "墳"), + (0xFA7E, "M", "奄"), + (0xFA7F, "M", "奔"), + (0xFA80, "M", "婢"), + (0xFA81, "M", "嬨"), + (0xFA82, "M", "廒"), + (0xFA83, "M", "廙"), + (0xFA84, "M", "彩"), + (0xFA85, "M", "徭"), + (0xFA86, "M", "惘"), + (0xFA87, "M", "慎"), + (0xFA88, "M", "愈"), + (0xFA89, "M", "憎"), + (0xFA8A, "M", "慠"), + (0xFA8B, "M", "懲"), + (0xFA8C, "M", "戴"), + (0xFA8D, "M", "揄"), + (0xFA8E, "M", "搜"), + (0xFA8F, "M", "摒"), + (0xFA90, "M", "敖"), + (0xFA91, "M", "晴"), + (0xFA92, "M", "朗"), + (0xFA93, "M", "望"), + (0xFA94, "M", "杖"), + (0xFA95, "M", "歹"), + (0xFA96, "M", "殺"), + (0xFA97, "M", "流"), + (0xFA98, "M", "滛"), + (0xFA99, "M", "滋"), + (0xFA9A, "M", "漢"), + (0xFA9B, "M", "瀞"), + (0xFA9C, "M", "煮"), + (0xFA9D, "M", "瞧"), + (0xFA9E, "M", "爵"), + (0xFA9F, "M", "犯"), + (0xFAA0, "M", "猪"), + (0xFAA1, "M", "瑱"), + (0xFAA2, "M", "甆"), + (0xFAA3, "M", "画"), + (0xFAA4, "M", "瘝"), + (0xFAA5, "M", "瘟"), + (0xFAA6, "M", "益"), + (0xFAA7, "M", "盛"), + (0xFAA8, "M", "直"), + (0xFAA9, "M", "睊"), + (0xFAAA, "M", "着"), + (0xFAAB, "M", "磌"), + (0xFAAC, "M", "窱"), + (0xFAAD, "M", "節"), + (0xFAAE, "M", "类"), + (0xFAAF, "M", "絛"), + (0xFAB0, "M", "練"), + (0xFAB1, "M", "缾"), + (0xFAB2, "M", "者"), + (0xFAB3, "M", "荒"), + (0xFAB4, "M", "華"), + (0xFAB5, "M", "蝹"), + (0xFAB6, "M", "襁"), + (0xFAB7, "M", "覆"), + (0xFAB8, "M", "視"), + (0xFAB9, "M", "調"), + (0xFABA, "M", "諸"), + (0xFABB, "M", "請"), + (0xFABC, "M", "謁"), + (0xFABD, "M", "諾"), + (0xFABE, "M", "諭"), + (0xFABF, "M", "謹"), + (0xFAC0, "M", "變"), + (0xFAC1, "M", "贈"), + (0xFAC2, "M", "輸"), + (0xFAC3, "M", "遲"), + (0xFAC4, "M", "醙"), + (0xFAC5, "M", "鉶"), + (0xFAC6, "M", "陼"), + (0xFAC7, "M", "難"), + (0xFAC8, "M", "靖"), + (0xFAC9, "M", "韛"), + (0xFACA, "M", "響"), + (0xFACB, "M", "頋"), + (0xFACC, "M", "頻"), + (0xFACD, "M", "鬒"), + (0xFACE, "M", "龜"), + (0xFACF, "M", "𢡊"), + (0xFAD0, "M", "𢡄"), + (0xFAD1, "M", "𣏕"), + (0xFAD2, "M", "㮝"), + (0xFAD3, "M", "䀘"), + (0xFAD4, "M", "䀹"), + (0xFAD5, "M", "𥉉"), + (0xFAD6, "M", "𥳐"), + (0xFAD7, "M", "𧻓"), + (0xFAD8, "M", "齃"), + (0xFAD9, "M", "龎"), + (0xFADA, "X"), + (0xFB00, "M", "ff"), + (0xFB01, "M", "fi"), + (0xFB02, "M", "fl"), + (0xFB03, "M", "ffi"), + (0xFB04, "M", "ffl"), + (0xFB05, "M", "st"), + ] + + +def _seg_44() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFB07, "X"), + (0xFB13, "M", "մն"), + (0xFB14, "M", "մե"), + (0xFB15, "M", "մի"), + (0xFB16, "M", "վն"), + (0xFB17, "M", "մխ"), + (0xFB18, "X"), + (0xFB1D, "M", "יִ"), + (0xFB1E, "V"), + (0xFB1F, "M", "ײַ"), + (0xFB20, "M", "ע"), + (0xFB21, "M", "א"), + (0xFB22, "M", "ד"), + (0xFB23, "M", "ה"), + (0xFB24, "M", "כ"), + (0xFB25, "M", "ל"), + (0xFB26, "M", "ם"), + (0xFB27, "M", "ר"), + (0xFB28, "M", "ת"), + (0xFB29, "3", "+"), + (0xFB2A, "M", "שׁ"), + (0xFB2B, "M", "שׂ"), + (0xFB2C, "M", "שּׁ"), + (0xFB2D, "M", "שּׂ"), + (0xFB2E, "M", "אַ"), + (0xFB2F, "M", "אָ"), + (0xFB30, "M", "אּ"), + (0xFB31, "M", "בּ"), + (0xFB32, "M", "גּ"), + (0xFB33, "M", "דּ"), + (0xFB34, "M", "הּ"), + (0xFB35, "M", "וּ"), + (0xFB36, "M", "זּ"), + (0xFB37, "X"), + (0xFB38, "M", "טּ"), + (0xFB39, "M", "יּ"), + (0xFB3A, "M", "ךּ"), + (0xFB3B, "M", "כּ"), + (0xFB3C, "M", "לּ"), + (0xFB3D, "X"), + (0xFB3E, "M", "מּ"), + (0xFB3F, "X"), + (0xFB40, "M", "נּ"), + (0xFB41, "M", "סּ"), + (0xFB42, "X"), + (0xFB43, "M", "ףּ"), + (0xFB44, "M", "פּ"), + (0xFB45, "X"), + (0xFB46, "M", "צּ"), + (0xFB47, "M", "קּ"), + (0xFB48, "M", "רּ"), + (0xFB49, "M", "שּ"), + (0xFB4A, "M", "תּ"), + (0xFB4B, "M", "וֹ"), + (0xFB4C, "M", "בֿ"), + (0xFB4D, "M", "כֿ"), + (0xFB4E, "M", "פֿ"), + (0xFB4F, "M", "אל"), + (0xFB50, "M", "ٱ"), + (0xFB52, "M", "ٻ"), + (0xFB56, "M", "پ"), + (0xFB5A, "M", "ڀ"), + (0xFB5E, "M", "ٺ"), + (0xFB62, "M", "ٿ"), + (0xFB66, "M", "ٹ"), + (0xFB6A, "M", "ڤ"), + (0xFB6E, "M", "ڦ"), + (0xFB72, "M", "ڄ"), + (0xFB76, "M", "ڃ"), + (0xFB7A, "M", "چ"), + (0xFB7E, "M", "ڇ"), + (0xFB82, "M", "ڍ"), + (0xFB84, "M", "ڌ"), + (0xFB86, "M", "ڎ"), + (0xFB88, "M", "ڈ"), + (0xFB8A, "M", "ژ"), + (0xFB8C, "M", "ڑ"), + (0xFB8E, "M", "ک"), + (0xFB92, "M", "گ"), + (0xFB96, "M", "ڳ"), + (0xFB9A, "M", "ڱ"), + (0xFB9E, "M", "ں"), + (0xFBA0, "M", "ڻ"), + (0xFBA4, "M", "ۀ"), + (0xFBA6, "M", "ہ"), + (0xFBAA, "M", "ھ"), + (0xFBAE, "M", "ے"), + (0xFBB0, "M", "ۓ"), + (0xFBB2, "V"), + (0xFBC3, "X"), + (0xFBD3, "M", "ڭ"), + (0xFBD7, "M", "ۇ"), + (0xFBD9, "M", "ۆ"), + (0xFBDB, "M", "ۈ"), + (0xFBDD, "M", "ۇٴ"), + (0xFBDE, "M", "ۋ"), + (0xFBE0, "M", "ۅ"), + (0xFBE2, "M", "ۉ"), + (0xFBE4, "M", "ې"), + (0xFBE8, "M", "ى"), + ] + + +def _seg_45() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFBEA, "M", "ئا"), + (0xFBEC, "M", "ئە"), + (0xFBEE, "M", "ئو"), + (0xFBF0, "M", "ئۇ"), + (0xFBF2, "M", "ئۆ"), + (0xFBF4, "M", "ئۈ"), + (0xFBF6, "M", "ئې"), + (0xFBF9, "M", "ئى"), + (0xFBFC, "M", "ی"), + (0xFC00, "M", "ئج"), + (0xFC01, "M", "ئح"), + (0xFC02, "M", "ئم"), + (0xFC03, "M", "ئى"), + (0xFC04, "M", "ئي"), + (0xFC05, "M", "بج"), + (0xFC06, "M", "بح"), + (0xFC07, "M", "بخ"), + (0xFC08, "M", "بم"), + (0xFC09, "M", "بى"), + (0xFC0A, "M", "بي"), + (0xFC0B, "M", "تج"), + (0xFC0C, "M", "تح"), + (0xFC0D, "M", "تخ"), + (0xFC0E, "M", "تم"), + (0xFC0F, "M", "تى"), + (0xFC10, "M", "تي"), + (0xFC11, "M", "ثج"), + (0xFC12, "M", "ثم"), + (0xFC13, "M", "ثى"), + (0xFC14, "M", "ثي"), + (0xFC15, "M", "جح"), + (0xFC16, "M", "جم"), + (0xFC17, "M", "حج"), + (0xFC18, "M", "حم"), + (0xFC19, "M", "خج"), + (0xFC1A, "M", "خح"), + (0xFC1B, "M", "خم"), + (0xFC1C, "M", "سج"), + (0xFC1D, "M", "سح"), + (0xFC1E, "M", "سخ"), + (0xFC1F, "M", "سم"), + (0xFC20, "M", "صح"), + (0xFC21, "M", "صم"), + (0xFC22, "M", "ضج"), + (0xFC23, "M", "ضح"), + (0xFC24, "M", "ضخ"), + (0xFC25, "M", "ضم"), + (0xFC26, "M", "طح"), + (0xFC27, "M", "طم"), + (0xFC28, "M", "ظم"), + (0xFC29, "M", "عج"), + (0xFC2A, "M", "عم"), + (0xFC2B, "M", "غج"), + (0xFC2C, "M", "غم"), + (0xFC2D, "M", "فج"), + (0xFC2E, "M", "فح"), + (0xFC2F, "M", "فخ"), + (0xFC30, "M", "فم"), + (0xFC31, "M", "فى"), + (0xFC32, "M", "في"), + (0xFC33, "M", "قح"), + (0xFC34, "M", "قم"), + (0xFC35, "M", "قى"), + (0xFC36, "M", "قي"), + (0xFC37, "M", "كا"), + (0xFC38, "M", "كج"), + (0xFC39, "M", "كح"), + (0xFC3A, "M", "كخ"), + (0xFC3B, "M", "كل"), + (0xFC3C, "M", "كم"), + (0xFC3D, "M", "كى"), + (0xFC3E, "M", "كي"), + (0xFC3F, "M", "لج"), + (0xFC40, "M", "لح"), + (0xFC41, "M", "لخ"), + (0xFC42, "M", "لم"), + (0xFC43, "M", "لى"), + (0xFC44, "M", "لي"), + (0xFC45, "M", "مج"), + (0xFC46, "M", "مح"), + (0xFC47, "M", "مخ"), + (0xFC48, "M", "مم"), + (0xFC49, "M", "مى"), + (0xFC4A, "M", "مي"), + (0xFC4B, "M", "نج"), + (0xFC4C, "M", "نح"), + (0xFC4D, "M", "نخ"), + (0xFC4E, "M", "نم"), + (0xFC4F, "M", "نى"), + (0xFC50, "M", "ني"), + (0xFC51, "M", "هج"), + (0xFC52, "M", "هم"), + (0xFC53, "M", "هى"), + (0xFC54, "M", "هي"), + (0xFC55, "M", "يج"), + (0xFC56, "M", "يح"), + (0xFC57, "M", "يخ"), + (0xFC58, "M", "يم"), + (0xFC59, "M", "يى"), + (0xFC5A, "M", "يي"), + ] + + +def _seg_46() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFC5B, "M", "ذٰ"), + (0xFC5C, "M", "رٰ"), + (0xFC5D, "M", "ىٰ"), + (0xFC5E, "3", " ٌّ"), + (0xFC5F, "3", " ٍّ"), + (0xFC60, "3", " َّ"), + (0xFC61, "3", " ُّ"), + (0xFC62, "3", " ِّ"), + (0xFC63, "3", " ّٰ"), + (0xFC64, "M", "ئر"), + (0xFC65, "M", "ئز"), + (0xFC66, "M", "ئم"), + (0xFC67, "M", "ئن"), + (0xFC68, "M", "ئى"), + (0xFC69, "M", "ئي"), + (0xFC6A, "M", "بر"), + (0xFC6B, "M", "بز"), + (0xFC6C, "M", "بم"), + (0xFC6D, "M", "بن"), + (0xFC6E, "M", "بى"), + (0xFC6F, "M", "بي"), + (0xFC70, "M", "تر"), + (0xFC71, "M", "تز"), + (0xFC72, "M", "تم"), + (0xFC73, "M", "تن"), + (0xFC74, "M", "تى"), + (0xFC75, "M", "تي"), + (0xFC76, "M", "ثر"), + (0xFC77, "M", "ثز"), + (0xFC78, "M", "ثم"), + (0xFC79, "M", "ثن"), + (0xFC7A, "M", "ثى"), + (0xFC7B, "M", "ثي"), + (0xFC7C, "M", "فى"), + (0xFC7D, "M", "في"), + (0xFC7E, "M", "قى"), + (0xFC7F, "M", "قي"), + (0xFC80, "M", "كا"), + (0xFC81, "M", "كل"), + (0xFC82, "M", "كم"), + (0xFC83, "M", "كى"), + (0xFC84, "M", "كي"), + (0xFC85, "M", "لم"), + (0xFC86, "M", "لى"), + (0xFC87, "M", "لي"), + (0xFC88, "M", "ما"), + (0xFC89, "M", "مم"), + (0xFC8A, "M", "نر"), + (0xFC8B, "M", "نز"), + (0xFC8C, "M", "نم"), + (0xFC8D, "M", "نن"), + (0xFC8E, "M", "نى"), + (0xFC8F, "M", "ني"), + (0xFC90, "M", "ىٰ"), + (0xFC91, "M", "ير"), + (0xFC92, "M", "يز"), + (0xFC93, "M", "يم"), + (0xFC94, "M", "ين"), + (0xFC95, "M", "يى"), + (0xFC96, "M", "يي"), + (0xFC97, "M", "ئج"), + (0xFC98, "M", "ئح"), + (0xFC99, "M", "ئخ"), + (0xFC9A, "M", "ئم"), + (0xFC9B, "M", "ئه"), + (0xFC9C, "M", "بج"), + (0xFC9D, "M", "بح"), + (0xFC9E, "M", "بخ"), + (0xFC9F, "M", "بم"), + (0xFCA0, "M", "به"), + (0xFCA1, "M", "تج"), + (0xFCA2, "M", "تح"), + (0xFCA3, "M", "تخ"), + (0xFCA4, "M", "تم"), + (0xFCA5, "M", "ته"), + (0xFCA6, "M", "ثم"), + (0xFCA7, "M", "جح"), + (0xFCA8, "M", "جم"), + (0xFCA9, "M", "حج"), + (0xFCAA, "M", "حم"), + (0xFCAB, "M", "خج"), + (0xFCAC, "M", "خم"), + (0xFCAD, "M", "سج"), + (0xFCAE, "M", "سح"), + (0xFCAF, "M", "سخ"), + (0xFCB0, "M", "سم"), + (0xFCB1, "M", "صح"), + (0xFCB2, "M", "صخ"), + (0xFCB3, "M", "صم"), + (0xFCB4, "M", "ضج"), + (0xFCB5, "M", "ضح"), + (0xFCB6, "M", "ضخ"), + (0xFCB7, "M", "ضم"), + (0xFCB8, "M", "طح"), + (0xFCB9, "M", "ظم"), + (0xFCBA, "M", "عج"), + (0xFCBB, "M", "عم"), + (0xFCBC, "M", "غج"), + (0xFCBD, "M", "غم"), + (0xFCBE, "M", "فج"), + ] + + +def _seg_47() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFCBF, "M", "فح"), + (0xFCC0, "M", "فخ"), + (0xFCC1, "M", "فم"), + (0xFCC2, "M", "قح"), + (0xFCC3, "M", "قم"), + (0xFCC4, "M", "كج"), + (0xFCC5, "M", "كح"), + (0xFCC6, "M", "كخ"), + (0xFCC7, "M", "كل"), + (0xFCC8, "M", "كم"), + (0xFCC9, "M", "لج"), + (0xFCCA, "M", "لح"), + (0xFCCB, "M", "لخ"), + (0xFCCC, "M", "لم"), + (0xFCCD, "M", "له"), + (0xFCCE, "M", "مج"), + (0xFCCF, "M", "مح"), + (0xFCD0, "M", "مخ"), + (0xFCD1, "M", "مم"), + (0xFCD2, "M", "نج"), + (0xFCD3, "M", "نح"), + (0xFCD4, "M", "نخ"), + (0xFCD5, "M", "نم"), + (0xFCD6, "M", "نه"), + (0xFCD7, "M", "هج"), + (0xFCD8, "M", "هم"), + (0xFCD9, "M", "هٰ"), + (0xFCDA, "M", "يج"), + (0xFCDB, "M", "يح"), + (0xFCDC, "M", "يخ"), + (0xFCDD, "M", "يم"), + (0xFCDE, "M", "يه"), + (0xFCDF, "M", "ئم"), + (0xFCE0, "M", "ئه"), + (0xFCE1, "M", "بم"), + (0xFCE2, "M", "به"), + (0xFCE3, "M", "تم"), + (0xFCE4, "M", "ته"), + (0xFCE5, "M", "ثم"), + (0xFCE6, "M", "ثه"), + (0xFCE7, "M", "سم"), + (0xFCE8, "M", "سه"), + (0xFCE9, "M", "شم"), + (0xFCEA, "M", "شه"), + (0xFCEB, "M", "كل"), + (0xFCEC, "M", "كم"), + (0xFCED, "M", "لم"), + (0xFCEE, "M", "نم"), + (0xFCEF, "M", "نه"), + (0xFCF0, "M", "يم"), + (0xFCF1, "M", "يه"), + (0xFCF2, "M", "ـَّ"), + (0xFCF3, "M", "ـُّ"), + (0xFCF4, "M", "ـِّ"), + (0xFCF5, "M", "طى"), + (0xFCF6, "M", "طي"), + (0xFCF7, "M", "عى"), + (0xFCF8, "M", "عي"), + (0xFCF9, "M", "غى"), + (0xFCFA, "M", "غي"), + (0xFCFB, "M", "سى"), + (0xFCFC, "M", "سي"), + (0xFCFD, "M", "شى"), + (0xFCFE, "M", "شي"), + (0xFCFF, "M", "حى"), + (0xFD00, "M", "حي"), + (0xFD01, "M", "جى"), + (0xFD02, "M", "جي"), + (0xFD03, "M", "خى"), + (0xFD04, "M", "خي"), + (0xFD05, "M", "صى"), + (0xFD06, "M", "صي"), + (0xFD07, "M", "ضى"), + (0xFD08, "M", "ضي"), + (0xFD09, "M", "شج"), + (0xFD0A, "M", "شح"), + (0xFD0B, "M", "شخ"), + (0xFD0C, "M", "شم"), + (0xFD0D, "M", "شر"), + (0xFD0E, "M", "سر"), + (0xFD0F, "M", "صر"), + (0xFD10, "M", "ضر"), + (0xFD11, "M", "طى"), + (0xFD12, "M", "طي"), + (0xFD13, "M", "عى"), + (0xFD14, "M", "عي"), + (0xFD15, "M", "غى"), + (0xFD16, "M", "غي"), + (0xFD17, "M", "سى"), + (0xFD18, "M", "سي"), + (0xFD19, "M", "شى"), + (0xFD1A, "M", "شي"), + (0xFD1B, "M", "حى"), + (0xFD1C, "M", "حي"), + (0xFD1D, "M", "جى"), + (0xFD1E, "M", "جي"), + (0xFD1F, "M", "خى"), + (0xFD20, "M", "خي"), + (0xFD21, "M", "صى"), + (0xFD22, "M", "صي"), + ] + + +def _seg_48() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFD23, "M", "ضى"), + (0xFD24, "M", "ضي"), + (0xFD25, "M", "شج"), + (0xFD26, "M", "شح"), + (0xFD27, "M", "شخ"), + (0xFD28, "M", "شم"), + (0xFD29, "M", "شر"), + (0xFD2A, "M", "سر"), + (0xFD2B, "M", "صر"), + (0xFD2C, "M", "ضر"), + (0xFD2D, "M", "شج"), + (0xFD2E, "M", "شح"), + (0xFD2F, "M", "شخ"), + (0xFD30, "M", "شم"), + (0xFD31, "M", "سه"), + (0xFD32, "M", "شه"), + (0xFD33, "M", "طم"), + (0xFD34, "M", "سج"), + (0xFD35, "M", "سح"), + (0xFD36, "M", "سخ"), + (0xFD37, "M", "شج"), + (0xFD38, "M", "شح"), + (0xFD39, "M", "شخ"), + (0xFD3A, "M", "طم"), + (0xFD3B, "M", "ظم"), + (0xFD3C, "M", "اً"), + (0xFD3E, "V"), + (0xFD50, "M", "تجم"), + (0xFD51, "M", "تحج"), + (0xFD53, "M", "تحم"), + (0xFD54, "M", "تخم"), + (0xFD55, "M", "تمج"), + (0xFD56, "M", "تمح"), + (0xFD57, "M", "تمخ"), + (0xFD58, "M", "جمح"), + (0xFD5A, "M", "حمي"), + (0xFD5B, "M", "حمى"), + (0xFD5C, "M", "سحج"), + (0xFD5D, "M", "سجح"), + (0xFD5E, "M", "سجى"), + (0xFD5F, "M", "سمح"), + (0xFD61, "M", "سمج"), + (0xFD62, "M", "سمم"), + (0xFD64, "M", "صحح"), + (0xFD66, "M", "صمم"), + (0xFD67, "M", "شحم"), + (0xFD69, "M", "شجي"), + (0xFD6A, "M", "شمخ"), + (0xFD6C, "M", "شمم"), + (0xFD6E, "M", "ضحى"), + (0xFD6F, "M", "ضخم"), + (0xFD71, "M", "طمح"), + (0xFD73, "M", "طمم"), + (0xFD74, "M", "طمي"), + (0xFD75, "M", "عجم"), + (0xFD76, "M", "عمم"), + (0xFD78, "M", "عمى"), + (0xFD79, "M", "غمم"), + (0xFD7A, "M", "غمي"), + (0xFD7B, "M", "غمى"), + (0xFD7C, "M", "فخم"), + (0xFD7E, "M", "قمح"), + (0xFD7F, "M", "قمم"), + (0xFD80, "M", "لحم"), + (0xFD81, "M", "لحي"), + (0xFD82, "M", "لحى"), + (0xFD83, "M", "لجج"), + (0xFD85, "M", "لخم"), + (0xFD87, "M", "لمح"), + (0xFD89, "M", "محج"), + (0xFD8A, "M", "محم"), + (0xFD8B, "M", "محي"), + (0xFD8C, "M", "مجح"), + (0xFD8D, "M", "مجم"), + (0xFD8E, "M", "مخج"), + (0xFD8F, "M", "مخم"), + (0xFD90, "X"), + (0xFD92, "M", "مجخ"), + (0xFD93, "M", "همج"), + (0xFD94, "M", "همم"), + (0xFD95, "M", "نحم"), + (0xFD96, "M", "نحى"), + (0xFD97, "M", "نجم"), + (0xFD99, "M", "نجى"), + (0xFD9A, "M", "نمي"), + (0xFD9B, "M", "نمى"), + (0xFD9C, "M", "يمم"), + (0xFD9E, "M", "بخي"), + (0xFD9F, "M", "تجي"), + (0xFDA0, "M", "تجى"), + (0xFDA1, "M", "تخي"), + (0xFDA2, "M", "تخى"), + (0xFDA3, "M", "تمي"), + (0xFDA4, "M", "تمى"), + (0xFDA5, "M", "جمي"), + (0xFDA6, "M", "جحى"), + (0xFDA7, "M", "جمى"), + (0xFDA8, "M", "سخى"), + (0xFDA9, "M", "صحي"), + (0xFDAA, "M", "شحي"), + ] + + +def _seg_49() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFDAB, "M", "ضحي"), + (0xFDAC, "M", "لجي"), + (0xFDAD, "M", "لمي"), + (0xFDAE, "M", "يحي"), + (0xFDAF, "M", "يجي"), + (0xFDB0, "M", "يمي"), + (0xFDB1, "M", "ممي"), + (0xFDB2, "M", "قمي"), + (0xFDB3, "M", "نحي"), + (0xFDB4, "M", "قمح"), + (0xFDB5, "M", "لحم"), + (0xFDB6, "M", "عمي"), + (0xFDB7, "M", "كمي"), + (0xFDB8, "M", "نجح"), + (0xFDB9, "M", "مخي"), + (0xFDBA, "M", "لجم"), + (0xFDBB, "M", "كمم"), + (0xFDBC, "M", "لجم"), + (0xFDBD, "M", "نجح"), + (0xFDBE, "M", "جحي"), + (0xFDBF, "M", "حجي"), + (0xFDC0, "M", "مجي"), + (0xFDC1, "M", "فمي"), + (0xFDC2, "M", "بحي"), + (0xFDC3, "M", "كمم"), + (0xFDC4, "M", "عجم"), + (0xFDC5, "M", "صمم"), + (0xFDC6, "M", "سخي"), + (0xFDC7, "M", "نجي"), + (0xFDC8, "X"), + (0xFDCF, "V"), + (0xFDD0, "X"), + (0xFDF0, "M", "صلے"), + (0xFDF1, "M", "قلے"), + (0xFDF2, "M", "الله"), + (0xFDF3, "M", "اكبر"), + (0xFDF4, "M", "محمد"), + (0xFDF5, "M", "صلعم"), + (0xFDF6, "M", "رسول"), + (0xFDF7, "M", "عليه"), + (0xFDF8, "M", "وسلم"), + (0xFDF9, "M", "صلى"), + (0xFDFA, "3", "صلى الله عليه وسلم"), + (0xFDFB, "3", "جل جلاله"), + (0xFDFC, "M", "ریال"), + (0xFDFD, "V"), + (0xFE00, "I"), + (0xFE10, "3", ","), + (0xFE11, "M", "、"), + (0xFE12, "X"), + (0xFE13, "3", ":"), + (0xFE14, "3", ";"), + (0xFE15, "3", "!"), + (0xFE16, "3", "?"), + (0xFE17, "M", "〖"), + (0xFE18, "M", "〗"), + (0xFE19, "X"), + (0xFE20, "V"), + (0xFE30, "X"), + (0xFE31, "M", "—"), + (0xFE32, "M", "–"), + (0xFE33, "3", "_"), + (0xFE35, "3", "("), + (0xFE36, "3", ")"), + (0xFE37, "3", "{"), + (0xFE38, "3", "}"), + (0xFE39, "M", "〔"), + (0xFE3A, "M", "〕"), + (0xFE3B, "M", "【"), + (0xFE3C, "M", "】"), + (0xFE3D, "M", "《"), + (0xFE3E, "M", "》"), + (0xFE3F, "M", "〈"), + (0xFE40, "M", "〉"), + (0xFE41, "M", "「"), + (0xFE42, "M", "」"), + (0xFE43, "M", "『"), + (0xFE44, "M", "』"), + (0xFE45, "V"), + (0xFE47, "3", "["), + (0xFE48, "3", "]"), + (0xFE49, "3", " ̅"), + (0xFE4D, "3", "_"), + (0xFE50, "3", ","), + (0xFE51, "M", "、"), + (0xFE52, "X"), + (0xFE54, "3", ";"), + (0xFE55, "3", ":"), + (0xFE56, "3", "?"), + (0xFE57, "3", "!"), + (0xFE58, "M", "—"), + (0xFE59, "3", "("), + (0xFE5A, "3", ")"), + (0xFE5B, "3", "{"), + (0xFE5C, "3", "}"), + (0xFE5D, "M", "〔"), + (0xFE5E, "M", "〕"), + (0xFE5F, "3", "#"), + (0xFE60, "3", "&"), + (0xFE61, "3", "*"), + ] + + +def _seg_50() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFE62, "3", "+"), + (0xFE63, "M", "-"), + (0xFE64, "3", "<"), + (0xFE65, "3", ">"), + (0xFE66, "3", "="), + (0xFE67, "X"), + (0xFE68, "3", "\\"), + (0xFE69, "3", "$"), + (0xFE6A, "3", "%"), + (0xFE6B, "3", "@"), + (0xFE6C, "X"), + (0xFE70, "3", " ً"), + (0xFE71, "M", "ـً"), + (0xFE72, "3", " ٌ"), + (0xFE73, "V"), + (0xFE74, "3", " ٍ"), + (0xFE75, "X"), + (0xFE76, "3", " َ"), + (0xFE77, "M", "ـَ"), + (0xFE78, "3", " ُ"), + (0xFE79, "M", "ـُ"), + (0xFE7A, "3", " ِ"), + (0xFE7B, "M", "ـِ"), + (0xFE7C, "3", " ّ"), + (0xFE7D, "M", "ـّ"), + (0xFE7E, "3", " ْ"), + (0xFE7F, "M", "ـْ"), + (0xFE80, "M", "ء"), + (0xFE81, "M", "آ"), + (0xFE83, "M", "أ"), + (0xFE85, "M", "ؤ"), + (0xFE87, "M", "إ"), + (0xFE89, "M", "ئ"), + (0xFE8D, "M", "ا"), + (0xFE8F, "M", "ب"), + (0xFE93, "M", "ة"), + (0xFE95, "M", "ت"), + (0xFE99, "M", "ث"), + (0xFE9D, "M", "ج"), + (0xFEA1, "M", "ح"), + (0xFEA5, "M", "خ"), + (0xFEA9, "M", "د"), + (0xFEAB, "M", "ذ"), + (0xFEAD, "M", "ر"), + (0xFEAF, "M", "ز"), + (0xFEB1, "M", "س"), + (0xFEB5, "M", "ش"), + (0xFEB9, "M", "ص"), + (0xFEBD, "M", "ض"), + (0xFEC1, "M", "ط"), + (0xFEC5, "M", "ظ"), + (0xFEC9, "M", "ع"), + (0xFECD, "M", "غ"), + (0xFED1, "M", "ف"), + (0xFED5, "M", "ق"), + (0xFED9, "M", "ك"), + (0xFEDD, "M", "ل"), + (0xFEE1, "M", "م"), + (0xFEE5, "M", "ن"), + (0xFEE9, "M", "ه"), + (0xFEED, "M", "و"), + (0xFEEF, "M", "ى"), + (0xFEF1, "M", "ي"), + (0xFEF5, "M", "لآ"), + (0xFEF7, "M", "لأ"), + (0xFEF9, "M", "لإ"), + (0xFEFB, "M", "لا"), + (0xFEFD, "X"), + (0xFEFF, "I"), + (0xFF00, "X"), + (0xFF01, "3", "!"), + (0xFF02, "3", '"'), + (0xFF03, "3", "#"), + (0xFF04, "3", "$"), + (0xFF05, "3", "%"), + (0xFF06, "3", "&"), + (0xFF07, "3", "'"), + (0xFF08, "3", "("), + (0xFF09, "3", ")"), + (0xFF0A, "3", "*"), + (0xFF0B, "3", "+"), + (0xFF0C, "3", ","), + (0xFF0D, "M", "-"), + (0xFF0E, "M", "."), + (0xFF0F, "3", "/"), + (0xFF10, "M", "0"), + (0xFF11, "M", "1"), + (0xFF12, "M", "2"), + (0xFF13, "M", "3"), + (0xFF14, "M", "4"), + (0xFF15, "M", "5"), + (0xFF16, "M", "6"), + (0xFF17, "M", "7"), + (0xFF18, "M", "8"), + (0xFF19, "M", "9"), + (0xFF1A, "3", ":"), + (0xFF1B, "3", ";"), + (0xFF1C, "3", "<"), + (0xFF1D, "3", "="), + (0xFF1E, "3", ">"), + ] + + +def _seg_51() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFF1F, "3", "?"), + (0xFF20, "3", "@"), + (0xFF21, "M", "a"), + (0xFF22, "M", "b"), + (0xFF23, "M", "c"), + (0xFF24, "M", "d"), + (0xFF25, "M", "e"), + (0xFF26, "M", "f"), + (0xFF27, "M", "g"), + (0xFF28, "M", "h"), + (0xFF29, "M", "i"), + (0xFF2A, "M", "j"), + (0xFF2B, "M", "k"), + (0xFF2C, "M", "l"), + (0xFF2D, "M", "m"), + (0xFF2E, "M", "n"), + (0xFF2F, "M", "o"), + (0xFF30, "M", "p"), + (0xFF31, "M", "q"), + (0xFF32, "M", "r"), + (0xFF33, "M", "s"), + (0xFF34, "M", "t"), + (0xFF35, "M", "u"), + (0xFF36, "M", "v"), + (0xFF37, "M", "w"), + (0xFF38, "M", "x"), + (0xFF39, "M", "y"), + (0xFF3A, "M", "z"), + (0xFF3B, "3", "["), + (0xFF3C, "3", "\\"), + (0xFF3D, "3", "]"), + (0xFF3E, "3", "^"), + (0xFF3F, "3", "_"), + (0xFF40, "3", "`"), + (0xFF41, "M", "a"), + (0xFF42, "M", "b"), + (0xFF43, "M", "c"), + (0xFF44, "M", "d"), + (0xFF45, "M", "e"), + (0xFF46, "M", "f"), + (0xFF47, "M", "g"), + (0xFF48, "M", "h"), + (0xFF49, "M", "i"), + (0xFF4A, "M", "j"), + (0xFF4B, "M", "k"), + (0xFF4C, "M", "l"), + (0xFF4D, "M", "m"), + (0xFF4E, "M", "n"), + (0xFF4F, "M", "o"), + (0xFF50, "M", "p"), + (0xFF51, "M", "q"), + (0xFF52, "M", "r"), + (0xFF53, "M", "s"), + (0xFF54, "M", "t"), + (0xFF55, "M", "u"), + (0xFF56, "M", "v"), + (0xFF57, "M", "w"), + (0xFF58, "M", "x"), + (0xFF59, "M", "y"), + (0xFF5A, "M", "z"), + (0xFF5B, "3", "{"), + (0xFF5C, "3", "|"), + (0xFF5D, "3", "}"), + (0xFF5E, "3", "~"), + (0xFF5F, "M", "⦅"), + (0xFF60, "M", "⦆"), + (0xFF61, "M", "."), + (0xFF62, "M", "「"), + (0xFF63, "M", "」"), + (0xFF64, "M", "、"), + (0xFF65, "M", "・"), + (0xFF66, "M", "ヲ"), + (0xFF67, "M", "ァ"), + (0xFF68, "M", "ィ"), + (0xFF69, "M", "ゥ"), + (0xFF6A, "M", "ェ"), + (0xFF6B, "M", "ォ"), + (0xFF6C, "M", "ャ"), + (0xFF6D, "M", "ュ"), + (0xFF6E, "M", "ョ"), + (0xFF6F, "M", "ッ"), + (0xFF70, "M", "ー"), + (0xFF71, "M", "ア"), + (0xFF72, "M", "イ"), + (0xFF73, "M", "ウ"), + (0xFF74, "M", "エ"), + (0xFF75, "M", "オ"), + (0xFF76, "M", "カ"), + (0xFF77, "M", "キ"), + (0xFF78, "M", "ク"), + (0xFF79, "M", "ケ"), + (0xFF7A, "M", "コ"), + (0xFF7B, "M", "サ"), + (0xFF7C, "M", "シ"), + (0xFF7D, "M", "ス"), + (0xFF7E, "M", "セ"), + (0xFF7F, "M", "ソ"), + (0xFF80, "M", "タ"), + (0xFF81, "M", "チ"), + (0xFF82, "M", "ツ"), + ] + + +def _seg_52() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFF83, "M", "テ"), + (0xFF84, "M", "ト"), + (0xFF85, "M", "ナ"), + (0xFF86, "M", "ニ"), + (0xFF87, "M", "ヌ"), + (0xFF88, "M", "ネ"), + (0xFF89, "M", "ノ"), + (0xFF8A, "M", "ハ"), + (0xFF8B, "M", "ヒ"), + (0xFF8C, "M", "フ"), + (0xFF8D, "M", "ヘ"), + (0xFF8E, "M", "ホ"), + (0xFF8F, "M", "マ"), + (0xFF90, "M", "ミ"), + (0xFF91, "M", "ム"), + (0xFF92, "M", "メ"), + (0xFF93, "M", "モ"), + (0xFF94, "M", "ヤ"), + (0xFF95, "M", "ユ"), + (0xFF96, "M", "ヨ"), + (0xFF97, "M", "ラ"), + (0xFF98, "M", "リ"), + (0xFF99, "M", "ル"), + (0xFF9A, "M", "レ"), + (0xFF9B, "M", "ロ"), + (0xFF9C, "M", "ワ"), + (0xFF9D, "M", "ン"), + (0xFF9E, "M", "゙"), + (0xFF9F, "M", "゚"), + (0xFFA0, "X"), + (0xFFA1, "M", "ᄀ"), + (0xFFA2, "M", "ᄁ"), + (0xFFA3, "M", "ᆪ"), + (0xFFA4, "M", "ᄂ"), + (0xFFA5, "M", "ᆬ"), + (0xFFA6, "M", "ᆭ"), + (0xFFA7, "M", "ᄃ"), + (0xFFA8, "M", "ᄄ"), + (0xFFA9, "M", "ᄅ"), + (0xFFAA, "M", "ᆰ"), + (0xFFAB, "M", "ᆱ"), + (0xFFAC, "M", "ᆲ"), + (0xFFAD, "M", "ᆳ"), + (0xFFAE, "M", "ᆴ"), + (0xFFAF, "M", "ᆵ"), + (0xFFB0, "M", "ᄚ"), + (0xFFB1, "M", "ᄆ"), + (0xFFB2, "M", "ᄇ"), + (0xFFB3, "M", "ᄈ"), + (0xFFB4, "M", "ᄡ"), + (0xFFB5, "M", "ᄉ"), + (0xFFB6, "M", "ᄊ"), + (0xFFB7, "M", "ᄋ"), + (0xFFB8, "M", "ᄌ"), + (0xFFB9, "M", "ᄍ"), + (0xFFBA, "M", "ᄎ"), + (0xFFBB, "M", "ᄏ"), + (0xFFBC, "M", "ᄐ"), + (0xFFBD, "M", "ᄑ"), + (0xFFBE, "M", "ᄒ"), + (0xFFBF, "X"), + (0xFFC2, "M", "ᅡ"), + (0xFFC3, "M", "ᅢ"), + (0xFFC4, "M", "ᅣ"), + (0xFFC5, "M", "ᅤ"), + (0xFFC6, "M", "ᅥ"), + (0xFFC7, "M", "ᅦ"), + (0xFFC8, "X"), + (0xFFCA, "M", "ᅧ"), + (0xFFCB, "M", "ᅨ"), + (0xFFCC, "M", "ᅩ"), + (0xFFCD, "M", "ᅪ"), + (0xFFCE, "M", "ᅫ"), + (0xFFCF, "M", "ᅬ"), + (0xFFD0, "X"), + (0xFFD2, "M", "ᅭ"), + (0xFFD3, "M", "ᅮ"), + (0xFFD4, "M", "ᅯ"), + (0xFFD5, "M", "ᅰ"), + (0xFFD6, "M", "ᅱ"), + (0xFFD7, "M", "ᅲ"), + (0xFFD8, "X"), + (0xFFDA, "M", "ᅳ"), + (0xFFDB, "M", "ᅴ"), + (0xFFDC, "M", "ᅵ"), + (0xFFDD, "X"), + (0xFFE0, "M", "¢"), + (0xFFE1, "M", "£"), + (0xFFE2, "M", "¬"), + (0xFFE3, "3", " ̄"), + (0xFFE4, "M", "¦"), + (0xFFE5, "M", "¥"), + (0xFFE6, "M", "₩"), + (0xFFE7, "X"), + (0xFFE8, "M", "│"), + (0xFFE9, "M", "←"), + (0xFFEA, "M", "↑"), + (0xFFEB, "M", "→"), + (0xFFEC, "M", "↓"), + (0xFFED, "M", "■"), + ] + + +def _seg_53() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0xFFEE, "M", "○"), + (0xFFEF, "X"), + (0x10000, "V"), + (0x1000C, "X"), + (0x1000D, "V"), + (0x10027, "X"), + (0x10028, "V"), + (0x1003B, "X"), + (0x1003C, "V"), + (0x1003E, "X"), + (0x1003F, "V"), + (0x1004E, "X"), + (0x10050, "V"), + (0x1005E, "X"), + (0x10080, "V"), + (0x100FB, "X"), + (0x10100, "V"), + (0x10103, "X"), + (0x10107, "V"), + (0x10134, "X"), + (0x10137, "V"), + (0x1018F, "X"), + (0x10190, "V"), + (0x1019D, "X"), + (0x101A0, "V"), + (0x101A1, "X"), + (0x101D0, "V"), + (0x101FE, "X"), + (0x10280, "V"), + (0x1029D, "X"), + (0x102A0, "V"), + (0x102D1, "X"), + (0x102E0, "V"), + (0x102FC, "X"), + (0x10300, "V"), + (0x10324, "X"), + (0x1032D, "V"), + (0x1034B, "X"), + (0x10350, "V"), + (0x1037B, "X"), + (0x10380, "V"), + (0x1039E, "X"), + (0x1039F, "V"), + (0x103C4, "X"), + (0x103C8, "V"), + (0x103D6, "X"), + (0x10400, "M", "𐐨"), + (0x10401, "M", "𐐩"), + (0x10402, "M", "𐐪"), + (0x10403, "M", "𐐫"), + (0x10404, "M", "𐐬"), + (0x10405, "M", "𐐭"), + (0x10406, "M", "𐐮"), + (0x10407, "M", "𐐯"), + (0x10408, "M", "𐐰"), + (0x10409, "M", "𐐱"), + (0x1040A, "M", "𐐲"), + (0x1040B, "M", "𐐳"), + (0x1040C, "M", "𐐴"), + (0x1040D, "M", "𐐵"), + (0x1040E, "M", "𐐶"), + (0x1040F, "M", "𐐷"), + (0x10410, "M", "𐐸"), + (0x10411, "M", "𐐹"), + (0x10412, "M", "𐐺"), + (0x10413, "M", "𐐻"), + (0x10414, "M", "𐐼"), + (0x10415, "M", "𐐽"), + (0x10416, "M", "𐐾"), + (0x10417, "M", "𐐿"), + (0x10418, "M", "𐑀"), + (0x10419, "M", "𐑁"), + (0x1041A, "M", "𐑂"), + (0x1041B, "M", "𐑃"), + (0x1041C, "M", "𐑄"), + (0x1041D, "M", "𐑅"), + (0x1041E, "M", "𐑆"), + (0x1041F, "M", "𐑇"), + (0x10420, "M", "𐑈"), + (0x10421, "M", "𐑉"), + (0x10422, "M", "𐑊"), + (0x10423, "M", "𐑋"), + (0x10424, "M", "𐑌"), + (0x10425, "M", "𐑍"), + (0x10426, "M", "𐑎"), + (0x10427, "M", "𐑏"), + (0x10428, "V"), + (0x1049E, "X"), + (0x104A0, "V"), + (0x104AA, "X"), + (0x104B0, "M", "𐓘"), + (0x104B1, "M", "𐓙"), + (0x104B2, "M", "𐓚"), + (0x104B3, "M", "𐓛"), + (0x104B4, "M", "𐓜"), + (0x104B5, "M", "𐓝"), + (0x104B6, "M", "𐓞"), + (0x104B7, "M", "𐓟"), + (0x104B8, "M", "𐓠"), + (0x104B9, "M", "𐓡"), + ] + + +def _seg_54() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x104BA, "M", "𐓢"), + (0x104BB, "M", "𐓣"), + (0x104BC, "M", "𐓤"), + (0x104BD, "M", "𐓥"), + (0x104BE, "M", "𐓦"), + (0x104BF, "M", "𐓧"), + (0x104C0, "M", "𐓨"), + (0x104C1, "M", "𐓩"), + (0x104C2, "M", "𐓪"), + (0x104C3, "M", "𐓫"), + (0x104C4, "M", "𐓬"), + (0x104C5, "M", "𐓭"), + (0x104C6, "M", "𐓮"), + (0x104C7, "M", "𐓯"), + (0x104C8, "M", "𐓰"), + (0x104C9, "M", "𐓱"), + (0x104CA, "M", "𐓲"), + (0x104CB, "M", "𐓳"), + (0x104CC, "M", "𐓴"), + (0x104CD, "M", "𐓵"), + (0x104CE, "M", "𐓶"), + (0x104CF, "M", "𐓷"), + (0x104D0, "M", "𐓸"), + (0x104D1, "M", "𐓹"), + (0x104D2, "M", "𐓺"), + (0x104D3, "M", "𐓻"), + (0x104D4, "X"), + (0x104D8, "V"), + (0x104FC, "X"), + (0x10500, "V"), + (0x10528, "X"), + (0x10530, "V"), + (0x10564, "X"), + (0x1056F, "V"), + (0x10570, "M", "𐖗"), + (0x10571, "M", "𐖘"), + (0x10572, "M", "𐖙"), + (0x10573, "M", "𐖚"), + (0x10574, "M", "𐖛"), + (0x10575, "M", "𐖜"), + (0x10576, "M", "𐖝"), + (0x10577, "M", "𐖞"), + (0x10578, "M", "𐖟"), + (0x10579, "M", "𐖠"), + (0x1057A, "M", "𐖡"), + (0x1057B, "X"), + (0x1057C, "M", "𐖣"), + (0x1057D, "M", "𐖤"), + (0x1057E, "M", "𐖥"), + (0x1057F, "M", "𐖦"), + (0x10580, "M", "𐖧"), + (0x10581, "M", "𐖨"), + (0x10582, "M", "𐖩"), + (0x10583, "M", "𐖪"), + (0x10584, "M", "𐖫"), + (0x10585, "M", "𐖬"), + (0x10586, "M", "𐖭"), + (0x10587, "M", "𐖮"), + (0x10588, "M", "𐖯"), + (0x10589, "M", "𐖰"), + (0x1058A, "M", "𐖱"), + (0x1058B, "X"), + (0x1058C, "M", "𐖳"), + (0x1058D, "M", "𐖴"), + (0x1058E, "M", "𐖵"), + (0x1058F, "M", "𐖶"), + (0x10590, "M", "𐖷"), + (0x10591, "M", "𐖸"), + (0x10592, "M", "𐖹"), + (0x10593, "X"), + (0x10594, "M", "𐖻"), + (0x10595, "M", "𐖼"), + (0x10596, "X"), + (0x10597, "V"), + (0x105A2, "X"), + (0x105A3, "V"), + (0x105B2, "X"), + (0x105B3, "V"), + (0x105BA, "X"), + (0x105BB, "V"), + (0x105BD, "X"), + (0x10600, "V"), + (0x10737, "X"), + (0x10740, "V"), + (0x10756, "X"), + (0x10760, "V"), + (0x10768, "X"), + (0x10780, "V"), + (0x10781, "M", "ː"), + (0x10782, "M", "ˑ"), + (0x10783, "M", "æ"), + (0x10784, "M", "ʙ"), + (0x10785, "M", "ɓ"), + (0x10786, "X"), + (0x10787, "M", "ʣ"), + (0x10788, "M", "ꭦ"), + (0x10789, "M", "ʥ"), + (0x1078A, "M", "ʤ"), + (0x1078B, "M", "ɖ"), + (0x1078C, "M", "ɗ"), + ] + + +def _seg_55() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1078D, "M", "ᶑ"), + (0x1078E, "M", "ɘ"), + (0x1078F, "M", "ɞ"), + (0x10790, "M", "ʩ"), + (0x10791, "M", "ɤ"), + (0x10792, "M", "ɢ"), + (0x10793, "M", "ɠ"), + (0x10794, "M", "ʛ"), + (0x10795, "M", "ħ"), + (0x10796, "M", "ʜ"), + (0x10797, "M", "ɧ"), + (0x10798, "M", "ʄ"), + (0x10799, "M", "ʪ"), + (0x1079A, "M", "ʫ"), + (0x1079B, "M", "ɬ"), + (0x1079C, "M", "𝼄"), + (0x1079D, "M", "ꞎ"), + (0x1079E, "M", "ɮ"), + (0x1079F, "M", "𝼅"), + (0x107A0, "M", "ʎ"), + (0x107A1, "M", "𝼆"), + (0x107A2, "M", "ø"), + (0x107A3, "M", "ɶ"), + (0x107A4, "M", "ɷ"), + (0x107A5, "M", "q"), + (0x107A6, "M", "ɺ"), + (0x107A7, "M", "𝼈"), + (0x107A8, "M", "ɽ"), + (0x107A9, "M", "ɾ"), + (0x107AA, "M", "ʀ"), + (0x107AB, "M", "ʨ"), + (0x107AC, "M", "ʦ"), + (0x107AD, "M", "ꭧ"), + (0x107AE, "M", "ʧ"), + (0x107AF, "M", "ʈ"), + (0x107B0, "M", "ⱱ"), + (0x107B1, "X"), + (0x107B2, "M", "ʏ"), + (0x107B3, "M", "ʡ"), + (0x107B4, "M", "ʢ"), + (0x107B5, "M", "ʘ"), + (0x107B6, "M", "ǀ"), + (0x107B7, "M", "ǁ"), + (0x107B8, "M", "ǂ"), + (0x107B9, "M", "𝼊"), + (0x107BA, "M", "𝼞"), + (0x107BB, "X"), + (0x10800, "V"), + (0x10806, "X"), + (0x10808, "V"), + (0x10809, "X"), + (0x1080A, "V"), + (0x10836, "X"), + (0x10837, "V"), + (0x10839, "X"), + (0x1083C, "V"), + (0x1083D, "X"), + (0x1083F, "V"), + (0x10856, "X"), + (0x10857, "V"), + (0x1089F, "X"), + (0x108A7, "V"), + (0x108B0, "X"), + (0x108E0, "V"), + (0x108F3, "X"), + (0x108F4, "V"), + (0x108F6, "X"), + (0x108FB, "V"), + (0x1091C, "X"), + (0x1091F, "V"), + (0x1093A, "X"), + (0x1093F, "V"), + (0x10940, "X"), + (0x10980, "V"), + (0x109B8, "X"), + (0x109BC, "V"), + (0x109D0, "X"), + (0x109D2, "V"), + (0x10A04, "X"), + (0x10A05, "V"), + (0x10A07, "X"), + (0x10A0C, "V"), + (0x10A14, "X"), + (0x10A15, "V"), + (0x10A18, "X"), + (0x10A19, "V"), + (0x10A36, "X"), + (0x10A38, "V"), + (0x10A3B, "X"), + (0x10A3F, "V"), + (0x10A49, "X"), + (0x10A50, "V"), + (0x10A59, "X"), + (0x10A60, "V"), + (0x10AA0, "X"), + (0x10AC0, "V"), + (0x10AE7, "X"), + (0x10AEB, "V"), + (0x10AF7, "X"), + (0x10B00, "V"), + ] + + +def _seg_56() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x10B36, "X"), + (0x10B39, "V"), + (0x10B56, "X"), + (0x10B58, "V"), + (0x10B73, "X"), + (0x10B78, "V"), + (0x10B92, "X"), + (0x10B99, "V"), + (0x10B9D, "X"), + (0x10BA9, "V"), + (0x10BB0, "X"), + (0x10C00, "V"), + (0x10C49, "X"), + (0x10C80, "M", "𐳀"), + (0x10C81, "M", "𐳁"), + (0x10C82, "M", "𐳂"), + (0x10C83, "M", "𐳃"), + (0x10C84, "M", "𐳄"), + (0x10C85, "M", "𐳅"), + (0x10C86, "M", "𐳆"), + (0x10C87, "M", "𐳇"), + (0x10C88, "M", "𐳈"), + (0x10C89, "M", "𐳉"), + (0x10C8A, "M", "𐳊"), + (0x10C8B, "M", "𐳋"), + (0x10C8C, "M", "𐳌"), + (0x10C8D, "M", "𐳍"), + (0x10C8E, "M", "𐳎"), + (0x10C8F, "M", "𐳏"), + (0x10C90, "M", "𐳐"), + (0x10C91, "M", "𐳑"), + (0x10C92, "M", "𐳒"), + (0x10C93, "M", "𐳓"), + (0x10C94, "M", "𐳔"), + (0x10C95, "M", "𐳕"), + (0x10C96, "M", "𐳖"), + (0x10C97, "M", "𐳗"), + (0x10C98, "M", "𐳘"), + (0x10C99, "M", "𐳙"), + (0x10C9A, "M", "𐳚"), + (0x10C9B, "M", "𐳛"), + (0x10C9C, "M", "𐳜"), + (0x10C9D, "M", "𐳝"), + (0x10C9E, "M", "𐳞"), + (0x10C9F, "M", "𐳟"), + (0x10CA0, "M", "𐳠"), + (0x10CA1, "M", "𐳡"), + (0x10CA2, "M", "𐳢"), + (0x10CA3, "M", "𐳣"), + (0x10CA4, "M", "𐳤"), + (0x10CA5, "M", "𐳥"), + (0x10CA6, "M", "𐳦"), + (0x10CA7, "M", "𐳧"), + (0x10CA8, "M", "𐳨"), + (0x10CA9, "M", "𐳩"), + (0x10CAA, "M", "𐳪"), + (0x10CAB, "M", "𐳫"), + (0x10CAC, "M", "𐳬"), + (0x10CAD, "M", "𐳭"), + (0x10CAE, "M", "𐳮"), + (0x10CAF, "M", "𐳯"), + (0x10CB0, "M", "𐳰"), + (0x10CB1, "M", "𐳱"), + (0x10CB2, "M", "𐳲"), + (0x10CB3, "X"), + (0x10CC0, "V"), + (0x10CF3, "X"), + (0x10CFA, "V"), + (0x10D28, "X"), + (0x10D30, "V"), + (0x10D3A, "X"), + (0x10E60, "V"), + (0x10E7F, "X"), + (0x10E80, "V"), + (0x10EAA, "X"), + (0x10EAB, "V"), + (0x10EAE, "X"), + (0x10EB0, "V"), + (0x10EB2, "X"), + (0x10EFD, "V"), + (0x10F28, "X"), + (0x10F30, "V"), + (0x10F5A, "X"), + (0x10F70, "V"), + (0x10F8A, "X"), + (0x10FB0, "V"), + (0x10FCC, "X"), + (0x10FE0, "V"), + (0x10FF7, "X"), + (0x11000, "V"), + (0x1104E, "X"), + (0x11052, "V"), + (0x11076, "X"), + (0x1107F, "V"), + (0x110BD, "X"), + (0x110BE, "V"), + (0x110C3, "X"), + (0x110D0, "V"), + (0x110E9, "X"), + (0x110F0, "V"), + ] + + +def _seg_57() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x110FA, "X"), + (0x11100, "V"), + (0x11135, "X"), + (0x11136, "V"), + (0x11148, "X"), + (0x11150, "V"), + (0x11177, "X"), + (0x11180, "V"), + (0x111E0, "X"), + (0x111E1, "V"), + (0x111F5, "X"), + (0x11200, "V"), + (0x11212, "X"), + (0x11213, "V"), + (0x11242, "X"), + (0x11280, "V"), + (0x11287, "X"), + (0x11288, "V"), + (0x11289, "X"), + (0x1128A, "V"), + (0x1128E, "X"), + (0x1128F, "V"), + (0x1129E, "X"), + (0x1129F, "V"), + (0x112AA, "X"), + (0x112B0, "V"), + (0x112EB, "X"), + (0x112F0, "V"), + (0x112FA, "X"), + (0x11300, "V"), + (0x11304, "X"), + (0x11305, "V"), + (0x1130D, "X"), + (0x1130F, "V"), + (0x11311, "X"), + (0x11313, "V"), + (0x11329, "X"), + (0x1132A, "V"), + (0x11331, "X"), + (0x11332, "V"), + (0x11334, "X"), + (0x11335, "V"), + (0x1133A, "X"), + (0x1133B, "V"), + (0x11345, "X"), + (0x11347, "V"), + (0x11349, "X"), + (0x1134B, "V"), + (0x1134E, "X"), + (0x11350, "V"), + (0x11351, "X"), + (0x11357, "V"), + (0x11358, "X"), + (0x1135D, "V"), + (0x11364, "X"), + (0x11366, "V"), + (0x1136D, "X"), + (0x11370, "V"), + (0x11375, "X"), + (0x11400, "V"), + (0x1145C, "X"), + (0x1145D, "V"), + (0x11462, "X"), + (0x11480, "V"), + (0x114C8, "X"), + (0x114D0, "V"), + (0x114DA, "X"), + (0x11580, "V"), + (0x115B6, "X"), + (0x115B8, "V"), + (0x115DE, "X"), + (0x11600, "V"), + (0x11645, "X"), + (0x11650, "V"), + (0x1165A, "X"), + (0x11660, "V"), + (0x1166D, "X"), + (0x11680, "V"), + (0x116BA, "X"), + (0x116C0, "V"), + (0x116CA, "X"), + (0x11700, "V"), + (0x1171B, "X"), + (0x1171D, "V"), + (0x1172C, "X"), + (0x11730, "V"), + (0x11747, "X"), + (0x11800, "V"), + (0x1183C, "X"), + (0x118A0, "M", "𑣀"), + (0x118A1, "M", "𑣁"), + (0x118A2, "M", "𑣂"), + (0x118A3, "M", "𑣃"), + (0x118A4, "M", "𑣄"), + (0x118A5, "M", "𑣅"), + (0x118A6, "M", "𑣆"), + (0x118A7, "M", "𑣇"), + (0x118A8, "M", "𑣈"), + (0x118A9, "M", "𑣉"), + (0x118AA, "M", "𑣊"), + ] + + +def _seg_58() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x118AB, "M", "𑣋"), + (0x118AC, "M", "𑣌"), + (0x118AD, "M", "𑣍"), + (0x118AE, "M", "𑣎"), + (0x118AF, "M", "𑣏"), + (0x118B0, "M", "𑣐"), + (0x118B1, "M", "𑣑"), + (0x118B2, "M", "𑣒"), + (0x118B3, "M", "𑣓"), + (0x118B4, "M", "𑣔"), + (0x118B5, "M", "𑣕"), + (0x118B6, "M", "𑣖"), + (0x118B7, "M", "𑣗"), + (0x118B8, "M", "𑣘"), + (0x118B9, "M", "𑣙"), + (0x118BA, "M", "𑣚"), + (0x118BB, "M", "𑣛"), + (0x118BC, "M", "𑣜"), + (0x118BD, "M", "𑣝"), + (0x118BE, "M", "𑣞"), + (0x118BF, "M", "𑣟"), + (0x118C0, "V"), + (0x118F3, "X"), + (0x118FF, "V"), + (0x11907, "X"), + (0x11909, "V"), + (0x1190A, "X"), + (0x1190C, "V"), + (0x11914, "X"), + (0x11915, "V"), + (0x11917, "X"), + (0x11918, "V"), + (0x11936, "X"), + (0x11937, "V"), + (0x11939, "X"), + (0x1193B, "V"), + (0x11947, "X"), + (0x11950, "V"), + (0x1195A, "X"), + (0x119A0, "V"), + (0x119A8, "X"), + (0x119AA, "V"), + (0x119D8, "X"), + (0x119DA, "V"), + (0x119E5, "X"), + (0x11A00, "V"), + (0x11A48, "X"), + (0x11A50, "V"), + (0x11AA3, "X"), + (0x11AB0, "V"), + (0x11AF9, "X"), + (0x11B00, "V"), + (0x11B0A, "X"), + (0x11C00, "V"), + (0x11C09, "X"), + (0x11C0A, "V"), + (0x11C37, "X"), + (0x11C38, "V"), + (0x11C46, "X"), + (0x11C50, "V"), + (0x11C6D, "X"), + (0x11C70, "V"), + (0x11C90, "X"), + (0x11C92, "V"), + (0x11CA8, "X"), + (0x11CA9, "V"), + (0x11CB7, "X"), + (0x11D00, "V"), + (0x11D07, "X"), + (0x11D08, "V"), + (0x11D0A, "X"), + (0x11D0B, "V"), + (0x11D37, "X"), + (0x11D3A, "V"), + (0x11D3B, "X"), + (0x11D3C, "V"), + (0x11D3E, "X"), + (0x11D3F, "V"), + (0x11D48, "X"), + (0x11D50, "V"), + (0x11D5A, "X"), + (0x11D60, "V"), + (0x11D66, "X"), + (0x11D67, "V"), + (0x11D69, "X"), + (0x11D6A, "V"), + (0x11D8F, "X"), + (0x11D90, "V"), + (0x11D92, "X"), + (0x11D93, "V"), + (0x11D99, "X"), + (0x11DA0, "V"), + (0x11DAA, "X"), + (0x11EE0, "V"), + (0x11EF9, "X"), + (0x11F00, "V"), + (0x11F11, "X"), + (0x11F12, "V"), + (0x11F3B, "X"), + (0x11F3E, "V"), + ] + + +def _seg_59() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x11F5A, "X"), + (0x11FB0, "V"), + (0x11FB1, "X"), + (0x11FC0, "V"), + (0x11FF2, "X"), + (0x11FFF, "V"), + (0x1239A, "X"), + (0x12400, "V"), + (0x1246F, "X"), + (0x12470, "V"), + (0x12475, "X"), + (0x12480, "V"), + (0x12544, "X"), + (0x12F90, "V"), + (0x12FF3, "X"), + (0x13000, "V"), + (0x13430, "X"), + (0x13440, "V"), + (0x13456, "X"), + (0x14400, "V"), + (0x14647, "X"), + (0x16800, "V"), + (0x16A39, "X"), + (0x16A40, "V"), + (0x16A5F, "X"), + (0x16A60, "V"), + (0x16A6A, "X"), + (0x16A6E, "V"), + (0x16ABF, "X"), + (0x16AC0, "V"), + (0x16ACA, "X"), + (0x16AD0, "V"), + (0x16AEE, "X"), + (0x16AF0, "V"), + (0x16AF6, "X"), + (0x16B00, "V"), + (0x16B46, "X"), + (0x16B50, "V"), + (0x16B5A, "X"), + (0x16B5B, "V"), + (0x16B62, "X"), + (0x16B63, "V"), + (0x16B78, "X"), + (0x16B7D, "V"), + (0x16B90, "X"), + (0x16E40, "M", "𖹠"), + (0x16E41, "M", "𖹡"), + (0x16E42, "M", "𖹢"), + (0x16E43, "M", "𖹣"), + (0x16E44, "M", "𖹤"), + (0x16E45, "M", "𖹥"), + (0x16E46, "M", "𖹦"), + (0x16E47, "M", "𖹧"), + (0x16E48, "M", "𖹨"), + (0x16E49, "M", "𖹩"), + (0x16E4A, "M", "𖹪"), + (0x16E4B, "M", "𖹫"), + (0x16E4C, "M", "𖹬"), + (0x16E4D, "M", "𖹭"), + (0x16E4E, "M", "𖹮"), + (0x16E4F, "M", "𖹯"), + (0x16E50, "M", "𖹰"), + (0x16E51, "M", "𖹱"), + (0x16E52, "M", "𖹲"), + (0x16E53, "M", "𖹳"), + (0x16E54, "M", "𖹴"), + (0x16E55, "M", "𖹵"), + (0x16E56, "M", "𖹶"), + (0x16E57, "M", "𖹷"), + (0x16E58, "M", "𖹸"), + (0x16E59, "M", "𖹹"), + (0x16E5A, "M", "𖹺"), + (0x16E5B, "M", "𖹻"), + (0x16E5C, "M", "𖹼"), + (0x16E5D, "M", "𖹽"), + (0x16E5E, "M", "𖹾"), + (0x16E5F, "M", "𖹿"), + (0x16E60, "V"), + (0x16E9B, "X"), + (0x16F00, "V"), + (0x16F4B, "X"), + (0x16F4F, "V"), + (0x16F88, "X"), + (0x16F8F, "V"), + (0x16FA0, "X"), + (0x16FE0, "V"), + (0x16FE5, "X"), + (0x16FF0, "V"), + (0x16FF2, "X"), + (0x17000, "V"), + (0x187F8, "X"), + (0x18800, "V"), + (0x18CD6, "X"), + (0x18D00, "V"), + (0x18D09, "X"), + (0x1AFF0, "V"), + (0x1AFF4, "X"), + (0x1AFF5, "V"), + (0x1AFFC, "X"), + (0x1AFFD, "V"), + ] + + +def _seg_60() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1AFFF, "X"), + (0x1B000, "V"), + (0x1B123, "X"), + (0x1B132, "V"), + (0x1B133, "X"), + (0x1B150, "V"), + (0x1B153, "X"), + (0x1B155, "V"), + (0x1B156, "X"), + (0x1B164, "V"), + (0x1B168, "X"), + (0x1B170, "V"), + (0x1B2FC, "X"), + (0x1BC00, "V"), + (0x1BC6B, "X"), + (0x1BC70, "V"), + (0x1BC7D, "X"), + (0x1BC80, "V"), + (0x1BC89, "X"), + (0x1BC90, "V"), + (0x1BC9A, "X"), + (0x1BC9C, "V"), + (0x1BCA0, "I"), + (0x1BCA4, "X"), + (0x1CF00, "V"), + (0x1CF2E, "X"), + (0x1CF30, "V"), + (0x1CF47, "X"), + (0x1CF50, "V"), + (0x1CFC4, "X"), + (0x1D000, "V"), + (0x1D0F6, "X"), + (0x1D100, "V"), + (0x1D127, "X"), + (0x1D129, "V"), + (0x1D15E, "M", "𝅗𝅥"), + (0x1D15F, "M", "𝅘𝅥"), + (0x1D160, "M", "𝅘𝅥𝅮"), + (0x1D161, "M", "𝅘𝅥𝅯"), + (0x1D162, "M", "𝅘𝅥𝅰"), + (0x1D163, "M", "𝅘𝅥𝅱"), + (0x1D164, "M", "𝅘𝅥𝅲"), + (0x1D165, "V"), + (0x1D173, "X"), + (0x1D17B, "V"), + (0x1D1BB, "M", "𝆹𝅥"), + (0x1D1BC, "M", "𝆺𝅥"), + (0x1D1BD, "M", "𝆹𝅥𝅮"), + (0x1D1BE, "M", "𝆺𝅥𝅮"), + (0x1D1BF, "M", "𝆹𝅥𝅯"), + (0x1D1C0, "M", "𝆺𝅥𝅯"), + (0x1D1C1, "V"), + (0x1D1EB, "X"), + (0x1D200, "V"), + (0x1D246, "X"), + (0x1D2C0, "V"), + (0x1D2D4, "X"), + (0x1D2E0, "V"), + (0x1D2F4, "X"), + (0x1D300, "V"), + (0x1D357, "X"), + (0x1D360, "V"), + (0x1D379, "X"), + (0x1D400, "M", "a"), + (0x1D401, "M", "b"), + (0x1D402, "M", "c"), + (0x1D403, "M", "d"), + (0x1D404, "M", "e"), + (0x1D405, "M", "f"), + (0x1D406, "M", "g"), + (0x1D407, "M", "h"), + (0x1D408, "M", "i"), + (0x1D409, "M", "j"), + (0x1D40A, "M", "k"), + (0x1D40B, "M", "l"), + (0x1D40C, "M", "m"), + (0x1D40D, "M", "n"), + (0x1D40E, "M", "o"), + (0x1D40F, "M", "p"), + (0x1D410, "M", "q"), + (0x1D411, "M", "r"), + (0x1D412, "M", "s"), + (0x1D413, "M", "t"), + (0x1D414, "M", "u"), + (0x1D415, "M", "v"), + (0x1D416, "M", "w"), + (0x1D417, "M", "x"), + (0x1D418, "M", "y"), + (0x1D419, "M", "z"), + (0x1D41A, "M", "a"), + (0x1D41B, "M", "b"), + (0x1D41C, "M", "c"), + (0x1D41D, "M", "d"), + (0x1D41E, "M", "e"), + (0x1D41F, "M", "f"), + (0x1D420, "M", "g"), + (0x1D421, "M", "h"), + (0x1D422, "M", "i"), + (0x1D423, "M", "j"), + (0x1D424, "M", "k"), + ] + + +def _seg_61() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D425, "M", "l"), + (0x1D426, "M", "m"), + (0x1D427, "M", "n"), + (0x1D428, "M", "o"), + (0x1D429, "M", "p"), + (0x1D42A, "M", "q"), + (0x1D42B, "M", "r"), + (0x1D42C, "M", "s"), + (0x1D42D, "M", "t"), + (0x1D42E, "M", "u"), + (0x1D42F, "M", "v"), + (0x1D430, "M", "w"), + (0x1D431, "M", "x"), + (0x1D432, "M", "y"), + (0x1D433, "M", "z"), + (0x1D434, "M", "a"), + (0x1D435, "M", "b"), + (0x1D436, "M", "c"), + (0x1D437, "M", "d"), + (0x1D438, "M", "e"), + (0x1D439, "M", "f"), + (0x1D43A, "M", "g"), + (0x1D43B, "M", "h"), + (0x1D43C, "M", "i"), + (0x1D43D, "M", "j"), + (0x1D43E, "M", "k"), + (0x1D43F, "M", "l"), + (0x1D440, "M", "m"), + (0x1D441, "M", "n"), + (0x1D442, "M", "o"), + (0x1D443, "M", "p"), + (0x1D444, "M", "q"), + (0x1D445, "M", "r"), + (0x1D446, "M", "s"), + (0x1D447, "M", "t"), + (0x1D448, "M", "u"), + (0x1D449, "M", "v"), + (0x1D44A, "M", "w"), + (0x1D44B, "M", "x"), + (0x1D44C, "M", "y"), + (0x1D44D, "M", "z"), + (0x1D44E, "M", "a"), + (0x1D44F, "M", "b"), + (0x1D450, "M", "c"), + (0x1D451, "M", "d"), + (0x1D452, "M", "e"), + (0x1D453, "M", "f"), + (0x1D454, "M", "g"), + (0x1D455, "X"), + (0x1D456, "M", "i"), + (0x1D457, "M", "j"), + (0x1D458, "M", "k"), + (0x1D459, "M", "l"), + (0x1D45A, "M", "m"), + (0x1D45B, "M", "n"), + (0x1D45C, "M", "o"), + (0x1D45D, "M", "p"), + (0x1D45E, "M", "q"), + (0x1D45F, "M", "r"), + (0x1D460, "M", "s"), + (0x1D461, "M", "t"), + (0x1D462, "M", "u"), + (0x1D463, "M", "v"), + (0x1D464, "M", "w"), + (0x1D465, "M", "x"), + (0x1D466, "M", "y"), + (0x1D467, "M", "z"), + (0x1D468, "M", "a"), + (0x1D469, "M", "b"), + (0x1D46A, "M", "c"), + (0x1D46B, "M", "d"), + (0x1D46C, "M", "e"), + (0x1D46D, "M", "f"), + (0x1D46E, "M", "g"), + (0x1D46F, "M", "h"), + (0x1D470, "M", "i"), + (0x1D471, "M", "j"), + (0x1D472, "M", "k"), + (0x1D473, "M", "l"), + (0x1D474, "M", "m"), + (0x1D475, "M", "n"), + (0x1D476, "M", "o"), + (0x1D477, "M", "p"), + (0x1D478, "M", "q"), + (0x1D479, "M", "r"), + (0x1D47A, "M", "s"), + (0x1D47B, "M", "t"), + (0x1D47C, "M", "u"), + (0x1D47D, "M", "v"), + (0x1D47E, "M", "w"), + (0x1D47F, "M", "x"), + (0x1D480, "M", "y"), + (0x1D481, "M", "z"), + (0x1D482, "M", "a"), + (0x1D483, "M", "b"), + (0x1D484, "M", "c"), + (0x1D485, "M", "d"), + (0x1D486, "M", "e"), + (0x1D487, "M", "f"), + (0x1D488, "M", "g"), + ] + + +def _seg_62() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D489, "M", "h"), + (0x1D48A, "M", "i"), + (0x1D48B, "M", "j"), + (0x1D48C, "M", "k"), + (0x1D48D, "M", "l"), + (0x1D48E, "M", "m"), + (0x1D48F, "M", "n"), + (0x1D490, "M", "o"), + (0x1D491, "M", "p"), + (0x1D492, "M", "q"), + (0x1D493, "M", "r"), + (0x1D494, "M", "s"), + (0x1D495, "M", "t"), + (0x1D496, "M", "u"), + (0x1D497, "M", "v"), + (0x1D498, "M", "w"), + (0x1D499, "M", "x"), + (0x1D49A, "M", "y"), + (0x1D49B, "M", "z"), + (0x1D49C, "M", "a"), + (0x1D49D, "X"), + (0x1D49E, "M", "c"), + (0x1D49F, "M", "d"), + (0x1D4A0, "X"), + (0x1D4A2, "M", "g"), + (0x1D4A3, "X"), + (0x1D4A5, "M", "j"), + (0x1D4A6, "M", "k"), + (0x1D4A7, "X"), + (0x1D4A9, "M", "n"), + (0x1D4AA, "M", "o"), + (0x1D4AB, "M", "p"), + (0x1D4AC, "M", "q"), + (0x1D4AD, "X"), + (0x1D4AE, "M", "s"), + (0x1D4AF, "M", "t"), + (0x1D4B0, "M", "u"), + (0x1D4B1, "M", "v"), + (0x1D4B2, "M", "w"), + (0x1D4B3, "M", "x"), + (0x1D4B4, "M", "y"), + (0x1D4B5, "M", "z"), + (0x1D4B6, "M", "a"), + (0x1D4B7, "M", "b"), + (0x1D4B8, "M", "c"), + (0x1D4B9, "M", "d"), + (0x1D4BA, "X"), + (0x1D4BB, "M", "f"), + (0x1D4BC, "X"), + (0x1D4BD, "M", "h"), + (0x1D4BE, "M", "i"), + (0x1D4BF, "M", "j"), + (0x1D4C0, "M", "k"), + (0x1D4C1, "M", "l"), + (0x1D4C2, "M", "m"), + (0x1D4C3, "M", "n"), + (0x1D4C4, "X"), + (0x1D4C5, "M", "p"), + (0x1D4C6, "M", "q"), + (0x1D4C7, "M", "r"), + (0x1D4C8, "M", "s"), + (0x1D4C9, "M", "t"), + (0x1D4CA, "M", "u"), + (0x1D4CB, "M", "v"), + (0x1D4CC, "M", "w"), + (0x1D4CD, "M", "x"), + (0x1D4CE, "M", "y"), + (0x1D4CF, "M", "z"), + (0x1D4D0, "M", "a"), + (0x1D4D1, "M", "b"), + (0x1D4D2, "M", "c"), + (0x1D4D3, "M", "d"), + (0x1D4D4, "M", "e"), + (0x1D4D5, "M", "f"), + (0x1D4D6, "M", "g"), + (0x1D4D7, "M", "h"), + (0x1D4D8, "M", "i"), + (0x1D4D9, "M", "j"), + (0x1D4DA, "M", "k"), + (0x1D4DB, "M", "l"), + (0x1D4DC, "M", "m"), + (0x1D4DD, "M", "n"), + (0x1D4DE, "M", "o"), + (0x1D4DF, "M", "p"), + (0x1D4E0, "M", "q"), + (0x1D4E1, "M", "r"), + (0x1D4E2, "M", "s"), + (0x1D4E3, "M", "t"), + (0x1D4E4, "M", "u"), + (0x1D4E5, "M", "v"), + (0x1D4E6, "M", "w"), + (0x1D4E7, "M", "x"), + (0x1D4E8, "M", "y"), + (0x1D4E9, "M", "z"), + (0x1D4EA, "M", "a"), + (0x1D4EB, "M", "b"), + (0x1D4EC, "M", "c"), + (0x1D4ED, "M", "d"), + (0x1D4EE, "M", "e"), + (0x1D4EF, "M", "f"), + ] + + +def _seg_63() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D4F0, "M", "g"), + (0x1D4F1, "M", "h"), + (0x1D4F2, "M", "i"), + (0x1D4F3, "M", "j"), + (0x1D4F4, "M", "k"), + (0x1D4F5, "M", "l"), + (0x1D4F6, "M", "m"), + (0x1D4F7, "M", "n"), + (0x1D4F8, "M", "o"), + (0x1D4F9, "M", "p"), + (0x1D4FA, "M", "q"), + (0x1D4FB, "M", "r"), + (0x1D4FC, "M", "s"), + (0x1D4FD, "M", "t"), + (0x1D4FE, "M", "u"), + (0x1D4FF, "M", "v"), + (0x1D500, "M", "w"), + (0x1D501, "M", "x"), + (0x1D502, "M", "y"), + (0x1D503, "M", "z"), + (0x1D504, "M", "a"), + (0x1D505, "M", "b"), + (0x1D506, "X"), + (0x1D507, "M", "d"), + (0x1D508, "M", "e"), + (0x1D509, "M", "f"), + (0x1D50A, "M", "g"), + (0x1D50B, "X"), + (0x1D50D, "M", "j"), + (0x1D50E, "M", "k"), + (0x1D50F, "M", "l"), + (0x1D510, "M", "m"), + (0x1D511, "M", "n"), + (0x1D512, "M", "o"), + (0x1D513, "M", "p"), + (0x1D514, "M", "q"), + (0x1D515, "X"), + (0x1D516, "M", "s"), + (0x1D517, "M", "t"), + (0x1D518, "M", "u"), + (0x1D519, "M", "v"), + (0x1D51A, "M", "w"), + (0x1D51B, "M", "x"), + (0x1D51C, "M", "y"), + (0x1D51D, "X"), + (0x1D51E, "M", "a"), + (0x1D51F, "M", "b"), + (0x1D520, "M", "c"), + (0x1D521, "M", "d"), + (0x1D522, "M", "e"), + (0x1D523, "M", "f"), + (0x1D524, "M", "g"), + (0x1D525, "M", "h"), + (0x1D526, "M", "i"), + (0x1D527, "M", "j"), + (0x1D528, "M", "k"), + (0x1D529, "M", "l"), + (0x1D52A, "M", "m"), + (0x1D52B, "M", "n"), + (0x1D52C, "M", "o"), + (0x1D52D, "M", "p"), + (0x1D52E, "M", "q"), + (0x1D52F, "M", "r"), + (0x1D530, "M", "s"), + (0x1D531, "M", "t"), + (0x1D532, "M", "u"), + (0x1D533, "M", "v"), + (0x1D534, "M", "w"), + (0x1D535, "M", "x"), + (0x1D536, "M", "y"), + (0x1D537, "M", "z"), + (0x1D538, "M", "a"), + (0x1D539, "M", "b"), + (0x1D53A, "X"), + (0x1D53B, "M", "d"), + (0x1D53C, "M", "e"), + (0x1D53D, "M", "f"), + (0x1D53E, "M", "g"), + (0x1D53F, "X"), + (0x1D540, "M", "i"), + (0x1D541, "M", "j"), + (0x1D542, "M", "k"), + (0x1D543, "M", "l"), + (0x1D544, "M", "m"), + (0x1D545, "X"), + (0x1D546, "M", "o"), + (0x1D547, "X"), + (0x1D54A, "M", "s"), + (0x1D54B, "M", "t"), + (0x1D54C, "M", "u"), + (0x1D54D, "M", "v"), + (0x1D54E, "M", "w"), + (0x1D54F, "M", "x"), + (0x1D550, "M", "y"), + (0x1D551, "X"), + (0x1D552, "M", "a"), + (0x1D553, "M", "b"), + (0x1D554, "M", "c"), + (0x1D555, "M", "d"), + (0x1D556, "M", "e"), + ] + + +def _seg_64() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D557, "M", "f"), + (0x1D558, "M", "g"), + (0x1D559, "M", "h"), + (0x1D55A, "M", "i"), + (0x1D55B, "M", "j"), + (0x1D55C, "M", "k"), + (0x1D55D, "M", "l"), + (0x1D55E, "M", "m"), + (0x1D55F, "M", "n"), + (0x1D560, "M", "o"), + (0x1D561, "M", "p"), + (0x1D562, "M", "q"), + (0x1D563, "M", "r"), + (0x1D564, "M", "s"), + (0x1D565, "M", "t"), + (0x1D566, "M", "u"), + (0x1D567, "M", "v"), + (0x1D568, "M", "w"), + (0x1D569, "M", "x"), + (0x1D56A, "M", "y"), + (0x1D56B, "M", "z"), + (0x1D56C, "M", "a"), + (0x1D56D, "M", "b"), + (0x1D56E, "M", "c"), + (0x1D56F, "M", "d"), + (0x1D570, "M", "e"), + (0x1D571, "M", "f"), + (0x1D572, "M", "g"), + (0x1D573, "M", "h"), + (0x1D574, "M", "i"), + (0x1D575, "M", "j"), + (0x1D576, "M", "k"), + (0x1D577, "M", "l"), + (0x1D578, "M", "m"), + (0x1D579, "M", "n"), + (0x1D57A, "M", "o"), + (0x1D57B, "M", "p"), + (0x1D57C, "M", "q"), + (0x1D57D, "M", "r"), + (0x1D57E, "M", "s"), + (0x1D57F, "M", "t"), + (0x1D580, "M", "u"), + (0x1D581, "M", "v"), + (0x1D582, "M", "w"), + (0x1D583, "M", "x"), + (0x1D584, "M", "y"), + (0x1D585, "M", "z"), + (0x1D586, "M", "a"), + (0x1D587, "M", "b"), + (0x1D588, "M", "c"), + (0x1D589, "M", "d"), + (0x1D58A, "M", "e"), + (0x1D58B, "M", "f"), + (0x1D58C, "M", "g"), + (0x1D58D, "M", "h"), + (0x1D58E, "M", "i"), + (0x1D58F, "M", "j"), + (0x1D590, "M", "k"), + (0x1D591, "M", "l"), + (0x1D592, "M", "m"), + (0x1D593, "M", "n"), + (0x1D594, "M", "o"), + (0x1D595, "M", "p"), + (0x1D596, "M", "q"), + (0x1D597, "M", "r"), + (0x1D598, "M", "s"), + (0x1D599, "M", "t"), + (0x1D59A, "M", "u"), + (0x1D59B, "M", "v"), + (0x1D59C, "M", "w"), + (0x1D59D, "M", "x"), + (0x1D59E, "M", "y"), + (0x1D59F, "M", "z"), + (0x1D5A0, "M", "a"), + (0x1D5A1, "M", "b"), + (0x1D5A2, "M", "c"), + (0x1D5A3, "M", "d"), + (0x1D5A4, "M", "e"), + (0x1D5A5, "M", "f"), + (0x1D5A6, "M", "g"), + (0x1D5A7, "M", "h"), + (0x1D5A8, "M", "i"), + (0x1D5A9, "M", "j"), + (0x1D5AA, "M", "k"), + (0x1D5AB, "M", "l"), + (0x1D5AC, "M", "m"), + (0x1D5AD, "M", "n"), + (0x1D5AE, "M", "o"), + (0x1D5AF, "M", "p"), + (0x1D5B0, "M", "q"), + (0x1D5B1, "M", "r"), + (0x1D5B2, "M", "s"), + (0x1D5B3, "M", "t"), + (0x1D5B4, "M", "u"), + (0x1D5B5, "M", "v"), + (0x1D5B6, "M", "w"), + (0x1D5B7, "M", "x"), + (0x1D5B8, "M", "y"), + (0x1D5B9, "M", "z"), + (0x1D5BA, "M", "a"), + ] + + +def _seg_65() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D5BB, "M", "b"), + (0x1D5BC, "M", "c"), + (0x1D5BD, "M", "d"), + (0x1D5BE, "M", "e"), + (0x1D5BF, "M", "f"), + (0x1D5C0, "M", "g"), + (0x1D5C1, "M", "h"), + (0x1D5C2, "M", "i"), + (0x1D5C3, "M", "j"), + (0x1D5C4, "M", "k"), + (0x1D5C5, "M", "l"), + (0x1D5C6, "M", "m"), + (0x1D5C7, "M", "n"), + (0x1D5C8, "M", "o"), + (0x1D5C9, "M", "p"), + (0x1D5CA, "M", "q"), + (0x1D5CB, "M", "r"), + (0x1D5CC, "M", "s"), + (0x1D5CD, "M", "t"), + (0x1D5CE, "M", "u"), + (0x1D5CF, "M", "v"), + (0x1D5D0, "M", "w"), + (0x1D5D1, "M", "x"), + (0x1D5D2, "M", "y"), + (0x1D5D3, "M", "z"), + (0x1D5D4, "M", "a"), + (0x1D5D5, "M", "b"), + (0x1D5D6, "M", "c"), + (0x1D5D7, "M", "d"), + (0x1D5D8, "M", "e"), + (0x1D5D9, "M", "f"), + (0x1D5DA, "M", "g"), + (0x1D5DB, "M", "h"), + (0x1D5DC, "M", "i"), + (0x1D5DD, "M", "j"), + (0x1D5DE, "M", "k"), + (0x1D5DF, "M", "l"), + (0x1D5E0, "M", "m"), + (0x1D5E1, "M", "n"), + (0x1D5E2, "M", "o"), + (0x1D5E3, "M", "p"), + (0x1D5E4, "M", "q"), + (0x1D5E5, "M", "r"), + (0x1D5E6, "M", "s"), + (0x1D5E7, "M", "t"), + (0x1D5E8, "M", "u"), + (0x1D5E9, "M", "v"), + (0x1D5EA, "M", "w"), + (0x1D5EB, "M", "x"), + (0x1D5EC, "M", "y"), + (0x1D5ED, "M", "z"), + (0x1D5EE, "M", "a"), + (0x1D5EF, "M", "b"), + (0x1D5F0, "M", "c"), + (0x1D5F1, "M", "d"), + (0x1D5F2, "M", "e"), + (0x1D5F3, "M", "f"), + (0x1D5F4, "M", "g"), + (0x1D5F5, "M", "h"), + (0x1D5F6, "M", "i"), + (0x1D5F7, "M", "j"), + (0x1D5F8, "M", "k"), + (0x1D5F9, "M", "l"), + (0x1D5FA, "M", "m"), + (0x1D5FB, "M", "n"), + (0x1D5FC, "M", "o"), + (0x1D5FD, "M", "p"), + (0x1D5FE, "M", "q"), + (0x1D5FF, "M", "r"), + (0x1D600, "M", "s"), + (0x1D601, "M", "t"), + (0x1D602, "M", "u"), + (0x1D603, "M", "v"), + (0x1D604, "M", "w"), + (0x1D605, "M", "x"), + (0x1D606, "M", "y"), + (0x1D607, "M", "z"), + (0x1D608, "M", "a"), + (0x1D609, "M", "b"), + (0x1D60A, "M", "c"), + (0x1D60B, "M", "d"), + (0x1D60C, "M", "e"), + (0x1D60D, "M", "f"), + (0x1D60E, "M", "g"), + (0x1D60F, "M", "h"), + (0x1D610, "M", "i"), + (0x1D611, "M", "j"), + (0x1D612, "M", "k"), + (0x1D613, "M", "l"), + (0x1D614, "M", "m"), + (0x1D615, "M", "n"), + (0x1D616, "M", "o"), + (0x1D617, "M", "p"), + (0x1D618, "M", "q"), + (0x1D619, "M", "r"), + (0x1D61A, "M", "s"), + (0x1D61B, "M", "t"), + (0x1D61C, "M", "u"), + (0x1D61D, "M", "v"), + (0x1D61E, "M", "w"), + ] + + +def _seg_66() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D61F, "M", "x"), + (0x1D620, "M", "y"), + (0x1D621, "M", "z"), + (0x1D622, "M", "a"), + (0x1D623, "M", "b"), + (0x1D624, "M", "c"), + (0x1D625, "M", "d"), + (0x1D626, "M", "e"), + (0x1D627, "M", "f"), + (0x1D628, "M", "g"), + (0x1D629, "M", "h"), + (0x1D62A, "M", "i"), + (0x1D62B, "M", "j"), + (0x1D62C, "M", "k"), + (0x1D62D, "M", "l"), + (0x1D62E, "M", "m"), + (0x1D62F, "M", "n"), + (0x1D630, "M", "o"), + (0x1D631, "M", "p"), + (0x1D632, "M", "q"), + (0x1D633, "M", "r"), + (0x1D634, "M", "s"), + (0x1D635, "M", "t"), + (0x1D636, "M", "u"), + (0x1D637, "M", "v"), + (0x1D638, "M", "w"), + (0x1D639, "M", "x"), + (0x1D63A, "M", "y"), + (0x1D63B, "M", "z"), + (0x1D63C, "M", "a"), + (0x1D63D, "M", "b"), + (0x1D63E, "M", "c"), + (0x1D63F, "M", "d"), + (0x1D640, "M", "e"), + (0x1D641, "M", "f"), + (0x1D642, "M", "g"), + (0x1D643, "M", "h"), + (0x1D644, "M", "i"), + (0x1D645, "M", "j"), + (0x1D646, "M", "k"), + (0x1D647, "M", "l"), + (0x1D648, "M", "m"), + (0x1D649, "M", "n"), + (0x1D64A, "M", "o"), + (0x1D64B, "M", "p"), + (0x1D64C, "M", "q"), + (0x1D64D, "M", "r"), + (0x1D64E, "M", "s"), + (0x1D64F, "M", "t"), + (0x1D650, "M", "u"), + (0x1D651, "M", "v"), + (0x1D652, "M", "w"), + (0x1D653, "M", "x"), + (0x1D654, "M", "y"), + (0x1D655, "M", "z"), + (0x1D656, "M", "a"), + (0x1D657, "M", "b"), + (0x1D658, "M", "c"), + (0x1D659, "M", "d"), + (0x1D65A, "M", "e"), + (0x1D65B, "M", "f"), + (0x1D65C, "M", "g"), + (0x1D65D, "M", "h"), + (0x1D65E, "M", "i"), + (0x1D65F, "M", "j"), + (0x1D660, "M", "k"), + (0x1D661, "M", "l"), + (0x1D662, "M", "m"), + (0x1D663, "M", "n"), + (0x1D664, "M", "o"), + (0x1D665, "M", "p"), + (0x1D666, "M", "q"), + (0x1D667, "M", "r"), + (0x1D668, "M", "s"), + (0x1D669, "M", "t"), + (0x1D66A, "M", "u"), + (0x1D66B, "M", "v"), + (0x1D66C, "M", "w"), + (0x1D66D, "M", "x"), + (0x1D66E, "M", "y"), + (0x1D66F, "M", "z"), + (0x1D670, "M", "a"), + (0x1D671, "M", "b"), + (0x1D672, "M", "c"), + (0x1D673, "M", "d"), + (0x1D674, "M", "e"), + (0x1D675, "M", "f"), + (0x1D676, "M", "g"), + (0x1D677, "M", "h"), + (0x1D678, "M", "i"), + (0x1D679, "M", "j"), + (0x1D67A, "M", "k"), + (0x1D67B, "M", "l"), + (0x1D67C, "M", "m"), + (0x1D67D, "M", "n"), + (0x1D67E, "M", "o"), + (0x1D67F, "M", "p"), + (0x1D680, "M", "q"), + (0x1D681, "M", "r"), + (0x1D682, "M", "s"), + ] + + +def _seg_67() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D683, "M", "t"), + (0x1D684, "M", "u"), + (0x1D685, "M", "v"), + (0x1D686, "M", "w"), + (0x1D687, "M", "x"), + (0x1D688, "M", "y"), + (0x1D689, "M", "z"), + (0x1D68A, "M", "a"), + (0x1D68B, "M", "b"), + (0x1D68C, "M", "c"), + (0x1D68D, "M", "d"), + (0x1D68E, "M", "e"), + (0x1D68F, "M", "f"), + (0x1D690, "M", "g"), + (0x1D691, "M", "h"), + (0x1D692, "M", "i"), + (0x1D693, "M", "j"), + (0x1D694, "M", "k"), + (0x1D695, "M", "l"), + (0x1D696, "M", "m"), + (0x1D697, "M", "n"), + (0x1D698, "M", "o"), + (0x1D699, "M", "p"), + (0x1D69A, "M", "q"), + (0x1D69B, "M", "r"), + (0x1D69C, "M", "s"), + (0x1D69D, "M", "t"), + (0x1D69E, "M", "u"), + (0x1D69F, "M", "v"), + (0x1D6A0, "M", "w"), + (0x1D6A1, "M", "x"), + (0x1D6A2, "M", "y"), + (0x1D6A3, "M", "z"), + (0x1D6A4, "M", "ı"), + (0x1D6A5, "M", "ȷ"), + (0x1D6A6, "X"), + (0x1D6A8, "M", "α"), + (0x1D6A9, "M", "β"), + (0x1D6AA, "M", "γ"), + (0x1D6AB, "M", "δ"), + (0x1D6AC, "M", "ε"), + (0x1D6AD, "M", "ζ"), + (0x1D6AE, "M", "η"), + (0x1D6AF, "M", "θ"), + (0x1D6B0, "M", "ι"), + (0x1D6B1, "M", "κ"), + (0x1D6B2, "M", "λ"), + (0x1D6B3, "M", "μ"), + (0x1D6B4, "M", "ν"), + (0x1D6B5, "M", "ξ"), + (0x1D6B6, "M", "ο"), + (0x1D6B7, "M", "π"), + (0x1D6B8, "M", "ρ"), + (0x1D6B9, "M", "θ"), + (0x1D6BA, "M", "σ"), + (0x1D6BB, "M", "τ"), + (0x1D6BC, "M", "υ"), + (0x1D6BD, "M", "φ"), + (0x1D6BE, "M", "χ"), + (0x1D6BF, "M", "ψ"), + (0x1D6C0, "M", "ω"), + (0x1D6C1, "M", "∇"), + (0x1D6C2, "M", "α"), + (0x1D6C3, "M", "β"), + (0x1D6C4, "M", "γ"), + (0x1D6C5, "M", "δ"), + (0x1D6C6, "M", "ε"), + (0x1D6C7, "M", "ζ"), + (0x1D6C8, "M", "η"), + (0x1D6C9, "M", "θ"), + (0x1D6CA, "M", "ι"), + (0x1D6CB, "M", "κ"), + (0x1D6CC, "M", "λ"), + (0x1D6CD, "M", "μ"), + (0x1D6CE, "M", "ν"), + (0x1D6CF, "M", "ξ"), + (0x1D6D0, "M", "ο"), + (0x1D6D1, "M", "π"), + (0x1D6D2, "M", "ρ"), + (0x1D6D3, "M", "σ"), + (0x1D6D5, "M", "τ"), + (0x1D6D6, "M", "υ"), + (0x1D6D7, "M", "φ"), + (0x1D6D8, "M", "χ"), + (0x1D6D9, "M", "ψ"), + (0x1D6DA, "M", "ω"), + (0x1D6DB, "M", "∂"), + (0x1D6DC, "M", "ε"), + (0x1D6DD, "M", "θ"), + (0x1D6DE, "M", "κ"), + (0x1D6DF, "M", "φ"), + (0x1D6E0, "M", "ρ"), + (0x1D6E1, "M", "π"), + (0x1D6E2, "M", "α"), + (0x1D6E3, "M", "β"), + (0x1D6E4, "M", "γ"), + (0x1D6E5, "M", "δ"), + (0x1D6E6, "M", "ε"), + (0x1D6E7, "M", "ζ"), + (0x1D6E8, "M", "η"), + ] + + +def _seg_68() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D6E9, "M", "θ"), + (0x1D6EA, "M", "ι"), + (0x1D6EB, "M", "κ"), + (0x1D6EC, "M", "λ"), + (0x1D6ED, "M", "μ"), + (0x1D6EE, "M", "ν"), + (0x1D6EF, "M", "ξ"), + (0x1D6F0, "M", "ο"), + (0x1D6F1, "M", "π"), + (0x1D6F2, "M", "ρ"), + (0x1D6F3, "M", "θ"), + (0x1D6F4, "M", "σ"), + (0x1D6F5, "M", "τ"), + (0x1D6F6, "M", "υ"), + (0x1D6F7, "M", "φ"), + (0x1D6F8, "M", "χ"), + (0x1D6F9, "M", "ψ"), + (0x1D6FA, "M", "ω"), + (0x1D6FB, "M", "∇"), + (0x1D6FC, "M", "α"), + (0x1D6FD, "M", "β"), + (0x1D6FE, "M", "γ"), + (0x1D6FF, "M", "δ"), + (0x1D700, "M", "ε"), + (0x1D701, "M", "ζ"), + (0x1D702, "M", "η"), + (0x1D703, "M", "θ"), + (0x1D704, "M", "ι"), + (0x1D705, "M", "κ"), + (0x1D706, "M", "λ"), + (0x1D707, "M", "μ"), + (0x1D708, "M", "ν"), + (0x1D709, "M", "ξ"), + (0x1D70A, "M", "ο"), + (0x1D70B, "M", "π"), + (0x1D70C, "M", "ρ"), + (0x1D70D, "M", "σ"), + (0x1D70F, "M", "τ"), + (0x1D710, "M", "υ"), + (0x1D711, "M", "φ"), + (0x1D712, "M", "χ"), + (0x1D713, "M", "ψ"), + (0x1D714, "M", "ω"), + (0x1D715, "M", "∂"), + (0x1D716, "M", "ε"), + (0x1D717, "M", "θ"), + (0x1D718, "M", "κ"), + (0x1D719, "M", "φ"), + (0x1D71A, "M", "ρ"), + (0x1D71B, "M", "π"), + (0x1D71C, "M", "α"), + (0x1D71D, "M", "β"), + (0x1D71E, "M", "γ"), + (0x1D71F, "M", "δ"), + (0x1D720, "M", "ε"), + (0x1D721, "M", "ζ"), + (0x1D722, "M", "η"), + (0x1D723, "M", "θ"), + (0x1D724, "M", "ι"), + (0x1D725, "M", "κ"), + (0x1D726, "M", "λ"), + (0x1D727, "M", "μ"), + (0x1D728, "M", "ν"), + (0x1D729, "M", "ξ"), + (0x1D72A, "M", "ο"), + (0x1D72B, "M", "π"), + (0x1D72C, "M", "ρ"), + (0x1D72D, "M", "θ"), + (0x1D72E, "M", "σ"), + (0x1D72F, "M", "τ"), + (0x1D730, "M", "υ"), + (0x1D731, "M", "φ"), + (0x1D732, "M", "χ"), + (0x1D733, "M", "ψ"), + (0x1D734, "M", "ω"), + (0x1D735, "M", "∇"), + (0x1D736, "M", "α"), + (0x1D737, "M", "β"), + (0x1D738, "M", "γ"), + (0x1D739, "M", "δ"), + (0x1D73A, "M", "ε"), + (0x1D73B, "M", "ζ"), + (0x1D73C, "M", "η"), + (0x1D73D, "M", "θ"), + (0x1D73E, "M", "ι"), + (0x1D73F, "M", "κ"), + (0x1D740, "M", "λ"), + (0x1D741, "M", "μ"), + (0x1D742, "M", "ν"), + (0x1D743, "M", "ξ"), + (0x1D744, "M", "ο"), + (0x1D745, "M", "π"), + (0x1D746, "M", "ρ"), + (0x1D747, "M", "σ"), + (0x1D749, "M", "τ"), + (0x1D74A, "M", "υ"), + (0x1D74B, "M", "φ"), + (0x1D74C, "M", "χ"), + (0x1D74D, "M", "ψ"), + (0x1D74E, "M", "ω"), + ] + + +def _seg_69() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D74F, "M", "∂"), + (0x1D750, "M", "ε"), + (0x1D751, "M", "θ"), + (0x1D752, "M", "κ"), + (0x1D753, "M", "φ"), + (0x1D754, "M", "ρ"), + (0x1D755, "M", "π"), + (0x1D756, "M", "α"), + (0x1D757, "M", "β"), + (0x1D758, "M", "γ"), + (0x1D759, "M", "δ"), + (0x1D75A, "M", "ε"), + (0x1D75B, "M", "ζ"), + (0x1D75C, "M", "η"), + (0x1D75D, "M", "θ"), + (0x1D75E, "M", "ι"), + (0x1D75F, "M", "κ"), + (0x1D760, "M", "λ"), + (0x1D761, "M", "μ"), + (0x1D762, "M", "ν"), + (0x1D763, "M", "ξ"), + (0x1D764, "M", "ο"), + (0x1D765, "M", "π"), + (0x1D766, "M", "ρ"), + (0x1D767, "M", "θ"), + (0x1D768, "M", "σ"), + (0x1D769, "M", "τ"), + (0x1D76A, "M", "υ"), + (0x1D76B, "M", "φ"), + (0x1D76C, "M", "χ"), + (0x1D76D, "M", "ψ"), + (0x1D76E, "M", "ω"), + (0x1D76F, "M", "∇"), + (0x1D770, "M", "α"), + (0x1D771, "M", "β"), + (0x1D772, "M", "γ"), + (0x1D773, "M", "δ"), + (0x1D774, "M", "ε"), + (0x1D775, "M", "ζ"), + (0x1D776, "M", "η"), + (0x1D777, "M", "θ"), + (0x1D778, "M", "ι"), + (0x1D779, "M", "κ"), + (0x1D77A, "M", "λ"), + (0x1D77B, "M", "μ"), + (0x1D77C, "M", "ν"), + (0x1D77D, "M", "ξ"), + (0x1D77E, "M", "ο"), + (0x1D77F, "M", "π"), + (0x1D780, "M", "ρ"), + (0x1D781, "M", "σ"), + (0x1D783, "M", "τ"), + (0x1D784, "M", "υ"), + (0x1D785, "M", "φ"), + (0x1D786, "M", "χ"), + (0x1D787, "M", "ψ"), + (0x1D788, "M", "ω"), + (0x1D789, "M", "∂"), + (0x1D78A, "M", "ε"), + (0x1D78B, "M", "θ"), + (0x1D78C, "M", "κ"), + (0x1D78D, "M", "φ"), + (0x1D78E, "M", "ρ"), + (0x1D78F, "M", "π"), + (0x1D790, "M", "α"), + (0x1D791, "M", "β"), + (0x1D792, "M", "γ"), + (0x1D793, "M", "δ"), + (0x1D794, "M", "ε"), + (0x1D795, "M", "ζ"), + (0x1D796, "M", "η"), + (0x1D797, "M", "θ"), + (0x1D798, "M", "ι"), + (0x1D799, "M", "κ"), + (0x1D79A, "M", "λ"), + (0x1D79B, "M", "μ"), + (0x1D79C, "M", "ν"), + (0x1D79D, "M", "ξ"), + (0x1D79E, "M", "ο"), + (0x1D79F, "M", "π"), + (0x1D7A0, "M", "ρ"), + (0x1D7A1, "M", "θ"), + (0x1D7A2, "M", "σ"), + (0x1D7A3, "M", "τ"), + (0x1D7A4, "M", "υ"), + (0x1D7A5, "M", "φ"), + (0x1D7A6, "M", "χ"), + (0x1D7A7, "M", "ψ"), + (0x1D7A8, "M", "ω"), + (0x1D7A9, "M", "∇"), + (0x1D7AA, "M", "α"), + (0x1D7AB, "M", "β"), + (0x1D7AC, "M", "γ"), + (0x1D7AD, "M", "δ"), + (0x1D7AE, "M", "ε"), + (0x1D7AF, "M", "ζ"), + (0x1D7B0, "M", "η"), + (0x1D7B1, "M", "θ"), + (0x1D7B2, "M", "ι"), + (0x1D7B3, "M", "κ"), + ] + + +def _seg_70() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1D7B4, "M", "λ"), + (0x1D7B5, "M", "μ"), + (0x1D7B6, "M", "ν"), + (0x1D7B7, "M", "ξ"), + (0x1D7B8, "M", "ο"), + (0x1D7B9, "M", "π"), + (0x1D7BA, "M", "ρ"), + (0x1D7BB, "M", "σ"), + (0x1D7BD, "M", "τ"), + (0x1D7BE, "M", "υ"), + (0x1D7BF, "M", "φ"), + (0x1D7C0, "M", "χ"), + (0x1D7C1, "M", "ψ"), + (0x1D7C2, "M", "ω"), + (0x1D7C3, "M", "∂"), + (0x1D7C4, "M", "ε"), + (0x1D7C5, "M", "θ"), + (0x1D7C6, "M", "κ"), + (0x1D7C7, "M", "φ"), + (0x1D7C8, "M", "ρ"), + (0x1D7C9, "M", "π"), + (0x1D7CA, "M", "ϝ"), + (0x1D7CC, "X"), + (0x1D7CE, "M", "0"), + (0x1D7CF, "M", "1"), + (0x1D7D0, "M", "2"), + (0x1D7D1, "M", "3"), + (0x1D7D2, "M", "4"), + (0x1D7D3, "M", "5"), + (0x1D7D4, "M", "6"), + (0x1D7D5, "M", "7"), + (0x1D7D6, "M", "8"), + (0x1D7D7, "M", "9"), + (0x1D7D8, "M", "0"), + (0x1D7D9, "M", "1"), + (0x1D7DA, "M", "2"), + (0x1D7DB, "M", "3"), + (0x1D7DC, "M", "4"), + (0x1D7DD, "M", "5"), + (0x1D7DE, "M", "6"), + (0x1D7DF, "M", "7"), + (0x1D7E0, "M", "8"), + (0x1D7E1, "M", "9"), + (0x1D7E2, "M", "0"), + (0x1D7E3, "M", "1"), + (0x1D7E4, "M", "2"), + (0x1D7E5, "M", "3"), + (0x1D7E6, "M", "4"), + (0x1D7E7, "M", "5"), + (0x1D7E8, "M", "6"), + (0x1D7E9, "M", "7"), + (0x1D7EA, "M", "8"), + (0x1D7EB, "M", "9"), + (0x1D7EC, "M", "0"), + (0x1D7ED, "M", "1"), + (0x1D7EE, "M", "2"), + (0x1D7EF, "M", "3"), + (0x1D7F0, "M", "4"), + (0x1D7F1, "M", "5"), + (0x1D7F2, "M", "6"), + (0x1D7F3, "M", "7"), + (0x1D7F4, "M", "8"), + (0x1D7F5, "M", "9"), + (0x1D7F6, "M", "0"), + (0x1D7F7, "M", "1"), + (0x1D7F8, "M", "2"), + (0x1D7F9, "M", "3"), + (0x1D7FA, "M", "4"), + (0x1D7FB, "M", "5"), + (0x1D7FC, "M", "6"), + (0x1D7FD, "M", "7"), + (0x1D7FE, "M", "8"), + (0x1D7FF, "M", "9"), + (0x1D800, "V"), + (0x1DA8C, "X"), + (0x1DA9B, "V"), + (0x1DAA0, "X"), + (0x1DAA1, "V"), + (0x1DAB0, "X"), + (0x1DF00, "V"), + (0x1DF1F, "X"), + (0x1DF25, "V"), + (0x1DF2B, "X"), + (0x1E000, "V"), + (0x1E007, "X"), + (0x1E008, "V"), + (0x1E019, "X"), + (0x1E01B, "V"), + (0x1E022, "X"), + (0x1E023, "V"), + (0x1E025, "X"), + (0x1E026, "V"), + (0x1E02B, "X"), + (0x1E030, "M", "а"), + (0x1E031, "M", "б"), + (0x1E032, "M", "в"), + (0x1E033, "M", "г"), + (0x1E034, "M", "д"), + (0x1E035, "M", "е"), + (0x1E036, "M", "ж"), + ] + + +def _seg_71() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E037, "M", "з"), + (0x1E038, "M", "и"), + (0x1E039, "M", "к"), + (0x1E03A, "M", "л"), + (0x1E03B, "M", "м"), + (0x1E03C, "M", "о"), + (0x1E03D, "M", "п"), + (0x1E03E, "M", "р"), + (0x1E03F, "M", "с"), + (0x1E040, "M", "т"), + (0x1E041, "M", "у"), + (0x1E042, "M", "ф"), + (0x1E043, "M", "х"), + (0x1E044, "M", "ц"), + (0x1E045, "M", "ч"), + (0x1E046, "M", "ш"), + (0x1E047, "M", "ы"), + (0x1E048, "M", "э"), + (0x1E049, "M", "ю"), + (0x1E04A, "M", "ꚉ"), + (0x1E04B, "M", "ә"), + (0x1E04C, "M", "і"), + (0x1E04D, "M", "ј"), + (0x1E04E, "M", "ө"), + (0x1E04F, "M", "ү"), + (0x1E050, "M", "ӏ"), + (0x1E051, "M", "а"), + (0x1E052, "M", "б"), + (0x1E053, "M", "в"), + (0x1E054, "M", "г"), + (0x1E055, "M", "д"), + (0x1E056, "M", "е"), + (0x1E057, "M", "ж"), + (0x1E058, "M", "з"), + (0x1E059, "M", "и"), + (0x1E05A, "M", "к"), + (0x1E05B, "M", "л"), + (0x1E05C, "M", "о"), + (0x1E05D, "M", "п"), + (0x1E05E, "M", "с"), + (0x1E05F, "M", "у"), + (0x1E060, "M", "ф"), + (0x1E061, "M", "х"), + (0x1E062, "M", "ц"), + (0x1E063, "M", "ч"), + (0x1E064, "M", "ш"), + (0x1E065, "M", "ъ"), + (0x1E066, "M", "ы"), + (0x1E067, "M", "ґ"), + (0x1E068, "M", "і"), + (0x1E069, "M", "ѕ"), + (0x1E06A, "M", "џ"), + (0x1E06B, "M", "ҫ"), + (0x1E06C, "M", "ꙑ"), + (0x1E06D, "M", "ұ"), + (0x1E06E, "X"), + (0x1E08F, "V"), + (0x1E090, "X"), + (0x1E100, "V"), + (0x1E12D, "X"), + (0x1E130, "V"), + (0x1E13E, "X"), + (0x1E140, "V"), + (0x1E14A, "X"), + (0x1E14E, "V"), + (0x1E150, "X"), + (0x1E290, "V"), + (0x1E2AF, "X"), + (0x1E2C0, "V"), + (0x1E2FA, "X"), + (0x1E2FF, "V"), + (0x1E300, "X"), + (0x1E4D0, "V"), + (0x1E4FA, "X"), + (0x1E7E0, "V"), + (0x1E7E7, "X"), + (0x1E7E8, "V"), + (0x1E7EC, "X"), + (0x1E7ED, "V"), + (0x1E7EF, "X"), + (0x1E7F0, "V"), + (0x1E7FF, "X"), + (0x1E800, "V"), + (0x1E8C5, "X"), + (0x1E8C7, "V"), + (0x1E8D7, "X"), + (0x1E900, "M", "𞤢"), + (0x1E901, "M", "𞤣"), + (0x1E902, "M", "𞤤"), + (0x1E903, "M", "𞤥"), + (0x1E904, "M", "𞤦"), + (0x1E905, "M", "𞤧"), + (0x1E906, "M", "𞤨"), + (0x1E907, "M", "𞤩"), + (0x1E908, "M", "𞤪"), + (0x1E909, "M", "𞤫"), + (0x1E90A, "M", "𞤬"), + (0x1E90B, "M", "𞤭"), + (0x1E90C, "M", "𞤮"), + (0x1E90D, "M", "𞤯"), + ] + + +def _seg_72() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1E90E, "M", "𞤰"), + (0x1E90F, "M", "𞤱"), + (0x1E910, "M", "𞤲"), + (0x1E911, "M", "𞤳"), + (0x1E912, "M", "𞤴"), + (0x1E913, "M", "𞤵"), + (0x1E914, "M", "𞤶"), + (0x1E915, "M", "𞤷"), + (0x1E916, "M", "𞤸"), + (0x1E917, "M", "𞤹"), + (0x1E918, "M", "𞤺"), + (0x1E919, "M", "𞤻"), + (0x1E91A, "M", "𞤼"), + (0x1E91B, "M", "𞤽"), + (0x1E91C, "M", "𞤾"), + (0x1E91D, "M", "𞤿"), + (0x1E91E, "M", "𞥀"), + (0x1E91F, "M", "𞥁"), + (0x1E920, "M", "𞥂"), + (0x1E921, "M", "𞥃"), + (0x1E922, "V"), + (0x1E94C, "X"), + (0x1E950, "V"), + (0x1E95A, "X"), + (0x1E95E, "V"), + (0x1E960, "X"), + (0x1EC71, "V"), + (0x1ECB5, "X"), + (0x1ED01, "V"), + (0x1ED3E, "X"), + (0x1EE00, "M", "ا"), + (0x1EE01, "M", "ب"), + (0x1EE02, "M", "ج"), + (0x1EE03, "M", "د"), + (0x1EE04, "X"), + (0x1EE05, "M", "و"), + (0x1EE06, "M", "ز"), + (0x1EE07, "M", "ح"), + (0x1EE08, "M", "ط"), + (0x1EE09, "M", "ي"), + (0x1EE0A, "M", "ك"), + (0x1EE0B, "M", "ل"), + (0x1EE0C, "M", "م"), + (0x1EE0D, "M", "ن"), + (0x1EE0E, "M", "س"), + (0x1EE0F, "M", "ع"), + (0x1EE10, "M", "ف"), + (0x1EE11, "M", "ص"), + (0x1EE12, "M", "ق"), + (0x1EE13, "M", "ر"), + (0x1EE14, "M", "ش"), + (0x1EE15, "M", "ت"), + (0x1EE16, "M", "ث"), + (0x1EE17, "M", "خ"), + (0x1EE18, "M", "ذ"), + (0x1EE19, "M", "ض"), + (0x1EE1A, "M", "ظ"), + (0x1EE1B, "M", "غ"), + (0x1EE1C, "M", "ٮ"), + (0x1EE1D, "M", "ں"), + (0x1EE1E, "M", "ڡ"), + (0x1EE1F, "M", "ٯ"), + (0x1EE20, "X"), + (0x1EE21, "M", "ب"), + (0x1EE22, "M", "ج"), + (0x1EE23, "X"), + (0x1EE24, "M", "ه"), + (0x1EE25, "X"), + (0x1EE27, "M", "ح"), + (0x1EE28, "X"), + (0x1EE29, "M", "ي"), + (0x1EE2A, "M", "ك"), + (0x1EE2B, "M", "ل"), + (0x1EE2C, "M", "م"), + (0x1EE2D, "M", "ن"), + (0x1EE2E, "M", "س"), + (0x1EE2F, "M", "ع"), + (0x1EE30, "M", "ف"), + (0x1EE31, "M", "ص"), + (0x1EE32, "M", "ق"), + (0x1EE33, "X"), + (0x1EE34, "M", "ش"), + (0x1EE35, "M", "ت"), + (0x1EE36, "M", "ث"), + (0x1EE37, "M", "خ"), + (0x1EE38, "X"), + (0x1EE39, "M", "ض"), + (0x1EE3A, "X"), + (0x1EE3B, "M", "غ"), + (0x1EE3C, "X"), + (0x1EE42, "M", "ج"), + (0x1EE43, "X"), + (0x1EE47, "M", "ح"), + (0x1EE48, "X"), + (0x1EE49, "M", "ي"), + (0x1EE4A, "X"), + (0x1EE4B, "M", "ل"), + (0x1EE4C, "X"), + (0x1EE4D, "M", "ن"), + (0x1EE4E, "M", "س"), + ] + + +def _seg_73() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EE4F, "M", "ع"), + (0x1EE50, "X"), + (0x1EE51, "M", "ص"), + (0x1EE52, "M", "ق"), + (0x1EE53, "X"), + (0x1EE54, "M", "ش"), + (0x1EE55, "X"), + (0x1EE57, "M", "خ"), + (0x1EE58, "X"), + (0x1EE59, "M", "ض"), + (0x1EE5A, "X"), + (0x1EE5B, "M", "غ"), + (0x1EE5C, "X"), + (0x1EE5D, "M", "ں"), + (0x1EE5E, "X"), + (0x1EE5F, "M", "ٯ"), + (0x1EE60, "X"), + (0x1EE61, "M", "ب"), + (0x1EE62, "M", "ج"), + (0x1EE63, "X"), + (0x1EE64, "M", "ه"), + (0x1EE65, "X"), + (0x1EE67, "M", "ح"), + (0x1EE68, "M", "ط"), + (0x1EE69, "M", "ي"), + (0x1EE6A, "M", "ك"), + (0x1EE6B, "X"), + (0x1EE6C, "M", "م"), + (0x1EE6D, "M", "ن"), + (0x1EE6E, "M", "س"), + (0x1EE6F, "M", "ع"), + (0x1EE70, "M", "ف"), + (0x1EE71, "M", "ص"), + (0x1EE72, "M", "ق"), + (0x1EE73, "X"), + (0x1EE74, "M", "ش"), + (0x1EE75, "M", "ت"), + (0x1EE76, "M", "ث"), + (0x1EE77, "M", "خ"), + (0x1EE78, "X"), + (0x1EE79, "M", "ض"), + (0x1EE7A, "M", "ظ"), + (0x1EE7B, "M", "غ"), + (0x1EE7C, "M", "ٮ"), + (0x1EE7D, "X"), + (0x1EE7E, "M", "ڡ"), + (0x1EE7F, "X"), + (0x1EE80, "M", "ا"), + (0x1EE81, "M", "ب"), + (0x1EE82, "M", "ج"), + (0x1EE83, "M", "د"), + (0x1EE84, "M", "ه"), + (0x1EE85, "M", "و"), + (0x1EE86, "M", "ز"), + (0x1EE87, "M", "ح"), + (0x1EE88, "M", "ط"), + (0x1EE89, "M", "ي"), + (0x1EE8A, "X"), + (0x1EE8B, "M", "ل"), + (0x1EE8C, "M", "م"), + (0x1EE8D, "M", "ن"), + (0x1EE8E, "M", "س"), + (0x1EE8F, "M", "ع"), + (0x1EE90, "M", "ف"), + (0x1EE91, "M", "ص"), + (0x1EE92, "M", "ق"), + (0x1EE93, "M", "ر"), + (0x1EE94, "M", "ش"), + (0x1EE95, "M", "ت"), + (0x1EE96, "M", "ث"), + (0x1EE97, "M", "خ"), + (0x1EE98, "M", "ذ"), + (0x1EE99, "M", "ض"), + (0x1EE9A, "M", "ظ"), + (0x1EE9B, "M", "غ"), + (0x1EE9C, "X"), + (0x1EEA1, "M", "ب"), + (0x1EEA2, "M", "ج"), + (0x1EEA3, "M", "د"), + (0x1EEA4, "X"), + (0x1EEA5, "M", "و"), + (0x1EEA6, "M", "ز"), + (0x1EEA7, "M", "ح"), + (0x1EEA8, "M", "ط"), + (0x1EEA9, "M", "ي"), + (0x1EEAA, "X"), + (0x1EEAB, "M", "ل"), + (0x1EEAC, "M", "م"), + (0x1EEAD, "M", "ن"), + (0x1EEAE, "M", "س"), + (0x1EEAF, "M", "ع"), + (0x1EEB0, "M", "ف"), + (0x1EEB1, "M", "ص"), + (0x1EEB2, "M", "ق"), + (0x1EEB3, "M", "ر"), + (0x1EEB4, "M", "ش"), + (0x1EEB5, "M", "ت"), + (0x1EEB6, "M", "ث"), + (0x1EEB7, "M", "خ"), + (0x1EEB8, "M", "ذ"), + ] + + +def _seg_74() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1EEB9, "M", "ض"), + (0x1EEBA, "M", "ظ"), + (0x1EEBB, "M", "غ"), + (0x1EEBC, "X"), + (0x1EEF0, "V"), + (0x1EEF2, "X"), + (0x1F000, "V"), + (0x1F02C, "X"), + (0x1F030, "V"), + (0x1F094, "X"), + (0x1F0A0, "V"), + (0x1F0AF, "X"), + (0x1F0B1, "V"), + (0x1F0C0, "X"), + (0x1F0C1, "V"), + (0x1F0D0, "X"), + (0x1F0D1, "V"), + (0x1F0F6, "X"), + (0x1F101, "3", "0,"), + (0x1F102, "3", "1,"), + (0x1F103, "3", "2,"), + (0x1F104, "3", "3,"), + (0x1F105, "3", "4,"), + (0x1F106, "3", "5,"), + (0x1F107, "3", "6,"), + (0x1F108, "3", "7,"), + (0x1F109, "3", "8,"), + (0x1F10A, "3", "9,"), + (0x1F10B, "V"), + (0x1F110, "3", "(a)"), + (0x1F111, "3", "(b)"), + (0x1F112, "3", "(c)"), + (0x1F113, "3", "(d)"), + (0x1F114, "3", "(e)"), + (0x1F115, "3", "(f)"), + (0x1F116, "3", "(g)"), + (0x1F117, "3", "(h)"), + (0x1F118, "3", "(i)"), + (0x1F119, "3", "(j)"), + (0x1F11A, "3", "(k)"), + (0x1F11B, "3", "(l)"), + (0x1F11C, "3", "(m)"), + (0x1F11D, "3", "(n)"), + (0x1F11E, "3", "(o)"), + (0x1F11F, "3", "(p)"), + (0x1F120, "3", "(q)"), + (0x1F121, "3", "(r)"), + (0x1F122, "3", "(s)"), + (0x1F123, "3", "(t)"), + (0x1F124, "3", "(u)"), + (0x1F125, "3", "(v)"), + (0x1F126, "3", "(w)"), + (0x1F127, "3", "(x)"), + (0x1F128, "3", "(y)"), + (0x1F129, "3", "(z)"), + (0x1F12A, "M", "〔s〕"), + (0x1F12B, "M", "c"), + (0x1F12C, "M", "r"), + (0x1F12D, "M", "cd"), + (0x1F12E, "M", "wz"), + (0x1F12F, "V"), + (0x1F130, "M", "a"), + (0x1F131, "M", "b"), + (0x1F132, "M", "c"), + (0x1F133, "M", "d"), + (0x1F134, "M", "e"), + (0x1F135, "M", "f"), + (0x1F136, "M", "g"), + (0x1F137, "M", "h"), + (0x1F138, "M", "i"), + (0x1F139, "M", "j"), + (0x1F13A, "M", "k"), + (0x1F13B, "M", "l"), + (0x1F13C, "M", "m"), + (0x1F13D, "M", "n"), + (0x1F13E, "M", "o"), + (0x1F13F, "M", "p"), + (0x1F140, "M", "q"), + (0x1F141, "M", "r"), + (0x1F142, "M", "s"), + (0x1F143, "M", "t"), + (0x1F144, "M", "u"), + (0x1F145, "M", "v"), + (0x1F146, "M", "w"), + (0x1F147, "M", "x"), + (0x1F148, "M", "y"), + (0x1F149, "M", "z"), + (0x1F14A, "M", "hv"), + (0x1F14B, "M", "mv"), + (0x1F14C, "M", "sd"), + (0x1F14D, "M", "ss"), + (0x1F14E, "M", "ppv"), + (0x1F14F, "M", "wc"), + (0x1F150, "V"), + (0x1F16A, "M", "mc"), + (0x1F16B, "M", "md"), + (0x1F16C, "M", "mr"), + (0x1F16D, "V"), + (0x1F190, "M", "dj"), + (0x1F191, "V"), + ] + + +def _seg_75() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1F1AE, "X"), + (0x1F1E6, "V"), + (0x1F200, "M", "ほか"), + (0x1F201, "M", "ココ"), + (0x1F202, "M", "サ"), + (0x1F203, "X"), + (0x1F210, "M", "手"), + (0x1F211, "M", "字"), + (0x1F212, "M", "双"), + (0x1F213, "M", "デ"), + (0x1F214, "M", "二"), + (0x1F215, "M", "多"), + (0x1F216, "M", "解"), + (0x1F217, "M", "天"), + (0x1F218, "M", "交"), + (0x1F219, "M", "映"), + (0x1F21A, "M", "無"), + (0x1F21B, "M", "料"), + (0x1F21C, "M", "前"), + (0x1F21D, "M", "後"), + (0x1F21E, "M", "再"), + (0x1F21F, "M", "新"), + (0x1F220, "M", "初"), + (0x1F221, "M", "終"), + (0x1F222, "M", "生"), + (0x1F223, "M", "販"), + (0x1F224, "M", "声"), + (0x1F225, "M", "吹"), + (0x1F226, "M", "演"), + (0x1F227, "M", "投"), + (0x1F228, "M", "捕"), + (0x1F229, "M", "一"), + (0x1F22A, "M", "三"), + (0x1F22B, "M", "遊"), + (0x1F22C, "M", "左"), + (0x1F22D, "M", "中"), + (0x1F22E, "M", "右"), + (0x1F22F, "M", "指"), + (0x1F230, "M", "走"), + (0x1F231, "M", "打"), + (0x1F232, "M", "禁"), + (0x1F233, "M", "空"), + (0x1F234, "M", "合"), + (0x1F235, "M", "満"), + (0x1F236, "M", "有"), + (0x1F237, "M", "月"), + (0x1F238, "M", "申"), + (0x1F239, "M", "割"), + (0x1F23A, "M", "営"), + (0x1F23B, "M", "配"), + (0x1F23C, "X"), + (0x1F240, "M", "〔本〕"), + (0x1F241, "M", "〔三〕"), + (0x1F242, "M", "〔二〕"), + (0x1F243, "M", "〔安〕"), + (0x1F244, "M", "〔点〕"), + (0x1F245, "M", "〔打〕"), + (0x1F246, "M", "〔盗〕"), + (0x1F247, "M", "〔勝〕"), + (0x1F248, "M", "〔敗〕"), + (0x1F249, "X"), + (0x1F250, "M", "得"), + (0x1F251, "M", "可"), + (0x1F252, "X"), + (0x1F260, "V"), + (0x1F266, "X"), + (0x1F300, "V"), + (0x1F6D8, "X"), + (0x1F6DC, "V"), + (0x1F6ED, "X"), + (0x1F6F0, "V"), + (0x1F6FD, "X"), + (0x1F700, "V"), + (0x1F777, "X"), + (0x1F77B, "V"), + (0x1F7DA, "X"), + (0x1F7E0, "V"), + (0x1F7EC, "X"), + (0x1F7F0, "V"), + (0x1F7F1, "X"), + (0x1F800, "V"), + (0x1F80C, "X"), + (0x1F810, "V"), + (0x1F848, "X"), + (0x1F850, "V"), + (0x1F85A, "X"), + (0x1F860, "V"), + (0x1F888, "X"), + (0x1F890, "V"), + (0x1F8AE, "X"), + (0x1F8B0, "V"), + (0x1F8B2, "X"), + (0x1F900, "V"), + (0x1FA54, "X"), + (0x1FA60, "V"), + (0x1FA6E, "X"), + (0x1FA70, "V"), + (0x1FA7D, "X"), + (0x1FA80, "V"), + (0x1FA89, "X"), + ] + + +def _seg_76() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x1FA90, "V"), + (0x1FABE, "X"), + (0x1FABF, "V"), + (0x1FAC6, "X"), + (0x1FACE, "V"), + (0x1FADC, "X"), + (0x1FAE0, "V"), + (0x1FAE9, "X"), + (0x1FAF0, "V"), + (0x1FAF9, "X"), + (0x1FB00, "V"), + (0x1FB93, "X"), + (0x1FB94, "V"), + (0x1FBCB, "X"), + (0x1FBF0, "M", "0"), + (0x1FBF1, "M", "1"), + (0x1FBF2, "M", "2"), + (0x1FBF3, "M", "3"), + (0x1FBF4, "M", "4"), + (0x1FBF5, "M", "5"), + (0x1FBF6, "M", "6"), + (0x1FBF7, "M", "7"), + (0x1FBF8, "M", "8"), + (0x1FBF9, "M", "9"), + (0x1FBFA, "X"), + (0x20000, "V"), + (0x2A6E0, "X"), + (0x2A700, "V"), + (0x2B73A, "X"), + (0x2B740, "V"), + (0x2B81E, "X"), + (0x2B820, "V"), + (0x2CEA2, "X"), + (0x2CEB0, "V"), + (0x2EBE1, "X"), + (0x2EBF0, "V"), + (0x2EE5E, "X"), + (0x2F800, "M", "丽"), + (0x2F801, "M", "丸"), + (0x2F802, "M", "乁"), + (0x2F803, "M", "𠄢"), + (0x2F804, "M", "你"), + (0x2F805, "M", "侮"), + (0x2F806, "M", "侻"), + (0x2F807, "M", "倂"), + (0x2F808, "M", "偺"), + (0x2F809, "M", "備"), + (0x2F80A, "M", "僧"), + (0x2F80B, "M", "像"), + (0x2F80C, "M", "㒞"), + (0x2F80D, "M", "𠘺"), + (0x2F80E, "M", "免"), + (0x2F80F, "M", "兔"), + (0x2F810, "M", "兤"), + (0x2F811, "M", "具"), + (0x2F812, "M", "𠔜"), + (0x2F813, "M", "㒹"), + (0x2F814, "M", "內"), + (0x2F815, "M", "再"), + (0x2F816, "M", "𠕋"), + (0x2F817, "M", "冗"), + (0x2F818, "M", "冤"), + (0x2F819, "M", "仌"), + (0x2F81A, "M", "冬"), + (0x2F81B, "M", "况"), + (0x2F81C, "M", "𩇟"), + (0x2F81D, "M", "凵"), + (0x2F81E, "M", "刃"), + (0x2F81F, "M", "㓟"), + (0x2F820, "M", "刻"), + (0x2F821, "M", "剆"), + (0x2F822, "M", "割"), + (0x2F823, "M", "剷"), + (0x2F824, "M", "㔕"), + (0x2F825, "M", "勇"), + (0x2F826, "M", "勉"), + (0x2F827, "M", "勤"), + (0x2F828, "M", "勺"), + (0x2F829, "M", "包"), + (0x2F82A, "M", "匆"), + (0x2F82B, "M", "北"), + (0x2F82C, "M", "卉"), + (0x2F82D, "M", "卑"), + (0x2F82E, "M", "博"), + (0x2F82F, "M", "即"), + (0x2F830, "M", "卽"), + (0x2F831, "M", "卿"), + (0x2F834, "M", "𠨬"), + (0x2F835, "M", "灰"), + (0x2F836, "M", "及"), + (0x2F837, "M", "叟"), + (0x2F838, "M", "𠭣"), + (0x2F839, "M", "叫"), + (0x2F83A, "M", "叱"), + (0x2F83B, "M", "吆"), + (0x2F83C, "M", "咞"), + (0x2F83D, "M", "吸"), + (0x2F83E, "M", "呈"), + (0x2F83F, "M", "周"), + (0x2F840, "M", "咢"), + ] + + +def _seg_77() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F841, "M", "哶"), + (0x2F842, "M", "唐"), + (0x2F843, "M", "啓"), + (0x2F844, "M", "啣"), + (0x2F845, "M", "善"), + (0x2F847, "M", "喙"), + (0x2F848, "M", "喫"), + (0x2F849, "M", "喳"), + (0x2F84A, "M", "嗂"), + (0x2F84B, "M", "圖"), + (0x2F84C, "M", "嘆"), + (0x2F84D, "M", "圗"), + (0x2F84E, "M", "噑"), + (0x2F84F, "M", "噴"), + (0x2F850, "M", "切"), + (0x2F851, "M", "壮"), + (0x2F852, "M", "城"), + (0x2F853, "M", "埴"), + (0x2F854, "M", "堍"), + (0x2F855, "M", "型"), + (0x2F856, "M", "堲"), + (0x2F857, "M", "報"), + (0x2F858, "M", "墬"), + (0x2F859, "M", "𡓤"), + (0x2F85A, "M", "売"), + (0x2F85B, "M", "壷"), + (0x2F85C, "M", "夆"), + (0x2F85D, "M", "多"), + (0x2F85E, "M", "夢"), + (0x2F85F, "M", "奢"), + (0x2F860, "M", "𡚨"), + (0x2F861, "M", "𡛪"), + (0x2F862, "M", "姬"), + (0x2F863, "M", "娛"), + (0x2F864, "M", "娧"), + (0x2F865, "M", "姘"), + (0x2F866, "M", "婦"), + (0x2F867, "M", "㛮"), + (0x2F868, "X"), + (0x2F869, "M", "嬈"), + (0x2F86A, "M", "嬾"), + (0x2F86C, "M", "𡧈"), + (0x2F86D, "M", "寃"), + (0x2F86E, "M", "寘"), + (0x2F86F, "M", "寧"), + (0x2F870, "M", "寳"), + (0x2F871, "M", "𡬘"), + (0x2F872, "M", "寿"), + (0x2F873, "M", "将"), + (0x2F874, "X"), + (0x2F875, "M", "尢"), + (0x2F876, "M", "㞁"), + (0x2F877, "M", "屠"), + (0x2F878, "M", "屮"), + (0x2F879, "M", "峀"), + (0x2F87A, "M", "岍"), + (0x2F87B, "M", "𡷤"), + (0x2F87C, "M", "嵃"), + (0x2F87D, "M", "𡷦"), + (0x2F87E, "M", "嵮"), + (0x2F87F, "M", "嵫"), + (0x2F880, "M", "嵼"), + (0x2F881, "M", "巡"), + (0x2F882, "M", "巢"), + (0x2F883, "M", "㠯"), + (0x2F884, "M", "巽"), + (0x2F885, "M", "帨"), + (0x2F886, "M", "帽"), + (0x2F887, "M", "幩"), + (0x2F888, "M", "㡢"), + (0x2F889, "M", "𢆃"), + (0x2F88A, "M", "㡼"), + (0x2F88B, "M", "庰"), + (0x2F88C, "M", "庳"), + (0x2F88D, "M", "庶"), + (0x2F88E, "M", "廊"), + (0x2F88F, "M", "𪎒"), + (0x2F890, "M", "廾"), + (0x2F891, "M", "𢌱"), + (0x2F893, "M", "舁"), + (0x2F894, "M", "弢"), + (0x2F896, "M", "㣇"), + (0x2F897, "M", "𣊸"), + (0x2F898, "M", "𦇚"), + (0x2F899, "M", "形"), + (0x2F89A, "M", "彫"), + (0x2F89B, "M", "㣣"), + (0x2F89C, "M", "徚"), + (0x2F89D, "M", "忍"), + (0x2F89E, "M", "志"), + (0x2F89F, "M", "忹"), + (0x2F8A0, "M", "悁"), + (0x2F8A1, "M", "㤺"), + (0x2F8A2, "M", "㤜"), + (0x2F8A3, "M", "悔"), + (0x2F8A4, "M", "𢛔"), + (0x2F8A5, "M", "惇"), + (0x2F8A6, "M", "慈"), + (0x2F8A7, "M", "慌"), + (0x2F8A8, "M", "慎"), + ] + + +def _seg_78() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F8A9, "M", "慌"), + (0x2F8AA, "M", "慺"), + (0x2F8AB, "M", "憎"), + (0x2F8AC, "M", "憲"), + (0x2F8AD, "M", "憤"), + (0x2F8AE, "M", "憯"), + (0x2F8AF, "M", "懞"), + (0x2F8B0, "M", "懲"), + (0x2F8B1, "M", "懶"), + (0x2F8B2, "M", "成"), + (0x2F8B3, "M", "戛"), + (0x2F8B4, "M", "扝"), + (0x2F8B5, "M", "抱"), + (0x2F8B6, "M", "拔"), + (0x2F8B7, "M", "捐"), + (0x2F8B8, "M", "𢬌"), + (0x2F8B9, "M", "挽"), + (0x2F8BA, "M", "拼"), + (0x2F8BB, "M", "捨"), + (0x2F8BC, "M", "掃"), + (0x2F8BD, "M", "揤"), + (0x2F8BE, "M", "𢯱"), + (0x2F8BF, "M", "搢"), + (0x2F8C0, "M", "揅"), + (0x2F8C1, "M", "掩"), + (0x2F8C2, "M", "㨮"), + (0x2F8C3, "M", "摩"), + (0x2F8C4, "M", "摾"), + (0x2F8C5, "M", "撝"), + (0x2F8C6, "M", "摷"), + (0x2F8C7, "M", "㩬"), + (0x2F8C8, "M", "敏"), + (0x2F8C9, "M", "敬"), + (0x2F8CA, "M", "𣀊"), + (0x2F8CB, "M", "旣"), + (0x2F8CC, "M", "書"), + (0x2F8CD, "M", "晉"), + (0x2F8CE, "M", "㬙"), + (0x2F8CF, "M", "暑"), + (0x2F8D0, "M", "㬈"), + (0x2F8D1, "M", "㫤"), + (0x2F8D2, "M", "冒"), + (0x2F8D3, "M", "冕"), + (0x2F8D4, "M", "最"), + (0x2F8D5, "M", "暜"), + (0x2F8D6, "M", "肭"), + (0x2F8D7, "M", "䏙"), + (0x2F8D8, "M", "朗"), + (0x2F8D9, "M", "望"), + (0x2F8DA, "M", "朡"), + (0x2F8DB, "M", "杞"), + (0x2F8DC, "M", "杓"), + (0x2F8DD, "M", "𣏃"), + (0x2F8DE, "M", "㭉"), + (0x2F8DF, "M", "柺"), + (0x2F8E0, "M", "枅"), + (0x2F8E1, "M", "桒"), + (0x2F8E2, "M", "梅"), + (0x2F8E3, "M", "𣑭"), + (0x2F8E4, "M", "梎"), + (0x2F8E5, "M", "栟"), + (0x2F8E6, "M", "椔"), + (0x2F8E7, "M", "㮝"), + (0x2F8E8, "M", "楂"), + (0x2F8E9, "M", "榣"), + (0x2F8EA, "M", "槪"), + (0x2F8EB, "M", "檨"), + (0x2F8EC, "M", "𣚣"), + (0x2F8ED, "M", "櫛"), + (0x2F8EE, "M", "㰘"), + (0x2F8EF, "M", "次"), + (0x2F8F0, "M", "𣢧"), + (0x2F8F1, "M", "歔"), + (0x2F8F2, "M", "㱎"), + (0x2F8F3, "M", "歲"), + (0x2F8F4, "M", "殟"), + (0x2F8F5, "M", "殺"), + (0x2F8F6, "M", "殻"), + (0x2F8F7, "M", "𣪍"), + (0x2F8F8, "M", "𡴋"), + (0x2F8F9, "M", "𣫺"), + (0x2F8FA, "M", "汎"), + (0x2F8FB, "M", "𣲼"), + (0x2F8FC, "M", "沿"), + (0x2F8FD, "M", "泍"), + (0x2F8FE, "M", "汧"), + (0x2F8FF, "M", "洖"), + (0x2F900, "M", "派"), + (0x2F901, "M", "海"), + (0x2F902, "M", "流"), + (0x2F903, "M", "浩"), + (0x2F904, "M", "浸"), + (0x2F905, "M", "涅"), + (0x2F906, "M", "𣴞"), + (0x2F907, "M", "洴"), + (0x2F908, "M", "港"), + (0x2F909, "M", "湮"), + (0x2F90A, "M", "㴳"), + (0x2F90B, "M", "滋"), + (0x2F90C, "M", "滇"), + ] + + +def _seg_79() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F90D, "M", "𣻑"), + (0x2F90E, "M", "淹"), + (0x2F90F, "M", "潮"), + (0x2F910, "M", "𣽞"), + (0x2F911, "M", "𣾎"), + (0x2F912, "M", "濆"), + (0x2F913, "M", "瀹"), + (0x2F914, "M", "瀞"), + (0x2F915, "M", "瀛"), + (0x2F916, "M", "㶖"), + (0x2F917, "M", "灊"), + (0x2F918, "M", "災"), + (0x2F919, "M", "灷"), + (0x2F91A, "M", "炭"), + (0x2F91B, "M", "𠔥"), + (0x2F91C, "M", "煅"), + (0x2F91D, "M", "𤉣"), + (0x2F91E, "M", "熜"), + (0x2F91F, "X"), + (0x2F920, "M", "爨"), + (0x2F921, "M", "爵"), + (0x2F922, "M", "牐"), + (0x2F923, "M", "𤘈"), + (0x2F924, "M", "犀"), + (0x2F925, "M", "犕"), + (0x2F926, "M", "𤜵"), + (0x2F927, "M", "𤠔"), + (0x2F928, "M", "獺"), + (0x2F929, "M", "王"), + (0x2F92A, "M", "㺬"), + (0x2F92B, "M", "玥"), + (0x2F92C, "M", "㺸"), + (0x2F92E, "M", "瑇"), + (0x2F92F, "M", "瑜"), + (0x2F930, "M", "瑱"), + (0x2F931, "M", "璅"), + (0x2F932, "M", "瓊"), + (0x2F933, "M", "㼛"), + (0x2F934, "M", "甤"), + (0x2F935, "M", "𤰶"), + (0x2F936, "M", "甾"), + (0x2F937, "M", "𤲒"), + (0x2F938, "M", "異"), + (0x2F939, "M", "𢆟"), + (0x2F93A, "M", "瘐"), + (0x2F93B, "M", "𤾡"), + (0x2F93C, "M", "𤾸"), + (0x2F93D, "M", "𥁄"), + (0x2F93E, "M", "㿼"), + (0x2F93F, "M", "䀈"), + (0x2F940, "M", "直"), + (0x2F941, "M", "𥃳"), + (0x2F942, "M", "𥃲"), + (0x2F943, "M", "𥄙"), + (0x2F944, "M", "𥄳"), + (0x2F945, "M", "眞"), + (0x2F946, "M", "真"), + (0x2F948, "M", "睊"), + (0x2F949, "M", "䀹"), + (0x2F94A, "M", "瞋"), + (0x2F94B, "M", "䁆"), + (0x2F94C, "M", "䂖"), + (0x2F94D, "M", "𥐝"), + (0x2F94E, "M", "硎"), + (0x2F94F, "M", "碌"), + (0x2F950, "M", "磌"), + (0x2F951, "M", "䃣"), + (0x2F952, "M", "𥘦"), + (0x2F953, "M", "祖"), + (0x2F954, "M", "𥚚"), + (0x2F955, "M", "𥛅"), + (0x2F956, "M", "福"), + (0x2F957, "M", "秫"), + (0x2F958, "M", "䄯"), + (0x2F959, "M", "穀"), + (0x2F95A, "M", "穊"), + (0x2F95B, "M", "穏"), + (0x2F95C, "M", "𥥼"), + (0x2F95D, "M", "𥪧"), + (0x2F95F, "X"), + (0x2F960, "M", "䈂"), + (0x2F961, "M", "𥮫"), + (0x2F962, "M", "篆"), + (0x2F963, "M", "築"), + (0x2F964, "M", "䈧"), + (0x2F965, "M", "𥲀"), + (0x2F966, "M", "糒"), + (0x2F967, "M", "䊠"), + (0x2F968, "M", "糨"), + (0x2F969, "M", "糣"), + (0x2F96A, "M", "紀"), + (0x2F96B, "M", "𥾆"), + (0x2F96C, "M", "絣"), + (0x2F96D, "M", "䌁"), + (0x2F96E, "M", "緇"), + (0x2F96F, "M", "縂"), + (0x2F970, "M", "繅"), + (0x2F971, "M", "䌴"), + (0x2F972, "M", "𦈨"), + (0x2F973, "M", "𦉇"), + ] + + +def _seg_80() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F974, "M", "䍙"), + (0x2F975, "M", "𦋙"), + (0x2F976, "M", "罺"), + (0x2F977, "M", "𦌾"), + (0x2F978, "M", "羕"), + (0x2F979, "M", "翺"), + (0x2F97A, "M", "者"), + (0x2F97B, "M", "𦓚"), + (0x2F97C, "M", "𦔣"), + (0x2F97D, "M", "聠"), + (0x2F97E, "M", "𦖨"), + (0x2F97F, "M", "聰"), + (0x2F980, "M", "𣍟"), + (0x2F981, "M", "䏕"), + (0x2F982, "M", "育"), + (0x2F983, "M", "脃"), + (0x2F984, "M", "䐋"), + (0x2F985, "M", "脾"), + (0x2F986, "M", "媵"), + (0x2F987, "M", "𦞧"), + (0x2F988, "M", "𦞵"), + (0x2F989, "M", "𣎓"), + (0x2F98A, "M", "𣎜"), + (0x2F98B, "M", "舁"), + (0x2F98C, "M", "舄"), + (0x2F98D, "M", "辞"), + (0x2F98E, "M", "䑫"), + (0x2F98F, "M", "芑"), + (0x2F990, "M", "芋"), + (0x2F991, "M", "芝"), + (0x2F992, "M", "劳"), + (0x2F993, "M", "花"), + (0x2F994, "M", "芳"), + (0x2F995, "M", "芽"), + (0x2F996, "M", "苦"), + (0x2F997, "M", "𦬼"), + (0x2F998, "M", "若"), + (0x2F999, "M", "茝"), + (0x2F99A, "M", "荣"), + (0x2F99B, "M", "莭"), + (0x2F99C, "M", "茣"), + (0x2F99D, "M", "莽"), + (0x2F99E, "M", "菧"), + (0x2F99F, "M", "著"), + (0x2F9A0, "M", "荓"), + (0x2F9A1, "M", "菊"), + (0x2F9A2, "M", "菌"), + (0x2F9A3, "M", "菜"), + (0x2F9A4, "M", "𦰶"), + (0x2F9A5, "M", "𦵫"), + (0x2F9A6, "M", "𦳕"), + (0x2F9A7, "M", "䔫"), + (0x2F9A8, "M", "蓱"), + (0x2F9A9, "M", "蓳"), + (0x2F9AA, "M", "蔖"), + (0x2F9AB, "M", "𧏊"), + (0x2F9AC, "M", "蕤"), + (0x2F9AD, "M", "𦼬"), + (0x2F9AE, "M", "䕝"), + (0x2F9AF, "M", "䕡"), + (0x2F9B0, "M", "𦾱"), + (0x2F9B1, "M", "𧃒"), + (0x2F9B2, "M", "䕫"), + (0x2F9B3, "M", "虐"), + (0x2F9B4, "M", "虜"), + (0x2F9B5, "M", "虧"), + (0x2F9B6, "M", "虩"), + (0x2F9B7, "M", "蚩"), + (0x2F9B8, "M", "蚈"), + (0x2F9B9, "M", "蜎"), + (0x2F9BA, "M", "蛢"), + (0x2F9BB, "M", "蝹"), + (0x2F9BC, "M", "蜨"), + (0x2F9BD, "M", "蝫"), + (0x2F9BE, "M", "螆"), + (0x2F9BF, "X"), + (0x2F9C0, "M", "蟡"), + (0x2F9C1, "M", "蠁"), + (0x2F9C2, "M", "䗹"), + (0x2F9C3, "M", "衠"), + (0x2F9C4, "M", "衣"), + (0x2F9C5, "M", "𧙧"), + (0x2F9C6, "M", "裗"), + (0x2F9C7, "M", "裞"), + (0x2F9C8, "M", "䘵"), + (0x2F9C9, "M", "裺"), + (0x2F9CA, "M", "㒻"), + (0x2F9CB, "M", "𧢮"), + (0x2F9CC, "M", "𧥦"), + (0x2F9CD, "M", "䚾"), + (0x2F9CE, "M", "䛇"), + (0x2F9CF, "M", "誠"), + (0x2F9D0, "M", "諭"), + (0x2F9D1, "M", "變"), + (0x2F9D2, "M", "豕"), + (0x2F9D3, "M", "𧲨"), + (0x2F9D4, "M", "貫"), + (0x2F9D5, "M", "賁"), + (0x2F9D6, "M", "贛"), + (0x2F9D7, "M", "起"), + ] + + +def _seg_81() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: + return [ + (0x2F9D8, "M", "𧼯"), + (0x2F9D9, "M", "𠠄"), + (0x2F9DA, "M", "跋"), + (0x2F9DB, "M", "趼"), + (0x2F9DC, "M", "跰"), + (0x2F9DD, "M", "𠣞"), + (0x2F9DE, "M", "軔"), + (0x2F9DF, "M", "輸"), + (0x2F9E0, "M", "𨗒"), + (0x2F9E1, "M", "𨗭"), + (0x2F9E2, "M", "邔"), + (0x2F9E3, "M", "郱"), + (0x2F9E4, "M", "鄑"), + (0x2F9E5, "M", "𨜮"), + (0x2F9E6, "M", "鄛"), + (0x2F9E7, "M", "鈸"), + (0x2F9E8, "M", "鋗"), + (0x2F9E9, "M", "鋘"), + (0x2F9EA, "M", "鉼"), + (0x2F9EB, "M", "鏹"), + (0x2F9EC, "M", "鐕"), + (0x2F9ED, "M", "𨯺"), + (0x2F9EE, "M", "開"), + (0x2F9EF, "M", "䦕"), + (0x2F9F0, "M", "閷"), + (0x2F9F1, "M", "𨵷"), + (0x2F9F2, "M", "䧦"), + (0x2F9F3, "M", "雃"), + (0x2F9F4, "M", "嶲"), + (0x2F9F5, "M", "霣"), + (0x2F9F6, "M", "𩅅"), + (0x2F9F7, "M", "𩈚"), + (0x2F9F8, "M", "䩮"), + (0x2F9F9, "M", "䩶"), + (0x2F9FA, "M", "韠"), + (0x2F9FB, "M", "𩐊"), + (0x2F9FC, "M", "䪲"), + (0x2F9FD, "M", "𩒖"), + (0x2F9FE, "M", "頋"), + (0x2FA00, "M", "頩"), + (0x2FA01, "M", "𩖶"), + (0x2FA02, "M", "飢"), + (0x2FA03, "M", "䬳"), + (0x2FA04, "M", "餩"), + (0x2FA05, "M", "馧"), + (0x2FA06, "M", "駂"), + (0x2FA07, "M", "駾"), + (0x2FA08, "M", "䯎"), + (0x2FA09, "M", "𩬰"), + (0x2FA0A, "M", "鬒"), + (0x2FA0B, "M", "鱀"), + (0x2FA0C, "M", "鳽"), + (0x2FA0D, "M", "䳎"), + (0x2FA0E, "M", "䳭"), + (0x2FA0F, "M", "鵧"), + (0x2FA10, "M", "𪃎"), + (0x2FA11, "M", "䳸"), + (0x2FA12, "M", "𪄅"), + (0x2FA13, "M", "𪈎"), + (0x2FA14, "M", "𪊑"), + (0x2FA15, "M", "麻"), + (0x2FA16, "M", "䵖"), + (0x2FA17, "M", "黹"), + (0x2FA18, "M", "黾"), + (0x2FA19, "M", "鼅"), + (0x2FA1A, "M", "鼏"), + (0x2FA1B, "M", "鼖"), + (0x2FA1C, "M", "鼻"), + (0x2FA1D, "M", "𪘀"), + (0x2FA1E, "X"), + (0x30000, "V"), + (0x3134B, "X"), + (0x31350, "V"), + (0x323B0, "X"), + (0xE0100, "I"), + (0xE01F0, "X"), + ] + + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() + + _seg_73() + + _seg_74() + + _seg_75() + + _seg_76() + + _seg_77() + + _seg_78() + + _seg_79() + + _seg_80() + + _seg_81() +) # type: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py new file mode 100644 index 0000000..b615105 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py @@ -0,0 +1,55 @@ +# ruff: noqa: F401 +import os + +from .exceptions import * # noqa: F403 +from .ext import ExtType, Timestamp + +version = (1, 1, 0) +__version__ = "1.1.0" + + +if os.environ.get("MSGPACK_PUREPYTHON"): + from .fallback import Packer, Unpacker, unpackb +else: + try: + from ._cmsgpack import Packer, Unpacker, unpackb + except ImportError: + from .fallback import Packer, Unpacker, unpackb + + +def pack(o, stream, **kwargs): + """ + Pack object `o` and write it to `stream` + + See :class:`Packer` for options. + """ + packer = Packer(**kwargs) + stream.write(packer.pack(o)) + + +def packb(o, **kwargs): + """ + Pack object `o` and return packed bytes + + See :class:`Packer` for options. + """ + return Packer(**kwargs).pack(o) + + +def unpack(stream, **kwargs): + """ + Unpack an object from `stream`. + + Raises `ExtraData` when `stream` contains extra bytes. + See :class:`Unpacker` for options. + """ + data = stream.read() + return unpackb(data, **kwargs) + + +# alias for compatibility to simplejson/marshal/pickle. +load = unpack +loads = unpackb + +dump = pack +dumps = packb diff --git a/backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..265295ee3bea2a40df6ea781eff4625f96bae40c GIT binary patch literal 1744 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py new file mode 100644 index 0000000..d6d2615 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py @@ -0,0 +1,48 @@ +class UnpackException(Exception): + """Base class for some exceptions raised while unpacking. + + NOTE: unpack may raise exception other than subclass of + UnpackException. If you want to catch all error, catch + Exception instead. + """ + + +class BufferFull(UnpackException): + pass + + +class OutOfData(UnpackException): + pass + + +class FormatError(ValueError, UnpackException): + """Invalid msgpack format""" + + +class StackError(ValueError, UnpackException): + """Too nested""" + + +# Deprecated. Use ValueError instead +UnpackValueError = ValueError + + +class ExtraData(UnpackValueError): + """ExtraData is raised when there is trailing data. + + This exception is raised while only one-shot (not streaming) + unpack. + """ + + def __init__(self, unpacked, extra): + self.unpacked = unpacked + self.extra = extra + + def __str__(self): + return "unpack(b) received extra data." + + +# Deprecated. Use Exception instead to catch all exception during packing. +PackException = Exception +PackValueError = ValueError +PackOverflowError = OverflowError diff --git a/backend/venv/Lib/site-packages/pip/_vendor/msgpack/ext.py b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/ext.py new file mode 100644 index 0000000..9694819 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/ext.py @@ -0,0 +1,170 @@ +import datetime +import struct +from collections import namedtuple + + +class ExtType(namedtuple("ExtType", "code data")): + """ExtType represents ext type in msgpack.""" + + def __new__(cls, code, data): + if not isinstance(code, int): + raise TypeError("code must be int") + if not isinstance(data, bytes): + raise TypeError("data must be bytes") + if not 0 <= code <= 127: + raise ValueError("code must be 0~127") + return super().__new__(cls, code, data) + + +class Timestamp: + """Timestamp represents the Timestamp extension type in msgpack. + + When built with Cython, msgpack uses C methods to pack and unpack `Timestamp`. + When using pure-Python msgpack, :func:`to_bytes` and :func:`from_bytes` are used to pack and + unpack `Timestamp`. + + This class is immutable: Do not override seconds and nanoseconds. + """ + + __slots__ = ["seconds", "nanoseconds"] + + def __init__(self, seconds, nanoseconds=0): + """Initialize a Timestamp object. + + :param int seconds: + Number of seconds since the UNIX epoch (00:00:00 UTC Jan 1 1970, minus leap seconds). + May be negative. + + :param int nanoseconds: + Number of nanoseconds to add to `seconds` to get fractional time. + Maximum is 999_999_999. Default is 0. + + Note: Negative times (before the UNIX epoch) are represented as neg. seconds + pos. ns. + """ + if not isinstance(seconds, int): + raise TypeError("seconds must be an integer") + if not isinstance(nanoseconds, int): + raise TypeError("nanoseconds must be an integer") + if not (0 <= nanoseconds < 10**9): + raise ValueError("nanoseconds must be a non-negative integer less than 999999999.") + self.seconds = seconds + self.nanoseconds = nanoseconds + + def __repr__(self): + """String representation of Timestamp.""" + return f"Timestamp(seconds={self.seconds}, nanoseconds={self.nanoseconds})" + + def __eq__(self, other): + """Check for equality with another Timestamp object""" + if type(other) is self.__class__: + return self.seconds == other.seconds and self.nanoseconds == other.nanoseconds + return False + + def __ne__(self, other): + """not-equals method (see :func:`__eq__()`)""" + return not self.__eq__(other) + + def __hash__(self): + return hash((self.seconds, self.nanoseconds)) + + @staticmethod + def from_bytes(b): + """Unpack bytes into a `Timestamp` object. + + Used for pure-Python msgpack unpacking. + + :param b: Payload from msgpack ext message with code -1 + :type b: bytes + + :returns: Timestamp object unpacked from msgpack ext payload + :rtype: Timestamp + """ + if len(b) == 4: + seconds = struct.unpack("!L", b)[0] + nanoseconds = 0 + elif len(b) == 8: + data64 = struct.unpack("!Q", b)[0] + seconds = data64 & 0x00000003FFFFFFFF + nanoseconds = data64 >> 34 + elif len(b) == 12: + nanoseconds, seconds = struct.unpack("!Iq", b) + else: + raise ValueError( + "Timestamp type can only be created from 32, 64, or 96-bit byte objects" + ) + return Timestamp(seconds, nanoseconds) + + def to_bytes(self): + """Pack this Timestamp object into bytes. + + Used for pure-Python msgpack packing. + + :returns data: Payload for EXT message with code -1 (timestamp type) + :rtype: bytes + """ + if (self.seconds >> 34) == 0: # seconds is non-negative and fits in 34 bits + data64 = self.nanoseconds << 34 | self.seconds + if data64 & 0xFFFFFFFF00000000 == 0: + # nanoseconds is zero and seconds < 2**32, so timestamp 32 + data = struct.pack("!L", data64) + else: + # timestamp 64 + data = struct.pack("!Q", data64) + else: + # timestamp 96 + data = struct.pack("!Iq", self.nanoseconds, self.seconds) + return data + + @staticmethod + def from_unix(unix_sec): + """Create a Timestamp from posix timestamp in seconds. + + :param unix_float: Posix timestamp in seconds. + :type unix_float: int or float + """ + seconds = int(unix_sec // 1) + nanoseconds = int((unix_sec % 1) * 10**9) + return Timestamp(seconds, nanoseconds) + + def to_unix(self): + """Get the timestamp as a floating-point value. + + :returns: posix timestamp + :rtype: float + """ + return self.seconds + self.nanoseconds / 1e9 + + @staticmethod + def from_unix_nano(unix_ns): + """Create a Timestamp from posix timestamp in nanoseconds. + + :param int unix_ns: Posix timestamp in nanoseconds. + :rtype: Timestamp + """ + return Timestamp(*divmod(unix_ns, 10**9)) + + def to_unix_nano(self): + """Get the timestamp as a unixtime in nanoseconds. + + :returns: posix timestamp in nanoseconds + :rtype: int + """ + return self.seconds * 10**9 + self.nanoseconds + + def to_datetime(self): + """Get the timestamp as a UTC datetime. + + :rtype: `datetime.datetime` + """ + utc = datetime.timezone.utc + return datetime.datetime.fromtimestamp(0, utc) + datetime.timedelta( + seconds=self.seconds, microseconds=self.nanoseconds // 1000 + ) + + @staticmethod + def from_datetime(dt): + """Create a Timestamp from datetime with tzinfo. + + :rtype: Timestamp + """ + return Timestamp(seconds=int(dt.timestamp()), nanoseconds=dt.microsecond * 1000) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py new file mode 100644 index 0000000..b02e47c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py @@ -0,0 +1,929 @@ +"""Fallback pure Python implementation of msgpack""" + +import struct +import sys +from datetime import datetime as _DateTime + +if hasattr(sys, "pypy_version_info"): + from __pypy__ import newlist_hint + from __pypy__.builders import BytesBuilder + + _USING_STRINGBUILDER = True + + class BytesIO: + def __init__(self, s=b""): + if s: + self.builder = BytesBuilder(len(s)) + self.builder.append(s) + else: + self.builder = BytesBuilder() + + def write(self, s): + if isinstance(s, memoryview): + s = s.tobytes() + elif isinstance(s, bytearray): + s = bytes(s) + self.builder.append(s) + + def getvalue(self): + return self.builder.build() + +else: + from io import BytesIO + + _USING_STRINGBUILDER = False + + def newlist_hint(size): + return [] + + +from .exceptions import BufferFull, ExtraData, FormatError, OutOfData, StackError +from .ext import ExtType, Timestamp + +EX_SKIP = 0 +EX_CONSTRUCT = 1 +EX_READ_ARRAY_HEADER = 2 +EX_READ_MAP_HEADER = 3 + +TYPE_IMMEDIATE = 0 +TYPE_ARRAY = 1 +TYPE_MAP = 2 +TYPE_RAW = 3 +TYPE_BIN = 4 +TYPE_EXT = 5 + +DEFAULT_RECURSE_LIMIT = 511 + + +def _check_type_strict(obj, t, type=type, tuple=tuple): + if type(t) is tuple: + return type(obj) in t + else: + return type(obj) is t + + +def _get_data_from_buffer(obj): + view = memoryview(obj) + if view.itemsize != 1: + raise ValueError("cannot unpack from multi-byte object") + return view + + +def unpackb(packed, **kwargs): + """ + Unpack an object from `packed`. + + Raises ``ExtraData`` when *packed* contains extra bytes. + Raises ``ValueError`` when *packed* is incomplete. + Raises ``FormatError`` when *packed* is not valid msgpack. + Raises ``StackError`` when *packed* contains too nested. + Other exceptions can be raised during unpacking. + + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(None, max_buffer_size=len(packed), **kwargs) + unpacker.feed(packed) + try: + ret = unpacker._unpack() + except OutOfData: + raise ValueError("Unpack failed: incomplete input") + except RecursionError: + raise StackError + if unpacker._got_extradata(): + raise ExtraData(ret, unpacker._get_extradata()) + return ret + + +_NO_FORMAT_USED = "" +_MSGPACK_HEADERS = { + 0xC4: (1, _NO_FORMAT_USED, TYPE_BIN), + 0xC5: (2, ">H", TYPE_BIN), + 0xC6: (4, ">I", TYPE_BIN), + 0xC7: (2, "Bb", TYPE_EXT), + 0xC8: (3, ">Hb", TYPE_EXT), + 0xC9: (5, ">Ib", TYPE_EXT), + 0xCA: (4, ">f"), + 0xCB: (8, ">d"), + 0xCC: (1, _NO_FORMAT_USED), + 0xCD: (2, ">H"), + 0xCE: (4, ">I"), + 0xCF: (8, ">Q"), + 0xD0: (1, "b"), + 0xD1: (2, ">h"), + 0xD2: (4, ">i"), + 0xD3: (8, ">q"), + 0xD4: (1, "b1s", TYPE_EXT), + 0xD5: (2, "b2s", TYPE_EXT), + 0xD6: (4, "b4s", TYPE_EXT), + 0xD7: (8, "b8s", TYPE_EXT), + 0xD8: (16, "b16s", TYPE_EXT), + 0xD9: (1, _NO_FORMAT_USED, TYPE_RAW), + 0xDA: (2, ">H", TYPE_RAW), + 0xDB: (4, ">I", TYPE_RAW), + 0xDC: (2, ">H", TYPE_ARRAY), + 0xDD: (4, ">I", TYPE_ARRAY), + 0xDE: (2, ">H", TYPE_MAP), + 0xDF: (4, ">I", TYPE_MAP), +} + + +class Unpacker: + """Streaming unpacker. + + Arguments: + + :param file_like: + File-like object having `.read(n)` method. + If specified, unpacker reads serialized data from it and `.feed()` is not usable. + + :param int read_size: + Used as `file_like.read(read_size)`. (default: `min(16*1024, max_buffer_size)`) + + :param bool use_list: + If true, unpack msgpack array to Python list. + Otherwise, unpack to Python tuple. (default: True) + + :param bool raw: + If true, unpack msgpack raw to Python bytes. + Otherwise, unpack to Python str by decoding with UTF-8 encoding (default). + + :param int timestamp: + Control how timestamp type is unpacked: + + 0 - Timestamp + 1 - float (Seconds from the EPOCH) + 2 - int (Nanoseconds from the EPOCH) + 3 - datetime.datetime (UTC). + + :param bool strict_map_key: + If true (default), only str or bytes are accepted for map (dict) keys. + + :param object_hook: + When specified, it should be callable. + Unpacker calls it with a dict argument after unpacking msgpack map. + (See also simplejson) + + :param object_pairs_hook: + When specified, it should be callable. + Unpacker calls it with a list of key-value pairs after unpacking msgpack map. + (See also simplejson) + + :param str unicode_errors: + The error handler for decoding unicode. (default: 'strict') + This option should be used only when you have msgpack data which + contains invalid UTF-8 string. + + :param int max_buffer_size: + Limits size of data waiting unpacked. 0 means 2**32-1. + The default value is 100*1024*1024 (100MiB). + Raises `BufferFull` exception when it is insufficient. + You should set this parameter when unpacking data from untrusted source. + + :param int max_str_len: + Deprecated, use *max_buffer_size* instead. + Limits max length of str. (default: max_buffer_size) + + :param int max_bin_len: + Deprecated, use *max_buffer_size* instead. + Limits max length of bin. (default: max_buffer_size) + + :param int max_array_len: + Limits max length of array. + (default: max_buffer_size) + + :param int max_map_len: + Limits max length of map. + (default: max_buffer_size//2) + + :param int max_ext_len: + Deprecated, use *max_buffer_size* instead. + Limits max size of ext type. (default: max_buffer_size) + + Example of streaming deserialize from file-like object:: + + unpacker = Unpacker(file_like) + for o in unpacker: + process(o) + + Example of streaming deserialize from socket:: + + unpacker = Unpacker() + while True: + buf = sock.recv(1024**2) + if not buf: + break + unpacker.feed(buf) + for o in unpacker: + process(o) + + Raises ``ExtraData`` when *packed* contains extra bytes. + Raises ``OutOfData`` when *packed* is incomplete. + Raises ``FormatError`` when *packed* is not valid msgpack. + Raises ``StackError`` when *packed* contains too nested. + Other exceptions can be raised during unpacking. + """ + + def __init__( + self, + file_like=None, + *, + read_size=0, + use_list=True, + raw=False, + timestamp=0, + strict_map_key=True, + object_hook=None, + object_pairs_hook=None, + list_hook=None, + unicode_errors=None, + max_buffer_size=100 * 1024 * 1024, + ext_hook=ExtType, + max_str_len=-1, + max_bin_len=-1, + max_array_len=-1, + max_map_len=-1, + max_ext_len=-1, + ): + if unicode_errors is None: + unicode_errors = "strict" + + if file_like is None: + self._feeding = True + else: + if not callable(file_like.read): + raise TypeError("`file_like.read` must be callable") + self.file_like = file_like + self._feeding = False + + #: array of bytes fed. + self._buffer = bytearray() + #: Which position we currently reads + self._buff_i = 0 + + # When Unpacker is used as an iterable, between the calls to next(), + # the buffer is not "consumed" completely, for efficiency sake. + # Instead, it is done sloppily. To make sure we raise BufferFull at + # the correct moments, we have to keep track of how sloppy we were. + # Furthermore, when the buffer is incomplete (that is: in the case + # we raise an OutOfData) we need to rollback the buffer to the correct + # state, which _buf_checkpoint records. + self._buf_checkpoint = 0 + + if not max_buffer_size: + max_buffer_size = 2**31 - 1 + if max_str_len == -1: + max_str_len = max_buffer_size + if max_bin_len == -1: + max_bin_len = max_buffer_size + if max_array_len == -1: + max_array_len = max_buffer_size + if max_map_len == -1: + max_map_len = max_buffer_size // 2 + if max_ext_len == -1: + max_ext_len = max_buffer_size + + self._max_buffer_size = max_buffer_size + if read_size > self._max_buffer_size: + raise ValueError("read_size must be smaller than max_buffer_size") + self._read_size = read_size or min(self._max_buffer_size, 16 * 1024) + self._raw = bool(raw) + self._strict_map_key = bool(strict_map_key) + self._unicode_errors = unicode_errors + self._use_list = use_list + if not (0 <= timestamp <= 3): + raise ValueError("timestamp must be 0..3") + self._timestamp = timestamp + self._list_hook = list_hook + self._object_hook = object_hook + self._object_pairs_hook = object_pairs_hook + self._ext_hook = ext_hook + self._max_str_len = max_str_len + self._max_bin_len = max_bin_len + self._max_array_len = max_array_len + self._max_map_len = max_map_len + self._max_ext_len = max_ext_len + self._stream_offset = 0 + + if list_hook is not None and not callable(list_hook): + raise TypeError("`list_hook` is not callable") + if object_hook is not None and not callable(object_hook): + raise TypeError("`object_hook` is not callable") + if object_pairs_hook is not None and not callable(object_pairs_hook): + raise TypeError("`object_pairs_hook` is not callable") + if object_hook is not None and object_pairs_hook is not None: + raise TypeError("object_pairs_hook and object_hook are mutually exclusive") + if not callable(ext_hook): + raise TypeError("`ext_hook` is not callable") + + def feed(self, next_bytes): + assert self._feeding + view = _get_data_from_buffer(next_bytes) + if len(self._buffer) - self._buff_i + len(view) > self._max_buffer_size: + raise BufferFull + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[: self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + # Use extend here: INPLACE_ADD += doesn't reliably typecast memoryview in jython + self._buffer.extend(view) + view.release() + + def _consume(self): + """Gets rid of the used parts of the buffer.""" + self._stream_offset += self._buff_i - self._buf_checkpoint + self._buf_checkpoint = self._buff_i + + def _got_extradata(self): + return self._buff_i < len(self._buffer) + + def _get_extradata(self): + return self._buffer[self._buff_i :] + + def read_bytes(self, n): + ret = self._read(n, raise_outofdata=False) + self._consume() + return ret + + def _read(self, n, raise_outofdata=True): + # (int) -> bytearray + self._reserve(n, raise_outofdata=raise_outofdata) + i = self._buff_i + ret = self._buffer[i : i + n] + self._buff_i = i + len(ret) + return ret + + def _reserve(self, n, raise_outofdata=True): + remain_bytes = len(self._buffer) - self._buff_i - n + + # Fast path: buffer has n bytes already + if remain_bytes >= 0: + return + + if self._feeding: + self._buff_i = self._buf_checkpoint + raise OutOfData + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[: self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + # Read from file + remain_bytes = -remain_bytes + if remain_bytes + len(self._buffer) > self._max_buffer_size: + raise BufferFull + while remain_bytes > 0: + to_read_bytes = max(self._read_size, remain_bytes) + read_data = self.file_like.read(to_read_bytes) + if not read_data: + break + assert isinstance(read_data, bytes) + self._buffer += read_data + remain_bytes -= len(read_data) + + if len(self._buffer) < n + self._buff_i and raise_outofdata: + self._buff_i = 0 # rollback + raise OutOfData + + def _read_header(self): + typ = TYPE_IMMEDIATE + n = 0 + obj = None + self._reserve(1) + b = self._buffer[self._buff_i] + self._buff_i += 1 + if b & 0b10000000 == 0: + obj = b + elif b & 0b11100000 == 0b11100000: + obj = -1 - (b ^ 0xFF) + elif b & 0b11100000 == 0b10100000: + n = b & 0b00011111 + typ = TYPE_RAW + if n > self._max_str_len: + raise ValueError(f"{n} exceeds max_str_len({self._max_str_len})") + obj = self._read(n) + elif b & 0b11110000 == 0b10010000: + n = b & 0b00001111 + typ = TYPE_ARRAY + if n > self._max_array_len: + raise ValueError(f"{n} exceeds max_array_len({self._max_array_len})") + elif b & 0b11110000 == 0b10000000: + n = b & 0b00001111 + typ = TYPE_MAP + if n > self._max_map_len: + raise ValueError(f"{n} exceeds max_map_len({self._max_map_len})") + elif b == 0xC0: + obj = None + elif b == 0xC2: + obj = False + elif b == 0xC3: + obj = True + elif 0xC4 <= b <= 0xC6: + size, fmt, typ = _MSGPACK_HEADERS[b] + self._reserve(size) + if len(fmt) > 0: + n = struct.unpack_from(fmt, self._buffer, self._buff_i)[0] + else: + n = self._buffer[self._buff_i] + self._buff_i += size + if n > self._max_bin_len: + raise ValueError(f"{n} exceeds max_bin_len({self._max_bin_len})") + obj = self._read(n) + elif 0xC7 <= b <= 0xC9: + size, fmt, typ = _MSGPACK_HEADERS[b] + self._reserve(size) + L, n = struct.unpack_from(fmt, self._buffer, self._buff_i) + self._buff_i += size + if L > self._max_ext_len: + raise ValueError(f"{L} exceeds max_ext_len({self._max_ext_len})") + obj = self._read(L) + elif 0xCA <= b <= 0xD3: + size, fmt = _MSGPACK_HEADERS[b] + self._reserve(size) + if len(fmt) > 0: + obj = struct.unpack_from(fmt, self._buffer, self._buff_i)[0] + else: + obj = self._buffer[self._buff_i] + self._buff_i += size + elif 0xD4 <= b <= 0xD8: + size, fmt, typ = _MSGPACK_HEADERS[b] + if self._max_ext_len < size: + raise ValueError(f"{size} exceeds max_ext_len({self._max_ext_len})") + self._reserve(size + 1) + n, obj = struct.unpack_from(fmt, self._buffer, self._buff_i) + self._buff_i += size + 1 + elif 0xD9 <= b <= 0xDB: + size, fmt, typ = _MSGPACK_HEADERS[b] + self._reserve(size) + if len(fmt) > 0: + (n,) = struct.unpack_from(fmt, self._buffer, self._buff_i) + else: + n = self._buffer[self._buff_i] + self._buff_i += size + if n > self._max_str_len: + raise ValueError(f"{n} exceeds max_str_len({self._max_str_len})") + obj = self._read(n) + elif 0xDC <= b <= 0xDD: + size, fmt, typ = _MSGPACK_HEADERS[b] + self._reserve(size) + (n,) = struct.unpack_from(fmt, self._buffer, self._buff_i) + self._buff_i += size + if n > self._max_array_len: + raise ValueError(f"{n} exceeds max_array_len({self._max_array_len})") + elif 0xDE <= b <= 0xDF: + size, fmt, typ = _MSGPACK_HEADERS[b] + self._reserve(size) + (n,) = struct.unpack_from(fmt, self._buffer, self._buff_i) + self._buff_i += size + if n > self._max_map_len: + raise ValueError(f"{n} exceeds max_map_len({self._max_map_len})") + else: + raise FormatError("Unknown header: 0x%x" % b) + return typ, n, obj + + def _unpack(self, execute=EX_CONSTRUCT): + typ, n, obj = self._read_header() + + if execute == EX_READ_ARRAY_HEADER: + if typ != TYPE_ARRAY: + raise ValueError("Expected array") + return n + if execute == EX_READ_MAP_HEADER: + if typ != TYPE_MAP: + raise ValueError("Expected map") + return n + # TODO should we eliminate the recursion? + if typ == TYPE_ARRAY: + if execute == EX_SKIP: + for i in range(n): + # TODO check whether we need to call `list_hook` + self._unpack(EX_SKIP) + return + ret = newlist_hint(n) + for i in range(n): + ret.append(self._unpack(EX_CONSTRUCT)) + if self._list_hook is not None: + ret = self._list_hook(ret) + # TODO is the interaction between `list_hook` and `use_list` ok? + return ret if self._use_list else tuple(ret) + if typ == TYPE_MAP: + if execute == EX_SKIP: + for i in range(n): + # TODO check whether we need to call hooks + self._unpack(EX_SKIP) + self._unpack(EX_SKIP) + return + if self._object_pairs_hook is not None: + ret = self._object_pairs_hook( + (self._unpack(EX_CONSTRUCT), self._unpack(EX_CONSTRUCT)) for _ in range(n) + ) + else: + ret = {} + for _ in range(n): + key = self._unpack(EX_CONSTRUCT) + if self._strict_map_key and type(key) not in (str, bytes): + raise ValueError("%s is not allowed for map key" % str(type(key))) + if isinstance(key, str): + key = sys.intern(key) + ret[key] = self._unpack(EX_CONSTRUCT) + if self._object_hook is not None: + ret = self._object_hook(ret) + return ret + if execute == EX_SKIP: + return + if typ == TYPE_RAW: + if self._raw: + obj = bytes(obj) + else: + obj = obj.decode("utf_8", self._unicode_errors) + return obj + if typ == TYPE_BIN: + return bytes(obj) + if typ == TYPE_EXT: + if n == -1: # timestamp + ts = Timestamp.from_bytes(bytes(obj)) + if self._timestamp == 1: + return ts.to_unix() + elif self._timestamp == 2: + return ts.to_unix_nano() + elif self._timestamp == 3: + return ts.to_datetime() + else: + return ts + else: + return self._ext_hook(n, bytes(obj)) + assert typ == TYPE_IMMEDIATE + return obj + + def __iter__(self): + return self + + def __next__(self): + try: + ret = self._unpack(EX_CONSTRUCT) + self._consume() + return ret + except OutOfData: + self._consume() + raise StopIteration + except RecursionError: + raise StackError + + next = __next__ + + def skip(self): + self._unpack(EX_SKIP) + self._consume() + + def unpack(self): + try: + ret = self._unpack(EX_CONSTRUCT) + except RecursionError: + raise StackError + self._consume() + return ret + + def read_array_header(self): + ret = self._unpack(EX_READ_ARRAY_HEADER) + self._consume() + return ret + + def read_map_header(self): + ret = self._unpack(EX_READ_MAP_HEADER) + self._consume() + return ret + + def tell(self): + return self._stream_offset + + +class Packer: + """ + MessagePack Packer + + Usage:: + + packer = Packer() + astream.write(packer.pack(a)) + astream.write(packer.pack(b)) + + Packer's constructor has some keyword arguments: + + :param default: + When specified, it should be callable. + Convert user type to builtin type that Packer supports. + See also simplejson's document. + + :param bool use_single_float: + Use single precision float type for float. (default: False) + + :param bool autoreset: + Reset buffer after each pack and return its content as `bytes`. (default: True). + If set this to false, use `bytes()` to get content and `.reset()` to clear buffer. + + :param bool use_bin_type: + Use bin type introduced in msgpack spec 2.0 for bytes. + It also enables str8 type for unicode. (default: True) + + :param bool strict_types: + If set to true, types will be checked to be exact. Derived classes + from serializable types will not be serialized and will be + treated as unsupported type and forwarded to default. + Additionally tuples will not be serialized as lists. + This is useful when trying to implement accurate serialization + for python types. + + :param bool datetime: + If set to true, datetime with tzinfo is packed into Timestamp type. + Note that the tzinfo is stripped in the timestamp. + You can get UTC datetime with `timestamp=3` option of the Unpacker. + + :param str unicode_errors: + The error handler for encoding unicode. (default: 'strict') + DO NOT USE THIS!! This option is kept for very specific usage. + + :param int buf_size: + Internal buffer size. This option is used only for C implementation. + """ + + def __init__( + self, + *, + default=None, + use_single_float=False, + autoreset=True, + use_bin_type=True, + strict_types=False, + datetime=False, + unicode_errors=None, + buf_size=None, + ): + self._strict_types = strict_types + self._use_float = use_single_float + self._autoreset = autoreset + self._use_bin_type = use_bin_type + self._buffer = BytesIO() + self._datetime = bool(datetime) + self._unicode_errors = unicode_errors or "strict" + if default is not None and not callable(default): + raise TypeError("default must be callable") + self._default = default + + def _pack( + self, + obj, + nest_limit=DEFAULT_RECURSE_LIMIT, + check=isinstance, + check_type_strict=_check_type_strict, + ): + default_used = False + if self._strict_types: + check = check_type_strict + list_types = list + else: + list_types = (list, tuple) + while True: + if nest_limit < 0: + raise ValueError("recursion limit exceeded") + if obj is None: + return self._buffer.write(b"\xc0") + if check(obj, bool): + if obj: + return self._buffer.write(b"\xc3") + return self._buffer.write(b"\xc2") + if check(obj, int): + if 0 <= obj < 0x80: + return self._buffer.write(struct.pack("B", obj)) + if -0x20 <= obj < 0: + return self._buffer.write(struct.pack("b", obj)) + if 0x80 <= obj <= 0xFF: + return self._buffer.write(struct.pack("BB", 0xCC, obj)) + if -0x80 <= obj < 0: + return self._buffer.write(struct.pack(">Bb", 0xD0, obj)) + if 0xFF < obj <= 0xFFFF: + return self._buffer.write(struct.pack(">BH", 0xCD, obj)) + if -0x8000 <= obj < -0x80: + return self._buffer.write(struct.pack(">Bh", 0xD1, obj)) + if 0xFFFF < obj <= 0xFFFFFFFF: + return self._buffer.write(struct.pack(">BI", 0xCE, obj)) + if -0x80000000 <= obj < -0x8000: + return self._buffer.write(struct.pack(">Bi", 0xD2, obj)) + if 0xFFFFFFFF < obj <= 0xFFFFFFFFFFFFFFFF: + return self._buffer.write(struct.pack(">BQ", 0xCF, obj)) + if -0x8000000000000000 <= obj < -0x80000000: + return self._buffer.write(struct.pack(">Bq", 0xD3, obj)) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = True + continue + raise OverflowError("Integer value out of range") + if check(obj, (bytes, bytearray)): + n = len(obj) + if n >= 2**32: + raise ValueError("%s is too large" % type(obj).__name__) + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, str): + obj = obj.encode("utf-8", self._unicode_errors) + n = len(obj) + if n >= 2**32: + raise ValueError("String is too large") + self._pack_raw_header(n) + return self._buffer.write(obj) + if check(obj, memoryview): + n = obj.nbytes + if n >= 2**32: + raise ValueError("Memoryview is too large") + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, float): + if self._use_float: + return self._buffer.write(struct.pack(">Bf", 0xCA, obj)) + return self._buffer.write(struct.pack(">Bd", 0xCB, obj)) + if check(obj, (ExtType, Timestamp)): + if check(obj, Timestamp): + code = -1 + data = obj.to_bytes() + else: + code = obj.code + data = obj.data + assert isinstance(code, int) + assert isinstance(data, bytes) + L = len(data) + if L == 1: + self._buffer.write(b"\xd4") + elif L == 2: + self._buffer.write(b"\xd5") + elif L == 4: + self._buffer.write(b"\xd6") + elif L == 8: + self._buffer.write(b"\xd7") + elif L == 16: + self._buffer.write(b"\xd8") + elif L <= 0xFF: + self._buffer.write(struct.pack(">BB", 0xC7, L)) + elif L <= 0xFFFF: + self._buffer.write(struct.pack(">BH", 0xC8, L)) + else: + self._buffer.write(struct.pack(">BI", 0xC9, L)) + self._buffer.write(struct.pack("b", code)) + self._buffer.write(data) + return + if check(obj, list_types): + n = len(obj) + self._pack_array_header(n) + for i in range(n): + self._pack(obj[i], nest_limit - 1) + return + if check(obj, dict): + return self._pack_map_pairs(len(obj), obj.items(), nest_limit - 1) + + if self._datetime and check(obj, _DateTime) and obj.tzinfo is not None: + obj = Timestamp.from_datetime(obj) + default_used = 1 + continue + + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = 1 + continue + + if self._datetime and check(obj, _DateTime): + raise ValueError(f"Cannot serialize {obj!r} where tzinfo=None") + + raise TypeError(f"Cannot serialize {obj!r}") + + def pack(self, obj): + try: + self._pack(obj) + except: + self._buffer = BytesIO() # force reset + raise + if self._autoreset: + ret = self._buffer.getvalue() + self._buffer = BytesIO() + return ret + + def pack_map_pairs(self, pairs): + self._pack_map_pairs(len(pairs), pairs) + if self._autoreset: + ret = self._buffer.getvalue() + self._buffer = BytesIO() + return ret + + def pack_array_header(self, n): + if n >= 2**32: + raise ValueError + self._pack_array_header(n) + if self._autoreset: + ret = self._buffer.getvalue() + self._buffer = BytesIO() + return ret + + def pack_map_header(self, n): + if n >= 2**32: + raise ValueError + self._pack_map_header(n) + if self._autoreset: + ret = self._buffer.getvalue() + self._buffer = BytesIO() + return ret + + def pack_ext_type(self, typecode, data): + if not isinstance(typecode, int): + raise TypeError("typecode must have int type.") + if not 0 <= typecode <= 127: + raise ValueError("typecode should be 0-127") + if not isinstance(data, bytes): + raise TypeError("data must have bytes type") + L = len(data) + if L > 0xFFFFFFFF: + raise ValueError("Too large data") + if L == 1: + self._buffer.write(b"\xd4") + elif L == 2: + self._buffer.write(b"\xd5") + elif L == 4: + self._buffer.write(b"\xd6") + elif L == 8: + self._buffer.write(b"\xd7") + elif L == 16: + self._buffer.write(b"\xd8") + elif L <= 0xFF: + self._buffer.write(b"\xc7" + struct.pack("B", L)) + elif L <= 0xFFFF: + self._buffer.write(b"\xc8" + struct.pack(">H", L)) + else: + self._buffer.write(b"\xc9" + struct.pack(">I", L)) + self._buffer.write(struct.pack("B", typecode)) + self._buffer.write(data) + + def _pack_array_header(self, n): + if n <= 0x0F: + return self._buffer.write(struct.pack("B", 0x90 + n)) + if n <= 0xFFFF: + return self._buffer.write(struct.pack(">BH", 0xDC, n)) + if n <= 0xFFFFFFFF: + return self._buffer.write(struct.pack(">BI", 0xDD, n)) + raise ValueError("Array is too large") + + def _pack_map_header(self, n): + if n <= 0x0F: + return self._buffer.write(struct.pack("B", 0x80 + n)) + if n <= 0xFFFF: + return self._buffer.write(struct.pack(">BH", 0xDE, n)) + if n <= 0xFFFFFFFF: + return self._buffer.write(struct.pack(">BI", 0xDF, n)) + raise ValueError("Dict is too large") + + def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT): + self._pack_map_header(n) + for k, v in pairs: + self._pack(k, nest_limit - 1) + self._pack(v, nest_limit - 1) + + def _pack_raw_header(self, n): + if n <= 0x1F: + self._buffer.write(struct.pack("B", 0xA0 + n)) + elif self._use_bin_type and n <= 0xFF: + self._buffer.write(struct.pack(">BB", 0xD9, n)) + elif n <= 0xFFFF: + self._buffer.write(struct.pack(">BH", 0xDA, n)) + elif n <= 0xFFFFFFFF: + self._buffer.write(struct.pack(">BI", 0xDB, n)) + else: + raise ValueError("Raw is too large") + + def _pack_bin_header(self, n): + if not self._use_bin_type: + return self._pack_raw_header(n) + elif n <= 0xFF: + return self._buffer.write(struct.pack(">BB", 0xC4, n)) + elif n <= 0xFFFF: + return self._buffer.write(struct.pack(">BH", 0xC5, n)) + elif n <= 0xFFFFFFFF: + return self._buffer.write(struct.pack(">BI", 0xC6, n)) + else: + raise ValueError("Bin is too large") + + def bytes(self): + """Return internal buffer contents as bytes object""" + return self._buffer.getvalue() + + def reset(self): + """Reset internal buffer. + + This method is useful only when autoreset=False. + """ + self._buffer = BytesIO() + + def getbuffer(self): + """Return view of internal buffer.""" + if _USING_STRINGBUILDER: + return memoryview(self.bytes()) + else: + return self._buffer.getbuffer() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__init__.py new file mode 100644 index 0000000..d79f73c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__init__.py @@ -0,0 +1,15 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "24.2" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD-2-Clause or Apache-2.0" +__copyright__ = f"2014 {__author__}" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d3b4d0354d747d988d7b18658d48eba7152e0b9 GIT binary patch literal 563 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 nQmX{eRS&+OxiL5~Sbi6nnsEc${VD-# literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..618db72cf9c154697a4509d7edae46c31d58bd43 GIT binary patch literal 9716 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b2933434eb1c20f6ef565ac8c3568aef45d130d GIT binary patch literal 4559 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74ea5b72605d5c807db5f70d22a50bd6ff448d2d GIT binary patch literal 3246 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 amiIaG|7r1pgR45h$LTQr$mr~In*J|6Ld2i| literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6ec11852a93d5511be88285eb058abbfa3be22e GIT binary patch literal 4415 zcmaJETWl29_1>AC@xHv?UE4T78jrCZv#qg1aTD-$OOF$w64rxkKhBTkcSm?W!Y^eIi& zCTya}mz7LTvp_FAG^VBW5gk-DHcm=0OhZq(!iJL7Qtm=sNS6Q&Z$<$wAPpt4ijtg) zll&x?;GOt@0YmHR+4AD1-V936jv12f@}!EDOXG?qjhHz@?UZt`eoL}0n7ND!G9wz1 zY*RXO;*9j_D+jySAcF~?!{erzGP7BYq%;{;1tv7fl^Q+kk|(pl+y%HNo+{c0jDwH}f1Y|@9{g|t1(03z zM}%hZ{UUyao8i)aCcg#DAlc^;K!Rln@7wJsu*E?XBakd+3WV%hPX=`8*=}pD&M5L` z2VHvRtl2RS1KqfXm-`BxfJbGsm(~V))N8i2U-sKg9x45Thn0JKhlf|pP#V+T?QyG* zUe>8Lw_LKpB$`C6$S$2v8zQ@|@OIg9B|FUU-k4rL!@tX^=nDS}ejJaZ3I1nj9N)u( zi8?1PgS&0bZiF5t3n_;O*KmB)106m`GVrb0j_CRvfozYQK*=#3G0U&C&A@7N`|{M%)T8G8cYgxk{xzxf z&dCo?zkm8s+iMTb7Nmnf46St>cyRJb&+(O>aSsGT|nXXub;(Gv}FTfSX8|2 zgQ2^z-<>POJ0G;2fyv$cc!?bl7powu2)LbkYJ)e2A_uNZuQRg zt~T#ko>-drNW5!*GJS8lu(!9+d^jI|akZf_zvJb6W5=CK`FP?{I6>w6X8YFSjdSXP zF>e&&?T^CklzMRX;A+E;IeTGZeqt^?*ZnBmvRYSvYkGEib;r(M2fT@x$n^a5Ts9wX zD}>wDc@%E?uSE~~-8VYl=)$Se^#CO5uk7+T2M82@I9lN1CPS9%m5533r=^wef>fk;4_!?d_Q2 zI}&}Q9z;nGfXW3zkwvsIy25Q4&ZVBD;`DZdCB~ZX_!ckU8Oqls^8Up0Yoghkt?4Ep z3zb(kN|!DVU=>?6OOL`n(xvOflZ4B;GQO)ssCP16|6BaA=;1?%?1YgLqT{=uSQngt zET=MxWx>X2<>nqAjZJoj)eJ<{o;Q$79RNkE55QHlR#*Qt+OQCrk35NXtVBE3dA>IC zG}ibe*0K_7dA#SqgX4c1_`^V9PhTPS`d0!lH+dl%Tt`A6=vuSVO4JXTHHX2SwpbIF zuVU|UVTm@CXKe`CB@2Qzs}x9{Wh&(Gx5-`Hi_ion5JoUw73ZdkTrq%=aWMkg|8+5_3K z410M&wk`VzO~r2VE$3a1#l9n$_62y|(3A9v2vL@`OW;58ikO5Fg3^8rV%ALn)O&U= zwtukuaoxVPdbp)qo{6aTrA2jFU(yTVy^lMOe5!q({w!VS99RhtY#?84=PEc`Xg;)< zTb@~(S&4pcg9l>K1Mjqd*!_O@N_78*0K|0>#Tpm<^ZvyX%L7XTE7A6i8cOz4a^(=~ zA+hL-@Bkz2ber^gaYUloIbt}zLDSHHLvI)N;yDJ`RIT@NeH)V9I|+_ZD&rS%hlfW7 z=)F$q)Ki&+<2!GfnMBZyLwZ1jrW!&kXaZ+bjLlam_8JAf6da|10nPvU=1lLxZJa)pDy> zA!q9ui@B5&JV)Q?>?!X)DyjEv+o9t>?7o2e$Z6ox8^)rk97;Ki|LsS(^`A)k2Ri%( hO8gD=e1Y2F_e|ume{t6{1l@naCov9gAPQNo`9B|OtGECF literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8f1dd09575352c6b801ea55552cd96fb1e26d7c8 GIT binary patch literal 39047 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 aI?Epa8VBVne`=kFa^p7B!t9{o>Hh;kt{eCO literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82d70dc0a74d0283041af370c0c7c251b48b2ded GIT binary patch literal 20491 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 None: + self._f = f + + try: + ident = self._read("16B") + except struct.error as e: + raise ELFInvalid("unable to parse identification") from e + magic = bytes(ident[:4]) + if magic != b"\x7fELF": + raise ELFInvalid(f"invalid magic: {magic!r}") + + self.capacity = ident[4] # Format for program header (bitness). + self.encoding = ident[5] # Data structure encoding (endianness). + + try: + # e_fmt: Format for program header. + # p_fmt: Format for section header. + # p_idx: Indexes to find p_type, p_offset, and p_filesz. + e_fmt, self._p_fmt, self._p_idx = { + (1, 1): ("HHIIIIIHHH", ">IIIIIIII", (0, 1, 4)), # 32-bit MSB. + (2, 1): ("HHIQQQIHHH", ">IIQQQQQQ", (0, 2, 5)), # 64-bit MSB. + }[(self.capacity, self.encoding)] + except KeyError as e: + raise ELFInvalid( + f"unrecognized capacity ({self.capacity}) or " + f"encoding ({self.encoding})" + ) from e + + try: + ( + _, + self.machine, # Architecture type. + _, + _, + self._e_phoff, # Offset of program header. + _, + self.flags, # Processor-specific flags. + _, + self._e_phentsize, # Size of section. + self._e_phnum, # Number of sections. + ) = self._read(e_fmt) + except struct.error as e: + raise ELFInvalid("unable to parse machine and section information") from e + + def _read(self, fmt: str) -> tuple[int, ...]: + return struct.unpack(fmt, self._f.read(struct.calcsize(fmt))) + + @property + def interpreter(self) -> str | None: + """ + The path recorded in the ``PT_INTERP`` section header. + """ + for index in range(self._e_phnum): + self._f.seek(self._e_phoff + self._e_phentsize * index) + try: + data = self._read(self._p_fmt) + except struct.error: + continue + if data[self._p_idx[0]] != 3: # Not PT_INTERP. + continue + self._f.seek(data[self._p_idx[1]]) + return os.fsdecode(self._f.read(data[self._p_idx[2]])).strip("\0") + return None diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py new file mode 100644 index 0000000..61339a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py @@ -0,0 +1,263 @@ +from __future__ import annotations + +import collections +import contextlib +import functools +import os +import re +import sys +import warnings +from typing import Generator, Iterator, NamedTuple, Sequence + +from ._elffile import EIClass, EIData, ELFFile, EMachine + +EF_ARM_ABIMASK = 0xFF000000 +EF_ARM_ABI_VER5 = 0x05000000 +EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + +# `os.PathLike` not a generic type until Python 3.9, so sticking with `str` +# as the type for `path` until then. +@contextlib.contextmanager +def _parse_elf(path: str) -> Generator[ELFFile | None, None, None]: + try: + with open(path, "rb") as f: + yield ELFFile(f) + except (OSError, TypeError, ValueError): + yield None + + +def _is_linux_armhf(executable: str) -> bool: + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + with _parse_elf(executable) as f: + return ( + f is not None + and f.capacity == EIClass.C32 + and f.encoding == EIData.Lsb + and f.machine == EMachine.Arm + and f.flags & EF_ARM_ABIMASK == EF_ARM_ABI_VER5 + and f.flags & EF_ARM_ABI_FLOAT_HARD == EF_ARM_ABI_FLOAT_HARD + ) + + +def _is_linux_i686(executable: str) -> bool: + with _parse_elf(executable) as f: + return ( + f is not None + and f.capacity == EIClass.C32 + and f.encoding == EIData.Lsb + and f.machine == EMachine.I386 + ) + + +def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool: + if "armv7l" in archs: + return _is_linux_armhf(executable) + if "i686" in archs: + return _is_linux_i686(executable) + allowed_archs = { + "x86_64", + "aarch64", + "ppc64", + "ppc64le", + "s390x", + "loongarch64", + "riscv64", + } + return any(arch in allowed_archs for arch in archs) + + +# If glibc ever changes its major version, we need to know what the last +# minor version was, so we can build the complete list of all versions. +# For now, guess what the highest minor version might be, assume it will +# be 50 for testing. Once this actually happens, update the dictionary +# with the actual value. +_LAST_GLIBC_MINOR: dict[int, int] = collections.defaultdict(lambda: 50) + + +class _GLibCVersion(NamedTuple): + major: int + minor: int + + +def _glibc_version_string_confstr() -> str | None: + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 + try: + # Should be a string like "glibc 2.17". + version_string: str | None = os.confstr("CS_GNU_LIBC_VERSION") + assert version_string is not None + _, version = version_string.rsplit() + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes() -> str | None: + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +def _glibc_version_string() -> str | None: + """Returns glibc version string, or None if not using glibc.""" + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _parse_glibc_version(version_str: str) -> tuple[int, int]: + """Parse glibc version. + + We use a regexp instead of str.split because we want to discard any + random junk that might come after the minor version -- this might happen + in patched/forked versions of glibc (e.g. Linaro's version of glibc + uses version strings like "2.20-2014.11"). See gh-3588. + """ + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + f"Expected glibc version with 2 components major.minor," + f" got: {version_str}", + RuntimeWarning, + stacklevel=2, + ) + return -1, -1 + return int(m.group("major")), int(m.group("minor")) + + +@functools.lru_cache +def _get_glibc_version() -> tuple[int, int]: + version_str = _glibc_version_string() + if version_str is None: + return (-1, -1) + return _parse_glibc_version(version_str) + + +# From PEP 513, PEP 600 +def _is_compatible(arch: str, version: _GLibCVersion) -> bool: + sys_glibc = _get_glibc_version() + if sys_glibc < version: + return False + # Check for presence of _manylinux module. + try: + import _manylinux + except ImportError: + return True + if hasattr(_manylinux, "manylinux_compatible"): + result = _manylinux.manylinux_compatible(version[0], version[1], arch) + if result is not None: + return bool(result) + return True + if version == _GLibCVersion(2, 5): + if hasattr(_manylinux, "manylinux1_compatible"): + return bool(_manylinux.manylinux1_compatible) + if version == _GLibCVersion(2, 12): + if hasattr(_manylinux, "manylinux2010_compatible"): + return bool(_manylinux.manylinux2010_compatible) + if version == _GLibCVersion(2, 17): + if hasattr(_manylinux, "manylinux2014_compatible"): + return bool(_manylinux.manylinux2014_compatible) + return True + + +_LEGACY_MANYLINUX_MAP = { + # CentOS 7 w/ glibc 2.17 (PEP 599) + (2, 17): "manylinux2014", + # CentOS 6 w/ glibc 2.12 (PEP 571) + (2, 12): "manylinux2010", + # CentOS 5 w/ glibc 2.5 (PEP 513) + (2, 5): "manylinux1", +} + + +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate manylinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be manylinux-compatible. + + :returns: An iterator of compatible manylinux tags. + """ + if not _have_compatible_abi(sys.executable, archs): + return + # Oldest glibc to be supported regardless of architecture is (2, 17). + too_old_glibc2 = _GLibCVersion(2, 16) + if set(archs) & {"x86_64", "i686"}: + # On x86/i686 also oldest glibc to be supported is (2, 5). + too_old_glibc2 = _GLibCVersion(2, 4) + current_glibc = _GLibCVersion(*_get_glibc_version()) + glibc_max_list = [current_glibc] + # We can assume compatibility across glibc major versions. + # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 + # + # Build a list of maximum glibc versions so that we can + # output the canonical list of all glibc from current_glibc + # down to too_old_glibc2, including all intermediary versions. + for glibc_major in range(current_glibc.major - 1, 1, -1): + glibc_minor = _LAST_GLIBC_MINOR[glibc_major] + glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) + for arch in archs: + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(arch, glibc_version): + yield f"{tag}_{arch}" + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(arch, glibc_version): + yield f"{legacy_tag}_{arch}" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py new file mode 100644 index 0000000..d2bf30b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py @@ -0,0 +1,85 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +from __future__ import annotations + +import functools +import re +import subprocess +import sys +from typing import Iterator, NamedTuple, Sequence + +from ._elffile import ELFFile + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> _MuslVersion | None: + lines = [n for n in (n.strip() for n in output.splitlines()) if n] + if len(lines) < 2 or lines[0][:4] != "musl": + return None + m = re.match(r"Version (\d+)\.(\d+)", lines[1]) + if not m: + return None + return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) + + +@functools.lru_cache +def _get_musl_version(executable: str) -> _MuslVersion | None: + """Detect currently-running musl runtime version. + + This is done by checking the specified executable's dynamic linking + information, and invoking the loader to parse its output for a version + string. If the loader is musl, the output would be something like:: + + musl libc (x86_64) + Version 1.2.2 + Dynamic Program Loader + """ + try: + with open(executable, "rb") as f: + ld = ELFFile(f).interpreter + except (OSError, TypeError, ValueError): + return None + if ld is None or "musl" not in ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be musllinux-compatible. + + :returns: An iterator of compatible musllinux tags. + """ + sys_musl = _get_musl_version(sys.executable) + if sys_musl is None: # Python not dynamically linked against musl. + return + for arch in archs: + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + + +if __name__ == "__main__": # pragma: no cover + import sysconfig + + plat = sysconfig.get_platform() + assert plat.startswith("linux-"), "not linux" + + print("plat:", plat) + print("musl:", _get_musl_version(sys.executable)) + print("tags:", end=" ") + for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): + print(t, end="\n ") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/_parser.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_parser.py new file mode 100644 index 0000000..c1238c0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_parser.py @@ -0,0 +1,354 @@ +"""Handwritten parser of dependency specifiers. + +The docstring for each __parse_* function contains EBNF-inspired grammar representing +the implementation. +""" + +from __future__ import annotations + +import ast +from typing import NamedTuple, Sequence, Tuple, Union + +from ._tokenizer import DEFAULT_RULES, Tokenizer + + +class Node: + def __init__(self, value: str) -> None: + self.value = value + + def __str__(self) -> str: + return self.value + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}('{self}')>" + + def serialize(self) -> str: + raise NotImplementedError + + +class Variable(Node): + def serialize(self) -> str: + return str(self) + + +class Value(Node): + def serialize(self) -> str: + return f'"{self}"' + + +class Op(Node): + def serialize(self) -> str: + return str(self) + + +MarkerVar = Union[Variable, Value] +MarkerItem = Tuple[MarkerVar, Op, MarkerVar] +MarkerAtom = Union[MarkerItem, Sequence["MarkerAtom"]] +MarkerList = Sequence[Union["MarkerList", MarkerAtom, str]] + + +class ParsedRequirement(NamedTuple): + name: str + url: str + extras: list[str] + specifier: str + marker: MarkerList | None + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for dependency specifier +# -------------------------------------------------------------------------------------- +def parse_requirement(source: str) -> ParsedRequirement: + return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement: + """ + requirement = WS? IDENTIFIER WS? extras WS? requirement_details + """ + tokenizer.consume("WS") + + name_token = tokenizer.expect( + "IDENTIFIER", expected="package name at the start of dependency specifier" + ) + name = name_token.text + tokenizer.consume("WS") + + extras = _parse_extras(tokenizer) + tokenizer.consume("WS") + + url, specifier, marker = _parse_requirement_details(tokenizer) + tokenizer.expect("END", expected="end of dependency specifier") + + return ParsedRequirement(name, url, extras, specifier, marker) + + +def _parse_requirement_details( + tokenizer: Tokenizer, +) -> tuple[str, str, MarkerList | None]: + """ + requirement_details = AT URL (WS requirement_marker?)? + | specifier WS? (requirement_marker)? + """ + + specifier = "" + url = "" + marker = None + + if tokenizer.check("AT"): + tokenizer.read() + tokenizer.consume("WS") + + url_start = tokenizer.position + url = tokenizer.expect("URL", expected="URL after @").text + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + tokenizer.expect("WS", expected="whitespace after URL") + + # The input might end after whitespace. + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, span_start=url_start, after="URL and whitespace" + ) + else: + specifier_start = tokenizer.position + specifier = _parse_specifier(tokenizer) + tokenizer.consume("WS") + + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, + span_start=specifier_start, + after=( + "version specifier" + if specifier + else "name and no valid version specifier" + ), + ) + + return (url, specifier, marker) + + +def _parse_requirement_marker( + tokenizer: Tokenizer, *, span_start: int, after: str +) -> MarkerList: + """ + requirement_marker = SEMICOLON marker WS? + """ + + if not tokenizer.check("SEMICOLON"): + tokenizer.raise_syntax_error( + f"Expected end or semicolon (after {after})", + span_start=span_start, + ) + tokenizer.read() + + marker = _parse_marker(tokenizer) + tokenizer.consume("WS") + + return marker + + +def _parse_extras(tokenizer: Tokenizer) -> list[str]: + """ + extras = (LEFT_BRACKET wsp* extras_list? wsp* RIGHT_BRACKET)? + """ + if not tokenizer.check("LEFT_BRACKET", peek=True): + return [] + + with tokenizer.enclosing_tokens( + "LEFT_BRACKET", + "RIGHT_BRACKET", + around="extras", + ): + tokenizer.consume("WS") + extras = _parse_extras_list(tokenizer) + tokenizer.consume("WS") + + return extras + + +def _parse_extras_list(tokenizer: Tokenizer) -> list[str]: + """ + extras_list = identifier (wsp* ',' wsp* identifier)* + """ + extras: list[str] = [] + + if not tokenizer.check("IDENTIFIER"): + return extras + + extras.append(tokenizer.read().text) + + while True: + tokenizer.consume("WS") + if tokenizer.check("IDENTIFIER", peek=True): + tokenizer.raise_syntax_error("Expected comma between extra names") + elif not tokenizer.check("COMMA"): + break + + tokenizer.read() + tokenizer.consume("WS") + + extra_token = tokenizer.expect("IDENTIFIER", expected="extra name after comma") + extras.append(extra_token.text) + + return extras + + +def _parse_specifier(tokenizer: Tokenizer) -> str: + """ + specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS + | WS? version_many WS? + """ + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="version specifier", + ): + tokenizer.consume("WS") + parsed_specifiers = _parse_version_many(tokenizer) + tokenizer.consume("WS") + + return parsed_specifiers + + +def _parse_version_many(tokenizer: Tokenizer) -> str: + """ + version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)? + """ + parsed_specifiers = "" + while tokenizer.check("SPECIFIER"): + span_start = tokenizer.position + parsed_specifiers += tokenizer.read().text + if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True): + tokenizer.raise_syntax_error( + ".* suffix can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position + 1, + ) + if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True): + tokenizer.raise_syntax_error( + "Local version label can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position, + ) + tokenizer.consume("WS") + if not tokenizer.check("COMMA"): + break + parsed_specifiers += tokenizer.read().text + tokenizer.consume("WS") + + return parsed_specifiers + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for marker expression +# -------------------------------------------------------------------------------------- +def parse_marker(source: str) -> MarkerList: + return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList: + retval = _parse_marker(tokenizer) + tokenizer.expect("END", expected="end of marker expression") + return retval + + +def _parse_marker(tokenizer: Tokenizer) -> MarkerList: + """ + marker = marker_atom (BOOLOP marker_atom)+ + """ + expression = [_parse_marker_atom(tokenizer)] + while tokenizer.check("BOOLOP"): + token = tokenizer.read() + expr_right = _parse_marker_atom(tokenizer) + expression.extend((token.text, expr_right)) + return expression + + +def _parse_marker_atom(tokenizer: Tokenizer) -> MarkerAtom: + """ + marker_atom = WS? LEFT_PARENTHESIS WS? marker WS? RIGHT_PARENTHESIS WS? + | WS? marker_item WS? + """ + + tokenizer.consume("WS") + if tokenizer.check("LEFT_PARENTHESIS", peek=True): + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="marker expression", + ): + tokenizer.consume("WS") + marker: MarkerAtom = _parse_marker(tokenizer) + tokenizer.consume("WS") + else: + marker = _parse_marker_item(tokenizer) + tokenizer.consume("WS") + return marker + + +def _parse_marker_item(tokenizer: Tokenizer) -> MarkerItem: + """ + marker_item = WS? marker_var WS? marker_op WS? marker_var WS? + """ + tokenizer.consume("WS") + marker_var_left = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + marker_op = _parse_marker_op(tokenizer) + tokenizer.consume("WS") + marker_var_right = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + return (marker_var_left, marker_op, marker_var_right) + + +def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: + """ + marker_var = VARIABLE | QUOTED_STRING + """ + if tokenizer.check("VARIABLE"): + return process_env_var(tokenizer.read().text.replace(".", "_")) + elif tokenizer.check("QUOTED_STRING"): + return process_python_str(tokenizer.read().text) + else: + tokenizer.raise_syntax_error( + message="Expected a marker variable or quoted string" + ) + + +def process_env_var(env_var: str) -> Variable: + if env_var in ("platform_python_implementation", "python_implementation"): + return Variable("platform_python_implementation") + else: + return Variable(env_var) + + +def process_python_str(python_str: str) -> Value: + value = ast.literal_eval(python_str) + return Value(str(value)) + + +def _parse_marker_op(tokenizer: Tokenizer) -> Op: + """ + marker_op = IN | NOT IN | OP + """ + if tokenizer.check("IN"): + tokenizer.read() + return Op("in") + elif tokenizer.check("NOT"): + tokenizer.read() + tokenizer.expect("WS", expected="whitespace after 'not'") + tokenizer.expect("IN", expected="'in' after 'not'") + return Op("not in") + elif tokenizer.check("OP"): + return Op(tokenizer.read().text) + else: + return tokenizer.raise_syntax_error( + "Expected marker operator, one of " + "<=, <, !=, ==, >=, >, ~=, ===, in, not in" + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/_structures.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_structures.py new file mode 100644 index 0000000..90a6465 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_structures.py @@ -0,0 +1,61 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +class InfinityType: + def __repr__(self) -> str: + return "Infinity" + + def __hash__(self) -> int: + return hash(repr(self)) + + def __lt__(self, other: object) -> bool: + return False + + def __le__(self, other: object) -> bool: + return False + + def __eq__(self, other: object) -> bool: + return isinstance(other, self.__class__) + + def __gt__(self, other: object) -> bool: + return True + + def __ge__(self, other: object) -> bool: + return True + + def __neg__(self: object) -> "NegativeInfinityType": + return NegativeInfinity + + +Infinity = InfinityType() + + +class NegativeInfinityType: + def __repr__(self) -> str: + return "-Infinity" + + def __hash__(self) -> int: + return hash(repr(self)) + + def __lt__(self, other: object) -> bool: + return True + + def __le__(self, other: object) -> bool: + return True + + def __eq__(self, other: object) -> bool: + return isinstance(other, self.__class__) + + def __gt__(self, other: object) -> bool: + return False + + def __ge__(self, other: object) -> bool: + return False + + def __neg__(self: object) -> InfinityType: + return Infinity + + +NegativeInfinity = NegativeInfinityType() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/_tokenizer.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_tokenizer.py new file mode 100644 index 0000000..89d0416 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/_tokenizer.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +import contextlib +import re +from dataclasses import dataclass +from typing import Iterator, NoReturn + +from .specifiers import Specifier + + +@dataclass +class Token: + name: str + text: str + position: int + + +class ParserSyntaxError(Exception): + """The provided source text could not be parsed correctly.""" + + def __init__( + self, + message: str, + *, + source: str, + span: tuple[int, int], + ) -> None: + self.span = span + self.message = message + self.source = source + + super().__init__() + + def __str__(self) -> str: + marker = " " * self.span[0] + "~" * (self.span[1] - self.span[0]) + "^" + return "\n ".join([self.message, self.source, marker]) + + +DEFAULT_RULES: dict[str, str | re.Pattern[str]] = { + "LEFT_PARENTHESIS": r"\(", + "RIGHT_PARENTHESIS": r"\)", + "LEFT_BRACKET": r"\[", + "RIGHT_BRACKET": r"\]", + "SEMICOLON": r";", + "COMMA": r",", + "QUOTED_STRING": re.compile( + r""" + ( + ('[^']*') + | + ("[^"]*") + ) + """, + re.VERBOSE, + ), + "OP": r"(===|==|~=|!=|<=|>=|<|>)", + "BOOLOP": r"\b(or|and)\b", + "IN": r"\bin\b", + "NOT": r"\bnot\b", + "VARIABLE": re.compile( + r""" + \b( + python_version + |python_full_version + |os[._]name + |sys[._]platform + |platform_(release|system) + |platform[._](version|machine|python_implementation) + |python_implementation + |implementation_(name|version) + |extra + )\b + """, + re.VERBOSE, + ), + "SPECIFIER": re.compile( + Specifier._operator_regex_str + Specifier._version_regex_str, + re.VERBOSE | re.IGNORECASE, + ), + "AT": r"\@", + "URL": r"[^ \t]+", + "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", + "VERSION_PREFIX_TRAIL": r"\.\*", + "VERSION_LOCAL_LABEL_TRAIL": r"\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*", + "WS": r"[ \t]+", + "END": r"$", +} + + +class Tokenizer: + """Context-sensitive token parsing. + + Provides methods to examine the input stream to check whether the next token + matches. + """ + + def __init__( + self, + source: str, + *, + rules: dict[str, str | re.Pattern[str]], + ) -> None: + self.source = source + self.rules: dict[str, re.Pattern[str]] = { + name: re.compile(pattern) for name, pattern in rules.items() + } + self.next_token: Token | None = None + self.position = 0 + + def consume(self, name: str) -> None: + """Move beyond provided token name, if at current position.""" + if self.check(name): + self.read() + + def check(self, name: str, *, peek: bool = False) -> bool: + """Check whether the next token has the provided name. + + By default, if the check succeeds, the token *must* be read before + another check. If `peek` is set to `True`, the token is not loaded and + would need to be checked again. + """ + assert ( + self.next_token is None + ), f"Cannot check for {name!r}, already have {self.next_token!r}" + assert name in self.rules, f"Unknown token name: {name!r}" + + expression = self.rules[name] + + match = expression.match(self.source, self.position) + if match is None: + return False + if not peek: + self.next_token = Token(name, match[0], self.position) + return True + + def expect(self, name: str, *, expected: str) -> Token: + """Expect a certain token name next, failing with a syntax error otherwise. + + The token is *not* read. + """ + if not self.check(name): + raise self.raise_syntax_error(f"Expected {expected}") + return self.read() + + def read(self) -> Token: + """Consume the next token and return it.""" + token = self.next_token + assert token is not None + + self.position += len(token.text) + self.next_token = None + + return token + + def raise_syntax_error( + self, + message: str, + *, + span_start: int | None = None, + span_end: int | None = None, + ) -> NoReturn: + """Raise ParserSyntaxError at the given position.""" + span = ( + self.position if span_start is None else span_start, + self.position if span_end is None else span_end, + ) + raise ParserSyntaxError( + message, + source=self.source, + span=span, + ) + + @contextlib.contextmanager + def enclosing_tokens( + self, open_token: str, close_token: str, *, around: str + ) -> Iterator[None]: + if self.check(open_token): + open_position = self.position + self.read() + else: + open_position = None + + yield + + if open_position is None: + return + + if not self.check(close_token): + self.raise_syntax_error( + f"Expected matching {close_token} for {open_token}, after {around}", + span_start=open_position, + ) + + self.read() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__init__.py new file mode 100644 index 0000000..71a1a77 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__init__.py @@ -0,0 +1,145 @@ +####################################################################################### +# +# Adapted from: +# https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py +# +# MIT License +# +# Copyright (c) 2017-present Ofek Lev +# +# 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. +# +# +# With additional allowance of arbitrary `LicenseRef-` identifiers, not just +# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`. +# +####################################################################################### +from __future__ import annotations + +import re +from typing import NewType, cast + +from pip._vendor.packaging.licenses._spdx import EXCEPTIONS, LICENSES + +__all__ = [ + "NormalizedLicenseExpression", + "InvalidLicenseExpression", + "canonicalize_license_expression", +] + +license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$") + +NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str) + + +class InvalidLicenseExpression(ValueError): + """Raised when a license-expression string is invalid + + >>> canonicalize_license_expression("invalid") + Traceback (most recent call last): + ... + packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid' + """ + + +def canonicalize_license_expression( + raw_license_expression: str, +) -> NormalizedLicenseExpression: + if not raw_license_expression: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) + + # Pad any parentheses so tokenization can be achieved by merely splitting on + # whitespace. + license_expression = raw_license_expression.replace("(", " ( ").replace(")", " ) ") + licenseref_prefix = "LicenseRef-" + license_refs = { + ref.lower(): "LicenseRef-" + ref[len(licenseref_prefix) :] + for ref in license_expression.split() + if ref.lower().startswith(licenseref_prefix.lower()) + } + + # Normalize to lower case so we can look up licenses/exceptions + # and so boolean operators are Python-compatible. + license_expression = license_expression.lower() + + tokens = license_expression.split() + + # Rather than implementing boolean logic, we create an expression that Python can + # parse. Everything that is not involved with the grammar itself is treated as + # `False` and the expression should evaluate as such. + python_tokens = [] + for token in tokens: + if token not in {"or", "and", "with", "(", ")"}: + python_tokens.append("False") + elif token == "with": + python_tokens.append("or") + elif token == "(" and python_tokens and python_tokens[-1] not in {"or", "and"}: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) + else: + python_tokens.append(token) + + python_expression = " ".join(python_tokens) + try: + invalid = eval(python_expression, globals(), locals()) + except Exception: + invalid = True + + if invalid is not False: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) from None + + # Take a final pass to check for unknown licenses/exceptions. + normalized_tokens = [] + for token in tokens: + if token in {"or", "and", "with", "(", ")"}: + normalized_tokens.append(token.upper()) + continue + + if normalized_tokens and normalized_tokens[-1] == "WITH": + if token not in EXCEPTIONS: + message = f"Unknown license exception: {token!r}" + raise InvalidLicenseExpression(message) + + normalized_tokens.append(EXCEPTIONS[token]["id"]) + else: + if token.endswith("+"): + final_token = token[:-1] + suffix = "+" + else: + final_token = token + suffix = "" + + if final_token.startswith("licenseref-"): + if not license_ref_allowed.match(final_token): + message = f"Invalid licenseref: {final_token!r}" + raise InvalidLicenseExpression(message) + normalized_tokens.append(license_refs[final_token] + suffix) + else: + if final_token not in LICENSES: + message = f"Unknown license: {final_token!r}" + raise InvalidLicenseExpression(message) + normalized_tokens.append(LICENSES[final_token]["id"] + suffix) + + normalized_expression = " ".join(normalized_tokens) + + return cast( + NormalizedLicenseExpression, + normalized_expression.replace("( ", "(").replace(" )", ")"), + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..450512cdb9a99570843ce155fff2deb545a6e68b GIT binary patch literal 4125 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%0AGNjB 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 VPiiPN?fqR<-@0|xc!#R0`hWcOat#0g literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/_spdx.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/_spdx.py new file mode 100644 index 0000000..eac2227 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/licenses/_spdx.py @@ -0,0 +1,759 @@ + +from __future__ import annotations + +from typing import TypedDict + +class SPDXLicense(TypedDict): + id: str + deprecated: bool + +class SPDXException(TypedDict): + id: str + deprecated: bool + + +VERSION = '3.25.0' + +LICENSES: dict[str, SPDXLicense] = { + '0bsd': {'id': '0BSD', 'deprecated': False}, + '3d-slicer-1.0': {'id': '3D-Slicer-1.0', 'deprecated': False}, + 'aal': {'id': 'AAL', 'deprecated': False}, + 'abstyles': {'id': 'Abstyles', 'deprecated': False}, + 'adacore-doc': {'id': 'AdaCore-doc', 'deprecated': False}, + 'adobe-2006': {'id': 'Adobe-2006', 'deprecated': False}, + 'adobe-display-postscript': {'id': 'Adobe-Display-PostScript', 'deprecated': False}, + 'adobe-glyph': {'id': 'Adobe-Glyph', 'deprecated': False}, + 'adobe-utopia': {'id': 'Adobe-Utopia', 'deprecated': False}, + 'adsl': {'id': 'ADSL', 'deprecated': False}, + 'afl-1.1': {'id': 'AFL-1.1', 'deprecated': False}, + 'afl-1.2': {'id': 'AFL-1.2', 'deprecated': False}, + 'afl-2.0': {'id': 'AFL-2.0', 'deprecated': False}, + 'afl-2.1': {'id': 'AFL-2.1', 'deprecated': False}, + 'afl-3.0': {'id': 'AFL-3.0', 'deprecated': False}, + 'afmparse': {'id': 'Afmparse', 'deprecated': False}, + 'agpl-1.0': {'id': 'AGPL-1.0', 'deprecated': True}, + 'agpl-1.0-only': {'id': 'AGPL-1.0-only', 'deprecated': False}, + 'agpl-1.0-or-later': {'id': 'AGPL-1.0-or-later', 'deprecated': False}, + 'agpl-3.0': {'id': 'AGPL-3.0', 'deprecated': True}, + 'agpl-3.0-only': {'id': 'AGPL-3.0-only', 'deprecated': False}, + 'agpl-3.0-or-later': {'id': 'AGPL-3.0-or-later', 'deprecated': False}, + 'aladdin': {'id': 'Aladdin', 'deprecated': False}, + 'amd-newlib': {'id': 'AMD-newlib', 'deprecated': False}, + 'amdplpa': {'id': 'AMDPLPA', 'deprecated': False}, + 'aml': {'id': 'AML', 'deprecated': False}, + 'aml-glslang': {'id': 'AML-glslang', 'deprecated': False}, + 'ampas': {'id': 'AMPAS', 'deprecated': False}, + 'antlr-pd': {'id': 'ANTLR-PD', 'deprecated': False}, + 'antlr-pd-fallback': {'id': 'ANTLR-PD-fallback', 'deprecated': False}, + 'any-osi': {'id': 'any-OSI', 'deprecated': False}, + 'apache-1.0': {'id': 'Apache-1.0', 'deprecated': False}, + 'apache-1.1': {'id': 'Apache-1.1', 'deprecated': False}, + 'apache-2.0': {'id': 'Apache-2.0', 'deprecated': False}, + 'apafml': {'id': 'APAFML', 'deprecated': False}, + 'apl-1.0': {'id': 'APL-1.0', 'deprecated': False}, + 'app-s2p': {'id': 'App-s2p', 'deprecated': False}, + 'apsl-1.0': {'id': 'APSL-1.0', 'deprecated': False}, + 'apsl-1.1': {'id': 'APSL-1.1', 'deprecated': False}, + 'apsl-1.2': {'id': 'APSL-1.2', 'deprecated': False}, + 'apsl-2.0': {'id': 'APSL-2.0', 'deprecated': False}, + 'arphic-1999': {'id': 'Arphic-1999', 'deprecated': False}, + 'artistic-1.0': {'id': 'Artistic-1.0', 'deprecated': False}, + 'artistic-1.0-cl8': {'id': 'Artistic-1.0-cl8', 'deprecated': False}, + 'artistic-1.0-perl': {'id': 'Artistic-1.0-Perl', 'deprecated': False}, + 'artistic-2.0': {'id': 'Artistic-2.0', 'deprecated': False}, + 'aswf-digital-assets-1.0': {'id': 'ASWF-Digital-Assets-1.0', 'deprecated': False}, + 'aswf-digital-assets-1.1': {'id': 'ASWF-Digital-Assets-1.1', 'deprecated': False}, + 'baekmuk': {'id': 'Baekmuk', 'deprecated': False}, + 'bahyph': {'id': 'Bahyph', 'deprecated': False}, + 'barr': {'id': 'Barr', 'deprecated': False}, + 'bcrypt-solar-designer': {'id': 'bcrypt-Solar-Designer', 'deprecated': False}, + 'beerware': {'id': 'Beerware', 'deprecated': False}, + 'bitstream-charter': {'id': 'Bitstream-Charter', 'deprecated': False}, + 'bitstream-vera': {'id': 'Bitstream-Vera', 'deprecated': False}, + 'bittorrent-1.0': {'id': 'BitTorrent-1.0', 'deprecated': False}, + 'bittorrent-1.1': {'id': 'BitTorrent-1.1', 'deprecated': False}, + 'blessing': {'id': 'blessing', 'deprecated': False}, + 'blueoak-1.0.0': {'id': 'BlueOak-1.0.0', 'deprecated': False}, + 'boehm-gc': {'id': 'Boehm-GC', 'deprecated': False}, + 'borceux': {'id': 'Borceux', 'deprecated': False}, + 'brian-gladman-2-clause': {'id': 'Brian-Gladman-2-Clause', 'deprecated': False}, + 'brian-gladman-3-clause': {'id': 'Brian-Gladman-3-Clause', 'deprecated': False}, + 'bsd-1-clause': {'id': 'BSD-1-Clause', 'deprecated': False}, + 'bsd-2-clause': {'id': 'BSD-2-Clause', 'deprecated': False}, + 'bsd-2-clause-darwin': {'id': 'BSD-2-Clause-Darwin', 'deprecated': False}, + 'bsd-2-clause-first-lines': {'id': 'BSD-2-Clause-first-lines', 'deprecated': False}, + 'bsd-2-clause-freebsd': {'id': 'BSD-2-Clause-FreeBSD', 'deprecated': True}, + 'bsd-2-clause-netbsd': {'id': 'BSD-2-Clause-NetBSD', 'deprecated': True}, + 'bsd-2-clause-patent': {'id': 'BSD-2-Clause-Patent', 'deprecated': False}, + 'bsd-2-clause-views': {'id': 'BSD-2-Clause-Views', 'deprecated': False}, + 'bsd-3-clause': {'id': 'BSD-3-Clause', 'deprecated': False}, + 'bsd-3-clause-acpica': {'id': 'BSD-3-Clause-acpica', 'deprecated': False}, + 'bsd-3-clause-attribution': {'id': 'BSD-3-Clause-Attribution', 'deprecated': False}, + 'bsd-3-clause-clear': {'id': 'BSD-3-Clause-Clear', 'deprecated': False}, + 'bsd-3-clause-flex': {'id': 'BSD-3-Clause-flex', 'deprecated': False}, + 'bsd-3-clause-hp': {'id': 'BSD-3-Clause-HP', 'deprecated': False}, + 'bsd-3-clause-lbnl': {'id': 'BSD-3-Clause-LBNL', 'deprecated': False}, + 'bsd-3-clause-modification': {'id': 'BSD-3-Clause-Modification', 'deprecated': False}, + 'bsd-3-clause-no-military-license': {'id': 'BSD-3-Clause-No-Military-License', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-license': {'id': 'BSD-3-Clause-No-Nuclear-License', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-license-2014': {'id': 'BSD-3-Clause-No-Nuclear-License-2014', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-warranty': {'id': 'BSD-3-Clause-No-Nuclear-Warranty', 'deprecated': False}, + 'bsd-3-clause-open-mpi': {'id': 'BSD-3-Clause-Open-MPI', 'deprecated': False}, + 'bsd-3-clause-sun': {'id': 'BSD-3-Clause-Sun', 'deprecated': False}, + 'bsd-4-clause': {'id': 'BSD-4-Clause', 'deprecated': False}, + 'bsd-4-clause-shortened': {'id': 'BSD-4-Clause-Shortened', 'deprecated': False}, + 'bsd-4-clause-uc': {'id': 'BSD-4-Clause-UC', 'deprecated': False}, + 'bsd-4.3reno': {'id': 'BSD-4.3RENO', 'deprecated': False}, + 'bsd-4.3tahoe': {'id': 'BSD-4.3TAHOE', 'deprecated': False}, + 'bsd-advertising-acknowledgement': {'id': 'BSD-Advertising-Acknowledgement', 'deprecated': False}, + 'bsd-attribution-hpnd-disclaimer': {'id': 'BSD-Attribution-HPND-disclaimer', 'deprecated': False}, + 'bsd-inferno-nettverk': {'id': 'BSD-Inferno-Nettverk', 'deprecated': False}, + 'bsd-protection': {'id': 'BSD-Protection', 'deprecated': False}, + 'bsd-source-beginning-file': {'id': 'BSD-Source-beginning-file', 'deprecated': False}, + 'bsd-source-code': {'id': 'BSD-Source-Code', 'deprecated': False}, + 'bsd-systemics': {'id': 'BSD-Systemics', 'deprecated': False}, + 'bsd-systemics-w3works': {'id': 'BSD-Systemics-W3Works', 'deprecated': False}, + 'bsl-1.0': {'id': 'BSL-1.0', 'deprecated': False}, + 'busl-1.1': {'id': 'BUSL-1.1', 'deprecated': False}, + 'bzip2-1.0.5': {'id': 'bzip2-1.0.5', 'deprecated': True}, + 'bzip2-1.0.6': {'id': 'bzip2-1.0.6', 'deprecated': False}, + 'c-uda-1.0': {'id': 'C-UDA-1.0', 'deprecated': False}, + 'cal-1.0': {'id': 'CAL-1.0', 'deprecated': False}, + 'cal-1.0-combined-work-exception': {'id': 'CAL-1.0-Combined-Work-Exception', 'deprecated': False}, + 'caldera': {'id': 'Caldera', 'deprecated': False}, + 'caldera-no-preamble': {'id': 'Caldera-no-preamble', 'deprecated': False}, + 'catharon': {'id': 'Catharon', 'deprecated': False}, + 'catosl-1.1': {'id': 'CATOSL-1.1', 'deprecated': False}, + 'cc-by-1.0': {'id': 'CC-BY-1.0', 'deprecated': False}, + 'cc-by-2.0': {'id': 'CC-BY-2.0', 'deprecated': False}, + 'cc-by-2.5': {'id': 'CC-BY-2.5', 'deprecated': False}, + 'cc-by-2.5-au': {'id': 'CC-BY-2.5-AU', 'deprecated': False}, + 'cc-by-3.0': {'id': 'CC-BY-3.0', 'deprecated': False}, + 'cc-by-3.0-at': {'id': 'CC-BY-3.0-AT', 'deprecated': False}, + 'cc-by-3.0-au': {'id': 'CC-BY-3.0-AU', 'deprecated': False}, + 'cc-by-3.0-de': {'id': 'CC-BY-3.0-DE', 'deprecated': False}, + 'cc-by-3.0-igo': {'id': 'CC-BY-3.0-IGO', 'deprecated': False}, + 'cc-by-3.0-nl': {'id': 'CC-BY-3.0-NL', 'deprecated': False}, + 'cc-by-3.0-us': {'id': 'CC-BY-3.0-US', 'deprecated': False}, + 'cc-by-4.0': {'id': 'CC-BY-4.0', 'deprecated': False}, + 'cc-by-nc-1.0': {'id': 'CC-BY-NC-1.0', 'deprecated': False}, + 'cc-by-nc-2.0': {'id': 'CC-BY-NC-2.0', 'deprecated': False}, + 'cc-by-nc-2.5': {'id': 'CC-BY-NC-2.5', 'deprecated': False}, + 'cc-by-nc-3.0': {'id': 'CC-BY-NC-3.0', 'deprecated': False}, + 'cc-by-nc-3.0-de': {'id': 'CC-BY-NC-3.0-DE', 'deprecated': False}, + 'cc-by-nc-4.0': {'id': 'CC-BY-NC-4.0', 'deprecated': False}, + 'cc-by-nc-nd-1.0': {'id': 'CC-BY-NC-ND-1.0', 'deprecated': False}, + 'cc-by-nc-nd-2.0': {'id': 'CC-BY-NC-ND-2.0', 'deprecated': False}, + 'cc-by-nc-nd-2.5': {'id': 'CC-BY-NC-ND-2.5', 'deprecated': False}, + 'cc-by-nc-nd-3.0': {'id': 'CC-BY-NC-ND-3.0', 'deprecated': False}, + 'cc-by-nc-nd-3.0-de': {'id': 'CC-BY-NC-ND-3.0-DE', 'deprecated': False}, + 'cc-by-nc-nd-3.0-igo': {'id': 'CC-BY-NC-ND-3.0-IGO', 'deprecated': False}, + 'cc-by-nc-nd-4.0': {'id': 'CC-BY-NC-ND-4.0', 'deprecated': False}, + 'cc-by-nc-sa-1.0': {'id': 'CC-BY-NC-SA-1.0', 'deprecated': False}, + 'cc-by-nc-sa-2.0': {'id': 'CC-BY-NC-SA-2.0', 'deprecated': False}, + 'cc-by-nc-sa-2.0-de': {'id': 'CC-BY-NC-SA-2.0-DE', 'deprecated': False}, + 'cc-by-nc-sa-2.0-fr': {'id': 'CC-BY-NC-SA-2.0-FR', 'deprecated': False}, + 'cc-by-nc-sa-2.0-uk': {'id': 'CC-BY-NC-SA-2.0-UK', 'deprecated': False}, + 'cc-by-nc-sa-2.5': {'id': 'CC-BY-NC-SA-2.5', 'deprecated': False}, + 'cc-by-nc-sa-3.0': {'id': 'CC-BY-NC-SA-3.0', 'deprecated': False}, + 'cc-by-nc-sa-3.0-de': {'id': 'CC-BY-NC-SA-3.0-DE', 'deprecated': False}, + 'cc-by-nc-sa-3.0-igo': {'id': 'CC-BY-NC-SA-3.0-IGO', 'deprecated': False}, + 'cc-by-nc-sa-4.0': {'id': 'CC-BY-NC-SA-4.0', 'deprecated': False}, + 'cc-by-nd-1.0': {'id': 'CC-BY-ND-1.0', 'deprecated': False}, + 'cc-by-nd-2.0': {'id': 'CC-BY-ND-2.0', 'deprecated': False}, + 'cc-by-nd-2.5': {'id': 'CC-BY-ND-2.5', 'deprecated': False}, + 'cc-by-nd-3.0': {'id': 'CC-BY-ND-3.0', 'deprecated': False}, + 'cc-by-nd-3.0-de': {'id': 'CC-BY-ND-3.0-DE', 'deprecated': False}, + 'cc-by-nd-4.0': {'id': 'CC-BY-ND-4.0', 'deprecated': False}, + 'cc-by-sa-1.0': {'id': 'CC-BY-SA-1.0', 'deprecated': False}, + 'cc-by-sa-2.0': {'id': 'CC-BY-SA-2.0', 'deprecated': False}, + 'cc-by-sa-2.0-uk': {'id': 'CC-BY-SA-2.0-UK', 'deprecated': False}, + 'cc-by-sa-2.1-jp': {'id': 'CC-BY-SA-2.1-JP', 'deprecated': False}, + 'cc-by-sa-2.5': {'id': 'CC-BY-SA-2.5', 'deprecated': False}, + 'cc-by-sa-3.0': {'id': 'CC-BY-SA-3.0', 'deprecated': False}, + 'cc-by-sa-3.0-at': {'id': 'CC-BY-SA-3.0-AT', 'deprecated': False}, + 'cc-by-sa-3.0-de': {'id': 'CC-BY-SA-3.0-DE', 'deprecated': False}, + 'cc-by-sa-3.0-igo': {'id': 'CC-BY-SA-3.0-IGO', 'deprecated': False}, + 'cc-by-sa-4.0': {'id': 'CC-BY-SA-4.0', 'deprecated': False}, + 'cc-pddc': {'id': 'CC-PDDC', 'deprecated': False}, + 'cc0-1.0': {'id': 'CC0-1.0', 'deprecated': False}, + 'cddl-1.0': {'id': 'CDDL-1.0', 'deprecated': False}, + 'cddl-1.1': {'id': 'CDDL-1.1', 'deprecated': False}, + 'cdl-1.0': {'id': 'CDL-1.0', 'deprecated': False}, + 'cdla-permissive-1.0': {'id': 'CDLA-Permissive-1.0', 'deprecated': False}, + 'cdla-permissive-2.0': {'id': 'CDLA-Permissive-2.0', 'deprecated': False}, + 'cdla-sharing-1.0': {'id': 'CDLA-Sharing-1.0', 'deprecated': False}, + 'cecill-1.0': {'id': 'CECILL-1.0', 'deprecated': False}, + 'cecill-1.1': {'id': 'CECILL-1.1', 'deprecated': False}, + 'cecill-2.0': {'id': 'CECILL-2.0', 'deprecated': False}, + 'cecill-2.1': {'id': 'CECILL-2.1', 'deprecated': False}, + 'cecill-b': {'id': 'CECILL-B', 'deprecated': False}, + 'cecill-c': {'id': 'CECILL-C', 'deprecated': False}, + 'cern-ohl-1.1': {'id': 'CERN-OHL-1.1', 'deprecated': False}, + 'cern-ohl-1.2': {'id': 'CERN-OHL-1.2', 'deprecated': False}, + 'cern-ohl-p-2.0': {'id': 'CERN-OHL-P-2.0', 'deprecated': False}, + 'cern-ohl-s-2.0': {'id': 'CERN-OHL-S-2.0', 'deprecated': False}, + 'cern-ohl-w-2.0': {'id': 'CERN-OHL-W-2.0', 'deprecated': False}, + 'cfitsio': {'id': 'CFITSIO', 'deprecated': False}, + 'check-cvs': {'id': 'check-cvs', 'deprecated': False}, + 'checkmk': {'id': 'checkmk', 'deprecated': False}, + 'clartistic': {'id': 'ClArtistic', 'deprecated': False}, + 'clips': {'id': 'Clips', 'deprecated': False}, + 'cmu-mach': {'id': 'CMU-Mach', 'deprecated': False}, + 'cmu-mach-nodoc': {'id': 'CMU-Mach-nodoc', 'deprecated': False}, + 'cnri-jython': {'id': 'CNRI-Jython', 'deprecated': False}, + 'cnri-python': {'id': 'CNRI-Python', 'deprecated': False}, + 'cnri-python-gpl-compatible': {'id': 'CNRI-Python-GPL-Compatible', 'deprecated': False}, + 'coil-1.0': {'id': 'COIL-1.0', 'deprecated': False}, + 'community-spec-1.0': {'id': 'Community-Spec-1.0', 'deprecated': False}, + 'condor-1.1': {'id': 'Condor-1.1', 'deprecated': False}, + 'copyleft-next-0.3.0': {'id': 'copyleft-next-0.3.0', 'deprecated': False}, + 'copyleft-next-0.3.1': {'id': 'copyleft-next-0.3.1', 'deprecated': False}, + 'cornell-lossless-jpeg': {'id': 'Cornell-Lossless-JPEG', 'deprecated': False}, + 'cpal-1.0': {'id': 'CPAL-1.0', 'deprecated': False}, + 'cpl-1.0': {'id': 'CPL-1.0', 'deprecated': False}, + 'cpol-1.02': {'id': 'CPOL-1.02', 'deprecated': False}, + 'cronyx': {'id': 'Cronyx', 'deprecated': False}, + 'crossword': {'id': 'Crossword', 'deprecated': False}, + 'crystalstacker': {'id': 'CrystalStacker', 'deprecated': False}, + 'cua-opl-1.0': {'id': 'CUA-OPL-1.0', 'deprecated': False}, + 'cube': {'id': 'Cube', 'deprecated': False}, + 'curl': {'id': 'curl', 'deprecated': False}, + 'cve-tou': {'id': 'cve-tou', 'deprecated': False}, + 'd-fsl-1.0': {'id': 'D-FSL-1.0', 'deprecated': False}, + 'dec-3-clause': {'id': 'DEC-3-Clause', 'deprecated': False}, + 'diffmark': {'id': 'diffmark', 'deprecated': False}, + 'dl-de-by-2.0': {'id': 'DL-DE-BY-2.0', 'deprecated': False}, + 'dl-de-zero-2.0': {'id': 'DL-DE-ZERO-2.0', 'deprecated': False}, + 'doc': {'id': 'DOC', 'deprecated': False}, + 'docbook-schema': {'id': 'DocBook-Schema', 'deprecated': False}, + 'docbook-xml': {'id': 'DocBook-XML', 'deprecated': False}, + 'dotseqn': {'id': 'Dotseqn', 'deprecated': False}, + 'drl-1.0': {'id': 'DRL-1.0', 'deprecated': False}, + 'drl-1.1': {'id': 'DRL-1.1', 'deprecated': False}, + 'dsdp': {'id': 'DSDP', 'deprecated': False}, + 'dtoa': {'id': 'dtoa', 'deprecated': False}, + 'dvipdfm': {'id': 'dvipdfm', 'deprecated': False}, + 'ecl-1.0': {'id': 'ECL-1.0', 'deprecated': False}, + 'ecl-2.0': {'id': 'ECL-2.0', 'deprecated': False}, + 'ecos-2.0': {'id': 'eCos-2.0', 'deprecated': True}, + 'efl-1.0': {'id': 'EFL-1.0', 'deprecated': False}, + 'efl-2.0': {'id': 'EFL-2.0', 'deprecated': False}, + 'egenix': {'id': 'eGenix', 'deprecated': False}, + 'elastic-2.0': {'id': 'Elastic-2.0', 'deprecated': False}, + 'entessa': {'id': 'Entessa', 'deprecated': False}, + 'epics': {'id': 'EPICS', 'deprecated': False}, + 'epl-1.0': {'id': 'EPL-1.0', 'deprecated': False}, + 'epl-2.0': {'id': 'EPL-2.0', 'deprecated': False}, + 'erlpl-1.1': {'id': 'ErlPL-1.1', 'deprecated': False}, + 'etalab-2.0': {'id': 'etalab-2.0', 'deprecated': False}, + 'eudatagrid': {'id': 'EUDatagrid', 'deprecated': False}, + 'eupl-1.0': {'id': 'EUPL-1.0', 'deprecated': False}, + 'eupl-1.1': {'id': 'EUPL-1.1', 'deprecated': False}, + 'eupl-1.2': {'id': 'EUPL-1.2', 'deprecated': False}, + 'eurosym': {'id': 'Eurosym', 'deprecated': False}, + 'fair': {'id': 'Fair', 'deprecated': False}, + 'fbm': {'id': 'FBM', 'deprecated': False}, + 'fdk-aac': {'id': 'FDK-AAC', 'deprecated': False}, + 'ferguson-twofish': {'id': 'Ferguson-Twofish', 'deprecated': False}, + 'frameworx-1.0': {'id': 'Frameworx-1.0', 'deprecated': False}, + 'freebsd-doc': {'id': 'FreeBSD-DOC', 'deprecated': False}, + 'freeimage': {'id': 'FreeImage', 'deprecated': False}, + 'fsfap': {'id': 'FSFAP', 'deprecated': False}, + 'fsfap-no-warranty-disclaimer': {'id': 'FSFAP-no-warranty-disclaimer', 'deprecated': False}, + 'fsful': {'id': 'FSFUL', 'deprecated': False}, + 'fsfullr': {'id': 'FSFULLR', 'deprecated': False}, + 'fsfullrwd': {'id': 'FSFULLRWD', 'deprecated': False}, + 'ftl': {'id': 'FTL', 'deprecated': False}, + 'furuseth': {'id': 'Furuseth', 'deprecated': False}, + 'fwlw': {'id': 'fwlw', 'deprecated': False}, + 'gcr-docs': {'id': 'GCR-docs', 'deprecated': False}, + 'gd': {'id': 'GD', 'deprecated': False}, + 'gfdl-1.1': {'id': 'GFDL-1.1', 'deprecated': True}, + 'gfdl-1.1-invariants-only': {'id': 'GFDL-1.1-invariants-only', 'deprecated': False}, + 'gfdl-1.1-invariants-or-later': {'id': 'GFDL-1.1-invariants-or-later', 'deprecated': False}, + 'gfdl-1.1-no-invariants-only': {'id': 'GFDL-1.1-no-invariants-only', 'deprecated': False}, + 'gfdl-1.1-no-invariants-or-later': {'id': 'GFDL-1.1-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.1-only': {'id': 'GFDL-1.1-only', 'deprecated': False}, + 'gfdl-1.1-or-later': {'id': 'GFDL-1.1-or-later', 'deprecated': False}, + 'gfdl-1.2': {'id': 'GFDL-1.2', 'deprecated': True}, + 'gfdl-1.2-invariants-only': {'id': 'GFDL-1.2-invariants-only', 'deprecated': False}, + 'gfdl-1.2-invariants-or-later': {'id': 'GFDL-1.2-invariants-or-later', 'deprecated': False}, + 'gfdl-1.2-no-invariants-only': {'id': 'GFDL-1.2-no-invariants-only', 'deprecated': False}, + 'gfdl-1.2-no-invariants-or-later': {'id': 'GFDL-1.2-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.2-only': {'id': 'GFDL-1.2-only', 'deprecated': False}, + 'gfdl-1.2-or-later': {'id': 'GFDL-1.2-or-later', 'deprecated': False}, + 'gfdl-1.3': {'id': 'GFDL-1.3', 'deprecated': True}, + 'gfdl-1.3-invariants-only': {'id': 'GFDL-1.3-invariants-only', 'deprecated': False}, + 'gfdl-1.3-invariants-or-later': {'id': 'GFDL-1.3-invariants-or-later', 'deprecated': False}, + 'gfdl-1.3-no-invariants-only': {'id': 'GFDL-1.3-no-invariants-only', 'deprecated': False}, + 'gfdl-1.3-no-invariants-or-later': {'id': 'GFDL-1.3-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.3-only': {'id': 'GFDL-1.3-only', 'deprecated': False}, + 'gfdl-1.3-or-later': {'id': 'GFDL-1.3-or-later', 'deprecated': False}, + 'giftware': {'id': 'Giftware', 'deprecated': False}, + 'gl2ps': {'id': 'GL2PS', 'deprecated': False}, + 'glide': {'id': 'Glide', 'deprecated': False}, + 'glulxe': {'id': 'Glulxe', 'deprecated': False}, + 'glwtpl': {'id': 'GLWTPL', 'deprecated': False}, + 'gnuplot': {'id': 'gnuplot', 'deprecated': False}, + 'gpl-1.0': {'id': 'GPL-1.0', 'deprecated': True}, + 'gpl-1.0+': {'id': 'GPL-1.0+', 'deprecated': True}, + 'gpl-1.0-only': {'id': 'GPL-1.0-only', 'deprecated': False}, + 'gpl-1.0-or-later': {'id': 'GPL-1.0-or-later', 'deprecated': False}, + 'gpl-2.0': {'id': 'GPL-2.0', 'deprecated': True}, + 'gpl-2.0+': {'id': 'GPL-2.0+', 'deprecated': True}, + 'gpl-2.0-only': {'id': 'GPL-2.0-only', 'deprecated': False}, + 'gpl-2.0-or-later': {'id': 'GPL-2.0-or-later', 'deprecated': False}, + 'gpl-2.0-with-autoconf-exception': {'id': 'GPL-2.0-with-autoconf-exception', 'deprecated': True}, + 'gpl-2.0-with-bison-exception': {'id': 'GPL-2.0-with-bison-exception', 'deprecated': True}, + 'gpl-2.0-with-classpath-exception': {'id': 'GPL-2.0-with-classpath-exception', 'deprecated': True}, + 'gpl-2.0-with-font-exception': {'id': 'GPL-2.0-with-font-exception', 'deprecated': True}, + 'gpl-2.0-with-gcc-exception': {'id': 'GPL-2.0-with-GCC-exception', 'deprecated': True}, + 'gpl-3.0': {'id': 'GPL-3.0', 'deprecated': True}, + 'gpl-3.0+': {'id': 'GPL-3.0+', 'deprecated': True}, + 'gpl-3.0-only': {'id': 'GPL-3.0-only', 'deprecated': False}, + 'gpl-3.0-or-later': {'id': 'GPL-3.0-or-later', 'deprecated': False}, + 'gpl-3.0-with-autoconf-exception': {'id': 'GPL-3.0-with-autoconf-exception', 'deprecated': True}, + 'gpl-3.0-with-gcc-exception': {'id': 'GPL-3.0-with-GCC-exception', 'deprecated': True}, + 'graphics-gems': {'id': 'Graphics-Gems', 'deprecated': False}, + 'gsoap-1.3b': {'id': 'gSOAP-1.3b', 'deprecated': False}, + 'gtkbook': {'id': 'gtkbook', 'deprecated': False}, + 'gutmann': {'id': 'Gutmann', 'deprecated': False}, + 'haskellreport': {'id': 'HaskellReport', 'deprecated': False}, + 'hdparm': {'id': 'hdparm', 'deprecated': False}, + 'hidapi': {'id': 'HIDAPI', 'deprecated': False}, + 'hippocratic-2.1': {'id': 'Hippocratic-2.1', 'deprecated': False}, + 'hp-1986': {'id': 'HP-1986', 'deprecated': False}, + 'hp-1989': {'id': 'HP-1989', 'deprecated': False}, + 'hpnd': {'id': 'HPND', 'deprecated': False}, + 'hpnd-dec': {'id': 'HPND-DEC', 'deprecated': False}, + 'hpnd-doc': {'id': 'HPND-doc', 'deprecated': False}, + 'hpnd-doc-sell': {'id': 'HPND-doc-sell', 'deprecated': False}, + 'hpnd-export-us': {'id': 'HPND-export-US', 'deprecated': False}, + 'hpnd-export-us-acknowledgement': {'id': 'HPND-export-US-acknowledgement', 'deprecated': False}, + 'hpnd-export-us-modify': {'id': 'HPND-export-US-modify', 'deprecated': False}, + 'hpnd-export2-us': {'id': 'HPND-export2-US', 'deprecated': False}, + 'hpnd-fenneberg-livingston': {'id': 'HPND-Fenneberg-Livingston', 'deprecated': False}, + 'hpnd-inria-imag': {'id': 'HPND-INRIA-IMAG', 'deprecated': False}, + 'hpnd-intel': {'id': 'HPND-Intel', 'deprecated': False}, + 'hpnd-kevlin-henney': {'id': 'HPND-Kevlin-Henney', 'deprecated': False}, + 'hpnd-markus-kuhn': {'id': 'HPND-Markus-Kuhn', 'deprecated': False}, + 'hpnd-merchantability-variant': {'id': 'HPND-merchantability-variant', 'deprecated': False}, + 'hpnd-mit-disclaimer': {'id': 'HPND-MIT-disclaimer', 'deprecated': False}, + 'hpnd-netrek': {'id': 'HPND-Netrek', 'deprecated': False}, + 'hpnd-pbmplus': {'id': 'HPND-Pbmplus', 'deprecated': False}, + 'hpnd-sell-mit-disclaimer-xserver': {'id': 'HPND-sell-MIT-disclaimer-xserver', 'deprecated': False}, + 'hpnd-sell-regexpr': {'id': 'HPND-sell-regexpr', 'deprecated': False}, + 'hpnd-sell-variant': {'id': 'HPND-sell-variant', 'deprecated': False}, + 'hpnd-sell-variant-mit-disclaimer': {'id': 'HPND-sell-variant-MIT-disclaimer', 'deprecated': False}, + 'hpnd-sell-variant-mit-disclaimer-rev': {'id': 'HPND-sell-variant-MIT-disclaimer-rev', 'deprecated': False}, + 'hpnd-uc': {'id': 'HPND-UC', 'deprecated': False}, + 'hpnd-uc-export-us': {'id': 'HPND-UC-export-US', 'deprecated': False}, + 'htmltidy': {'id': 'HTMLTIDY', 'deprecated': False}, + 'ibm-pibs': {'id': 'IBM-pibs', 'deprecated': False}, + 'icu': {'id': 'ICU', 'deprecated': False}, + 'iec-code-components-eula': {'id': 'IEC-Code-Components-EULA', 'deprecated': False}, + 'ijg': {'id': 'IJG', 'deprecated': False}, + 'ijg-short': {'id': 'IJG-short', 'deprecated': False}, + 'imagemagick': {'id': 'ImageMagick', 'deprecated': False}, + 'imatix': {'id': 'iMatix', 'deprecated': False}, + 'imlib2': {'id': 'Imlib2', 'deprecated': False}, + 'info-zip': {'id': 'Info-ZIP', 'deprecated': False}, + 'inner-net-2.0': {'id': 'Inner-Net-2.0', 'deprecated': False}, + 'intel': {'id': 'Intel', 'deprecated': False}, + 'intel-acpi': {'id': 'Intel-ACPI', 'deprecated': False}, + 'interbase-1.0': {'id': 'Interbase-1.0', 'deprecated': False}, + 'ipa': {'id': 'IPA', 'deprecated': False}, + 'ipl-1.0': {'id': 'IPL-1.0', 'deprecated': False}, + 'isc': {'id': 'ISC', 'deprecated': False}, + 'isc-veillard': {'id': 'ISC-Veillard', 'deprecated': False}, + 'jam': {'id': 'Jam', 'deprecated': False}, + 'jasper-2.0': {'id': 'JasPer-2.0', 'deprecated': False}, + 'jpl-image': {'id': 'JPL-image', 'deprecated': False}, + 'jpnic': {'id': 'JPNIC', 'deprecated': False}, + 'json': {'id': 'JSON', 'deprecated': False}, + 'kastrup': {'id': 'Kastrup', 'deprecated': False}, + 'kazlib': {'id': 'Kazlib', 'deprecated': False}, + 'knuth-ctan': {'id': 'Knuth-CTAN', 'deprecated': False}, + 'lal-1.2': {'id': 'LAL-1.2', 'deprecated': False}, + 'lal-1.3': {'id': 'LAL-1.3', 'deprecated': False}, + 'latex2e': {'id': 'Latex2e', 'deprecated': False}, + 'latex2e-translated-notice': {'id': 'Latex2e-translated-notice', 'deprecated': False}, + 'leptonica': {'id': 'Leptonica', 'deprecated': False}, + 'lgpl-2.0': {'id': 'LGPL-2.0', 'deprecated': True}, + 'lgpl-2.0+': {'id': 'LGPL-2.0+', 'deprecated': True}, + 'lgpl-2.0-only': {'id': 'LGPL-2.0-only', 'deprecated': False}, + 'lgpl-2.0-or-later': {'id': 'LGPL-2.0-or-later', 'deprecated': False}, + 'lgpl-2.1': {'id': 'LGPL-2.1', 'deprecated': True}, + 'lgpl-2.1+': {'id': 'LGPL-2.1+', 'deprecated': True}, + 'lgpl-2.1-only': {'id': 'LGPL-2.1-only', 'deprecated': False}, + 'lgpl-2.1-or-later': {'id': 'LGPL-2.1-or-later', 'deprecated': False}, + 'lgpl-3.0': {'id': 'LGPL-3.0', 'deprecated': True}, + 'lgpl-3.0+': {'id': 'LGPL-3.0+', 'deprecated': True}, + 'lgpl-3.0-only': {'id': 'LGPL-3.0-only', 'deprecated': False}, + 'lgpl-3.0-or-later': {'id': 'LGPL-3.0-or-later', 'deprecated': False}, + 'lgpllr': {'id': 'LGPLLR', 'deprecated': False}, + 'libpng': {'id': 'Libpng', 'deprecated': False}, + 'libpng-2.0': {'id': 'libpng-2.0', 'deprecated': False}, + 'libselinux-1.0': {'id': 'libselinux-1.0', 'deprecated': False}, + 'libtiff': {'id': 'libtiff', 'deprecated': False}, + 'libutil-david-nugent': {'id': 'libutil-David-Nugent', 'deprecated': False}, + 'liliq-p-1.1': {'id': 'LiLiQ-P-1.1', 'deprecated': False}, + 'liliq-r-1.1': {'id': 'LiLiQ-R-1.1', 'deprecated': False}, + 'liliq-rplus-1.1': {'id': 'LiLiQ-Rplus-1.1', 'deprecated': False}, + 'linux-man-pages-1-para': {'id': 'Linux-man-pages-1-para', 'deprecated': False}, + 'linux-man-pages-copyleft': {'id': 'Linux-man-pages-copyleft', 'deprecated': False}, + 'linux-man-pages-copyleft-2-para': {'id': 'Linux-man-pages-copyleft-2-para', 'deprecated': False}, + 'linux-man-pages-copyleft-var': {'id': 'Linux-man-pages-copyleft-var', 'deprecated': False}, + 'linux-openib': {'id': 'Linux-OpenIB', 'deprecated': False}, + 'loop': {'id': 'LOOP', 'deprecated': False}, + 'lpd-document': {'id': 'LPD-document', 'deprecated': False}, + 'lpl-1.0': {'id': 'LPL-1.0', 'deprecated': False}, + 'lpl-1.02': {'id': 'LPL-1.02', 'deprecated': False}, + 'lppl-1.0': {'id': 'LPPL-1.0', 'deprecated': False}, + 'lppl-1.1': {'id': 'LPPL-1.1', 'deprecated': False}, + 'lppl-1.2': {'id': 'LPPL-1.2', 'deprecated': False}, + 'lppl-1.3a': {'id': 'LPPL-1.3a', 'deprecated': False}, + 'lppl-1.3c': {'id': 'LPPL-1.3c', 'deprecated': False}, + 'lsof': {'id': 'lsof', 'deprecated': False}, + 'lucida-bitmap-fonts': {'id': 'Lucida-Bitmap-Fonts', 'deprecated': False}, + 'lzma-sdk-9.11-to-9.20': {'id': 'LZMA-SDK-9.11-to-9.20', 'deprecated': False}, + 'lzma-sdk-9.22': {'id': 'LZMA-SDK-9.22', 'deprecated': False}, + 'mackerras-3-clause': {'id': 'Mackerras-3-Clause', 'deprecated': False}, + 'mackerras-3-clause-acknowledgment': {'id': 'Mackerras-3-Clause-acknowledgment', 'deprecated': False}, + 'magaz': {'id': 'magaz', 'deprecated': False}, + 'mailprio': {'id': 'mailprio', 'deprecated': False}, + 'makeindex': {'id': 'MakeIndex', 'deprecated': False}, + 'martin-birgmeier': {'id': 'Martin-Birgmeier', 'deprecated': False}, + 'mcphee-slideshow': {'id': 'McPhee-slideshow', 'deprecated': False}, + 'metamail': {'id': 'metamail', 'deprecated': False}, + 'minpack': {'id': 'Minpack', 'deprecated': False}, + 'miros': {'id': 'MirOS', 'deprecated': False}, + 'mit': {'id': 'MIT', 'deprecated': False}, + 'mit-0': {'id': 'MIT-0', 'deprecated': False}, + 'mit-advertising': {'id': 'MIT-advertising', 'deprecated': False}, + 'mit-cmu': {'id': 'MIT-CMU', 'deprecated': False}, + 'mit-enna': {'id': 'MIT-enna', 'deprecated': False}, + 'mit-feh': {'id': 'MIT-feh', 'deprecated': False}, + 'mit-festival': {'id': 'MIT-Festival', 'deprecated': False}, + 'mit-khronos-old': {'id': 'MIT-Khronos-old', 'deprecated': False}, + 'mit-modern-variant': {'id': 'MIT-Modern-Variant', 'deprecated': False}, + 'mit-open-group': {'id': 'MIT-open-group', 'deprecated': False}, + 'mit-testregex': {'id': 'MIT-testregex', 'deprecated': False}, + 'mit-wu': {'id': 'MIT-Wu', 'deprecated': False}, + 'mitnfa': {'id': 'MITNFA', 'deprecated': False}, + 'mmixware': {'id': 'MMIXware', 'deprecated': False}, + 'motosoto': {'id': 'Motosoto', 'deprecated': False}, + 'mpeg-ssg': {'id': 'MPEG-SSG', 'deprecated': False}, + 'mpi-permissive': {'id': 'mpi-permissive', 'deprecated': False}, + 'mpich2': {'id': 'mpich2', 'deprecated': False}, + 'mpl-1.0': {'id': 'MPL-1.0', 'deprecated': False}, + 'mpl-1.1': {'id': 'MPL-1.1', 'deprecated': False}, + 'mpl-2.0': {'id': 'MPL-2.0', 'deprecated': False}, + 'mpl-2.0-no-copyleft-exception': {'id': 'MPL-2.0-no-copyleft-exception', 'deprecated': False}, + 'mplus': {'id': 'mplus', 'deprecated': False}, + 'ms-lpl': {'id': 'MS-LPL', 'deprecated': False}, + 'ms-pl': {'id': 'MS-PL', 'deprecated': False}, + 'ms-rl': {'id': 'MS-RL', 'deprecated': False}, + 'mtll': {'id': 'MTLL', 'deprecated': False}, + 'mulanpsl-1.0': {'id': 'MulanPSL-1.0', 'deprecated': False}, + 'mulanpsl-2.0': {'id': 'MulanPSL-2.0', 'deprecated': False}, + 'multics': {'id': 'Multics', 'deprecated': False}, + 'mup': {'id': 'Mup', 'deprecated': False}, + 'naist-2003': {'id': 'NAIST-2003', 'deprecated': False}, + 'nasa-1.3': {'id': 'NASA-1.3', 'deprecated': False}, + 'naumen': {'id': 'Naumen', 'deprecated': False}, + 'nbpl-1.0': {'id': 'NBPL-1.0', 'deprecated': False}, + 'ncbi-pd': {'id': 'NCBI-PD', 'deprecated': False}, + 'ncgl-uk-2.0': {'id': 'NCGL-UK-2.0', 'deprecated': False}, + 'ncl': {'id': 'NCL', 'deprecated': False}, + 'ncsa': {'id': 'NCSA', 'deprecated': False}, + 'net-snmp': {'id': 'Net-SNMP', 'deprecated': True}, + 'netcdf': {'id': 'NetCDF', 'deprecated': False}, + 'newsletr': {'id': 'Newsletr', 'deprecated': False}, + 'ngpl': {'id': 'NGPL', 'deprecated': False}, + 'nicta-1.0': {'id': 'NICTA-1.0', 'deprecated': False}, + 'nist-pd': {'id': 'NIST-PD', 'deprecated': False}, + 'nist-pd-fallback': {'id': 'NIST-PD-fallback', 'deprecated': False}, + 'nist-software': {'id': 'NIST-Software', 'deprecated': False}, + 'nlod-1.0': {'id': 'NLOD-1.0', 'deprecated': False}, + 'nlod-2.0': {'id': 'NLOD-2.0', 'deprecated': False}, + 'nlpl': {'id': 'NLPL', 'deprecated': False}, + 'nokia': {'id': 'Nokia', 'deprecated': False}, + 'nosl': {'id': 'NOSL', 'deprecated': False}, + 'noweb': {'id': 'Noweb', 'deprecated': False}, + 'npl-1.0': {'id': 'NPL-1.0', 'deprecated': False}, + 'npl-1.1': {'id': 'NPL-1.1', 'deprecated': False}, + 'nposl-3.0': {'id': 'NPOSL-3.0', 'deprecated': False}, + 'nrl': {'id': 'NRL', 'deprecated': False}, + 'ntp': {'id': 'NTP', 'deprecated': False}, + 'ntp-0': {'id': 'NTP-0', 'deprecated': False}, + 'nunit': {'id': 'Nunit', 'deprecated': True}, + 'o-uda-1.0': {'id': 'O-UDA-1.0', 'deprecated': False}, + 'oar': {'id': 'OAR', 'deprecated': False}, + 'occt-pl': {'id': 'OCCT-PL', 'deprecated': False}, + 'oclc-2.0': {'id': 'OCLC-2.0', 'deprecated': False}, + 'odbl-1.0': {'id': 'ODbL-1.0', 'deprecated': False}, + 'odc-by-1.0': {'id': 'ODC-By-1.0', 'deprecated': False}, + 'offis': {'id': 'OFFIS', 'deprecated': False}, + 'ofl-1.0': {'id': 'OFL-1.0', 'deprecated': False}, + 'ofl-1.0-no-rfn': {'id': 'OFL-1.0-no-RFN', 'deprecated': False}, + 'ofl-1.0-rfn': {'id': 'OFL-1.0-RFN', 'deprecated': False}, + 'ofl-1.1': {'id': 'OFL-1.1', 'deprecated': False}, + 'ofl-1.1-no-rfn': {'id': 'OFL-1.1-no-RFN', 'deprecated': False}, + 'ofl-1.1-rfn': {'id': 'OFL-1.1-RFN', 'deprecated': False}, + 'ogc-1.0': {'id': 'OGC-1.0', 'deprecated': False}, + 'ogdl-taiwan-1.0': {'id': 'OGDL-Taiwan-1.0', 'deprecated': False}, + 'ogl-canada-2.0': {'id': 'OGL-Canada-2.0', 'deprecated': False}, + 'ogl-uk-1.0': {'id': 'OGL-UK-1.0', 'deprecated': False}, + 'ogl-uk-2.0': {'id': 'OGL-UK-2.0', 'deprecated': False}, + 'ogl-uk-3.0': {'id': 'OGL-UK-3.0', 'deprecated': False}, + 'ogtsl': {'id': 'OGTSL', 'deprecated': False}, + 'oldap-1.1': {'id': 'OLDAP-1.1', 'deprecated': False}, + 'oldap-1.2': {'id': 'OLDAP-1.2', 'deprecated': False}, + 'oldap-1.3': {'id': 'OLDAP-1.3', 'deprecated': False}, + 'oldap-1.4': {'id': 'OLDAP-1.4', 'deprecated': False}, + 'oldap-2.0': {'id': 'OLDAP-2.0', 'deprecated': False}, + 'oldap-2.0.1': {'id': 'OLDAP-2.0.1', 'deprecated': False}, + 'oldap-2.1': {'id': 'OLDAP-2.1', 'deprecated': False}, + 'oldap-2.2': {'id': 'OLDAP-2.2', 'deprecated': False}, + 'oldap-2.2.1': {'id': 'OLDAP-2.2.1', 'deprecated': False}, + 'oldap-2.2.2': {'id': 'OLDAP-2.2.2', 'deprecated': False}, + 'oldap-2.3': {'id': 'OLDAP-2.3', 'deprecated': False}, + 'oldap-2.4': {'id': 'OLDAP-2.4', 'deprecated': False}, + 'oldap-2.5': {'id': 'OLDAP-2.5', 'deprecated': False}, + 'oldap-2.6': {'id': 'OLDAP-2.6', 'deprecated': False}, + 'oldap-2.7': {'id': 'OLDAP-2.7', 'deprecated': False}, + 'oldap-2.8': {'id': 'OLDAP-2.8', 'deprecated': False}, + 'olfl-1.3': {'id': 'OLFL-1.3', 'deprecated': False}, + 'oml': {'id': 'OML', 'deprecated': False}, + 'openpbs-2.3': {'id': 'OpenPBS-2.3', 'deprecated': False}, + 'openssl': {'id': 'OpenSSL', 'deprecated': False}, + 'openssl-standalone': {'id': 'OpenSSL-standalone', 'deprecated': False}, + 'openvision': {'id': 'OpenVision', 'deprecated': False}, + 'opl-1.0': {'id': 'OPL-1.0', 'deprecated': False}, + 'opl-uk-3.0': {'id': 'OPL-UK-3.0', 'deprecated': False}, + 'opubl-1.0': {'id': 'OPUBL-1.0', 'deprecated': False}, + 'oset-pl-2.1': {'id': 'OSET-PL-2.1', 'deprecated': False}, + 'osl-1.0': {'id': 'OSL-1.0', 'deprecated': False}, + 'osl-1.1': {'id': 'OSL-1.1', 'deprecated': False}, + 'osl-2.0': {'id': 'OSL-2.0', 'deprecated': False}, + 'osl-2.1': {'id': 'OSL-2.1', 'deprecated': False}, + 'osl-3.0': {'id': 'OSL-3.0', 'deprecated': False}, + 'padl': {'id': 'PADL', 'deprecated': False}, + 'parity-6.0.0': {'id': 'Parity-6.0.0', 'deprecated': False}, + 'parity-7.0.0': {'id': 'Parity-7.0.0', 'deprecated': False}, + 'pddl-1.0': {'id': 'PDDL-1.0', 'deprecated': False}, + 'php-3.0': {'id': 'PHP-3.0', 'deprecated': False}, + 'php-3.01': {'id': 'PHP-3.01', 'deprecated': False}, + 'pixar': {'id': 'Pixar', 'deprecated': False}, + 'pkgconf': {'id': 'pkgconf', 'deprecated': False}, + 'plexus': {'id': 'Plexus', 'deprecated': False}, + 'pnmstitch': {'id': 'pnmstitch', 'deprecated': False}, + 'polyform-noncommercial-1.0.0': {'id': 'PolyForm-Noncommercial-1.0.0', 'deprecated': False}, + 'polyform-small-business-1.0.0': {'id': 'PolyForm-Small-Business-1.0.0', 'deprecated': False}, + 'postgresql': {'id': 'PostgreSQL', 'deprecated': False}, + 'ppl': {'id': 'PPL', 'deprecated': False}, + 'psf-2.0': {'id': 'PSF-2.0', 'deprecated': False}, + 'psfrag': {'id': 'psfrag', 'deprecated': False}, + 'psutils': {'id': 'psutils', 'deprecated': False}, + 'python-2.0': {'id': 'Python-2.0', 'deprecated': False}, + 'python-2.0.1': {'id': 'Python-2.0.1', 'deprecated': False}, + 'python-ldap': {'id': 'python-ldap', 'deprecated': False}, + 'qhull': {'id': 'Qhull', 'deprecated': False}, + 'qpl-1.0': {'id': 'QPL-1.0', 'deprecated': False}, + 'qpl-1.0-inria-2004': {'id': 'QPL-1.0-INRIA-2004', 'deprecated': False}, + 'radvd': {'id': 'radvd', 'deprecated': False}, + 'rdisc': {'id': 'Rdisc', 'deprecated': False}, + 'rhecos-1.1': {'id': 'RHeCos-1.1', 'deprecated': False}, + 'rpl-1.1': {'id': 'RPL-1.1', 'deprecated': False}, + 'rpl-1.5': {'id': 'RPL-1.5', 'deprecated': False}, + 'rpsl-1.0': {'id': 'RPSL-1.0', 'deprecated': False}, + 'rsa-md': {'id': 'RSA-MD', 'deprecated': False}, + 'rscpl': {'id': 'RSCPL', 'deprecated': False}, + 'ruby': {'id': 'Ruby', 'deprecated': False}, + 'ruby-pty': {'id': 'Ruby-pty', 'deprecated': False}, + 'sax-pd': {'id': 'SAX-PD', 'deprecated': False}, + 'sax-pd-2.0': {'id': 'SAX-PD-2.0', 'deprecated': False}, + 'saxpath': {'id': 'Saxpath', 'deprecated': False}, + 'scea': {'id': 'SCEA', 'deprecated': False}, + 'schemereport': {'id': 'SchemeReport', 'deprecated': False}, + 'sendmail': {'id': 'Sendmail', 'deprecated': False}, + 'sendmail-8.23': {'id': 'Sendmail-8.23', 'deprecated': False}, + 'sgi-b-1.0': {'id': 'SGI-B-1.0', 'deprecated': False}, + 'sgi-b-1.1': {'id': 'SGI-B-1.1', 'deprecated': False}, + 'sgi-b-2.0': {'id': 'SGI-B-2.0', 'deprecated': False}, + 'sgi-opengl': {'id': 'SGI-OpenGL', 'deprecated': False}, + 'sgp4': {'id': 'SGP4', 'deprecated': False}, + 'shl-0.5': {'id': 'SHL-0.5', 'deprecated': False}, + 'shl-0.51': {'id': 'SHL-0.51', 'deprecated': False}, + 'simpl-2.0': {'id': 'SimPL-2.0', 'deprecated': False}, + 'sissl': {'id': 'SISSL', 'deprecated': False}, + 'sissl-1.2': {'id': 'SISSL-1.2', 'deprecated': False}, + 'sl': {'id': 'SL', 'deprecated': False}, + 'sleepycat': {'id': 'Sleepycat', 'deprecated': False}, + 'smlnj': {'id': 'SMLNJ', 'deprecated': False}, + 'smppl': {'id': 'SMPPL', 'deprecated': False}, + 'snia': {'id': 'SNIA', 'deprecated': False}, + 'snprintf': {'id': 'snprintf', 'deprecated': False}, + 'softsurfer': {'id': 'softSurfer', 'deprecated': False}, + 'soundex': {'id': 'Soundex', 'deprecated': False}, + 'spencer-86': {'id': 'Spencer-86', 'deprecated': False}, + 'spencer-94': {'id': 'Spencer-94', 'deprecated': False}, + 'spencer-99': {'id': 'Spencer-99', 'deprecated': False}, + 'spl-1.0': {'id': 'SPL-1.0', 'deprecated': False}, + 'ssh-keyscan': {'id': 'ssh-keyscan', 'deprecated': False}, + 'ssh-openssh': {'id': 'SSH-OpenSSH', 'deprecated': False}, + 'ssh-short': {'id': 'SSH-short', 'deprecated': False}, + 'ssleay-standalone': {'id': 'SSLeay-standalone', 'deprecated': False}, + 'sspl-1.0': {'id': 'SSPL-1.0', 'deprecated': False}, + 'standardml-nj': {'id': 'StandardML-NJ', 'deprecated': True}, + 'sugarcrm-1.1.3': {'id': 'SugarCRM-1.1.3', 'deprecated': False}, + 'sun-ppp': {'id': 'Sun-PPP', 'deprecated': False}, + 'sun-ppp-2000': {'id': 'Sun-PPP-2000', 'deprecated': False}, + 'sunpro': {'id': 'SunPro', 'deprecated': False}, + 'swl': {'id': 'SWL', 'deprecated': False}, + 'swrule': {'id': 'swrule', 'deprecated': False}, + 'symlinks': {'id': 'Symlinks', 'deprecated': False}, + 'tapr-ohl-1.0': {'id': 'TAPR-OHL-1.0', 'deprecated': False}, + 'tcl': {'id': 'TCL', 'deprecated': False}, + 'tcp-wrappers': {'id': 'TCP-wrappers', 'deprecated': False}, + 'termreadkey': {'id': 'TermReadKey', 'deprecated': False}, + 'tgppl-1.0': {'id': 'TGPPL-1.0', 'deprecated': False}, + 'threeparttable': {'id': 'threeparttable', 'deprecated': False}, + 'tmate': {'id': 'TMate', 'deprecated': False}, + 'torque-1.1': {'id': 'TORQUE-1.1', 'deprecated': False}, + 'tosl': {'id': 'TOSL', 'deprecated': False}, + 'tpdl': {'id': 'TPDL', 'deprecated': False}, + 'tpl-1.0': {'id': 'TPL-1.0', 'deprecated': False}, + 'ttwl': {'id': 'TTWL', 'deprecated': False}, + 'ttyp0': {'id': 'TTYP0', 'deprecated': False}, + 'tu-berlin-1.0': {'id': 'TU-Berlin-1.0', 'deprecated': False}, + 'tu-berlin-2.0': {'id': 'TU-Berlin-2.0', 'deprecated': False}, + 'ubuntu-font-1.0': {'id': 'Ubuntu-font-1.0', 'deprecated': False}, + 'ucar': {'id': 'UCAR', 'deprecated': False}, + 'ucl-1.0': {'id': 'UCL-1.0', 'deprecated': False}, + 'ulem': {'id': 'ulem', 'deprecated': False}, + 'umich-merit': {'id': 'UMich-Merit', 'deprecated': False}, + 'unicode-3.0': {'id': 'Unicode-3.0', 'deprecated': False}, + 'unicode-dfs-2015': {'id': 'Unicode-DFS-2015', 'deprecated': False}, + 'unicode-dfs-2016': {'id': 'Unicode-DFS-2016', 'deprecated': False}, + 'unicode-tou': {'id': 'Unicode-TOU', 'deprecated': False}, + 'unixcrypt': {'id': 'UnixCrypt', 'deprecated': False}, + 'unlicense': {'id': 'Unlicense', 'deprecated': False}, + 'upl-1.0': {'id': 'UPL-1.0', 'deprecated': False}, + 'urt-rle': {'id': 'URT-RLE', 'deprecated': False}, + 'vim': {'id': 'Vim', 'deprecated': False}, + 'vostrom': {'id': 'VOSTROM', 'deprecated': False}, + 'vsl-1.0': {'id': 'VSL-1.0', 'deprecated': False}, + 'w3c': {'id': 'W3C', 'deprecated': False}, + 'w3c-19980720': {'id': 'W3C-19980720', 'deprecated': False}, + 'w3c-20150513': {'id': 'W3C-20150513', 'deprecated': False}, + 'w3m': {'id': 'w3m', 'deprecated': False}, + 'watcom-1.0': {'id': 'Watcom-1.0', 'deprecated': False}, + 'widget-workshop': {'id': 'Widget-Workshop', 'deprecated': False}, + 'wsuipa': {'id': 'Wsuipa', 'deprecated': False}, + 'wtfpl': {'id': 'WTFPL', 'deprecated': False}, + 'wxwindows': {'id': 'wxWindows', 'deprecated': True}, + 'x11': {'id': 'X11', 'deprecated': False}, + 'x11-distribute-modifications-variant': {'id': 'X11-distribute-modifications-variant', 'deprecated': False}, + 'x11-swapped': {'id': 'X11-swapped', 'deprecated': False}, + 'xdebug-1.03': {'id': 'Xdebug-1.03', 'deprecated': False}, + 'xerox': {'id': 'Xerox', 'deprecated': False}, + 'xfig': {'id': 'Xfig', 'deprecated': False}, + 'xfree86-1.1': {'id': 'XFree86-1.1', 'deprecated': False}, + 'xinetd': {'id': 'xinetd', 'deprecated': False}, + 'xkeyboard-config-zinoviev': {'id': 'xkeyboard-config-Zinoviev', 'deprecated': False}, + 'xlock': {'id': 'xlock', 'deprecated': False}, + 'xnet': {'id': 'Xnet', 'deprecated': False}, + 'xpp': {'id': 'xpp', 'deprecated': False}, + 'xskat': {'id': 'XSkat', 'deprecated': False}, + 'xzoom': {'id': 'xzoom', 'deprecated': False}, + 'ypl-1.0': {'id': 'YPL-1.0', 'deprecated': False}, + 'ypl-1.1': {'id': 'YPL-1.1', 'deprecated': False}, + 'zed': {'id': 'Zed', 'deprecated': False}, + 'zeeff': {'id': 'Zeeff', 'deprecated': False}, + 'zend-2.0': {'id': 'Zend-2.0', 'deprecated': False}, + 'zimbra-1.3': {'id': 'Zimbra-1.3', 'deprecated': False}, + 'zimbra-1.4': {'id': 'Zimbra-1.4', 'deprecated': False}, + 'zlib': {'id': 'Zlib', 'deprecated': False}, + 'zlib-acknowledgement': {'id': 'zlib-acknowledgement', 'deprecated': False}, + 'zpl-1.1': {'id': 'ZPL-1.1', 'deprecated': False}, + 'zpl-2.0': {'id': 'ZPL-2.0', 'deprecated': False}, + 'zpl-2.1': {'id': 'ZPL-2.1', 'deprecated': False}, +} + +EXCEPTIONS: dict[str, SPDXException] = { + '389-exception': {'id': '389-exception', 'deprecated': False}, + 'asterisk-exception': {'id': 'Asterisk-exception', 'deprecated': False}, + 'asterisk-linking-protocols-exception': {'id': 'Asterisk-linking-protocols-exception', 'deprecated': False}, + 'autoconf-exception-2.0': {'id': 'Autoconf-exception-2.0', 'deprecated': False}, + 'autoconf-exception-3.0': {'id': 'Autoconf-exception-3.0', 'deprecated': False}, + 'autoconf-exception-generic': {'id': 'Autoconf-exception-generic', 'deprecated': False}, + 'autoconf-exception-generic-3.0': {'id': 'Autoconf-exception-generic-3.0', 'deprecated': False}, + 'autoconf-exception-macro': {'id': 'Autoconf-exception-macro', 'deprecated': False}, + 'bison-exception-1.24': {'id': 'Bison-exception-1.24', 'deprecated': False}, + 'bison-exception-2.2': {'id': 'Bison-exception-2.2', 'deprecated': False}, + 'bootloader-exception': {'id': 'Bootloader-exception', 'deprecated': False}, + 'classpath-exception-2.0': {'id': 'Classpath-exception-2.0', 'deprecated': False}, + 'clisp-exception-2.0': {'id': 'CLISP-exception-2.0', 'deprecated': False}, + 'cryptsetup-openssl-exception': {'id': 'cryptsetup-OpenSSL-exception', 'deprecated': False}, + 'digirule-foss-exception': {'id': 'DigiRule-FOSS-exception', 'deprecated': False}, + 'ecos-exception-2.0': {'id': 'eCos-exception-2.0', 'deprecated': False}, + 'erlang-otp-linking-exception': {'id': 'erlang-otp-linking-exception', 'deprecated': False}, + 'fawkes-runtime-exception': {'id': 'Fawkes-Runtime-exception', 'deprecated': False}, + 'fltk-exception': {'id': 'FLTK-exception', 'deprecated': False}, + 'fmt-exception': {'id': 'fmt-exception', 'deprecated': False}, + 'font-exception-2.0': {'id': 'Font-exception-2.0', 'deprecated': False}, + 'freertos-exception-2.0': {'id': 'freertos-exception-2.0', 'deprecated': False}, + 'gcc-exception-2.0': {'id': 'GCC-exception-2.0', 'deprecated': False}, + 'gcc-exception-2.0-note': {'id': 'GCC-exception-2.0-note', 'deprecated': False}, + 'gcc-exception-3.1': {'id': 'GCC-exception-3.1', 'deprecated': False}, + 'gmsh-exception': {'id': 'Gmsh-exception', 'deprecated': False}, + 'gnat-exception': {'id': 'GNAT-exception', 'deprecated': False}, + 'gnome-examples-exception': {'id': 'GNOME-examples-exception', 'deprecated': False}, + 'gnu-compiler-exception': {'id': 'GNU-compiler-exception', 'deprecated': False}, + 'gnu-javamail-exception': {'id': 'gnu-javamail-exception', 'deprecated': False}, + 'gpl-3.0-interface-exception': {'id': 'GPL-3.0-interface-exception', 'deprecated': False}, + 'gpl-3.0-linking-exception': {'id': 'GPL-3.0-linking-exception', 'deprecated': False}, + 'gpl-3.0-linking-source-exception': {'id': 'GPL-3.0-linking-source-exception', 'deprecated': False}, + 'gpl-cc-1.0': {'id': 'GPL-CC-1.0', 'deprecated': False}, + 'gstreamer-exception-2005': {'id': 'GStreamer-exception-2005', 'deprecated': False}, + 'gstreamer-exception-2008': {'id': 'GStreamer-exception-2008', 'deprecated': False}, + 'i2p-gpl-java-exception': {'id': 'i2p-gpl-java-exception', 'deprecated': False}, + 'kicad-libraries-exception': {'id': 'KiCad-libraries-exception', 'deprecated': False}, + 'lgpl-3.0-linking-exception': {'id': 'LGPL-3.0-linking-exception', 'deprecated': False}, + 'libpri-openh323-exception': {'id': 'libpri-OpenH323-exception', 'deprecated': False}, + 'libtool-exception': {'id': 'Libtool-exception', 'deprecated': False}, + 'linux-syscall-note': {'id': 'Linux-syscall-note', 'deprecated': False}, + 'llgpl': {'id': 'LLGPL', 'deprecated': False}, + 'llvm-exception': {'id': 'LLVM-exception', 'deprecated': False}, + 'lzma-exception': {'id': 'LZMA-exception', 'deprecated': False}, + 'mif-exception': {'id': 'mif-exception', 'deprecated': False}, + 'nokia-qt-exception-1.1': {'id': 'Nokia-Qt-exception-1.1', 'deprecated': True}, + 'ocaml-lgpl-linking-exception': {'id': 'OCaml-LGPL-linking-exception', 'deprecated': False}, + 'occt-exception-1.0': {'id': 'OCCT-exception-1.0', 'deprecated': False}, + 'openjdk-assembly-exception-1.0': {'id': 'OpenJDK-assembly-exception-1.0', 'deprecated': False}, + 'openvpn-openssl-exception': {'id': 'openvpn-openssl-exception', 'deprecated': False}, + 'pcre2-exception': {'id': 'PCRE2-exception', 'deprecated': False}, + 'ps-or-pdf-font-exception-20170817': {'id': 'PS-or-PDF-font-exception-20170817', 'deprecated': False}, + 'qpl-1.0-inria-2004-exception': {'id': 'QPL-1.0-INRIA-2004-exception', 'deprecated': False}, + 'qt-gpl-exception-1.0': {'id': 'Qt-GPL-exception-1.0', 'deprecated': False}, + 'qt-lgpl-exception-1.1': {'id': 'Qt-LGPL-exception-1.1', 'deprecated': False}, + 'qwt-exception-1.0': {'id': 'Qwt-exception-1.0', 'deprecated': False}, + 'romic-exception': {'id': 'romic-exception', 'deprecated': False}, + 'rrdtool-floss-exception-2.0': {'id': 'RRDtool-FLOSS-exception-2.0', 'deprecated': False}, + 'sane-exception': {'id': 'SANE-exception', 'deprecated': False}, + 'shl-2.0': {'id': 'SHL-2.0', 'deprecated': False}, + 'shl-2.1': {'id': 'SHL-2.1', 'deprecated': False}, + 'stunnel-exception': {'id': 'stunnel-exception', 'deprecated': False}, + 'swi-exception': {'id': 'SWI-exception', 'deprecated': False}, + 'swift-exception': {'id': 'Swift-exception', 'deprecated': False}, + 'texinfo-exception': {'id': 'Texinfo-exception', 'deprecated': False}, + 'u-boot-exception-2.0': {'id': 'u-boot-exception-2.0', 'deprecated': False}, + 'ubdl-exception': {'id': 'UBDL-exception', 'deprecated': False}, + 'universal-foss-exception-1.0': {'id': 'Universal-FOSS-exception-1.0', 'deprecated': False}, + 'vsftpd-openssl-exception': {'id': 'vsftpd-openssl-exception', 'deprecated': False}, + 'wxwindows-exception-3.1': {'id': 'WxWindows-exception-3.1', 'deprecated': False}, + 'x11vnc-openssl-exception': {'id': 'x11vnc-openssl-exception', 'deprecated': False}, +} diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/markers.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/markers.py new file mode 100644 index 0000000..fb7f49c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/markers.py @@ -0,0 +1,331 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import operator +import os +import platform +import sys +from typing import Any, Callable, TypedDict, cast + +from ._parser import MarkerAtom, MarkerList, Op, Value, Variable +from ._parser import parse_marker as _parse_marker +from ._tokenizer import ParserSyntaxError +from .specifiers import InvalidSpecifier, Specifier +from .utils import canonicalize_name + +__all__ = [ + "InvalidMarker", + "Marker", + "UndefinedComparison", + "UndefinedEnvironmentName", + "default_environment", +] + +Operator = Callable[[str, str], bool] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Environment(TypedDict): + implementation_name: str + """The implementation's identifier, e.g. ``'cpython'``.""" + + implementation_version: str + """ + The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or + ``'7.3.13'`` for PyPy3.10 v7.3.13. + """ + + os_name: str + """ + The value of :py:data:`os.name`. The name of the operating system dependent module + imported, e.g. ``'posix'``. + """ + + platform_machine: str + """ + Returns the machine type, e.g. ``'i386'``. + + An empty string if the value cannot be determined. + """ + + platform_release: str + """ + The system's release, e.g. ``'2.2.0'`` or ``'NT'``. + + An empty string if the value cannot be determined. + """ + + platform_system: str + """ + The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``. + + An empty string if the value cannot be determined. + """ + + platform_version: str + """ + The system's release version, e.g. ``'#3 on degas'``. + + An empty string if the value cannot be determined. + """ + + python_full_version: str + """ + The Python version as string ``'major.minor.patchlevel'``. + + Note that unlike the Python :py:data:`sys.version`, this value will always include + the patchlevel (it defaults to 0). + """ + + platform_python_implementation: str + """ + A string identifying the Python implementation, e.g. ``'CPython'``. + """ + + python_version: str + """The Python version as string ``'major.minor'``.""" + + sys_platform: str + """ + This string contains a platform identifier that can be used to append + platform-specific components to :py:data:`sys.path`, for instance. + + For Unix systems, except on Linux and AIX, this is the lowercased OS name as + returned by ``uname -s`` with the first part of the version as returned by + ``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python + was built. + """ + + +def _normalize_extra_values(results: Any) -> Any: + """ + Normalize extra values. + """ + if isinstance(results[0], tuple): + lhs, op, rhs = results[0] + if isinstance(lhs, Variable) and lhs.value == "extra": + normalized_extra = canonicalize_name(rhs.value) + rhs = Value(normalized_extra) + elif isinstance(rhs, Variable) and rhs.value == "extra": + normalized_extra = canonicalize_name(lhs.value) + lhs = Value(normalized_extra) + results[0] = lhs, op, rhs + return results + + +def _format_marker( + marker: list[str] | MarkerAtom | str, first: bool | None = True +) -> str: + assert isinstance(marker, (list, tuple, str)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if ( + isinstance(marker, list) + and len(marker) == 1 + and isinstance(marker[0], (list, tuple)) + ): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators: dict[str, Operator] = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs: str, op: Op, rhs: str) -> bool: + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs, prereleases=True) + + oper: Operator | None = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") + + return oper(lhs, rhs) + + +def _normalize(*values: str, key: str) -> tuple[str, ...]: + # PEP 685 – Comparison of extra names for optional distribution dependencies + # https://peps.python.org/pep-0685/ + # > When comparing extra names, tools MUST normalize the names being + # > compared using the semantics outlined in PEP 503 for names + if key == "extra": + return tuple(canonicalize_name(v) for v in values) + + # other environment markers don't have such standards + return values + + +def _evaluate_markers(markers: MarkerList, environment: dict[str, str]) -> bool: + groups: list[list[bool]] = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, str)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + environment_key = lhs.value + lhs_value = environment[environment_key] + rhs_value = rhs.value + else: + lhs_value = lhs.value + environment_key = rhs.value + rhs_value = environment[environment_key] + + lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key) + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info: sys._version_info) -> str: + version = f"{info.major}.{info.minor}.{info.micro}" + kind = info.releaselevel + if kind != "final": + version += kind[0] + str(info.serial) + return version + + +def default_environment() -> Environment: + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": ".".join(platform.python_version_tuple()[:2]), + "sys_platform": sys.platform, + } + + +class Marker: + def __init__(self, marker: str) -> None: + # Note: We create a Marker object without calling this constructor in + # packaging.requirements.Requirement. If any additional logic is + # added here, make sure to mirror/adapt Requirement. + try: + self._markers = _normalize_extra_values(_parse_marker(marker)) + # The attribute `_markers` can be described in terms of a recursive type: + # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]] + # + # For example, the following expression: + # python_version > "3.6" or (python_version == "3.6" and os_name == "unix") + # + # is parsed into: + # [ + # (, ')>, ), + # 'and', + # [ + # (, , ), + # 'or', + # (, , ) + # ] + # ] + except ParserSyntaxError as e: + raise InvalidMarker(str(e)) from e + + def __str__(self) -> str: + return _format_marker(self._markers) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash((self.__class__.__name__, str(self))) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Marker): + return NotImplemented + + return str(self) == str(other) + + def evaluate(self, environment: dict[str, str] | None = None) -> bool: + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = cast("dict[str, str]", default_environment()) + current_environment["extra"] = "" + if environment is not None: + current_environment.update(environment) + # The API used to allow setting extra to None. We need to handle this + # case for backwards compatibility. + if current_environment["extra"] is None: + current_environment["extra"] = "" + + return _evaluate_markers( + self._markers, _repair_python_full_version(current_environment) + ) + + +def _repair_python_full_version(env: dict[str, str]) -> dict[str, str]: + """ + Work around platform.python_version() returning something that is not PEP 440 + compliant for non-tagged Python builds. + """ + if env["python_full_version"].endswith("+"): + env["python_full_version"] += "local" + return env diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/metadata.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/metadata.py new file mode 100644 index 0000000..721f411 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/metadata.py @@ -0,0 +1,863 @@ +from __future__ import annotations + +import email.feedparser +import email.header +import email.message +import email.parser +import email.policy +import pathlib +import sys +import typing +from typing import ( + Any, + Callable, + Generic, + Literal, + TypedDict, + cast, +) + +from . import licenses, requirements, specifiers, utils +from . import version as version_module +from .licenses import NormalizedLicenseExpression + +T = typing.TypeVar("T") + + +if sys.version_info >= (3, 11): # pragma: no cover + ExceptionGroup = ExceptionGroup +else: # pragma: no cover + + class ExceptionGroup(Exception): + """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. + + If :external:exc:`ExceptionGroup` is already defined by Python itself, + that version is used instead. + """ + + message: str + exceptions: list[Exception] + + def __init__(self, message: str, exceptions: list[Exception]) -> None: + self.message = message + self.exceptions = exceptions + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" + + +class InvalidMetadata(ValueError): + """A metadata field contains invalid data.""" + + field: str + """The name of the field that contains invalid data.""" + + def __init__(self, field: str, message: str) -> None: + self.field = field + super().__init__(message) + + +# The RawMetadata class attempts to make as few assumptions about the underlying +# serialization formats as possible. The idea is that as long as a serialization +# formats offer some very basic primitives in *some* way then we can support +# serializing to and from that format. +class RawMetadata(TypedDict, total=False): + """A dictionary of raw core metadata. + + Each field in core metadata maps to a key of this dictionary (when data is + provided). The key is lower-case and underscores are used instead of dashes + compared to the equivalent core metadata field. Any core metadata field that + can be specified multiple times or can hold multiple values in a single + field have a key with a plural name. See :class:`Metadata` whose attributes + match the keys of this dictionary. + + Core metadata fields that can be specified multiple times are stored as a + list or dict depending on which is appropriate for the field. Any fields + which hold multiple values in a single field are stored as a list. + + """ + + # Metadata 1.0 - PEP 241 + metadata_version: str + name: str + version: str + platforms: list[str] + summary: str + description: str + keywords: list[str] + home_page: str + author: str + author_email: str + license: str + + # Metadata 1.1 - PEP 314 + supported_platforms: list[str] + download_url: str + classifiers: list[str] + requires: list[str] + provides: list[str] + obsoletes: list[str] + + # Metadata 1.2 - PEP 345 + maintainer: str + maintainer_email: str + requires_dist: list[str] + provides_dist: list[str] + obsoletes_dist: list[str] + requires_python: str + requires_external: list[str] + project_urls: dict[str, str] + + # Metadata 2.0 + # PEP 426 attempted to completely revamp the metadata format + # but got stuck without ever being able to build consensus on + # it and ultimately ended up withdrawn. + # + # However, a number of tools had started emitting METADATA with + # `2.0` Metadata-Version, so for historical reasons, this version + # was skipped. + + # Metadata 2.1 - PEP 566 + description_content_type: str + provides_extra: list[str] + + # Metadata 2.2 - PEP 643 + dynamic: list[str] + + # Metadata 2.3 - PEP 685 + # No new fields were added in PEP 685, just some edge case were + # tightened up to provide better interoptability. + + # Metadata 2.4 - PEP 639 + license_expression: str + license_files: list[str] + + +_STRING_FIELDS = { + "author", + "author_email", + "description", + "description_content_type", + "download_url", + "home_page", + "license", + "license_expression", + "maintainer", + "maintainer_email", + "metadata_version", + "name", + "requires_python", + "summary", + "version", +} + +_LIST_FIELDS = { + "classifiers", + "dynamic", + "license_files", + "obsoletes", + "obsoletes_dist", + "platforms", + "provides", + "provides_dist", + "provides_extra", + "requires", + "requires_dist", + "requires_external", + "supported_platforms", +} + +_DICT_FIELDS = { + "project_urls", +} + + +def _parse_keywords(data: str) -> list[str]: + """Split a string of comma-separated keywords into a list of keywords.""" + return [k.strip() for k in data.split(",")] + + +def _parse_project_urls(data: list[str]) -> dict[str, str]: + """Parse a list of label/URL string pairings separated by a comma.""" + urls = {} + for pair in data: + # Our logic is slightly tricky here as we want to try and do + # *something* reasonable with malformed data. + # + # The main thing that we have to worry about, is data that does + # not have a ',' at all to split the label from the Value. There + # isn't a singular right answer here, and we will fail validation + # later on (if the caller is validating) so it doesn't *really* + # matter, but since the missing value has to be an empty str + # and our return value is dict[str, str], if we let the key + # be the missing value, then they'd have multiple '' values that + # overwrite each other in a accumulating dict. + # + # The other potentional issue is that it's possible to have the + # same label multiple times in the metadata, with no solid "right" + # answer with what to do in that case. As such, we'll do the only + # thing we can, which is treat the field as unparseable and add it + # to our list of unparsed fields. + parts = [p.strip() for p in pair.split(",", 1)] + parts.extend([""] * (max(0, 2 - len(parts)))) # Ensure 2 items + + # TODO: The spec doesn't say anything about if the keys should be + # considered case sensitive or not... logically they should + # be case-preserving and case-insensitive, but doing that + # would open up more cases where we might have duplicate + # entries. + label, url = parts + if label in urls: + # The label already exists in our set of urls, so this field + # is unparseable, and we can just add the whole thing to our + # unparseable data and stop processing it. + raise KeyError("duplicate labels in project urls") + urls[label] = url + + return urls + + +def _get_payload(msg: email.message.Message, source: bytes | str) -> str: + """Get the body of the message.""" + # If our source is a str, then our caller has managed encodings for us, + # and we don't need to deal with it. + if isinstance(source, str): + payload = msg.get_payload() + assert isinstance(payload, str) + return payload + # If our source is a bytes, then we're managing the encoding and we need + # to deal with it. + else: + bpayload = msg.get_payload(decode=True) + assert isinstance(bpayload, bytes) + try: + return bpayload.decode("utf8", "strict") + except UnicodeDecodeError as exc: + raise ValueError("payload in an invalid encoding") from exc + + +# The various parse_FORMAT functions here are intended to be as lenient as +# possible in their parsing, while still returning a correctly typed +# RawMetadata. +# +# To aid in this, we also generally want to do as little touching of the +# data as possible, except where there are possibly some historic holdovers +# that make valid data awkward to work with. +# +# While this is a lower level, intermediate format than our ``Metadata`` +# class, some light touch ups can make a massive difference in usability. + +# Map METADATA fields to RawMetadata. +_EMAIL_TO_RAW_MAPPING = { + "author": "author", + "author-email": "author_email", + "classifier": "classifiers", + "description": "description", + "description-content-type": "description_content_type", + "download-url": "download_url", + "dynamic": "dynamic", + "home-page": "home_page", + "keywords": "keywords", + "license": "license", + "license-expression": "license_expression", + "license-file": "license_files", + "maintainer": "maintainer", + "maintainer-email": "maintainer_email", + "metadata-version": "metadata_version", + "name": "name", + "obsoletes": "obsoletes", + "obsoletes-dist": "obsoletes_dist", + "platform": "platforms", + "project-url": "project_urls", + "provides": "provides", + "provides-dist": "provides_dist", + "provides-extra": "provides_extra", + "requires": "requires", + "requires-dist": "requires_dist", + "requires-external": "requires_external", + "requires-python": "requires_python", + "summary": "summary", + "supported-platform": "supported_platforms", + "version": "version", +} +_RAW_TO_EMAIL_MAPPING = {raw: email for email, raw in _EMAIL_TO_RAW_MAPPING.items()} + + +def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]: + """Parse a distribution's metadata stored as email headers (e.g. from ``METADATA``). + + This function returns a two-item tuple of dicts. The first dict is of + recognized fields from the core metadata specification. Fields that can be + parsed and translated into Python's built-in types are converted + appropriately. All other fields are left as-is. Fields that are allowed to + appear multiple times are stored as lists. + + The second dict contains all other fields from the metadata. This includes + any unrecognized fields. It also includes any fields which are expected to + be parsed into a built-in type but were not formatted appropriately. Finally, + any fields that are expected to appear only once but are repeated are + included in this dict. + + """ + raw: dict[str, str | list[str] | dict[str, str]] = {} + unparsed: dict[str, list[str]] = {} + + if isinstance(data, str): + parsed = email.parser.Parser(policy=email.policy.compat32).parsestr(data) + else: + parsed = email.parser.BytesParser(policy=email.policy.compat32).parsebytes(data) + + # We have to wrap parsed.keys() in a set, because in the case of multiple + # values for a key (a list), the key will appear multiple times in the + # list of keys, but we're avoiding that by using get_all(). + for name in frozenset(parsed.keys()): + # Header names in RFC are case insensitive, so we'll normalize to all + # lower case to make comparisons easier. + name = name.lower() + + # We use get_all() here, even for fields that aren't multiple use, + # because otherwise someone could have e.g. two Name fields, and we + # would just silently ignore it rather than doing something about it. + headers = parsed.get_all(name) or [] + + # The way the email module works when parsing bytes is that it + # unconditionally decodes the bytes as ascii using the surrogateescape + # handler. When you pull that data back out (such as with get_all() ), + # it looks to see if the str has any surrogate escapes, and if it does + # it wraps it in a Header object instead of returning the string. + # + # As such, we'll look for those Header objects, and fix up the encoding. + value = [] + # Flag if we have run into any issues processing the headers, thus + # signalling that the data belongs in 'unparsed'. + valid_encoding = True + for h in headers: + # It's unclear if this can return more types than just a Header or + # a str, so we'll just assert here to make sure. + assert isinstance(h, (email.header.Header, str)) + + # If it's a header object, we need to do our little dance to get + # the real data out of it. In cases where there is invalid data + # we're going to end up with mojibake, but there's no obvious, good + # way around that without reimplementing parts of the Header object + # ourselves. + # + # That should be fine since, if mojibacked happens, this key is + # going into the unparsed dict anyways. + if isinstance(h, email.header.Header): + # The Header object stores it's data as chunks, and each chunk + # can be independently encoded, so we'll need to check each + # of them. + chunks: list[tuple[bytes, str | None]] = [] + for bin, encoding in email.header.decode_header(h): + try: + bin.decode("utf8", "strict") + except UnicodeDecodeError: + # Enable mojibake. + encoding = "latin1" + valid_encoding = False + else: + encoding = "utf8" + chunks.append((bin, encoding)) + + # Turn our chunks back into a Header object, then let that + # Header object do the right thing to turn them into a + # string for us. + value.append(str(email.header.make_header(chunks))) + # This is already a string, so just add it. + else: + value.append(h) + + # We've processed all of our values to get them into a list of str, + # but we may have mojibake data, in which case this is an unparsed + # field. + if not valid_encoding: + unparsed[name] = value + continue + + raw_name = _EMAIL_TO_RAW_MAPPING.get(name) + if raw_name is None: + # This is a bit of a weird situation, we've encountered a key that + # we don't know what it means, so we don't know whether it's meant + # to be a list or not. + # + # Since we can't really tell one way or another, we'll just leave it + # as a list, even though it may be a single item list, because that's + # what makes the most sense for email headers. + unparsed[name] = value + continue + + # If this is one of our string fields, then we'll check to see if our + # value is a list of a single item. If it is then we'll assume that + # it was emitted as a single string, and unwrap the str from inside + # the list. + # + # If it's any other kind of data, then we haven't the faintest clue + # what we should parse it as, and we have to just add it to our list + # of unparsed stuff. + if raw_name in _STRING_FIELDS and len(value) == 1: + raw[raw_name] = value[0] + # If this is one of our list of string fields, then we can just assign + # the value, since email *only* has strings, and our get_all() call + # above ensures that this is a list. + elif raw_name in _LIST_FIELDS: + raw[raw_name] = value + # Special Case: Keywords + # The keywords field is implemented in the metadata spec as a str, + # but it conceptually is a list of strings, and is serialized using + # ", ".join(keywords), so we'll do some light data massaging to turn + # this into what it logically is. + elif raw_name == "keywords" and len(value) == 1: + raw[raw_name] = _parse_keywords(value[0]) + # Special Case: Project-URL + # The project urls is implemented in the metadata spec as a list of + # specially-formatted strings that represent a key and a value, which + # is fundamentally a mapping, however the email format doesn't support + # mappings in a sane way, so it was crammed into a list of strings + # instead. + # + # We will do a little light data massaging to turn this into a map as + # it logically should be. + elif raw_name == "project_urls": + try: + raw[raw_name] = _parse_project_urls(value) + except KeyError: + unparsed[name] = value + # Nothing that we've done has managed to parse this, so it'll just + # throw it in our unparseable data and move on. + else: + unparsed[name] = value + + # We need to support getting the Description from the message payload in + # addition to getting it from the the headers. This does mean, though, there + # is the possibility of it being set both ways, in which case we put both + # in 'unparsed' since we don't know which is right. + try: + payload = _get_payload(parsed, data) + except ValueError: + unparsed.setdefault("description", []).append( + parsed.get_payload(decode=isinstance(data, bytes)) # type: ignore[call-overload] + ) + else: + if payload: + # Check to see if we've already got a description, if so then both + # it, and this body move to unparseable. + if "description" in raw: + description_header = cast(str, raw.pop("description")) + unparsed.setdefault("description", []).extend( + [description_header, payload] + ) + elif "description" in unparsed: + unparsed["description"].append(payload) + else: + raw["description"] = payload + + # We need to cast our `raw` to a metadata, because a TypedDict only support + # literal key names, but we're computing our key names on purpose, but the + # way this function is implemented, our `TypedDict` can only have valid key + # names. + return cast(RawMetadata, raw), unparsed + + +_NOT_FOUND = object() + + +# Keep the two values in sync. +_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] +_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] + +_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"]) + + +class _Validator(Generic[T]): + """Validate a metadata field. + + All _process_*() methods correspond to a core metadata field. The method is + called with the field's raw value. If the raw value is valid it is returned + in its "enriched" form (e.g. ``version.Version`` for the ``Version`` field). + If the raw value is invalid, :exc:`InvalidMetadata` is raised (with a cause + as appropriate). + """ + + name: str + raw_name: str + added: _MetadataVersion + + def __init__( + self, + *, + added: _MetadataVersion = "1.0", + ) -> None: + self.added = added + + def __set_name__(self, _owner: Metadata, name: str) -> None: + self.name = name + self.raw_name = _RAW_TO_EMAIL_MAPPING[name] + + def __get__(self, instance: Metadata, _owner: type[Metadata]) -> T: + # With Python 3.8, the caching can be replaced with functools.cached_property(). + # No need to check the cache as attribute lookup will resolve into the + # instance's __dict__ before __get__ is called. + cache = instance.__dict__ + value = instance._raw.get(self.name) + + # To make the _process_* methods easier, we'll check if the value is None + # and if this field is NOT a required attribute, and if both of those + # things are true, we'll skip the the converter. This will mean that the + # converters never have to deal with the None union. + if self.name in _REQUIRED_ATTRS or value is not None: + try: + converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") + except AttributeError: + pass + else: + value = converter(value) + + cache[self.name] = value + try: + del instance._raw[self.name] # type: ignore[misc] + except KeyError: + pass + + return cast(T, value) + + def _invalid_metadata( + self, msg: str, cause: Exception | None = None + ) -> InvalidMetadata: + exc = InvalidMetadata( + self.raw_name, msg.format_map({"field": repr(self.raw_name)}) + ) + exc.__cause__ = cause + return exc + + def _process_metadata_version(self, value: str) -> _MetadataVersion: + # Implicitly makes Metadata-Version required. + if value not in _VALID_METADATA_VERSIONS: + raise self._invalid_metadata(f"{value!r} is not a valid metadata version") + return cast(_MetadataVersion, value) + + def _process_name(self, value: str) -> str: + if not value: + raise self._invalid_metadata("{field} is a required field") + # Validate the name as a side-effect. + try: + utils.canonicalize_name(value, validate=True) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return value + + def _process_version(self, value: str) -> version_module.Version: + if not value: + raise self._invalid_metadata("{field} is a required field") + try: + return version_module.parse(value) + except version_module.InvalidVersion as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_summary(self, value: str) -> str: + """Check the field contains no newlines.""" + if "\n" in value: + raise self._invalid_metadata("{field} must be a single line") + return value + + def _process_description_content_type(self, value: str) -> str: + content_types = {"text/plain", "text/x-rst", "text/markdown"} + message = email.message.EmailMessage() + message["content-type"] = value + + content_type, parameters = ( + # Defaults to `text/plain` if parsing failed. + message.get_content_type().lower(), + message["content-type"].params, + ) + # Check if content-type is valid or defaulted to `text/plain` and thus was + # not parseable. + if content_type not in content_types or content_type not in value.lower(): + raise self._invalid_metadata( + f"{{field}} must be one of {list(content_types)}, not {value!r}" + ) + + charset = parameters.get("charset", "UTF-8") + if charset != "UTF-8": + raise self._invalid_metadata( + f"{{field}} can only specify the UTF-8 charset, not {list(charset)}" + ) + + markdown_variants = {"GFM", "CommonMark"} + variant = parameters.get("variant", "GFM") # Use an acceptable default. + if content_type == "text/markdown" and variant not in markdown_variants: + raise self._invalid_metadata( + f"valid Markdown variants for {{field}} are {list(markdown_variants)}, " + f"not {variant!r}", + ) + return value + + def _process_dynamic(self, value: list[str]) -> list[str]: + for dynamic_field in map(str.lower, value): + if dynamic_field in {"name", "version", "metadata-version"}: + raise self._invalid_metadata( + f"{dynamic_field!r} is not allowed as a dynamic field" + ) + elif dynamic_field not in _EMAIL_TO_RAW_MAPPING: + raise self._invalid_metadata( + f"{dynamic_field!r} is not a valid dynamic field" + ) + return list(map(str.lower, value)) + + def _process_provides_extra( + self, + value: list[str], + ) -> list[utils.NormalizedName]: + normalized_names = [] + try: + for name in value: + normalized_names.append(utils.canonicalize_name(name, validate=True)) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{name!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return normalized_names + + def _process_requires_python(self, value: str) -> specifiers.SpecifierSet: + try: + return specifiers.SpecifierSet(value) + except specifiers.InvalidSpecifier as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_requires_dist( + self, + value: list[str], + ) -> list[requirements.Requirement]: + reqs = [] + try: + for req in value: + reqs.append(requirements.Requirement(req)) + except requirements.InvalidRequirement as exc: + raise self._invalid_metadata( + f"{req!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return reqs + + def _process_license_expression( + self, value: str + ) -> NormalizedLicenseExpression | None: + try: + return licenses.canonicalize_license_expression(value) + except ValueError as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_license_files(self, value: list[str]) -> list[str]: + paths = [] + for path in value: + if ".." in path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, " + "parent directory indicators are not allowed" + ) + if "*" in path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, paths must be resolved" + ) + if ( + pathlib.PurePosixPath(path).is_absolute() + or pathlib.PureWindowsPath(path).is_absolute() + ): + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, paths must be relative" + ) + if pathlib.PureWindowsPath(path).as_posix() != path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, " + "paths must use '/' delimiter" + ) + paths.append(path) + return paths + + +class Metadata: + """Representation of distribution metadata. + + Compared to :class:`RawMetadata`, this class provides objects representing + metadata fields instead of only using built-in types. Any invalid metadata + will cause :exc:`InvalidMetadata` to be raised (with a + :py:attr:`~BaseException.__cause__` attribute as appropriate). + """ + + _raw: RawMetadata + + @classmethod + def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata: + """Create an instance from :class:`RawMetadata`. + + If *validate* is true, all metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + ins = cls() + ins._raw = data.copy() # Mutations occur due to caching enriched values. + + if validate: + exceptions: list[Exception] = [] + try: + metadata_version = ins.metadata_version + metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) + except InvalidMetadata as metadata_version_exc: + exceptions.append(metadata_version_exc) + metadata_version = None + + # Make sure to check for the fields that are present, the required + # fields (so their absence can be reported). + fields_to_check = frozenset(ins._raw) | _REQUIRED_ATTRS + # Remove fields that have already been checked. + fields_to_check -= {"metadata_version"} + + for key in fields_to_check: + try: + if metadata_version: + # Can't use getattr() as that triggers descriptor protocol which + # will fail due to no value for the instance argument. + try: + field_metadata_version = cls.__dict__[key].added + except KeyError: + exc = InvalidMetadata(key, f"unrecognized field: {key!r}") + exceptions.append(exc) + continue + field_age = _VALID_METADATA_VERSIONS.index( + field_metadata_version + ) + if field_age > metadata_age: + field = _RAW_TO_EMAIL_MAPPING[key] + exc = InvalidMetadata( + field, + f"{field} introduced in metadata version " + f"{field_metadata_version}, not {metadata_version}", + ) + exceptions.append(exc) + continue + getattr(ins, key) + except InvalidMetadata as exc: + exceptions.append(exc) + + if exceptions: + raise ExceptionGroup("invalid metadata", exceptions) + + return ins + + @classmethod + def from_email(cls, data: bytes | str, *, validate: bool = True) -> Metadata: + """Parse metadata from email headers. + + If *validate* is true, the metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + raw, unparsed = parse_email(data) + + if validate: + exceptions: list[Exception] = [] + for unparsed_key in unparsed: + if unparsed_key in _EMAIL_TO_RAW_MAPPING: + message = f"{unparsed_key!r} has invalid data" + else: + message = f"unrecognized field: {unparsed_key!r}" + exceptions.append(InvalidMetadata(unparsed_key, message)) + + if exceptions: + raise ExceptionGroup("unparsed", exceptions) + + try: + return cls.from_raw(raw, validate=validate) + except ExceptionGroup as exc_group: + raise ExceptionGroup( + "invalid or unparsed metadata", exc_group.exceptions + ) from None + + metadata_version: _Validator[_MetadataVersion] = _Validator() + """:external:ref:`core-metadata-metadata-version` + (required; validated to be a valid metadata version)""" + # `name` is not normalized/typed to NormalizedName so as to provide access to + # the original/raw name. + name: _Validator[str] = _Validator() + """:external:ref:`core-metadata-name` + (required; validated using :func:`~packaging.utils.canonicalize_name` and its + *validate* parameter)""" + version: _Validator[version_module.Version] = _Validator() + """:external:ref:`core-metadata-version` (required)""" + dynamic: _Validator[list[str] | None] = _Validator( + added="2.2", + ) + """:external:ref:`core-metadata-dynamic` + (validated against core metadata field names and lowercased)""" + platforms: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-platform`""" + supported_platforms: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-supported-platform`""" + summary: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-summary` (validated to contain no newlines)""" + description: _Validator[str | None] = _Validator() # TODO 2.1: can be in body + """:external:ref:`core-metadata-description`""" + description_content_type: _Validator[str | None] = _Validator(added="2.1") + """:external:ref:`core-metadata-description-content-type` (validated)""" + keywords: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-keywords`""" + home_page: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-home-page`""" + download_url: _Validator[str | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-download-url`""" + author: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author`""" + author_email: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author-email`""" + maintainer: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer`""" + maintainer_email: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer-email`""" + license: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-license`""" + license_expression: _Validator[NormalizedLicenseExpression | None] = _Validator( + added="2.4" + ) + """:external:ref:`core-metadata-license-expression`""" + license_files: _Validator[list[str] | None] = _Validator(added="2.4") + """:external:ref:`core-metadata-license-file`""" + classifiers: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-classifier`""" + requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-dist`""" + requires_python: _Validator[specifiers.SpecifierSet | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-python`""" + # Because `Requires-External` allows for non-PEP 440 version specifiers, we + # don't do any processing on the values. + requires_external: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-requires-external`""" + project_urls: _Validator[dict[str, str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-project-url`""" + # PEP 685 lets us raise an error if an extra doesn't pass `Name` validation + # regardless of metadata version. + provides_extra: _Validator[list[utils.NormalizedName] | None] = _Validator( + added="2.1", + ) + """:external:ref:`core-metadata-provides-extra`""" + provides_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-provides-dist`""" + obsoletes_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-obsoletes-dist`""" + requires: _Validator[list[str] | None] = _Validator(added="1.1") + """``Requires`` (deprecated)""" + provides: _Validator[list[str] | None] = _Validator(added="1.1") + """``Provides`` (deprecated)""" + obsoletes: _Validator[list[str] | None] = _Validator(added="1.1") + """``Obsoletes`` (deprecated)""" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/packaging/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/requirements.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/requirements.py new file mode 100644 index 0000000..4e068c9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/requirements.py @@ -0,0 +1,91 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import annotations + +from typing import Any, Iterator + +from ._parser import parse_requirement as _parse_requirement +from ._tokenizer import ParserSyntaxError +from .markers import Marker, _normalize_extra_values +from .specifiers import SpecifierSet +from .utils import canonicalize_name + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +class Requirement: + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string: str) -> None: + try: + parsed = _parse_requirement(requirement_string) + except ParserSyntaxError as e: + raise InvalidRequirement(str(e)) from e + + self.name: str = parsed.name + self.url: str | None = parsed.url or None + self.extras: set[str] = set(parsed.extras or []) + self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) + self.marker: Marker | None = None + if parsed.marker is not None: + self.marker = Marker.__new__(Marker) + self.marker._markers = _normalize_extra_values(parsed.marker) + + def _iter_parts(self, name: str) -> Iterator[str]: + yield name + + if self.extras: + formatted_extras = ",".join(sorted(self.extras)) + yield f"[{formatted_extras}]" + + if self.specifier: + yield str(self.specifier) + + if self.url: + yield f"@ {self.url}" + if self.marker: + yield " " + + if self.marker: + yield f"; {self.marker}" + + def __str__(self) -> str: + return "".join(self._iter_parts(self.name)) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash( + ( + self.__class__.__name__, + *self._iter_parts(canonicalize_name(self.name)), + ) + ) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Requirement): + return NotImplemented + + return ( + canonicalize_name(self.name) == canonicalize_name(other.name) + and self.extras == other.extras + and self.specifier == other.specifier + and self.url == other.url + and self.marker == other.marker + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py new file mode 100644 index 0000000..f18016e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py @@ -0,0 +1,1020 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +.. testsetup:: + + from pip._vendor.packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier + from pip._vendor.packaging.version import Version +""" + +from __future__ import annotations + +import abc +import itertools +import re +from typing import Callable, Iterable, Iterator, TypeVar, Union + +from .utils import canonicalize_version +from .version import Version + +UnparsedVersion = Union[Version, str] +UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion) +CallableOperator = Callable[[Version, str], bool] + + +def _coerce_version(version: UnparsedVersion) -> Version: + if not isinstance(version, Version): + version = Version(version) + return version + + +class InvalidSpecifier(ValueError): + """ + Raised when attempting to create a :class:`Specifier` with a specifier + string that is invalid. + + >>> Specifier("lolwat") + Traceback (most recent call last): + ... + packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat' + """ + + +class BaseSpecifier(metaclass=abc.ABCMeta): + @abc.abstractmethod + def __str__(self) -> str: + """ + Returns the str representation of this Specifier-like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self) -> int: + """ + Returns a hash value for this Specifier-like object. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Returns a boolean representing whether or not the two Specifier-like + objects are equal. + + :param other: The other object to check against. + """ + + @property + @abc.abstractmethod + def prereleases(self) -> bool | None: + """Whether or not pre-releases as a whole are allowed. + + This can be set to either ``True`` or ``False`` to explicitly enable or disable + prereleases or it can be set to ``None`` (the default) to use default semantics. + """ + + @prereleases.setter + def prereleases(self, value: bool) -> None: + """Setter for :attr:`prereleases`. + + :param value: The value to set. + """ + + @abc.abstractmethod + def contains(self, item: str, prereleases: bool | None = None) -> bool: + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class Specifier(BaseSpecifier): + """This class abstracts handling of version specifiers. + + .. tip:: + + It is generally not required to instantiate this manually. You should instead + prefer to work with :class:`SpecifierSet` instead, which can parse + comma-separated version specifiers (which is what package metadata contains). + """ + + _operator_regex_str = r""" + (?P(~=|==|!=|<=|>=|<|>|===)) + """ + _version_regex_str = r""" + (?P + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s;)]* # The arbitrary version can be just about anything, + # we match everything except for whitespace, a + # semi-colon for marker support, and a closing paren + # since versions can be enclosed in them. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + + # You cannot use a wild card and a pre-release, post-release, a dev or + # local version together so group them with a | and make them optional. + (?: + \.\* # Wild card syntax of .* + | + (?: # pre release + [-_\.]? + (alpha|beta|preview|pre|a|b|c|rc) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (alpha|beta|preview|pre|a|b|c|rc) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + def __init__(self, spec: str = "", prereleases: bool | None = None) -> None: + """Initialize a Specifier instance. + + :param spec: + The string representation of a specifier which will be parsed and + normalized before use. + :param prereleases: + This tells the specifier if it should accept prerelease versions if + applicable or not. The default of ``None`` will autodetect it from the + given specifiers. + :raises InvalidSpecifier: + If the given specifier is invalid (i.e. bad syntax). + """ + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier(f"Invalid specifier: {spec!r}") + + self._spec: tuple[str, str] = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515 + @property # type: ignore[override] + def prereleases(self) -> bool: + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "===", ">", "<"]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if Version(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value: bool) -> None: + self._prereleases = value + + @property + def operator(self) -> str: + """The operator of this specifier. + + >>> Specifier("==1.2.3").operator + '==' + """ + return self._spec[0] + + @property + def version(self) -> str: + """The version of this specifier. + + >>> Specifier("==1.2.3").version + '1.2.3' + """ + return self._spec[1] + + def __repr__(self) -> str: + """A representation of the Specifier that shows all internal state. + + >>> Specifier('>=1.0.0') + =1.0.0')> + >>> Specifier('>=1.0.0', prereleases=False) + =1.0.0', prereleases=False)> + >>> Specifier('>=1.0.0', prereleases=True) + =1.0.0', prereleases=True)> + """ + pre = ( + f", prereleases={self.prereleases!r}" + if self._prereleases is not None + else "" + ) + + return f"<{self.__class__.__name__}({str(self)!r}{pre})>" + + def __str__(self) -> str: + """A string representation of the Specifier that can be round-tripped. + + >>> str(Specifier('>=1.0.0')) + '>=1.0.0' + >>> str(Specifier('>=1.0.0', prereleases=False)) + '>=1.0.0' + """ + return "{}{}".format(*self._spec) + + @property + def _canonical_spec(self) -> tuple[str, str]: + canonical_version = canonicalize_version( + self._spec[1], + strip_trailing_zero=(self._spec[0] != "~="), + ) + return self._spec[0], canonical_version + + def __hash__(self) -> int: + return hash(self._canonical_spec) + + def __eq__(self, other: object) -> bool: + """Whether or not the two Specifier-like objects are equal. + + :param other: The other object to check against. + + The value of :attr:`prereleases` is ignored. + + >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0") + True + >>> (Specifier("==1.2.3", prereleases=False) == + ... Specifier("==1.2.3", prereleases=True)) + True + >>> Specifier("==1.2.3") == "==1.2.3" + True + >>> Specifier("==1.2.3") == Specifier("==1.2.4") + False + >>> Specifier("==1.2.3") == Specifier("~=1.2.3") + False + """ + if isinstance(other, str): + try: + other = self.__class__(str(other)) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._canonical_spec == other._canonical_spec + + def _get_operator(self, op: str) -> CallableOperator: + operator_callable: CallableOperator = getattr( + self, f"_compare_{self._operators[op]}" + ) + return operator_callable + + def _compare_compatible(self, prospective: Version, spec: str) -> bool: + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore suffix segments. + prefix = _version_join( + list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( + prospective, prefix + ) + + def _compare_equal(self, prospective: Version, spec: str) -> bool: + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + normalized_prospective = canonicalize_version( + prospective.public, strip_trailing_zero=False + ) + # Get the normalized version string ignoring the trailing .* + normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False) + # Split the spec out by bangs and dots, and pretend that there is + # an implicit dot in between a release segment and a pre-release segment. + split_spec = _version_split(normalized_spec) + + # Split the prospective version out by bangs and dots, and pretend + # that there is an implicit dot in between a release segment and + # a pre-release segment. + split_prospective = _version_split(normalized_prospective) + + # 0-pad the prospective version before shortening it to get the correct + # shortened version. + padded_prospective, _ = _pad_version(split_prospective, split_spec) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + shortened_prospective = padded_prospective[: len(split_spec)] + + return shortened_prospective == split_spec + else: + # Convert our spec string into a Version + spec_version = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec_version.local: + prospective = Version(prospective.public) + + return prospective == spec_version + + def _compare_not_equal(self, prospective: Version, spec: str) -> bool: + return not self._compare_equal(prospective, spec) + + def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool: + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) <= Version(spec) + + def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool: + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) >= Version(spec) + + def _compare_less_than(self, prospective: Version, spec_str: str) -> bool: + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool: + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is technically greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: + return str(prospective).lower() == str(spec).lower() + + def __contains__(self, item: str | Version) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: The item to check for. + + This is used for the ``in`` operator and behaves the same as + :meth:`contains` with no ``prereleases`` argument passed. + + >>> "1.2.3" in Specifier(">=1.2.3") + True + >>> Version("1.2.3") in Specifier(">=1.2.3") + True + >>> "1.0.0" in Specifier(">=1.2.3") + False + >>> "1.3.0a1" in Specifier(">=1.2.3") + False + >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True) + True + """ + return self.contains(item) + + def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: + The item to check for, which can be a version string or a + :class:`Version` instance. + :param prereleases: + Whether or not to match prereleases with this Specifier. If set to + ``None`` (the default), it uses :attr:`prereleases` to determine + whether or not prereleases are allowed. + + >>> Specifier(">=1.2.3").contains("1.2.3") + True + >>> Specifier(">=1.2.3").contains(Version("1.2.3")) + True + >>> Specifier(">=1.2.3").contains("1.0.0") + False + >>> Specifier(">=1.2.3").contains("1.3.0a1") + False + >>> Specifier(">=1.2.3", prereleases=True).contains("1.3.0a1") + True + >>> Specifier(">=1.2.3").contains("1.3.0a1", prereleases=True) + True + """ + + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version, this allows us to have a shortcut for + # "2.0" in Specifier(">=2") + normalized_item = _coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if normalized_item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + operator_callable: CallableOperator = self._get_operator(self.operator) + return operator_callable(normalized_item, self.version) + + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """Filter items in the given iterable, that match the specifier. + + :param iterable: + An iterable that can contain version strings and :class:`Version` instances. + The items in the iterable will be filtered according to the specifier. + :param prereleases: + Whether or not to allow prereleases in the returned iterator. If set to + ``None`` (the default), it will be intelligently decide whether to allow + prereleases or not (based on the :attr:`prereleases` attribute, and + whether the only versions matching are prereleases). + + This method is smarter than just ``filter(Specifier().contains, [...])`` + because it implements the rule from :pep:`440` that a prerelease item + SHOULD be accepted if no other versions match the given specifier. + + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) + ['1.3'] + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")])) + ['1.2.3', '1.3', ] + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"])) + ['1.5a1'] + >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + """ + + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = _coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later in case nothing + # else matches this specifier. + if parsed_version.is_prerelease and not ( + prereleases or self.prereleases + ): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version: str) -> list[str]: + """Split version into components. + + The split components are intended for version comparison. The logic does + not attempt to retain the original version string, so joining the + components back with :func:`_version_join` may not produce the original + version string. + """ + result: list[str] = [] + + epoch, _, rest = version.rpartition("!") + result.append(epoch or "0") + + for item in rest.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _version_join(components: list[str]) -> str: + """Join split version components into a version string. + + This function assumes the input came from :func:`_version_split`, where the + first component must be the epoch (either empty or numeric), and all other + components numeric. + """ + epoch, *rest = components + return f"{epoch}!{'.'.join(rest)}" + + +def _is_not_suffix(segment: str) -> bool: + return not any( + segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") + ) + + +def _pad_version(left: list[str], right: list[str]) -> tuple[list[str], list[str]]: + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]) :]) + right_split.append(right[len(right_split[0]) :]) + + # Insert our padding + left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) + right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) + + return ( + list(itertools.chain.from_iterable(left_split)), + list(itertools.chain.from_iterable(right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + """This class abstracts handling of a set of version specifiers. + + It can be passed a single specifier (``>=3.0``), a comma-separated list of + specifiers (``>=3.0,!=3.1``), or no specifier at all. + """ + + def __init__( + self, + specifiers: str | Iterable[Specifier] = "", + prereleases: bool | None = None, + ) -> None: + """Initialize a SpecifierSet instance. + + :param specifiers: + The string representation of a specifier or a comma-separated list of + specifiers which will be parsed and normalized before use. + May also be an iterable of ``Specifier`` instances, which will be used + as is. + :param prereleases: + This tells the SpecifierSet if it should accept prerelease versions if + applicable or not. The default of ``None`` will autodetect it from the + given specifiers. + + :raises InvalidSpecifier: + If the given ``specifiers`` are not parseable than this exception will be + raised. + """ + + if isinstance(specifiers, str): + # Split on `,` to break each individual specifier into its own item, and + # strip each item to remove leading/trailing whitespace. + split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Make each individual specifier a Specifier and save in a frozen set + # for later. + self._specs = frozenset(map(Specifier, split_specifiers)) + else: + # Save the supplied specifiers in a frozen set. + self._specs = frozenset(specifiers) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + @property + def prereleases(self) -> bool | None: + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value: bool) -> None: + self._prereleases = value + + def __repr__(self) -> str: + """A representation of the specifier set that shows all internal state. + + Note that the ordering of the individual specifiers within the set may not + match the input string. + + >>> SpecifierSet('>=1.0.0,!=2.0.0') + =1.0.0')> + >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False) + =1.0.0', prereleases=False)> + >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True) + =1.0.0', prereleases=True)> + """ + pre = ( + f", prereleases={self.prereleases!r}" + if self._prereleases is not None + else "" + ) + + return f"" + + def __str__(self) -> str: + """A string representation of the specifier set that can be round-tripped. + + Note that the ordering of the individual specifiers within the set may not + match the input string. + + >>> str(SpecifierSet(">=1.0.0,!=1.0.1")) + '!=1.0.1,>=1.0.0' + >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False)) + '!=1.0.1,>=1.0.0' + """ + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self) -> int: + return hash(self._specs) + + def __and__(self, other: SpecifierSet | str) -> SpecifierSet: + """Return a SpecifierSet which is a combination of the two sets. + + :param other: The other object to combine with. + + >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1' + =1.0.0')> + >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1') + =1.0.0')> + """ + if isinstance(other, str): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other: object) -> bool: + """Whether or not the two SpecifierSet-like objects are equal. + + :param other: The other object to check against. + + The value of :attr:`prereleases` is ignored. + + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) == + ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)) + True + >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1" + True + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2") + False + """ + if isinstance(other, (str, Specifier)): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __len__(self) -> int: + """Returns the number of specifiers in this specifier set.""" + return len(self._specs) + + def __iter__(self) -> Iterator[Specifier]: + """ + Returns an iterator over all the underlying :class:`Specifier` instances + in this specifier set. + + >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str) + [, =1.0.0')>] + """ + return iter(self._specs) + + def __contains__(self, item: UnparsedVersion) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: The item to check for. + + This is used for the ``in`` operator and behaves the same as + :meth:`contains` with no ``prereleases`` argument passed. + + >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1") + False + >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1") + False + >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True) + True + """ + return self.contains(item) + + def contains( + self, + item: UnparsedVersion, + prereleases: bool | None = None, + installed: bool | None = None, + ) -> bool: + """Return whether or not the item is contained in this SpecifierSet. + + :param item: + The item to check for, which can be a version string or a + :class:`Version` instance. + :param prereleases: + Whether or not to match prereleases with this SpecifierSet. If set to + ``None`` (the default), it uses :attr:`prereleases` to determine + whether or not prereleases are allowed. + + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3") + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3")) + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True).contains("1.3.0a1") + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True) + True + """ + # Ensure that our item is a Version instance. + if not isinstance(item, Version): + item = Version(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + if installed and item.is_prerelease: + item = Version(item.base_version) + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all(s.contains(item, prereleases=prereleases) for s in self._specs) + + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """Filter items in the given iterable, that match the specifiers in this set. + + :param iterable: + An iterable that can contain version strings and :class:`Version` instances. + The items in the iterable will be filtered according to the specifier. + :param prereleases: + Whether or not to allow prereleases in the returned iterator. If set to + ``None`` (the default), it will be intelligently decide whether to allow + prereleases or not (based on the :attr:`prereleases` attribute, and + whether the only versions matching are prereleases). + + This method is smarter than just ``filter(SpecifierSet(...).contains, [...])`` + because it implements the rule from :pep:`440` that a prerelease item + SHOULD be accepted if no other versions match the given specifier. + + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) + ['1.3'] + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")])) + ['1.3', ] + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"])) + [] + >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + + An "empty" SpecifierSet will filter items based on the presence of prerelease + versions in the set. + + >>> list(SpecifierSet("").filter(["1.3", "1.5a1"])) + ['1.3'] + >>> list(SpecifierSet("").filter(["1.5a1"])) + ['1.5a1'] + >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + """ + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iter(iterable) + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases. + else: + filtered: list[UnparsedVersionVar] = [] + found_prereleases: list[UnparsedVersionVar] = [] + + for item in iterable: + parsed_version = _coerce_version(item) + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return iter(found_prereleases) + + return iter(filtered) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/tags.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/tags.py new file mode 100644 index 0000000..f590340 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/tags.py @@ -0,0 +1,617 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import logging +import platform +import re +import struct +import subprocess +import sys +import sysconfig +from importlib.machinery import EXTENSION_SUFFIXES +from typing import ( + Iterable, + Iterator, + Sequence, + Tuple, + cast, +) + +from . import _manylinux, _musllinux + +logger = logging.getLogger(__name__) + +PythonVersion = Sequence[int] +AppleVersion = Tuple[int, int] + +INTERPRETER_SHORT_NAMES: dict[str, str] = { + "python": "py", # Generic. + "cpython": "cp", + "pypy": "pp", + "ironpython": "ip", + "jython": "jy", +} + + +_32_BIT_INTERPRETER = struct.calcsize("P") == 4 + + +class Tag: + """ + A representation of the tag triple for a wheel. + + Instances are considered immutable and thus are hashable. Equality checking + is also supported. + """ + + __slots__ = ["_abi", "_hash", "_interpreter", "_platform"] + + def __init__(self, interpreter: str, abi: str, platform: str) -> None: + self._interpreter = interpreter.lower() + self._abi = abi.lower() + self._platform = platform.lower() + # The __hash__ of every single element in a Set[Tag] will be evaluated each time + # that a set calls its `.disjoint()` method, which may be called hundreds of + # times when scanning a page of links for packages with tags matching that + # Set[Tag]. Pre-computing the value here produces significant speedups for + # downstream consumers. + self._hash = hash((self._interpreter, self._abi, self._platform)) + + @property + def interpreter(self) -> str: + return self._interpreter + + @property + def abi(self) -> str: + return self._abi + + @property + def platform(self) -> str: + return self._platform + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Tag): + return NotImplemented + + return ( + (self._hash == other._hash) # Short-circuit ASAP for perf reasons. + and (self._platform == other._platform) + and (self._abi == other._abi) + and (self._interpreter == other._interpreter) + ) + + def __hash__(self) -> int: + return self._hash + + def __str__(self) -> str: + return f"{self._interpreter}-{self._abi}-{self._platform}" + + def __repr__(self) -> str: + return f"<{self} @ {id(self)}>" + + +def parse_tag(tag: str) -> frozenset[Tag]: + """ + Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. + + Returning a set is required due to the possibility that the tag is a + compressed tag set. + """ + tags = set() + interpreters, abis, platforms = tag.split("-") + for interpreter in interpreters.split("."): + for abi in abis.split("."): + for platform_ in platforms.split("."): + tags.add(Tag(interpreter, abi, platform_)) + return frozenset(tags) + + +def _get_config_var(name: str, warn: bool = False) -> int | str | None: + value: int | str | None = sysconfig.get_config_var(name) + if value is None and warn: + logger.debug( + "Config variable '%s' is unset, Python ABI tag may be incorrect", name + ) + return value + + +def _normalize_string(string: str) -> str: + return string.replace(".", "_").replace("-", "_").replace(" ", "_") + + +def _is_threaded_cpython(abis: list[str]) -> bool: + """ + Determine if the ABI corresponds to a threaded (`--disable-gil`) build. + + The threaded builds are indicated by a "t" in the abiflags. + """ + if len(abis) == 0: + return False + # expect e.g., cp313 + m = re.match(r"cp\d+(.*)", abis[0]) + if not m: + return False + abiflags = m.group(1) + return "t" in abiflags + + +def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool: + """ + Determine if the Python version supports abi3. + + PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`) + builds do not support abi3. + """ + return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading + + +def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]: + py_version = tuple(py_version) # To allow for version comparison. + abis = [] + version = _version_nodot(py_version[:2]) + threading = debug = pymalloc = ucs4 = "" + with_debug = _get_config_var("Py_DEBUG", warn) + has_refcount = hasattr(sys, "gettotalrefcount") + # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled + # extension modules is the best option. + # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 + has_ext = "_d.pyd" in EXTENSION_SUFFIXES + if with_debug or (with_debug is None and (has_refcount or has_ext)): + debug = "d" + if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn): + threading = "t" + if py_version < (3, 8): + with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) + if with_pymalloc or with_pymalloc is None: + pymalloc = "m" + if py_version < (3, 3): + unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) + if unicode_size == 4 or ( + unicode_size is None and sys.maxunicode == 0x10FFFF + ): + ucs4 = "u" + elif debug: + # Debug builds can also load "normal" extension modules. + # We can also assume no UCS-4 or pymalloc requirement. + abis.append(f"cp{version}{threading}") + abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}") + return abis + + +def cpython_tags( + python_version: PythonVersion | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = None, + *, + warn: bool = False, +) -> Iterator[Tag]: + """ + Yields the tags for a CPython interpreter. + + The tags consist of: + - cp-- + - cp-abi3- + - cp-none- + - cp-abi3- # Older Python versions down to 3.2. + + If python_version only specifies a major version then user-provided ABIs and + the 'none' ABItag will be used. + + If 'abi3' or 'none' are specified in 'abis' then they will be yielded at + their normal position and not at the beginning. + """ + if not python_version: + python_version = sys.version_info[:2] + + interpreter = f"cp{_version_nodot(python_version[:2])}" + + if abis is None: + if len(python_version) > 1: + abis = _cpython_abis(python_version, warn) + else: + abis = [] + abis = list(abis) + # 'abi3' and 'none' are explicitly handled later. + for explicit_abi in ("abi3", "none"): + try: + abis.remove(explicit_abi) + except ValueError: + pass + + platforms = list(platforms or platform_tags()) + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + + threading = _is_threaded_cpython(abis) + use_abi3 = _abi3_applies(python_version, threading) + if use_abi3: + yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) + yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) + + if use_abi3: + for minor_version in range(python_version[1] - 1, 1, -1): + for platform_ in platforms: + version = _version_nodot((python_version[0], minor_version)) + interpreter = f"cp{version}" + yield Tag(interpreter, "abi3", platform_) + + +def _generic_abi() -> list[str]: + """ + Return the ABI tag based on EXT_SUFFIX. + """ + # The following are examples of `EXT_SUFFIX`. + # We want to keep the parts which are related to the ABI and remove the + # parts which are related to the platform: + # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 + # - mac: '.cpython-310-darwin.so' => cp310 + # - win: '.cp310-win_amd64.pyd' => cp310 + # - win: '.pyd' => cp37 (uses _cpython_abis()) + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 + # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' + # => graalpy_38_native + + ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) + if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": + raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") + parts = ext_suffix.split(".") + if len(parts) < 3: + # CPython3.7 and earlier uses ".pyd" on Windows. + return _cpython_abis(sys.version_info[:2]) + soabi = parts[1] + if soabi.startswith("cpython"): + # non-windows + abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("cp"): + # windows + abi = soabi.split("-")[0] + elif soabi.startswith("pypy"): + abi = "-".join(soabi.split("-")[:2]) + elif soabi.startswith("graalpy"): + abi = "-".join(soabi.split("-")[:3]) + elif soabi: + # pyston, ironpython, others? + abi = soabi + else: + return [] + return [_normalize_string(abi)] + + +def generic_tags( + interpreter: str | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = None, + *, + warn: bool = False, +) -> Iterator[Tag]: + """ + Yields the tags for a generic interpreter. + + The tags consist of: + - -- + + The "none" ABI will be added if it was not explicitly provided. + """ + if not interpreter: + interp_name = interpreter_name() + interp_version = interpreter_version(warn=warn) + interpreter = "".join([interp_name, interp_version]) + if abis is None: + abis = _generic_abi() + else: + abis = list(abis) + platforms = list(platforms or platform_tags()) + if "none" not in abis: + abis.append("none") + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + + +def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: + """ + Yields Python versions in descending order. + + After the latest version, the major-only version will be yielded, and then + all previous versions of that major version. + """ + if len(py_version) > 1: + yield f"py{_version_nodot(py_version[:2])}" + yield f"py{py_version[0]}" + if len(py_version) > 1: + for minor in range(py_version[1] - 1, -1, -1): + yield f"py{_version_nodot((py_version[0], minor))}" + + +def compatible_tags( + python_version: PythonVersion | None = None, + interpreter: str | None = None, + platforms: Iterable[str] | None = None, +) -> Iterator[Tag]: + """ + Yields the sequence of tags that are compatible with a specific version of Python. + + The tags consist of: + - py*-none- + - -none-any # ... if `interpreter` is provided. + - py*-none-any + """ + if not python_version: + python_version = sys.version_info[:2] + platforms = list(platforms or platform_tags()) + for version in _py_interpreter_range(python_version): + for platform_ in platforms: + yield Tag(version, "none", platform_) + if interpreter: + yield Tag(interpreter, "none", "any") + for version in _py_interpreter_range(python_version): + yield Tag(version, "none", "any") + + +def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: + if not is_32bit: + return arch + + if arch.startswith("ppc"): + return "ppc" + + return "i386" + + +def _mac_binary_formats(version: AppleVersion, cpu_arch: str) -> list[str]: + formats = [cpu_arch] + if cpu_arch == "x86_64": + if version < (10, 4): + return [] + formats.extend(["intel", "fat64", "fat32"]) + + elif cpu_arch == "i386": + if version < (10, 4): + return [] + formats.extend(["intel", "fat32", "fat"]) + + elif cpu_arch == "ppc64": + # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? + if version > (10, 5) or version < (10, 4): + return [] + formats.append("fat64") + + elif cpu_arch == "ppc": + if version > (10, 6): + return [] + formats.extend(["fat32", "fat"]) + + if cpu_arch in {"arm64", "x86_64"}: + formats.append("universal2") + + if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: + formats.append("universal") + + return formats + + +def mac_platforms( + version: AppleVersion | None = None, arch: str | None = None +) -> Iterator[str]: + """ + Yields the platform tags for a macOS system. + + The `version` parameter is a two-item tuple specifying the macOS version to + generate platform tags for. The `arch` parameter is the CPU architecture to + generate platform tags for. Both parameters default to the appropriate value + for the current system. + """ + version_str, _, cpu_arch = platform.mac_ver() + if version is None: + version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) + if version == (10, 16): + # When built against an older macOS SDK, Python will report macOS 10.16 + # instead of the real version. + version_str = subprocess.run( + [ + sys.executable, + "-sS", + "-c", + "import platform; print(platform.mac_ver()[0])", + ], + check=True, + env={"SYSTEM_VERSION_COMPAT": "0"}, + stdout=subprocess.PIPE, + text=True, + ).stdout + version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) + else: + version = version + if arch is None: + arch = _mac_arch(cpu_arch) + else: + arch = arch + + if (10, 0) <= version and version < (11, 0): + # Prior to Mac OS 11, each yearly release of Mac OS bumped the + # "minor" version number. The major version was always 10. + major_version = 10 + for minor_version in range(version[1], -1, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + if version >= (11, 0): + # Starting with Mac OS 11, each yearly release bumps the major version + # number. The minor versions are now the midyear updates. + minor_version = 0 + for major_version in range(version[0], 10, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + if version >= (11, 0): + # Mac OS 11 on x86_64 is compatible with binaries from previous releases. + # Arm64 support was introduced in 11.0, so no Arm binaries from previous + # releases exist. + # + # However, the "universal2" binary format can have a + # macOS version earlier than 11.0 when the x86_64 part of the binary supports + # that version of macOS. + major_version = 10 + if arch == "x86_64": + for minor_version in range(16, 3, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + else: + for minor_version in range(16, 3, -1): + compat_version = major_version, minor_version + binary_format = "universal2" + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + +def ios_platforms( + version: AppleVersion | None = None, multiarch: str | None = None +) -> Iterator[str]: + """ + Yields the platform tags for an iOS system. + + :param version: A two-item tuple specifying the iOS version to generate + platform tags for. Defaults to the current iOS version. + :param multiarch: The CPU architecture+ABI to generate platform tags for - + (the value used by `sys.implementation._multiarch` e.g., + `arm64_iphoneos` or `x84_64_iphonesimulator`). Defaults to the current + multiarch value. + """ + if version is None: + # if iOS is the current platform, ios_ver *must* be defined. However, + # it won't exist for CPython versions before 3.13, which causes a mypy + # error. + _, release, _, _ = platform.ios_ver() # type: ignore[attr-defined, unused-ignore] + version = cast("AppleVersion", tuple(map(int, release.split(".")[:2]))) + + if multiarch is None: + multiarch = sys.implementation._multiarch + multiarch = multiarch.replace("-", "_") + + ios_platform_template = "ios_{major}_{minor}_{multiarch}" + + # Consider any iOS major.minor version from the version requested, down to + # 12.0. 12.0 is the first iOS version that is known to have enough features + # to support CPython. Consider every possible minor release up to X.9. There + # highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra + # candidates that won't ever match doesn't really hurt, and it saves us from + # having to keep an explicit list of known iOS versions in the code. Return + # the results descending order of version number. + + # If the requested major version is less than 12, there won't be any matches. + if version[0] < 12: + return + + # Consider the actual X.Y version that was requested. + yield ios_platform_template.format( + major=version[0], minor=version[1], multiarch=multiarch + ) + + # Consider every minor version from X.0 to the minor version prior to the + # version requested by the platform. + for minor in range(version[1] - 1, -1, -1): + yield ios_platform_template.format( + major=version[0], minor=minor, multiarch=multiarch + ) + + for major in range(version[0] - 1, 11, -1): + for minor in range(9, -1, -1): + yield ios_platform_template.format( + major=major, minor=minor, multiarch=multiarch + ) + + +def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: + linux = _normalize_string(sysconfig.get_platform()) + if not linux.startswith("linux_"): + # we should never be here, just yield the sysconfig one and return + yield linux + return + if is_32bit: + if linux == "linux_x86_64": + linux = "linux_i686" + elif linux == "linux_aarch64": + linux = "linux_armv8l" + _, arch = linux.split("_", 1) + archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch]) + yield from _manylinux.platform_tags(archs) + yield from _musllinux.platform_tags(archs) + for arch in archs: + yield f"linux_{arch}" + + +def _generic_platforms() -> Iterator[str]: + yield _normalize_string(sysconfig.get_platform()) + + +def platform_tags() -> Iterator[str]: + """ + Provides the platform tags for this installation. + """ + if platform.system() == "Darwin": + return mac_platforms() + elif platform.system() == "iOS": + return ios_platforms() + elif platform.system() == "Linux": + return _linux_platforms() + else: + return _generic_platforms() + + +def interpreter_name() -> str: + """ + Returns the name of the running interpreter. + + Some implementations have a reserved, two-letter abbreviation which will + be returned when appropriate. + """ + name = sys.implementation.name + return INTERPRETER_SHORT_NAMES.get(name) or name + + +def interpreter_version(*, warn: bool = False) -> str: + """ + Returns the version of the running interpreter. + """ + version = _get_config_var("py_version_nodot", warn=warn) + if version: + version = str(version) + else: + version = _version_nodot(sys.version_info[:2]) + return version + + +def _version_nodot(version: PythonVersion) -> str: + return "".join(map(str, version)) + + +def sys_tags(*, warn: bool = False) -> Iterator[Tag]: + """ + Returns the sequence of tag triples for the running interpreter. + + The order of the sequence corresponds to priority order for the + interpreter, from most to least important. + """ + + interp_name = interpreter_name() + if interp_name == "cp": + yield from cpython_tags(warn=warn) + else: + yield from generic_tags() + + if interp_name == "pp": + interp = "pp3" + elif interp_name == "cp": + interp = "cp" + interpreter_version(warn=warn) + else: + interp = None + yield from compatible_tags(interpreter=interp) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/utils.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/utils.py new file mode 100644 index 0000000..2345095 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/utils.py @@ -0,0 +1,163 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import functools +import re +from typing import NewType, Tuple, Union, cast + +from .tags import Tag, parse_tag +from .version import InvalidVersion, Version, _TrimmedRelease + +BuildTag = Union[Tuple[()], Tuple[int, str]] +NormalizedName = NewType("NormalizedName", str) + + +class InvalidName(ValueError): + """ + An invalid distribution name; users should refer to the packaging user guide. + """ + + +class InvalidWheelFilename(ValueError): + """ + An invalid wheel filename was found, users should refer to PEP 427. + """ + + +class InvalidSdistFilename(ValueError): + """ + An invalid sdist filename was found, users should refer to the packaging user guide. + """ + + +# Core metadata spec for `Name` +_validate_regex = re.compile( + r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE +) +_canonicalize_regex = re.compile(r"[-_.]+") +_normalized_regex = re.compile(r"^([a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9])$") +# PEP 427: The build number must start with a digit. +_build_tag_regex = re.compile(r"(\d+)(.*)") + + +def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName: + if validate and not _validate_regex.match(name): + raise InvalidName(f"name is invalid: {name!r}") + # This is taken from PEP 503. + value = _canonicalize_regex.sub("-", name).lower() + return cast(NormalizedName, value) + + +def is_normalized_name(name: str) -> bool: + return _normalized_regex.match(name) is not None + + +@functools.singledispatch +def canonicalize_version( + version: Version | str, *, strip_trailing_zero: bool = True +) -> str: + """ + Return a canonical form of a version as a string. + + >>> canonicalize_version('1.0.1') + '1.0.1' + + Per PEP 625, versions may have multiple canonical forms, differing + only by trailing zeros. + + >>> canonicalize_version('1.0.0') + '1' + >>> canonicalize_version('1.0.0', strip_trailing_zero=False) + '1.0.0' + + Invalid versions are returned unaltered. + + >>> canonicalize_version('foo bar baz') + 'foo bar baz' + """ + return str(_TrimmedRelease(str(version)) if strip_trailing_zero else version) + + +@canonicalize_version.register +def _(version: str, *, strip_trailing_zero: bool = True) -> str: + try: + parsed = Version(version) + except InvalidVersion: + # Legacy versions cannot be normalized + return version + return canonicalize_version(parsed, strip_trailing_zero=strip_trailing_zero) + + +def parse_wheel_filename( + filename: str, +) -> tuple[NormalizedName, Version, BuildTag, frozenset[Tag]]: + if not filename.endswith(".whl"): + raise InvalidWheelFilename( + f"Invalid wheel filename (extension must be '.whl'): {filename!r}" + ) + + filename = filename[:-4] + dashes = filename.count("-") + if dashes not in (4, 5): + raise InvalidWheelFilename( + f"Invalid wheel filename (wrong number of parts): {filename!r}" + ) + + parts = filename.split("-", dashes - 2) + name_part = parts[0] + # See PEP 427 for the rules on escaping the project name. + if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: + raise InvalidWheelFilename(f"Invalid project name: {filename!r}") + name = canonicalize_name(name_part) + + try: + version = Version(parts[1]) + except InvalidVersion as e: + raise InvalidWheelFilename( + f"Invalid wheel filename (invalid version): {filename!r}" + ) from e + + if dashes == 5: + build_part = parts[2] + build_match = _build_tag_regex.match(build_part) + if build_match is None: + raise InvalidWheelFilename( + f"Invalid build number: {build_part} in {filename!r}" + ) + build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) + else: + build = () + tags = parse_tag(parts[-1]) + return (name, version, build, tags) + + +def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]: + if filename.endswith(".tar.gz"): + file_stem = filename[: -len(".tar.gz")] + elif filename.endswith(".zip"): + file_stem = filename[: -len(".zip")] + else: + raise InvalidSdistFilename( + f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" + f" {filename!r}" + ) + + # We are requiring a PEP 440 version, which cannot contain dashes, + # so we split on the last dash. + name_part, sep, version_part = file_stem.rpartition("-") + if not sep: + raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}") + + name = canonicalize_name(name_part) + + try: + version = Version(version_part) + except InvalidVersion as e: + raise InvalidSdistFilename( + f"Invalid sdist filename (invalid version): {filename!r}" + ) from e + + return (name, version) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/packaging/version.py b/backend/venv/Lib/site-packages/pip/_vendor/packaging/version.py new file mode 100644 index 0000000..21f44ca --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/packaging/version.py @@ -0,0 +1,582 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +.. testsetup:: + + from pip._vendor.packaging.version import parse, Version +""" + +from __future__ import annotations + +import itertools +import re +from typing import Any, Callable, NamedTuple, SupportsInt, Tuple, Union + +from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType + +__all__ = ["VERSION_PATTERN", "InvalidVersion", "Version", "parse"] + +LocalType = Tuple[Union[int, str], ...] + +CmpPrePostDevType = Union[InfinityType, NegativeInfinityType, Tuple[str, int]] +CmpLocalType = Union[ + NegativeInfinityType, + Tuple[Union[Tuple[int, str], Tuple[NegativeInfinityType, Union[int, str]]], ...], +] +CmpKey = Tuple[ + int, + Tuple[int, ...], + CmpPrePostDevType, + CmpPrePostDevType, + CmpPrePostDevType, + CmpLocalType, +] +VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool] + + +class _Version(NamedTuple): + epoch: int + release: tuple[int, ...] + dev: tuple[str, int] | None + pre: tuple[str, int] | None + post: tuple[str, int] | None + local: LocalType | None + + +def parse(version: str) -> Version: + """Parse the given version string. + + >>> parse('1.0.dev1') + + + :param version: The version string to parse. + :raises InvalidVersion: When the version string is not a valid version. + """ + return Version(version) + + +class InvalidVersion(ValueError): + """Raised when a version string is not a valid version. + + >>> Version("invalid") + Traceback (most recent call last): + ... + packaging.version.InvalidVersion: Invalid version: 'invalid' + """ + + +class _BaseVersion: + _key: tuple[Any, ...] + + def __hash__(self) -> int: + return hash(self._key) + + # Please keep the duplicated `isinstance` check + # in the six comparisons hereunder + # unless you find a way to avoid adding overhead function calls. + def __lt__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key < other._key + + def __le__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key <= other._key + + def __eq__(self, other: object) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key == other._key + + def __ge__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key >= other._key + + def __gt__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key > other._key + + def __ne__(self, other: object) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key != other._key + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +_VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P

        !I7S{BS4i1|@R7s@ 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/t64.exe b/backend/venv/Lib/site-packages/pip/_vendor/distlib/t64.exe new file mode 100644 index 0000000000000000000000000000000000000000..e8bebdba6d8f242244bf397ab067965d47c5093e GIT binary patch literal 108032 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%0AHbpwE%ZM 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 H#ex3;_fXA_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/util.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/util.py new file mode 100644 index 0000000..0d5bd7a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/util.py @@ -0,0 +1,1984 @@ +# +# Copyright (C) 2012-2023 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import codecs +from collections import deque +import contextlib +import csv +from glob import iglob as std_iglob +import io +import json +import logging +import os +import py_compile +import re +import socket +try: + import ssl +except ImportError: # pragma: no cover + ssl = None +import subprocess +import sys +import tarfile +import tempfile +import textwrap + +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import time + +from . import DistlibException +from .compat import (string_types, text_type, shutil, raw_input, StringIO, cache_from_source, urlopen, urljoin, httplib, + xmlrpclib, HTTPHandler, BaseConfigurator, valid_ident, Container, configparser, URLError, ZipFile, + fsdecode, unquote, urlparse) + +logger = logging.getLogger(__name__) + +# +# Requirement parsing code as per PEP 508 +# + +IDENTIFIER = re.compile(r'^([\w\.-]+)\s*') +VERSION_IDENTIFIER = re.compile(r'^([\w\.*+-]+)\s*') +COMPARE_OP = re.compile(r'^(<=?|>=?|={2,3}|[~!]=)\s*') +MARKER_OP = re.compile(r'^((<=?)|(>=?)|={2,3}|[~!]=|in|not\s+in)\s*') +OR = re.compile(r'^or\b\s*') +AND = re.compile(r'^and\b\s*') +NON_SPACE = re.compile(r'(\S+)\s*') +STRING_CHUNK = re.compile(r'([\s\w\.{}()*+#:;,/?!~`@$%^&=|<>\[\]-]+)') + + +def parse_marker(marker_string): + """ + Parse a marker string and return a dictionary containing a marker expression. + + The dictionary will contain keys "op", "lhs" and "rhs" for non-terminals in + the expression grammar, or strings. A string contained in quotes is to be + interpreted as a literal string, and a string not contained in quotes is a + variable (such as os_name). + """ + + def marker_var(remaining): + # either identifier, or literal string + m = IDENTIFIER.match(remaining) + if m: + result = m.groups()[0] + remaining = remaining[m.end():] + elif not remaining: + raise SyntaxError('unexpected end of input') + else: + q = remaining[0] + if q not in '\'"': + raise SyntaxError('invalid expression: %s' % remaining) + oq = '\'"'.replace(q, '') + remaining = remaining[1:] + parts = [q] + while remaining: + # either a string chunk, or oq, or q to terminate + if remaining[0] == q: + break + elif remaining[0] == oq: + parts.append(oq) + remaining = remaining[1:] + else: + m = STRING_CHUNK.match(remaining) + if not m: + raise SyntaxError('error in string literal: %s' % remaining) + parts.append(m.groups()[0]) + remaining = remaining[m.end():] + else: + s = ''.join(parts) + raise SyntaxError('unterminated string: %s' % s) + parts.append(q) + result = ''.join(parts) + remaining = remaining[1:].lstrip() # skip past closing quote + return result, remaining + + def marker_expr(remaining): + if remaining and remaining[0] == '(': + result, remaining = marker(remaining[1:].lstrip()) + if remaining[0] != ')': + raise SyntaxError('unterminated parenthesis: %s' % remaining) + remaining = remaining[1:].lstrip() + else: + lhs, remaining = marker_var(remaining) + while remaining: + m = MARKER_OP.match(remaining) + if not m: + break + op = m.groups()[0] + remaining = remaining[m.end():] + rhs, remaining = marker_var(remaining) + lhs = {'op': op, 'lhs': lhs, 'rhs': rhs} + result = lhs + return result, remaining + + def marker_and(remaining): + lhs, remaining = marker_expr(remaining) + while remaining: + m = AND.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_expr(remaining) + lhs = {'op': 'and', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + def marker(remaining): + lhs, remaining = marker_and(remaining) + while remaining: + m = OR.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_and(remaining) + lhs = {'op': 'or', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + return marker(marker_string) + + +def parse_requirement(req): + """ + Parse a requirement passed in as a string. Return a Container + whose attributes contain the various parts of the requirement. + """ + remaining = req.strip() + if not remaining or remaining.startswith('#'): + return None + m = IDENTIFIER.match(remaining) + if not m: + raise SyntaxError('name expected: %s' % remaining) + distname = m.groups()[0] + remaining = remaining[m.end():] + extras = mark_expr = versions = uri = None + if remaining and remaining[0] == '[': + i = remaining.find(']', 1) + if i < 0: + raise SyntaxError('unterminated extra: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + extras = [] + while s: + m = IDENTIFIER.match(s) + if not m: + raise SyntaxError('malformed extra: %s' % s) + extras.append(m.groups()[0]) + s = s[m.end():] + if not s: + break + if s[0] != ',': + raise SyntaxError('comma expected in extras: %s' % s) + s = s[1:].lstrip() + if not extras: + extras = None + if remaining: + if remaining[0] == '@': + # it's a URI + remaining = remaining[1:].lstrip() + m = NON_SPACE.match(remaining) + if not m: + raise SyntaxError('invalid URI: %s' % remaining) + uri = m.groups()[0] + t = urlparse(uri) + # there are issues with Python and URL parsing, so this test + # is a bit crude. See bpo-20271, bpo-23505. Python doesn't + # always parse invalid URLs correctly - it should raise + # exceptions for malformed URLs + if not (t.scheme and t.netloc): + raise SyntaxError('Invalid URL: %s' % uri) + remaining = remaining[m.end():].lstrip() + else: + + def get_versions(ver_remaining): + """ + Return a list of operator, version tuples if any are + specified, else None. + """ + m = COMPARE_OP.match(ver_remaining) + versions = None + if m: + versions = [] + while True: + op = m.groups()[0] + ver_remaining = ver_remaining[m.end():] + m = VERSION_IDENTIFIER.match(ver_remaining) + if not m: + raise SyntaxError('invalid version: %s' % ver_remaining) + v = m.groups()[0] + versions.append((op, v)) + ver_remaining = ver_remaining[m.end():] + if not ver_remaining or ver_remaining[0] != ',': + break + ver_remaining = ver_remaining[1:].lstrip() + # Some packages have a trailing comma which would break things + # See issue #148 + if not ver_remaining: + break + m = COMPARE_OP.match(ver_remaining) + if not m: + raise SyntaxError('invalid constraint: %s' % ver_remaining) + if not versions: + versions = None + return versions, ver_remaining + + if remaining[0] != '(': + versions, remaining = get_versions(remaining) + else: + i = remaining.find(')', 1) + if i < 0: + raise SyntaxError('unterminated parenthesis: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + # As a special diversion from PEP 508, allow a version number + # a.b.c in parentheses as a synonym for ~= a.b.c (because this + # is allowed in earlier PEPs) + if COMPARE_OP.match(s): + versions, _ = get_versions(s) + else: + m = VERSION_IDENTIFIER.match(s) + if not m: + raise SyntaxError('invalid constraint: %s' % s) + v = m.groups()[0] + s = s[m.end():].lstrip() + if s: + raise SyntaxError('invalid constraint: %s' % s) + versions = [('~=', v)] + + if remaining: + if remaining[0] != ';': + raise SyntaxError('invalid requirement: %s' % remaining) + remaining = remaining[1:].lstrip() + + mark_expr, remaining = parse_marker(remaining) + + if remaining and remaining[0] != '#': + raise SyntaxError('unexpected trailing data: %s' % remaining) + + if not versions: + rs = distname + else: + rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions])) + return Container(name=distname, extras=extras, constraints=versions, marker=mark_expr, url=uri, requirement=rs) + + +def get_resources_dests(resources_root, rules): + """Find destinations for resources files""" + + def get_rel_path(root, path): + # normalizes and returns a lstripped-/-separated path + root = root.replace(os.path.sep, '/') + path = path.replace(os.path.sep, '/') + assert path.startswith(root) + return path[len(root):].lstrip('/') + + destinations = {} + for base, suffix, dest in rules: + prefix = os.path.join(resources_root, base) + for abs_base in iglob(prefix): + abs_glob = os.path.join(abs_base, suffix) + for abs_path in iglob(abs_glob): + resource_file = get_rel_path(resources_root, abs_path) + if dest is None: # remove the entry if it was here + destinations.pop(resource_file, None) + else: + rel_path = get_rel_path(abs_base, abs_path) + rel_dest = dest.replace(os.path.sep, '/').rstrip('/') + destinations[resource_file] = rel_dest + '/' + rel_path + return destinations + + +def in_venv(): + if hasattr(sys, 'real_prefix'): + # virtualenv venvs + result = True + else: + # PEP 405 venvs + result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix) + return result + + +def get_executable(): + # The __PYVENV_LAUNCHER__ dance is apparently no longer needed, as + # changes to the stub launcher mean that sys.executable always points + # to the stub on OS X + # if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__' + # in os.environ): + # result = os.environ['__PYVENV_LAUNCHER__'] + # else: + # result = sys.executable + # return result + # Avoid normcasing: see issue #143 + # result = os.path.normcase(sys.executable) + result = sys.executable + if not isinstance(result, text_type): + result = fsdecode(result) + return result + + +def proceed(prompt, allowed_chars, error_prompt=None, default=None): + p = prompt + while True: + s = raw_input(p) + p = prompt + if not s and default: + s = default + if s: + c = s[0].lower() + if c in allowed_chars: + break + if error_prompt: + p = '%c: %s\n%s' % (c, error_prompt, prompt) + return c + + +def extract_by_key(d, keys): + if isinstance(keys, string_types): + keys = keys.split() + result = {} + for key in keys: + if key in d: + result[key] = d[key] + return result + + +def read_exports(stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + # Try to load as JSON, falling back on legacy format + data = stream.read() + stream = StringIO(data) + try: + jdata = json.load(stream) + result = jdata['extensions']['python.exports']['exports'] + for group, entries in result.items(): + for k, v in entries.items(): + s = '%s = %s' % (k, v) + entry = get_export_entry(s) + assert entry is not None + entries[k] = entry + return result + except Exception: + stream.seek(0, 0) + + def read_stream(cp, stream): + if hasattr(cp, 'read_file'): + cp.read_file(stream) + else: + cp.readfp(stream) + + cp = configparser.ConfigParser() + try: + read_stream(cp, stream) + except configparser.MissingSectionHeaderError: + stream.close() + data = textwrap.dedent(data) + stream = StringIO(data) + read_stream(cp, stream) + + result = {} + for key in cp.sections(): + result[key] = entries = {} + for name, value in cp.items(key): + s = '%s = %s' % (name, value) + entry = get_export_entry(s) + assert entry is not None + # entry.dist = self + entries[name] = entry + return result + + +def write_exports(exports, stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getwriter('utf-8')(stream) + cp = configparser.ConfigParser() + for k, v in exports.items(): + # TODO check k, v for valid values + cp.add_section(k) + for entry in v.values(): + if entry.suffix is None: + s = entry.prefix + else: + s = '%s:%s' % (entry.prefix, entry.suffix) + if entry.flags: + s = '%s [%s]' % (s, ', '.join(entry.flags)) + cp.set(k, entry.name, s) + cp.write(stream) + + +@contextlib.contextmanager +def tempdir(): + td = tempfile.mkdtemp() + try: + yield td + finally: + shutil.rmtree(td) + + +@contextlib.contextmanager +def chdir(d): + cwd = os.getcwd() + try: + os.chdir(d) + yield + finally: + os.chdir(cwd) + + +@contextlib.contextmanager +def socket_timeout(seconds=15): + cto = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(seconds) + yield + finally: + socket.setdefaulttimeout(cto) + + +class cached_property(object): + + def __init__(self, func): + self.func = func + # for attr in ('__name__', '__module__', '__doc__'): + # setattr(self, attr, getattr(func, attr, None)) + + def __get__(self, obj, cls=None): + if obj is None: + return self + value = self.func(obj) + object.__setattr__(obj, self.func.__name__, value) + # obj.__dict__[self.func.__name__] = value = self.func(obj) + return value + + +def convert_path(pathname): + """Return 'pathname' as a name that will work on the native filesystem. + + The path is split on '/' and put back together again using the current + directory separator. Needed because filenames in the setup script are + always supplied in Unix style, and have to be converted to the local + convention before we can actually use them in the filesystem. Raises + ValueError on non-Unix-ish systems if 'pathname' either starts or + ends with a slash. + """ + if os.sep == '/': + return pathname + if not pathname: + return pathname + if pathname[0] == '/': + raise ValueError("path '%s' cannot be absolute" % pathname) + if pathname[-1] == '/': + raise ValueError("path '%s' cannot end with '/'" % pathname) + + paths = pathname.split('/') + while os.curdir in paths: + paths.remove(os.curdir) + if not paths: + return os.curdir + return os.path.join(*paths) + + +class FileOperator(object): + + def __init__(self, dry_run=False): + self.dry_run = dry_run + self.ensured = set() + self._init_record() + + def _init_record(self): + self.record = False + self.files_written = set() + self.dirs_created = set() + + def record_as_written(self, path): + if self.record: + self.files_written.add(path) + + def newer(self, source, target): + """Tell if the target is newer than the source. + + Returns true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. + + Returns false if both exist and 'target' is the same age or younger + than 'source'. Raise PackagingFileError if 'source' does not exist. + + Note that this test is not very accurate: files created in the same + second will have the same "age". + """ + if not os.path.exists(source): + raise DistlibException("file '%r' does not exist" % os.path.abspath(source)) + if not os.path.exists(target): + return True + + return os.stat(source).st_mtime > os.stat(target).st_mtime + + def copy_file(self, infile, outfile, check=True): + """Copy a file respecting dry-run and force flags. + """ + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying %s to %s', infile, outfile) + if not self.dry_run: + msg = None + if check: + if os.path.islink(outfile): + msg = '%s is a symlink' % outfile + elif os.path.exists(outfile) and not os.path.isfile(outfile): + msg = '%s is a non-regular file' % outfile + if msg: + raise ValueError(msg + ' which would be overwritten') + shutil.copyfile(infile, outfile) + self.record_as_written(outfile) + + def copy_stream(self, instream, outfile, encoding=None): + assert not os.path.isdir(outfile) + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying stream %s to %s', instream, outfile) + if not self.dry_run: + if encoding is None: + outstream = open(outfile, 'wb') + else: + outstream = codecs.open(outfile, 'w', encoding=encoding) + try: + shutil.copyfileobj(instream, outstream) + finally: + outstream.close() + self.record_as_written(outfile) + + def write_binary_file(self, path, data): + self.ensure_dir(os.path.dirname(path)) + if not self.dry_run: + if os.path.exists(path): + os.remove(path) + with open(path, 'wb') as f: + f.write(data) + self.record_as_written(path) + + def write_text_file(self, path, data, encoding): + self.write_binary_file(path, data.encode(encoding)) + + def set_mode(self, bits, mask, files): + if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'): + # Set the executable bits (owner, group, and world) on + # all the files specified. + for f in files: + if self.dry_run: + logger.info("changing mode of %s", f) + else: + mode = (os.stat(f).st_mode | bits) & mask + logger.info("changing mode of %s to %o", f, mode) + os.chmod(f, mode) + + set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f) + + def ensure_dir(self, path): + path = os.path.abspath(path) + if path not in self.ensured and not os.path.exists(path): + self.ensured.add(path) + d, f = os.path.split(path) + self.ensure_dir(d) + logger.info('Creating %s' % path) + if not self.dry_run: + os.mkdir(path) + if self.record: + self.dirs_created.add(path) + + def byte_compile(self, path, optimize=False, force=False, prefix=None, hashed_invalidation=False): + dpath = cache_from_source(path, not optimize) + logger.info('Byte-compiling %s to %s', path, dpath) + if not self.dry_run: + if force or self.newer(path, dpath): + if not prefix: + diagpath = None + else: + assert path.startswith(prefix) + diagpath = path[len(prefix):] + compile_kwargs = {} + if hashed_invalidation and hasattr(py_compile, 'PycInvalidationMode'): + if not isinstance(hashed_invalidation, py_compile.PycInvalidationMode): + hashed_invalidation = py_compile.PycInvalidationMode.CHECKED_HASH + compile_kwargs['invalidation_mode'] = hashed_invalidation + py_compile.compile(path, dpath, diagpath, True, **compile_kwargs) # raise error + self.record_as_written(dpath) + return dpath + + def ensure_removed(self, path): + if os.path.exists(path): + if os.path.isdir(path) and not os.path.islink(path): + logger.debug('Removing directory tree at %s', path) + if not self.dry_run: + shutil.rmtree(path) + if self.record: + if path in self.dirs_created: + self.dirs_created.remove(path) + else: + if os.path.islink(path): + s = 'link' + else: + s = 'file' + logger.debug('Removing %s %s', s, path) + if not self.dry_run: + os.remove(path) + if self.record: + if path in self.files_written: + self.files_written.remove(path) + + def is_writable(self, path): + result = False + while not result: + if os.path.exists(path): + result = os.access(path, os.W_OK) + break + parent = os.path.dirname(path) + if parent == path: + break + path = parent + return result + + def commit(self): + """ + Commit recorded changes, turn off recording, return + changes. + """ + assert self.record + result = self.files_written, self.dirs_created + self._init_record() + return result + + def rollback(self): + if not self.dry_run: + for f in list(self.files_written): + if os.path.exists(f): + os.remove(f) + # dirs should all be empty now, except perhaps for + # __pycache__ subdirs + # reverse so that subdirs appear before their parents + dirs = sorted(self.dirs_created, reverse=True) + for d in dirs: + flist = os.listdir(d) + if flist: + assert flist == ['__pycache__'] + sd = os.path.join(d, flist[0]) + os.rmdir(sd) + os.rmdir(d) # should fail if non-empty + self._init_record() + + +def resolve(module_name, dotted_path): + if module_name in sys.modules: + mod = sys.modules[module_name] + else: + mod = __import__(module_name) + if dotted_path is None: + result = mod + else: + parts = dotted_path.split('.') + result = getattr(mod, parts.pop(0)) + for p in parts: + result = getattr(result, p) + return result + + +class ExportEntry(object): + + def __init__(self, name, prefix, suffix, flags): + self.name = name + self.prefix = prefix + self.suffix = suffix + self.flags = flags + + @cached_property + def value(self): + return resolve(self.prefix, self.suffix) + + def __repr__(self): # pragma: no cover + return '' % (self.name, self.prefix, self.suffix, self.flags) + + def __eq__(self, other): + if not isinstance(other, ExportEntry): + result = False + else: + result = (self.name == other.name and self.prefix == other.prefix and self.suffix == other.suffix and + self.flags == other.flags) + return result + + __hash__ = object.__hash__ + + +ENTRY_RE = re.compile( + r'''(?P([^\[]\S*)) + \s*=\s*(?P(\w+)([:\.]\w+)*) + \s*(\[\s*(?P[\w-]+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])? + ''', re.VERBOSE) + + +def get_export_entry(specification): + m = ENTRY_RE.search(specification) + if not m: + result = None + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + else: + d = m.groupdict() + name = d['name'] + path = d['callable'] + colons = path.count(':') + if colons == 0: + prefix, suffix = path, None + else: + if colons != 1: + raise DistlibException("Invalid specification " + "'%s'" % specification) + prefix, suffix = path.split(':') + flags = d['flags'] + if flags is None: + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + flags = [] + else: + flags = [f.strip() for f in flags.split(',')] + result = ExportEntry(name, prefix, suffix, flags) + return result + + +def get_cache_base(suffix=None): + """ + Return the default base location for distlib caches. If the directory does + not exist, it is created. Use the suffix provided for the base directory, + and default to '.distlib' if it isn't provided. + + On Windows, if LOCALAPPDATA is defined in the environment, then it is + assumed to be a directory, and will be the parent directory of the result. + On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home + directory - using os.expanduser('~') - will be the parent directory of + the result. + + The result is just the directory '.distlib' in the parent directory as + determined above, or with the name specified with ``suffix``. + """ + if suffix is None: + suffix = '.distlib' + if os.name == 'nt' and 'LOCALAPPDATA' in os.environ: + result = os.path.expandvars('$localappdata') + else: + # Assume posix, or old Windows + result = os.path.expanduser('~') + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if os.path.isdir(result): + usable = os.access(result, os.W_OK) + if not usable: + logger.warning('Directory exists but is not writable: %s', result) + else: + try: + os.makedirs(result) + usable = True + except OSError: + logger.warning('Unable to create %s', result, exc_info=True) + usable = False + if not usable: + result = tempfile.mkdtemp() + logger.warning('Default location unusable, using %s', result) + return os.path.join(result, suffix) + + +def path_to_cache_dir(path, use_abspath=True): + """ + Convert an absolute path to a directory name for use in a cache. + + The algorithm used is: + + #. On Windows, any ``':'`` in the drive is replaced with ``'---'``. + #. Any occurrence of ``os.sep`` is replaced with ``'--'``. + #. ``'.cache'`` is appended. + """ + d, p = os.path.splitdrive(os.path.abspath(path) if use_abspath else path) + if d: + d = d.replace(':', '---') + p = p.replace(os.sep, '--') + return d + p + '.cache' + + +def ensure_slash(s): + if not s.endswith('/'): + return s + '/' + return s + + +def parse_credentials(netloc): + username = password = None + if '@' in netloc: + prefix, netloc = netloc.rsplit('@', 1) + if ':' not in prefix: + username = prefix + else: + username, password = prefix.split(':', 1) + if username: + username = unquote(username) + if password: + password = unquote(password) + return username, password, netloc + + +def get_process_umask(): + result = os.umask(0o22) + os.umask(result) + return result + + +def is_string_sequence(seq): + result = True + i = None + for i, s in enumerate(seq): + if not isinstance(s, string_types): + result = False + break + assert i is not None + return result + + +PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-' + '([a-z0-9_.+-]+)', re.I) +PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)') + + +def split_filename(filename, project_name=None): + """ + Extract name, version, python version from a filename (no extension) + + Return name, version, pyver or None + """ + result = None + pyver = None + filename = unquote(filename).replace(' ', '-') + m = PYTHON_VERSION.search(filename) + if m: + pyver = m.group(1) + filename = filename[:m.start()] + if project_name and len(filename) > len(project_name) + 1: + m = re.match(re.escape(project_name) + r'\b', filename) + if m: + n = m.end() + result = filename[:n], filename[n + 1:], pyver + if result is None: + m = PROJECT_NAME_AND_VERSION.match(filename) + if m: + result = m.group(1), m.group(3), pyver + return result + + +# Allow spaces in name because of legacy dists like "Twisted Core" +NAME_VERSION_RE = re.compile(r'(?P[\w .-]+)\s*' + r'\(\s*(?P[^\s)]+)\)$') + + +def parse_name_and_version(p): + """ + A utility method used to get name and version from a string. + + From e.g. a Provides-Dist value. + + :param p: A value in a form 'foo (1.0)' + :return: The name and version as a tuple. + """ + m = NAME_VERSION_RE.match(p) + if not m: + raise DistlibException('Ill-formed name/version string: \'%s\'' % p) + d = m.groupdict() + return d['name'].strip().lower(), d['ver'] + + +def get_extras(requested, available): + result = set() + requested = set(requested or []) + available = set(available or []) + if '*' in requested: + requested.remove('*') + result |= available + for r in requested: + if r == '-': + result.add(r) + elif r.startswith('-'): + unwanted = r[1:] + if unwanted not in available: + logger.warning('undeclared extra: %s' % unwanted) + if unwanted in result: + result.remove(unwanted) + else: + if r not in available: + logger.warning('undeclared extra: %s' % r) + result.add(r) + return result + + +# +# Extended metadata functionality +# + + +def _get_external_data(url): + result = {} + try: + # urlopen might fail if it runs into redirections, + # because of Python issue #13696. Fixed in locators + # using a custom redirect handler. + resp = urlopen(url) + headers = resp.info() + ct = headers.get('Content-Type') + if not ct.startswith('application/json'): + logger.debug('Unexpected response for JSON request: %s', ct) + else: + reader = codecs.getreader('utf-8')(resp) + # data = reader.read().decode('utf-8') + # result = json.loads(data) + result = json.load(reader) + except Exception as e: + logger.exception('Failed to get external data for %s: %s', url, e) + return result + + +_external_data_base_url = 'https://www.red-dove.com/pypi/projects/' + + +def get_project_data(name): + url = '%s/%s/project.json' % (name[0].upper(), name) + url = urljoin(_external_data_base_url, url) + result = _get_external_data(url) + return result + + +def get_package_data(name, version): + url = '%s/%s/package-%s.json' % (name[0].upper(), name, version) + url = urljoin(_external_data_base_url, url) + return _get_external_data(url) + + +class Cache(object): + """ + A class implementing a cache for resources that need to live in the file system + e.g. shared libraries. This class was moved from resources to here because it + could be used by other modules, e.g. the wheel module. + """ + + def __init__(self, base): + """ + Initialise an instance. + + :param base: The base directory where the cache should be located. + """ + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if not os.path.isdir(base): # pragma: no cover + os.makedirs(base) + if (os.stat(base).st_mode & 0o77) != 0: + logger.warning('Directory \'%s\' is not private', base) + self.base = os.path.abspath(os.path.normpath(base)) + + def prefix_to_dir(self, prefix, use_abspath=True): + """ + Converts a resource prefix to a directory name in the cache. + """ + return path_to_cache_dir(prefix, use_abspath=use_abspath) + + def clear(self): + """ + Clear the cache. + """ + not_removed = [] + for fn in os.listdir(self.base): + fn = os.path.join(self.base, fn) + try: + if os.path.islink(fn) or os.path.isfile(fn): + os.remove(fn) + elif os.path.isdir(fn): + shutil.rmtree(fn) + except Exception: + not_removed.append(fn) + return not_removed + + +class EventMixin(object): + """ + A very simple publish/subscribe system. + """ + + def __init__(self): + self._subscribers = {} + + def add(self, event, subscriber, append=True): + """ + Add a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be added (and called when the + event is published). + :param append: Whether to append or prepend the subscriber to an + existing subscriber list for the event. + """ + subs = self._subscribers + if event not in subs: + subs[event] = deque([subscriber]) + else: + sq = subs[event] + if append: + sq.append(subscriber) + else: + sq.appendleft(subscriber) + + def remove(self, event, subscriber): + """ + Remove a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be removed. + """ + subs = self._subscribers + if event not in subs: + raise ValueError('No subscribers: %r' % event) + subs[event].remove(subscriber) + + def get_subscribers(self, event): + """ + Return an iterator for the subscribers for an event. + :param event: The event to return subscribers for. + """ + return iter(self._subscribers.get(event, ())) + + def publish(self, event, *args, **kwargs): + """ + Publish a event and return a list of values returned by its + subscribers. + + :param event: The event to publish. + :param args: The positional arguments to pass to the event's + subscribers. + :param kwargs: The keyword arguments to pass to the event's + subscribers. + """ + result = [] + for subscriber in self.get_subscribers(event): + try: + value = subscriber(event, *args, **kwargs) + except Exception: + logger.exception('Exception during event publication') + value = None + result.append(value) + logger.debug('publish %s: args = %s, kwargs = %s, result = %s', event, args, kwargs, result) + return result + + +# +# Simple sequencing +# +class Sequencer(object): + + def __init__(self): + self._preds = {} + self._succs = {} + self._nodes = set() # nodes with no preds/succs + + def add_node(self, node): + self._nodes.add(node) + + def remove_node(self, node, edges=False): + if node in self._nodes: + self._nodes.remove(node) + if edges: + for p in set(self._preds.get(node, ())): + self.remove(p, node) + for s in set(self._succs.get(node, ())): + self.remove(node, s) + # Remove empties + for k, v in list(self._preds.items()): + if not v: + del self._preds[k] + for k, v in list(self._succs.items()): + if not v: + del self._succs[k] + + def add(self, pred, succ): + assert pred != succ + self._preds.setdefault(succ, set()).add(pred) + self._succs.setdefault(pred, set()).add(succ) + + def remove(self, pred, succ): + assert pred != succ + try: + preds = self._preds[succ] + succs = self._succs[pred] + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of anything' % succ) + try: + preds.remove(pred) + succs.remove(succ) + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of %r' % (succ, pred)) + + def is_step(self, step): + return (step in self._preds or step in self._succs or step in self._nodes) + + def get_steps(self, final): + if not self.is_step(final): + raise ValueError('Unknown: %r' % final) + result = [] + todo = [] + seen = set() + todo.append(final) + while todo: + step = todo.pop(0) + if step in seen: + # if a step was already seen, + # move it to the end (so it will appear earlier + # when reversed on return) ... but not for the + # final step, as that would be confusing for + # users + if step != final: + result.remove(step) + result.append(step) + else: + seen.add(step) + result.append(step) + preds = self._preds.get(step, ()) + todo.extend(preds) + return reversed(result) + + @property + def strong_connections(self): + # http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + index_counter = [0] + stack = [] + lowlinks = {} + index = {} + result = [] + + graph = self._succs + + def strongconnect(node): + # set the depth index for this node to the smallest unused index + index[node] = index_counter[0] + lowlinks[node] = index_counter[0] + index_counter[0] += 1 + stack.append(node) + + # Consider successors + try: + successors = graph[node] + except Exception: + successors = [] + for successor in successors: + if successor not in lowlinks: + # Successor has not yet been visited + strongconnect(successor) + lowlinks[node] = min(lowlinks[node], lowlinks[successor]) + elif successor in stack: + # the successor is in the stack and hence in the current + # strongly connected component (SCC) + lowlinks[node] = min(lowlinks[node], index[successor]) + + # If `node` is a root node, pop the stack and generate an SCC + if lowlinks[node] == index[node]: + connected_component = [] + + while True: + successor = stack.pop() + connected_component.append(successor) + if successor == node: + break + component = tuple(connected_component) + # storing the result + result.append(component) + + for node in graph: + if node not in lowlinks: + strongconnect(node) + + return result + + @property + def dot(self): + result = ['digraph G {'] + for succ in self._preds: + preds = self._preds[succ] + for pred in preds: + result.append(' %s -> %s;' % (pred, succ)) + for node in self._nodes: + result.append(' %s;' % node) + result.append('}') + return '\n'.join(result) + + +# +# Unarchiving functionality for zip, tar, tgz, tbz, whl +# + +ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz', '.whl') + + +def unarchive(archive_filename, dest_dir, format=None, check=True): + + def check_path(path): + if not isinstance(path, text_type): + path = path.decode('utf-8') + p = os.path.abspath(os.path.join(dest_dir, path)) + if not p.startswith(dest_dir) or p[plen] != os.sep: + raise ValueError('path outside destination: %r' % p) + + dest_dir = os.path.abspath(dest_dir) + plen = len(dest_dir) + archive = None + if format is None: + if archive_filename.endswith(('.zip', '.whl')): + format = 'zip' + elif archive_filename.endswith(('.tar.gz', '.tgz')): + format = 'tgz' + mode = 'r:gz' + elif archive_filename.endswith(('.tar.bz2', '.tbz')): + format = 'tbz' + mode = 'r:bz2' + elif archive_filename.endswith('.tar'): + format = 'tar' + mode = 'r' + else: # pragma: no cover + raise ValueError('Unknown format for %r' % archive_filename) + try: + if format == 'zip': + archive = ZipFile(archive_filename, 'r') + if check: + names = archive.namelist() + for name in names: + check_path(name) + else: + archive = tarfile.open(archive_filename, mode) + if check: + names = archive.getnames() + for name in names: + check_path(name) + if format != 'zip' and sys.version_info[0] < 3: + # See Python issue 17153. If the dest path contains Unicode, + # tarfile extraction fails on Python 2.x if a member path name + # contains non-ASCII characters - it leads to an implicit + # bytes -> unicode conversion using ASCII to decode. + for tarinfo in archive.getmembers(): + if not isinstance(tarinfo.name, text_type): + tarinfo.name = tarinfo.name.decode('utf-8') + + # Limit extraction of dangerous items, if this Python + # allows it easily. If not, just trust the input. + # See: https://docs.python.org/3/library/tarfile.html#extraction-filters + def extraction_filter(member, path): + """Run tarfile.tar_filter, but raise the expected ValueError""" + # This is only called if the current Python has tarfile filters + try: + return tarfile.tar_filter(member, path) + except tarfile.FilterError as exc: + raise ValueError(str(exc)) + + archive.extraction_filter = extraction_filter + + archive.extractall(dest_dir) + + finally: + if archive: + archive.close() + + +def zip_dir(directory): + """zip a directory tree into a BytesIO object""" + result = io.BytesIO() + dlen = len(directory) + with ZipFile(result, "w") as zf: + for root, dirs, files in os.walk(directory): + for name in files: + full = os.path.join(root, name) + rel = root[dlen:] + dest = os.path.join(rel, name) + zf.write(full, dest) + return result + + +# +# Simple progress bar +# + +UNITS = ('', 'K', 'M', 'G', 'T', 'P') + + +class Progress(object): + unknown = 'UNKNOWN' + + def __init__(self, minval=0, maxval=100): + assert maxval is None or maxval >= minval + self.min = self.cur = minval + self.max = maxval + self.started = None + self.elapsed = 0 + self.done = False + + def update(self, curval): + assert self.min <= curval + assert self.max is None or curval <= self.max + self.cur = curval + now = time.time() + if self.started is None: + self.started = now + else: + self.elapsed = now - self.started + + def increment(self, incr): + assert incr >= 0 + self.update(self.cur + incr) + + def start(self): + self.update(self.min) + return self + + def stop(self): + if self.max is not None: + self.update(self.max) + self.done = True + + @property + def maximum(self): + return self.unknown if self.max is None else self.max + + @property + def percentage(self): + if self.done: + result = '100 %' + elif self.max is None: + result = ' ?? %' + else: + v = 100.0 * (self.cur - self.min) / (self.max - self.min) + result = '%3d %%' % v + return result + + def format_duration(self, duration): + if (duration <= 0) and self.max is None or self.cur == self.min: + result = '??:??:??' + # elif duration < 1: + # result = '--:--:--' + else: + result = time.strftime('%H:%M:%S', time.gmtime(duration)) + return result + + @property + def ETA(self): + if self.done: + prefix = 'Done' + t = self.elapsed + # import pdb; pdb.set_trace() + else: + prefix = 'ETA ' + if self.max is None: + t = -1 + elif self.elapsed == 0 or (self.cur == self.min): + t = 0 + else: + # import pdb; pdb.set_trace() + t = float(self.max - self.min) + t /= self.cur - self.min + t = (t - 1) * self.elapsed + return '%s: %s' % (prefix, self.format_duration(t)) + + @property + def speed(self): + if self.elapsed == 0: + result = 0.0 + else: + result = (self.cur - self.min) / self.elapsed + for unit in UNITS: + if result < 1000: + break + result /= 1000.0 + return '%d %sB/s' % (result, unit) + + +# +# Glob functionality +# + +RICH_GLOB = re.compile(r'\{([^}]*)\}') +_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]') +_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$') + + +def iglob(path_glob): + """Extended globbing function that supports ** and {opt1,opt2,opt3}.""" + if _CHECK_RECURSIVE_GLOB.search(path_glob): + msg = """invalid glob %r: recursive glob "**" must be used alone""" + raise ValueError(msg % path_glob) + if _CHECK_MISMATCH_SET.search(path_glob): + msg = """invalid glob %r: mismatching set marker '{' or '}'""" + raise ValueError(msg % path_glob) + return _iglob(path_glob) + + +def _iglob(path_glob): + rich_path_glob = RICH_GLOB.split(path_glob, 1) + if len(rich_path_glob) > 1: + assert len(rich_path_glob) == 3, rich_path_glob + prefix, set, suffix = rich_path_glob + for item in set.split(','): + for path in _iglob(''.join((prefix, item, suffix))): + yield path + else: + if '**' not in path_glob: + for item in std_iglob(path_glob): + yield item + else: + prefix, radical = path_glob.split('**', 1) + if prefix == '': + prefix = '.' + if radical == '': + radical = '*' + else: + # we support both + radical = radical.lstrip('/') + radical = radical.lstrip('\\') + for path, dir, files in os.walk(prefix): + path = os.path.normpath(path) + for fn in _iglob(os.path.join(path, radical)): + yield fn + + +if ssl: + from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname, CertificateError) + + # + # HTTPSConnection which verifies certificates/matches domains + # + + class HTTPSConnection(httplib.HTTPSConnection): + ca_certs = None # set this to the path to the certs file (.pem) + check_domain = True # only used if ca_certs is not None + + # noinspection PyPropertyAccess + def connect(self): + sock = socket.create_connection((self.host, self.port), self.timeout) + if getattr(self, '_tunnel_host', False): + self.sock = sock + self._tunnel() + + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + if hasattr(ssl, 'OP_NO_SSLv2'): + context.options |= ssl.OP_NO_SSLv2 + if getattr(self, 'cert_file', None): + context.load_cert_chain(self.cert_file, self.key_file) + kwargs = {} + if self.ca_certs: + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(cafile=self.ca_certs) + if getattr(ssl, 'HAS_SNI', False): + kwargs['server_hostname'] = self.host + + self.sock = context.wrap_socket(sock, **kwargs) + if self.ca_certs and self.check_domain: + try: + match_hostname(self.sock.getpeercert(), self.host) + logger.debug('Host verified: %s', self.host) + except CertificateError: # pragma: no cover + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + + class HTTPSHandler(BaseHTTPSHandler): + + def __init__(self, ca_certs, check_domain=True): + BaseHTTPSHandler.__init__(self) + self.ca_certs = ca_certs + self.check_domain = check_domain + + def _conn_maker(self, *args, **kwargs): + """ + This is called to create a connection instance. Normally you'd + pass a connection class to do_open, but it doesn't actually check for + a class, and just expects a callable. As long as we behave just as a + constructor would have, we should be OK. If it ever changes so that + we *must* pass a class, we'll create an UnsafeHTTPSConnection class + which just sets check_domain to False in the class definition, and + choose which one to pass to do_open. + """ + result = HTTPSConnection(*args, **kwargs) + if self.ca_certs: + result.ca_certs = self.ca_certs + result.check_domain = self.check_domain + return result + + def https_open(self, req): + try: + return self.do_open(self._conn_maker, req) + except URLError as e: + if 'certificate verify failed' in str(e.reason): + raise CertificateError('Unable to verify server certificate ' + 'for %s' % req.host) + else: + raise + + # + # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The- + # Middle proxy using HTTP listens on port 443, or an index mistakenly serves + # HTML containing a http://xyz link when it should be https://xyz), + # you can use the following handler class, which does not allow HTTP traffic. + # + # It works by inheriting from HTTPHandler - so build_opener won't add a + # handler for HTTP itself. + # + class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler): + + def http_open(self, req): + raise URLError('Unexpected HTTP request on what should be a secure ' + 'connection: %s' % req) + + +# +# XML-RPC with timeouts +# +class Transport(xmlrpclib.Transport): + + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.Transport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, x509 = self.get_host_info(host) + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPConnection(h) + return self._connection[1] + + +if ssl: + + class SafeTransport(xmlrpclib.SafeTransport): + + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.SafeTransport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, kwargs = self.get_host_info(host) + if not kwargs: + kwargs = {} + kwargs['timeout'] = self.timeout + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPSConnection(h, None, **kwargs) + return self._connection[1] + + +class ServerProxy(xmlrpclib.ServerProxy): + + def __init__(self, uri, **kwargs): + self.timeout = timeout = kwargs.pop('timeout', None) + # The above classes only come into play if a timeout + # is specified + if timeout is not None: + # scheme = splittype(uri) # deprecated as of Python 3.8 + scheme = urlparse(uri)[0] + use_datetime = kwargs.get('use_datetime', 0) + if scheme == 'https': + tcls = SafeTransport + else: + tcls = Transport + kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime) + self.transport = t + xmlrpclib.ServerProxy.__init__(self, uri, **kwargs) + + +# +# CSV functionality. This is provided because on 2.x, the csv module can't +# handle Unicode. However, we need to deal with Unicode in e.g. RECORD files. +# + + +def _csv_open(fn, mode, **kwargs): + if sys.version_info[0] < 3: + mode += 'b' + else: + kwargs['newline'] = '' + # Python 3 determines encoding from locale. Force 'utf-8' + # file encoding to match other forced utf-8 encoding + kwargs['encoding'] = 'utf-8' + return open(fn, mode, **kwargs) + + +class CSVBase(object): + defaults = { + 'delimiter': str(','), # The strs are used because we need native + 'quotechar': str('"'), # str in the csv API (2.x won't take + 'lineterminator': str('\n') # Unicode) + } + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.stream.close() + + +class CSVReader(CSVBase): + + def __init__(self, **kwargs): + if 'stream' in kwargs: + stream = kwargs['stream'] + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + self.stream = stream + else: + self.stream = _csv_open(kwargs['path'], 'r') + self.reader = csv.reader(self.stream, **self.defaults) + + def __iter__(self): + return self + + def next(self): + result = next(self.reader) + if sys.version_info[0] < 3: + for i, item in enumerate(result): + if not isinstance(item, text_type): + result[i] = item.decode('utf-8') + return result + + __next__ = next + + +class CSVWriter(CSVBase): + + def __init__(self, fn, **kwargs): + self.stream = _csv_open(fn, 'w') + self.writer = csv.writer(self.stream, **self.defaults) + + def writerow(self, row): + if sys.version_info[0] < 3: + r = [] + for item in row: + if isinstance(item, text_type): + item = item.encode('utf-8') + r.append(item) + row = r + self.writer.writerow(row) + + +# +# Configurator functionality +# + + +class Configurator(BaseConfigurator): + + value_converters = dict(BaseConfigurator.value_converters) + value_converters['inc'] = 'inc_convert' + + def __init__(self, config, base=None): + super(Configurator, self).__init__(config) + self.base = base or os.getcwd() + + def configure_custom(self, config): + + def convert(o): + if isinstance(o, (list, tuple)): + result = type(o)([convert(i) for i in o]) + elif isinstance(o, dict): + if '()' in o: + result = self.configure_custom(o) + else: + result = {} + for k in o: + result[k] = convert(o[k]) + else: + result = self.convert(o) + return result + + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + args = config.pop('[]', ()) + if args: + args = tuple([convert(o) for o in args]) + items = [(k, convert(config[k])) for k in config if valid_ident(k)] + kwargs = dict(items) + result = c(*args, **kwargs) + if props: + for n, v in props.items(): + setattr(result, n, convert(v)) + return result + + def __getitem__(self, key): + result = self.config[key] + if isinstance(result, dict) and '()' in result: + self.config[key] = result = self.configure_custom(result) + return result + + def inc_convert(self, value): + """Default converter for the inc:// protocol.""" + if not os.path.isabs(value): + value = os.path.join(self.base, value) + with codecs.open(value, 'r', encoding='utf-8') as f: + result = json.load(f) + return result + + +class SubprocessMixin(object): + """ + Mixin for running subprocesses and capturing their output + """ + + def __init__(self, verbose=False, progress=None): + self.verbose = verbose + self.progress = progress + + def reader(self, stream, context): + """ + Read lines from a subprocess' output stream and either pass to a progress + callable (if specified) or write progress information to sys.stderr. + """ + progress = self.progress + verbose = self.verbose + while True: + s = stream.readline() + if not s: + break + if progress is not None: + progress(s, context) + else: + if not verbose: + sys.stderr.write('.') + else: + sys.stderr.write(s.decode('utf-8')) + sys.stderr.flush() + stream.close() + + def run_command(self, cmd, **kwargs): + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) + t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout')) + t1.start() + t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr')) + t2.start() + p.wait() + t1.join() + t2.join() + if self.progress is not None: + self.progress('done.', 'main') + elif self.verbose: + sys.stderr.write('done.\n') + return p + + +def normalize_name(name): + """Normalize a python package name a la PEP 503""" + # https://www.python.org/dev/peps/pep-0503/#normalized-names + return re.sub('[-_.]+', '-', name).lower() + + +# def _get_pypirc_command(): +# """ +# Get the distutils command for interacting with PyPI configurations. +# :return: the command. +# """ +# from distutils.core import Distribution +# from distutils.config import PyPIRCCommand +# d = Distribution() +# return PyPIRCCommand(d) + + +class PyPIRCFile(object): + + DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/' + DEFAULT_REALM = 'pypi' + + def __init__(self, fn=None, url=None): + if fn is None: + fn = os.path.join(os.path.expanduser('~'), '.pypirc') + self.filename = fn + self.url = url + + def read(self): + result = {} + + if os.path.exists(self.filename): + repository = self.url or self.DEFAULT_REPOSITORY + + config = configparser.RawConfigParser() + config.read(self.filename) + sections = config.sections() + if 'distutils' in sections: + # let's get the list of servers + index_servers = config.get('distutils', 'index-servers') + _servers = [server.strip() for server in index_servers.split('\n') if server.strip() != ''] + if _servers == []: + # nothing set, let's try to get the default pypi + if 'pypi' in sections: + _servers = ['pypi'] + else: + for server in _servers: + result = {'server': server} + result['username'] = config.get(server, 'username') + + # optional params + for key, default in (('repository', self.DEFAULT_REPOSITORY), ('realm', self.DEFAULT_REALM), + ('password', None)): + if config.has_option(server, key): + result[key] = config.get(server, key) + else: + result[key] = default + + # work around people having "repository" for the "pypi" + # section of their config set to the HTTP (rather than + # HTTPS) URL + if (server == 'pypi' and repository in (self.DEFAULT_REPOSITORY, 'pypi')): + result['repository'] = self.DEFAULT_REPOSITORY + elif (result['server'] != repository and result['repository'] != repository): + result = {} + elif 'server-login' in sections: + # old format + server = 'server-login' + if config.has_option(server, 'repository'): + repository = config.get(server, 'repository') + else: + repository = self.DEFAULT_REPOSITORY + result = { + 'username': config.get(server, 'username'), + 'password': config.get(server, 'password'), + 'repository': repository, + 'server': server, + 'realm': self.DEFAULT_REALM + } + return result + + def update(self, username, password): + # import pdb; pdb.set_trace() + config = configparser.RawConfigParser() + fn = self.filename + config.read(fn) + if not config.has_section('pypi'): + config.add_section('pypi') + config.set('pypi', 'username', username) + config.set('pypi', 'password', password) + with open(fn, 'w') as f: + config.write(f) + + +def _load_pypirc(index): + """ + Read the PyPI access configuration as supported by distutils. + """ + return PyPIRCFile(url=index.url).read() + + +def _store_pypirc(index): + PyPIRCFile().update(index.username, index.password) + + +# +# get_platform()/get_host_platform() copied from Python 3.10.a0 source, with some minor +# tweaks +# + + +def get_host_platform(): + """Return a string that identifies the current platform. This is used mainly to + distinguish platform-specific build directories and platform-specific built + distributions. Typically includes the OS name and version and the + architecture (as supplied by 'os.uname()'), although the exact information + included depends on the OS; eg. on Linux, the kernel version isn't + particularly important. + + Examples of returned values: + linux-i586 + linux-alpha (?) + solaris-2.6-sun4u + + Windows will return one of: + win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. + + """ + if os.name == 'nt': + if 'amd64' in sys.version.lower(): + return 'win-amd64' + if '(arm)' in sys.version.lower(): + return 'win-arm32' + if '(arm64)' in sys.version.lower(): + return 'win-arm64' + return sys.platform + + # Set for cross builds explicitly + if "_PYTHON_HOST_PLATFORM" in os.environ: + return os.environ["_PYTHON_HOST_PLATFORM"] + + if os.name != 'posix' or not hasattr(os, 'uname'): + # XXX what about the architecture? NT is Intel or Alpha, + # Mac OS is M68k or PPC, etc. + return sys.platform + + # Try to distinguish various flavours of Unix + + (osname, host, release, version, machine) = os.uname() + + # Convert the OS name to lowercase, remove '/' characters, and translate + # spaces (for "Power Macintosh") + osname = osname.lower().replace('/', '') + machine = machine.replace(' ', '_').replace('/', '-') + + if osname[:5] == 'linux': + # At least on Linux/Intel, 'machine' is the processor -- + # i386, etc. + # XXX what about Alpha, SPARC, etc? + return "%s-%s" % (osname, machine) + + elif osname[:5] == 'sunos': + if release[0] >= '5': # SunOS 5 == Solaris 2 + osname = 'solaris' + release = '%d.%s' % (int(release[0]) - 3, release[2:]) + # We can't use 'platform.architecture()[0]' because a + # bootstrap problem. We use a dict to get an error + # if some suspicious happens. + bitness = {2147483647: '32bit', 9223372036854775807: '64bit'} + machine += '.%s' % bitness[sys.maxsize] + # fall through to standard osname-release-machine representation + elif osname[:3] == 'aix': + from _aix_support import aix_platform + return aix_platform() + elif osname[:6] == 'cygwin': + osname = 'cygwin' + rel_re = re.compile(r'[\d.]+', re.ASCII) + m = rel_re.match(release) + if m: + release = m.group() + elif osname[:6] == 'darwin': + import _osx_support + try: + from distutils import sysconfig + except ImportError: + import sysconfig + osname, release, machine = _osx_support.get_platform_osx(sysconfig.get_config_vars(), osname, release, machine) + + return '%s-%s-%s' % (osname, release, machine) + + +_TARGET_TO_PLAT = { + 'x86': 'win32', + 'x64': 'win-amd64', + 'arm': 'win-arm32', +} + + +def get_platform(): + if os.name != 'nt': + return get_host_platform() + cross_compilation_target = os.environ.get('VSCMD_ARG_TGT_ARCH') + if cross_compilation_target not in _TARGET_TO_PLAT: + return get_host_platform() + return _TARGET_TO_PLAT[cross_compilation_target] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/version.py b/backend/venv/Lib/site-packages/pip/_vendor/distlib/version.py new file mode 100644 index 0000000..d70a96e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/distlib/version.py @@ -0,0 +1,750 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2023 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Implementation of a flexible versioning scheme providing support for PEP-440, +setuptools-compatible and semantic versioning. +""" + +import logging +import re + +from .compat import string_types +from .util import parse_requirement + +__all__ = ['NormalizedVersion', 'NormalizedMatcher', + 'LegacyVersion', 'LegacyMatcher', + 'SemanticVersion', 'SemanticMatcher', + 'UnsupportedVersionError', 'get_scheme'] + +logger = logging.getLogger(__name__) + + +class UnsupportedVersionError(ValueError): + """This is an unsupported version.""" + pass + + +class Version(object): + def __init__(self, s): + self._string = s = s.strip() + self._parts = parts = self.parse(s) + assert isinstance(parts, tuple) + assert len(parts) > 0 + + def parse(self, s): + raise NotImplementedError('please implement in a subclass') + + def _check_compatible(self, other): + if type(self) != type(other): + raise TypeError('cannot compare %r and %r' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + def __lt__(self, other): + self._check_compatible(other) + return self._parts < other._parts + + def __gt__(self, other): + return not (self.__lt__(other) or self.__eq__(other)) + + def __le__(self, other): + return self.__lt__(other) or self.__eq__(other) + + def __ge__(self, other): + return self.__gt__(other) or self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self._parts) + + def __repr__(self): + return "%s('%s')" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + @property + def is_prerelease(self): + raise NotImplementedError('Please implement in subclasses.') + + +class Matcher(object): + version_class = None + + # value is either a callable or the name of a method + _operators = { + '<': lambda v, c, p: v < c, + '>': lambda v, c, p: v > c, + '<=': lambda v, c, p: v == c or v < c, + '>=': lambda v, c, p: v == c or v > c, + '==': lambda v, c, p: v == c, + '===': lambda v, c, p: v == c, + # by default, compatible => >=. + '~=': lambda v, c, p: v == c or v > c, + '!=': lambda v, c, p: v != c, + } + + # this is a method only to support alternative implementations + # via overriding + def parse_requirement(self, s): + return parse_requirement(s) + + def __init__(self, s): + if self.version_class is None: + raise ValueError('Please specify a version class') + self._string = s = s.strip() + r = self.parse_requirement(s) + if not r: + raise ValueError('Not valid: %r' % s) + self.name = r.name + self.key = self.name.lower() # for case-insensitive comparisons + clist = [] + if r.constraints: + # import pdb; pdb.set_trace() + for op, s in r.constraints: + if s.endswith('.*'): + if op not in ('==', '!='): + raise ValueError('\'.*\' not allowed for ' + '%r constraints' % op) + # Could be a partial version (e.g. for '2.*') which + # won't parse as a version, so keep it as a string + vn, prefix = s[:-2], True + # Just to check that vn is a valid version + self.version_class(vn) + else: + # Should parse as a version, so we can create an + # instance for the comparison + vn, prefix = self.version_class(s), False + clist.append((op, vn, prefix)) + self._parts = tuple(clist) + + def match(self, version): + """ + Check if the provided version matches the constraints. + + :param version: The version to match against this instance. + :type version: String or :class:`Version` instance. + """ + if isinstance(version, string_types): + version = self.version_class(version) + for operator, constraint, prefix in self._parts: + f = self._operators.get(operator) + if isinstance(f, string_types): + f = getattr(self, f) + if not f: + msg = ('%r not implemented ' + 'for %s' % (operator, self.__class__.__name__)) + raise NotImplementedError(msg) + if not f(version, constraint, prefix): + return False + return True + + @property + def exact_version(self): + result = None + if len(self._parts) == 1 and self._parts[0][0] in ('==', '==='): + result = self._parts[0][1] + return result + + def _check_compatible(self, other): + if type(self) != type(other) or self.name != other.name: + raise TypeError('cannot compare %s and %s' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self.key == other.key and self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self.key) + hash(self._parts) + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + +PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|alpha|b|beta|c|rc|pre|preview)(\d+)?)?' + r'(\.(post|r|rev)(\d+)?)?([._-]?(dev)(\d+)?)?' + r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$', re.I) + + +def _pep_440_key(s): + s = s.strip() + m = PEP440_VERSION_RE.match(s) + if not m: + raise UnsupportedVersionError('Not a valid version: %s' % s) + groups = m.groups() + nums = tuple(int(v) for v in groups[1].split('.')) + while len(nums) > 1 and nums[-1] == 0: + nums = nums[:-1] + + if not groups[0]: + epoch = 0 + else: + epoch = int(groups[0][:-1]) + pre = groups[4:6] + post = groups[7:9] + dev = groups[10:12] + local = groups[13] + if pre == (None, None): + pre = () + else: + if pre[1] is None: + pre = pre[0], 0 + else: + pre = pre[0], int(pre[1]) + if post == (None, None): + post = () + else: + if post[1] is None: + post = post[0], 0 + else: + post = post[0], int(post[1]) + if dev == (None, None): + dev = () + else: + if dev[1] is None: + dev = dev[0], 0 + else: + dev = dev[0], int(dev[1]) + if local is None: + local = () + else: + parts = [] + for part in local.split('.'): + # to ensure that numeric compares as > lexicographic, avoid + # comparing them directly, but encode a tuple which ensures + # correct sorting + if part.isdigit(): + part = (1, int(part)) + else: + part = (0, part) + parts.append(part) + local = tuple(parts) + if not pre: + # either before pre-release, or final release and after + if not post and dev: + # before pre-release + pre = ('a', -1) # to sort before a0 + else: + pre = ('z',) # to sort after all pre-releases + # now look at the state of post and dev. + if not post: + post = ('_',) # sort before 'a' + if not dev: + dev = ('final',) + + return epoch, nums, pre, post, dev, local + + +_normalized_key = _pep_440_key + + +class NormalizedVersion(Version): + """A rational version. + + Good: + 1.2 # equivalent to "1.2.0" + 1.2.0 + 1.2a1 + 1.2.3a2 + 1.2.3b1 + 1.2.3c1 + 1.2.3.4 + TODO: fill this out + + Bad: + 1 # minimum two numbers + 1.2a # release level must have a release serial + 1.2.3b + """ + def parse(self, s): + result = _normalized_key(s) + # _normalized_key loses trailing zeroes in the release + # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0 + # However, PEP 440 prefix matching needs it: for example, + # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0). + m = PEP440_VERSION_RE.match(s) # must succeed + groups = m.groups() + self._release_clause = tuple(int(v) for v in groups[1].split('.')) + return result + + PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev']) + + @property + def is_prerelease(self): + return any(t[0] in self.PREREL_TAGS for t in self._parts if t) + + +def _match_prefix(x, y): + x = str(x) + y = str(y) + if x == y: + return True + if not x.startswith(y): + return False + n = len(y) + return x[n] == '.' + + +class NormalizedMatcher(Matcher): + version_class = NormalizedVersion + + # value is either a callable or the name of a method + _operators = { + '~=': '_match_compatible', + '<': '_match_lt', + '>': '_match_gt', + '<=': '_match_le', + '>=': '_match_ge', + '==': '_match_eq', + '===': '_match_arbitrary', + '!=': '_match_ne', + } + + def _adjust_local(self, version, constraint, prefix): + if prefix: + strip_local = '+' not in constraint and version._parts[-1] + else: + # both constraint and version are + # NormalizedVersion instances. + # If constraint does not have a local component, + # ensure the version doesn't, either. + strip_local = not constraint._parts[-1] and version._parts[-1] + if strip_local: + s = version._string.split('+', 1)[0] + version = self.version_class(s) + return version, constraint + + def _match_lt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version >= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_gt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version <= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_le(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version <= constraint + + def _match_ge(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version >= constraint + + def _match_eq(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version == constraint) + else: + result = _match_prefix(version, constraint) + return result + + def _match_arbitrary(self, version, constraint, prefix): + return str(version) == str(constraint) + + def _match_ne(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version != constraint) + else: + result = not _match_prefix(version, constraint) + return result + + def _match_compatible(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version == constraint: + return True + if version < constraint: + return False +# if not prefix: +# return True + release_clause = constraint._release_clause + if len(release_clause) > 1: + release_clause = release_clause[:-1] + pfx = '.'.join([str(i) for i in release_clause]) + return _match_prefix(version, pfx) + + +_REPLACEMENTS = ( + (re.compile('[.+-]$'), ''), # remove trailing puncts + (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start + (re.compile('^[.-]'), ''), # remove leading puncts + (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses + (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha + (re.compile(r'\b(pre-alpha|prealpha)\b'), + 'pre.alpha'), # standardise + (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses +) + +_SUFFIX_REPLACEMENTS = ( + (re.compile('^[:~._+-]+'), ''), # remove leading puncts + (re.compile('[,*")([\\]]'), ''), # remove unwanted chars + (re.compile('[~:+_ -]'), '.'), # replace illegal chars + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\.$'), ''), # trailing '.' +) + +_NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)') + + +def _suggest_semantic_version(s): + """ + Try to suggest a semantic form for a version for which + _suggest_normalized_version couldn't come up with anything. + """ + result = s.strip().lower() + for pat, repl in _REPLACEMENTS: + result = pat.sub(repl, result) + if not result: + result = '0.0.0' + + # Now look for numeric prefix, and separate it out from + # the rest. + # import pdb; pdb.set_trace() + m = _NUMERIC_PREFIX.match(result) + if not m: + prefix = '0.0.0' + suffix = result + else: + prefix = m.groups()[0].split('.') + prefix = [int(i) for i in prefix] + while len(prefix) < 3: + prefix.append(0) + if len(prefix) == 3: + suffix = result[m.end():] + else: + suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():] + prefix = prefix[:3] + prefix = '.'.join([str(i) for i in prefix]) + suffix = suffix.strip() + if suffix: + # import pdb; pdb.set_trace() + # massage the suffix. + for pat, repl in _SUFFIX_REPLACEMENTS: + suffix = pat.sub(repl, suffix) + + if not suffix: + result = prefix + else: + sep = '-' if 'dev' in suffix else '+' + result = prefix + sep + suffix + if not is_semver(result): + result = None + return result + + +def _suggest_normalized_version(s): + """Suggest a normalized version close to the given version string. + + If you have a version string that isn't rational (i.e. NormalizedVersion + doesn't like it) then you might be able to get an equivalent (or close) + rational version from this function. + + This does a number of simple normalizations to the given string, based + on observation of versions currently in use on PyPI. Given a dump of + those version during PyCon 2009, 4287 of them: + - 2312 (53.93%) match NormalizedVersion without change + with the automatic suggestion + - 3474 (81.04%) match when using this suggestion method + + @param s {str} An irrational version string. + @returns A rational version string, or None, if couldn't determine one. + """ + try: + _normalized_key(s) + return s # already rational + except UnsupportedVersionError: + pass + + rs = s.lower() + + # part of this could use maketrans + for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), + ('beta', 'b'), ('rc', 'c'), ('-final', ''), + ('-pre', 'c'), + ('-release', ''), ('.release', ''), ('-stable', ''), + ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), + ('final', '')): + rs = rs.replace(orig, repl) + + # if something ends with dev or pre, we add a 0 + rs = re.sub(r"pre$", r"pre0", rs) + rs = re.sub(r"dev$", r"dev0", rs) + + # if we have something like "b-2" or "a.2" at the end of the + # version, that is probably beta, alpha, etc + # let's remove the dash or dot + rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs) + + # 1.0-dev-r371 -> 1.0.dev371 + # 0.1-dev-r79 -> 0.1.dev79 + rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) + + # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 + rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) + + # Clean: v0.3, v1.0 + if rs.startswith('v'): + rs = rs[1:] + + # Clean leading '0's on numbers. + # TODO: unintended side-effect on, e.g., "2003.05.09" + # PyPI stats: 77 (~2%) better + rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) + + # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers + # zero. + # PyPI stats: 245 (7.56%) better + rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) + + # the 'dev-rNNN' tag is a dev tag + rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) + + # clean the - when used as a pre delimiter + rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) + + # a terminal "dev" or "devel" can be changed into ".dev0" + rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) + + # a terminal "dev" can be changed into ".dev0" + rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) + + # a terminal "final" or "stable" can be removed + rs = re.sub(r"(final|stable)$", "", rs) + + # The 'r' and the '-' tags are post release tags + # 0.4a1.r10 -> 0.4a1.post10 + # 0.9.33-17222 -> 0.9.33.post17222 + # 0.9.33-r17222 -> 0.9.33.post17222 + rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) + + # Clean 'r' instead of 'dev' usage: + # 0.9.33+r17222 -> 0.9.33.dev17222 + # 1.0dev123 -> 1.0.dev123 + # 1.0.git123 -> 1.0.dev123 + # 1.0.bzr123 -> 1.0.dev123 + # 0.1a0dev.123 -> 0.1a0.dev123 + # PyPI stats: ~150 (~4%) better + rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) + + # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: + # 0.2.pre1 -> 0.2c1 + # 0.2-c1 -> 0.2c1 + # 1.0preview123 -> 1.0c123 + # PyPI stats: ~21 (0.62%) better + rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) + + # Tcl/Tk uses "px" for their post release markers + rs = re.sub(r"p(\d+)$", r".post\1", rs) + + try: + _normalized_key(rs) + except UnsupportedVersionError: + rs = None + return rs + +# +# Legacy version processing (distribute-compatible) +# + + +_VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I) +_VERSION_REPLACE = { + 'pre': 'c', + 'preview': 'c', + '-': 'final-', + 'rc': 'c', + 'dev': '@', + '': None, + '.': None, +} + + +def _legacy_key(s): + def get_parts(s): + result = [] + for p in _VERSION_PART.split(s.lower()): + p = _VERSION_REPLACE.get(p, p) + if p: + if '0' <= p[:1] <= '9': + p = p.zfill(8) + else: + p = '*' + p + result.append(p) + result.append('*final') + return result + + result = [] + for p in get_parts(s): + if p.startswith('*'): + if p < '*final': + while result and result[-1] == '*final-': + result.pop() + while result and result[-1] == '00000000': + result.pop() + result.append(p) + return tuple(result) + + +class LegacyVersion(Version): + def parse(self, s): + return _legacy_key(s) + + @property + def is_prerelease(self): + result = False + for x in self._parts: + if (isinstance(x, string_types) and x.startswith('*') and x < '*final'): + result = True + break + return result + + +class LegacyMatcher(Matcher): + version_class = LegacyVersion + + _operators = dict(Matcher._operators) + _operators['~='] = '_match_compatible' + + numeric_re = re.compile(r'^(\d+(\.\d+)*)') + + def _match_compatible(self, version, constraint, prefix): + if version < constraint: + return False + m = self.numeric_re.match(str(constraint)) + if not m: + logger.warning('Cannot compute compatible match for version %s ' + ' and constraint %s', version, constraint) + return True + s = m.groups()[0] + if '.' in s: + s = s.rsplit('.', 1)[0] + return _match_prefix(version, s) + +# +# Semantic versioning +# + + +_SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)' + r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?' + r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I) + + +def is_semver(s): + return _SEMVER_RE.match(s) + + +def _semantic_key(s): + def make_tuple(s, absent): + if s is None: + result = (absent,) + else: + parts = s[1:].split('.') + # We can't compare ints and strings on Python 3, so fudge it + # by zero-filling numeric values so simulate a numeric comparison + result = tuple([p.zfill(8) if p.isdigit() else p for p in parts]) + return result + + m = is_semver(s) + if not m: + raise UnsupportedVersionError(s) + groups = m.groups() + major, minor, patch = [int(i) for i in groups[:3]] + # choose the '|' and '*' so that versions sort correctly + pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*') + return (major, minor, patch), pre, build + + +class SemanticVersion(Version): + def parse(self, s): + return _semantic_key(s) + + @property + def is_prerelease(self): + return self._parts[1][0] != '|' + + +class SemanticMatcher(Matcher): + version_class = SemanticVersion + + +class VersionScheme(object): + def __init__(self, key, matcher, suggester=None): + self.key = key + self.matcher = matcher + self.suggester = suggester + + def is_valid_version(self, s): + try: + self.matcher.version_class(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_matcher(self, s): + try: + self.matcher(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_constraint_list(self, s): + """ + Used for processing some metadata fields + """ + # See issue #140. Be tolerant of a single trailing comma. + if s.endswith(','): + s = s[:-1] + return self.is_valid_matcher('dummy_name (%s)' % s) + + def suggest(self, s): + if self.suggester is None: + result = None + else: + result = self.suggester(s) + return result + + +_SCHEMES = { + 'normalized': VersionScheme(_normalized_key, NormalizedMatcher, + _suggest_normalized_version), + 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s), + 'semantic': VersionScheme(_semantic_key, SemanticMatcher, + _suggest_semantic_version), +} + +_SCHEMES['default'] = _SCHEMES['normalized'] + + +def get_scheme(name): + if name not in _SCHEMES: + raise ValueError('unknown scheme name: %r' % name) + return _SCHEMES[name] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/w32.exe b/backend/venv/Lib/site-packages/pip/_vendor/distlib/w32.exe new file mode 100644 index 0000000000000000000000000000000000000000..4ee2d3a31b59e8b50f433ecdf0be9e496e8cc3b8 GIT binary patch literal 91648 zcmeFae|%KMxj%k3yGb@-le0hq;dg{!!Jx)2QPL&2NH)YubYozb6#{w->ALj?hI0Tb zfutv^IULt|d$ph1tM^LLe(bgP*4xStt3bli1S)Dki}6A=wyDl~VvT~yA~EOle&*~Z zLEHPee|*2M?>}EO=bV{&=9!sio_Xe(XP%j@zU@)LDhPrNe}*9l2k@qU9{&9A9|*qL*S!FoDk2>;;Q0JsgS!E#|Np=L2Pm*g>+^@! ze&i91{FPlELF?b0n7dSnw8>K<1Jbpj5K{a`{t6`RF%zVzp#$RtAuNQP=%hh(?A64I^Ygs)dNNee8#q3xXNzV;c>_P>vRaEk?dT?X4biy~du%5rpGZV<1M3 zzmNFhrHE_%95G^j>^H-I1F8V$R{33Z_8aO_-fc?lLSFI>WH*S(_W$| zEz50})3iji%A$Gg#qH6Gk|F&Kt#dsmrqZ{-9|(1WDpBu{%Lw&M0}{1yNNwzAKSwdH zR5U**Gx~fn0CfuEkR<$t!$OHl9 zn!q6&MqJoZ%kG^j2(?;2E8}DqR_2m)FOSE|AZ&Toiyeia3pGY5lG?_n`QATWAQ)P~|=!tEXsh zU$OUmI32|X0sO>hxy%N6qa0nJRrgw}d&0u}YG%mze@J;(U`x%C4pUIGv77 zYdch^dxXJmzmH`Af4w&Dz+yxwM~mvw2kB~EzrK>1K%}}q&D9nbz*$4Azlc|z<5~q= zS_0MWoYuw>9sH6QpeR}~%g}S{HRnr&vEDsi%B*t7Hvd((s@{G=a_2XY(c2$fzmBt< z(&zApufh;=4XAR0&2|VvFbJNQ;SVKdEHzo!k7SH3I~W!zQl)-hAmjn|sQ0`N+~8yP z@Rpv}cpsK=zRGhC%Qr^73EyEKAc+(7!Z9e(o>7!?9svgY>>cz5Skm1gzolDU1C>$Q$#bsOzzk^=+Iwq-t^8C&P<4uKOr4fmo6 z-xK$*vIn$9+8f_Hp02dp+$S3Xwf@j>9!M=^+SoPd^XTG3(RB{+HAbG@{odwc?PBq; zW<~BvO2UxFD~Vyrp>?(=(tPX@jHaLxvnic6cb&cA9U|w)1&CX>W$O)=DctzS{7BaXS3D){WO&bYlpvW?)} z-UNLhseA+V_8BQxxoAjPwZ_{(hWfeAl+_JMPNi|kkg`E~ zHytAW_lL8LQc5=ROQ?ozsNq2Z*d(We{d5SH&|^U1W6j9joI}G$D53rjZyJ-AMo{QQ z4i^MmxFQ;P5=a6*cJ*!OrK5Rf7^7$rAO|DIkSJsbf*6U6bl4^R73l$lak^HG^x}gZ z8#0VeThUv*guw)OXD}-x8i$iPBO*Fza5cbOXy0BOe23S0-?uvbI+hCKU;|D9x~D>?c=hFcrP$2 zx~3zT|sZ!mvFLn z@U`oBqzyVkZAkc-l!S4pP4s~RaepQ>A}U}a;eH~CTT1b0ZKwj^K6ZA1H(cpVLknDj(J>*9+R9G)3H>K?yaf1XL)kzAQujFqyC@Re;^qR0g&Wyh&aTt!C)Fq0OntaVW-w zmOs?I4z&a-+PXDK{jnr-toT638u_*^=mE;2*^(_>sHcZ#D{Z!5jgKt?o11;u8F>rM zUx|UH7ezOv>Eo#m6aH3l>Ry606`Dh&0s5hM=P%#|lv8-NWLNi|1&p548KL)|5UH>< z?QsgYjz^!OkzB7jZs;)8P_~-}Nw=#la)#8d5GToJ=fS2?h4d!ZKu~+t-Mu+~*Z8I{ zawJF77uizgQuncjPxLhHQ)C;UY)w4d%akn`h(^xS2Iz#~1icDUbDSybjaZackNWcp|c0DgU zoVMQVthdBuhHUE~^%dq0#wRTvHq1OvsjlC7>8$v~J;AJH!L6BZ#^_reSdp1~ua# z!q-9y)GIq@&X$YA&Nb2Hh2hygmIH$Wk&Y8PkYxO7lmg*T#LI}<*87quqLE%q62P<) zn4$+Mpmj!lY4w_2X-lh*9G5>YK5{al^=rJ=(JG`kdCDoIw4Y3&Q(bNP1Avend|83@%ex?0*%A&donqn~TCUiUGly;CIiY0<`f)6* z>dV}6A^XkeU@*uX=q$bLKaoEM zfzA$s3xYAtpmnh(+aa$fvJ51KC#_RUm=9IeI`pDY6Y>Ek*0F2?@SqSi17gXBc4V^C zsI4YI0pw_)o78Ko9J;;U{d;Kwx?e3)W?47dYP3ScIB;sYk>gUDaZ>59xn)N~U#dw;`O52-3W78xL~nNQ zH7F33hN6c0P*jjT2L&ngG};hq#e?mp>e5WO61wztHHaw!z=0;D9csZNs3qJTn?)@X zXwr->(!_@wK2^$BQ#tF`Nz+2~#nO`{IiNbGkxZpnB4M~N)I;p{%xrX(odt;mqiQMrjqI5s^?E z-%{(&s*T;sCpLV$FE-r7PRtjCvP|h?1eO@rQ8xAxqSQ>|O%oqQrBIaBot2?McT2g1 zr>;x&c5|#+U6=lRr?>YR(4e`o_XWH*j|W3)!~{eLZ?8@Npwrv)A_wR>kOb%%1?b@b zCOa3RF-oITkmq;uRzr3XIqt(CBxYfJ@r!iHj@UI68)N$}1M7261yN~v!+wRK0gg^` z8)9ie#-2#UVuc1krkddxE!YtJelo~0v5(PFl<8XZaxesgwZMJ_7C6CEv5*s_E0K)i zN`_&uwYDS9jYN$`K79GNXb`buvC`ao@Wie0-%Dh9; zM7A1Ph#A=}gsFN+wev-BYApJ-Pdh3dfRMjq_E)7{tGY|g)v7}3%{DF9opZpkRFEcU zIh(SvV6NIEXR;^V=+_Lb(&kRzmW9Mg8ZwQf+u21I(kpF<9q?>Qlk=3SO=&2^qGxM% zVD{K35i7zYHo+u7pVQS=8z}QS#g-ESYFTHGoRO!pryw|!Lh%FWfd@dbo$==hpwSUA zr1xN8$ct9@bF&dvTFSOOL0($?p19xURuW4aa+JhvTQPkUiu?O9?e~+$i0E+?ox!8q zpmZ74PN||EO6c|V?tUqzFCuv!eJrI-%UL>C5#{vCKx67ouwgzkENYUTSGGHH3@Q$?P{XM_M`r8O&R% ze@Cl!K;ZnT_*1kf_bV;xLW{b@{g$t_sGYY6^*TlM>XKr-UPp@C^@+sJB%_H_uyzJh zJ5!ugOB(pao~`%#14=pZpdc5p>#oLdnaP^3gzVxx8~uWdtuvBMi^0-@CHg4K{sb(m zB_f7=dDyY8EWHRgq?}q7rBMa$`UNI}*I*gItkJ<=q<-powd^heV82FOrvQlz5w)f+ zc0dr83bEZD$Qyq+ZyoYy9uS~T=o#*g#!Rha52b`{KK9~b@H#*^0TIxSv?tOvTcq%E z$iXj^4`;Q1n4#IgK89p>cStr=C{4Wv*>7mRun8HqzrG&k;~2Z{dO>I^Cuu53>C9SA zvXshV6KN$kI-~IRx%(StHxJ*AvbRpvUN1h@egW1SXAOJ)GC^p**&#HcX?nKOQ3wOl zlb~*@uP}ouiM+;1N}JQib^sXad~=lv4(#@?@bC`n1?5x2^#=9h`+~*NEcIyL9s>S3-_)fk?QthQ9r#Ss zkFAg1V62HnZx~)rPmD}Fhww~^LezJH!tBk9{`g0*KL-3dV)rBoYidT#E42`st}_Am zIVf%yV0$!`p=B^$#1~k&p!YL3I03dJue~9Y>$>_MKt)Z^Jb6&+=W8AHWizE|P<@mO zB#|zVL~1XrSGl%ZRv`by)fWE~=v7-AHvESLV1?o20Cx4XW6(|1>V*4Mc{1CM!aD`% zE&{s`pPCT=4}6zZ+c%Hrg|anNyV>zNNKW^wJC=oeT&GqKehTwq!*$V$EPFW_Ew)Z% z2MO^}cTAezDV%@=*2nwUU!d&=5tY>`5IvMOJ0zOc4Z)nlY`k0=t@?w!Sv6G6fUzl$ z;x>4;VXiefmYyxVYoQl?fX0A5AcGlzqh<}H2%y69= z94zzZZMlq$d5+pJ>=aeYdBXwFJ_@jPulTFRyunI`16_(u5bZt5u2mLb??KP(^qwc9 z5mss~{{_+}fussdv><1>*!me_wTtfV25h&u8;8V)UPeT~xR#75Fv9yQ1!4XUn`Mcm zF;V;;g!}x)A+51L9s!iQ?tH^qrSZHV&3cKZQP(N=J6p1}_Cai7wCkB#j6Pz;NAz)g z?s0c-P19m9T5eqfq9^?9hp2AQ$G)sE+temKK(cUy#hWPZp6?yfi~P)vo)1#&t*~7R z(rmDc;Z3w!(7c-r=pEkkSgc1bN9me3Fa8S6KaCF9YSC%bJ$5!3^+&g{pTn5kDL``- z;y)y)n;nH(XECJrpzMsdm@!VhFYE{jpF+oN132wM^p?p^>FP2$Pr9N^E|9O}*hOHc zeF*kjuZjFdj+`&FeuN3d)y95@7_4;)%;ByQEekH;mbbB{$C7o-GAW%p!rQC!Y(FI_ zVG5CvY_P1M%-c90=A|SEC@To{WnR0CbbjHw`oWQhf$#bYV-> zYsb^be+I%B6OQ#VGO5vDwPQ|ulIJ1Wk(AFG(4r)Nz6`WrIF#yfCW{8to&rot$zXHe zJjmiP@(h!IfEYKkmN`JDpz>@F<|`q*0?TrIU>}KnA3Yz9P_!E9#xoiz;bd{ZRLUcJ z5LBaQ>G^m!J)e4uo_o9KdGG|D^$$Ou;IC*Oe?4`KzamHZ>)AH``uA7xdh&!M9_NIYirmI{UbuiZ#cY=A(bC(_|i#v1&B0 z6aAdWcIA!q^P2!5KEk>j>OO3!)pm%g85%t&vpYrs|BVC29|6;f`^N`JGrUUNzXaLp zA>}4$o%QY`(irn#KWvo(BHFPu9}j5x5A{l!pjHn_iy`dA{fn@Cr=0oX{%a_62Vjo? z7G|0@EaR1L2{L7-OxTd)=28p7XaWSkcc{31uzOnD9PbcqUL^H@M=c~T6b1K1jKiN# z9BJbxM9^bKd?R=o8%J5x-~B=CIF_xqVF!4<4f~^h_JN3A<0JghR>0Qgql1}i^aQvzva}nPuTE;R6XMlA#Px~!y>l4$V<0@YWB-k zosU0D!McPdCyLvxN7^r@qonBcr>IOAa5O6~wFIT!&lm8J;&!t!v|&`JEytv5w;t28 znigftR>N!eK!rOuxZEKWV(#^j+~lJF&83_Ik+%EOK`wm}SC%1KwmP+290Tok$v)Ul zbG>BMmSeI(!2=Z~Hk(8!AsisVHSc+=cW50gS0GpmNw9tw?W47d9cCvkWO7Ct%>3vH zDrp|cxw$aLa`OTOu0WSzpYdxZrFF>6O-k6!O36zU?GHrSwguhkc2HzrktaO00d#>tHSbGLyYzk*-x1 zml#q>vMTb7;#Vc-jgtMwzf%jvk%1wq=d(94uP1A92A^sHuLKr4DcuwMui*T{NJ9j&gxbWgA6hZ21J;h&I_yUOYuqRx|4q#m##8B(ObaF@3!P}u) z6h4#+weihIc$_ioG9ygjW223kHIkiJ@W4#u(| z*H~v$dL~a#C7vEhOozIv!$1Yzu2(B|42w^-VQY#@O0(5iB|rn~$C@Ikft8tcuZuxe zQ3LG(teTuK$vMkphdcpGJ6fh;&d%h9EZNC^Gm<&3A&Kol7%egt1oy=)S7?it!KGuR z1m6Egu4ELD#JG`tpH?!9X3KSK6TZ|%Z~!U@BmqMJbREY!r(RvLW0>Hlz!+*kIpFIb zX+I*Q@3LpUEeLxGpH-a15?$2UZ@elbX zGZX5xl-q{gRG+~raI2Qk=lNJ4eY!ihOw}^#mBri2?z)6Rlq;4Q?D4PbSTmyKl}N7>iGnlawFcX7Tbr| zILGt@p~O|RHw=A(RyiFV1%Ii;hoDmZbga7S9RgWJIrko;Zu$#~;L{wo0!p6z!36I0^{oPXQ70vxoH*53|M8M`L)GmazI;KnwRdf-D>R z^1j_%J07;kSp!Wi$YOzNj}bC`z*Aw7CSl3r258uVwtkcHfGefxes(#1W6~xs6EI=6 zxqSiVO>e@Lpgy2yrM@JkjvW`2a^mH~a#`xB6H5yu4eyljL z!aRn^1J$>Y2?2fSfxVfA>9xBT?2 zlRZVK8*8}i_lSu9QwVGC>f6W)+0u(Y1$FngCn_wpXK zNExtk9Mi4gY)rD`)uFTEH^}5B)05+o##JEVcS9oRjCngcJm= zH!{t87U0mC1cJYT;Qs-Sq(s3~&t3!BVl0Fz$7%154{*~mvZus}59e3$SI%Pono+=C>3RG$*U4X3I`De(hv^=?G_SB{A%ENUEW#Vcojny4 z<~Ehi^d{m9{I{DD_bf!HGkqSOSuibhrZ3>BNt=ynfZ5%O)sSg?F-;wNwgCua{k97< zzzof;9wFN)4?fA}p_CHXk0oM1wP`w~;d$a>tldl5WvT&G~^mNDZEsjJSbs}kxe z^6G?Jl(M8yA_o;EaR(Mdi3VwolGrLuW_>U#C3T?EPslnEzavc$UbY}w&vBhms)sCk z*2`HW39EqUB^S9`2A#z-7nT{~F*px)A_``p~ppteftWazj zz^B5-Nw-!>%M?~1U8%5a=`!pIh>_jMQRYpEkrROF^d=A#lvkbc7~bRF;~M8c%p*qr zoyU9lR$`~OpTOcz;4u(O6C;n}16B&<&%@9{lvmTnb)x<8Cd9(~Qjnz)yoLHb3R@}N zrm$SeTLn6xQuzwY5F=B7aWE#df!N-0|D`V{yQ}PO-Z*3&CJsDL1?t!E*tuD&hEg%J zl6l5Azbc?ST|B_e!QF79IIgFS>mG675+i3x<7({3HvZGV6)s$F_Dk6kDG|2%Lk@I0 zyP*bECT&2Bv;s)!$QT7e50=X^btTV|9?C-w%v2CTJPV|JM>eVfy-QyTU#LQ!yl`x? zlakW}eReoAw2&v~k0ei1I&vx5B8=e|7yP4^NE28mnxAA6=f@bq(?d;&fgTa{l3yV7 zn2?WZo`>m?)TTn{-$r^Kc$apss~lwT+h$W2soU)8w&`k>lbhnh&d|Ki(CS|Um+K67 zu>qgo4jD=-SkiHN+X|(c7CE?sUAzF$3 zwY88ESObYIv=HIBjD;`w*=ER+V33D3+Y198%=-?XpZ%UkSL**r-VD9^cfyOWD1iO>J>chIb@~hXG?ZZi(h}Oty7&c@psuII z)1>C_^4&k!!_@V5b(Xq*x^jy%CF|HY)LiRi*u=qv)YuEMY_g$FBen0VG6w*YR zxKz1tWy7b@s*jZmJ)SMXL#pzwrBDm=mlqZCyXuy^QG z?<#Ue@mJgfUqo)Gz6Qrfe&-J!!s$z;lGW2p$&T|Urej+-=IPtMBCQWmeOD9 zYGTPP$>j31fN%0>o9(Vra)=6O8692&l7f%O=mSnHeqcwv*=Bvidi3@i*s}pQ)`E`H4u_at?pAU4omB!HwsbP8g0dcdC`gou?p=cMK^(+ z{5-DBaLy(Fzh}5xF*!PZE1wXICx7g1q>^*O`E{2Lz zYxUzGYjfFmHs9SN&sWL|F%t_?VTj)B&rnB{qqKh{YO5gmZ#D8MUO5WGq60DPG1Lbt zciC!(G=Y1G1++J{W9-LfH1=?4#C@e!g+WtFohkS0LwaA)bt~T8G$j3qF!) zUu8>?6rX~a6XZI)vdD?9&eK*D6|B0|S5p)6RgUn0xi@iCtthf@Q0G!30a~K1wgY;B zYl^nXp$rd8Zs1s`d@(H9+@Ec^D!On>bnS1P+Bno$dB7&fCqfo##WFklQMDkvgl`^r z1_Awr4L`)dCfXE$m@%NW4KB4oS_lUSPI93Q>`6C@{<*`P(|u-q#MQuaJU1J!osbg0g$DJEqRC>zpw^hrQKCzzqQ7Yit^ZA zng&pjBX&5_&>5A(z6t2u#h=@3q-D;C+CCTXr7q$k$0$)c3sTlQ$x*2c7j1tNP8{pk z#grlrh#KghYDTR#qYHAze~2;%v?Wl=Co0%jlyU;bn*p}`3`)Hm3VMgVdAKkg-VbLv z2R(Q|~VNN#@t8>Y)x4w(k~;|%gZfjwv+ zxEBs60wkEJBRkL+!5~&G(S^Li*hIH!o%-G30=5x*(&RRGQ5M+-AWM0Z=suX(R-=2k zC3B`+%xM7!=cE;La)52Yzz(vjM>4^#sgF~a=$QewhLTdtPzXDWm0tEwfQ$j_e01-q z81+ZZmSOWmp6Fw9D3NQ>Y3b zbl6n6pF^2uGpW$f;VM$+_#V{L6CrX_RNeCoLVKR0$1mye0v<_w3|Uok&NK99na>6> z@agvk99CFL+pwB%==L8kPV7DY^ zp>aEJlJd1!I4xM*F3rXt4*yB`mY1N2{`x7*vO-io5BduQIl-)!t-v zM55>>yOyEXXmINgrEfxik}j))mazK*bs-i<0{aM)s{Ya;s?%S8d%D_J#uE)$`*lx%Dla_=vao)6Lhsfy;CmQVg9)| z4(6YWHf-|Ta=Tjnmb(0Q#LG*xTQ;cGU7gD}JPb4xvp~yXASYHFT23E6tUOp&eYSCm zR(%!()dFkPit%>CdshD=dl9+Rj8s>`qRw&5GPZ80HCFWm^(i1GOu@8Lfg7U0-oh?r zFvim^trq+sQ+3MFyj|+@4cNT4gG{4LZ~#;o?e#scTpDZ}4H~5sFbPF-1Jo{~3*5?2 zPtYkdEJKrg7Blj@K~Cdu@Ox0txW;+5J1Pe*lv;!WJ#Fh zGfKNgAmPcGLn+2?!bj=3=(b*DQgV0+@hxC?43p=G_1?t-I#h9rIR9b7E89CO*RBTT zm3lk8sh6ue^3)xhIvzX*;x6lW@FpZ~_@1h~Qn|vPeZEU%VeL^;}R1WGs_86)YL$Rm_&=;Yi@H2L>Y5arauxaiv zN~wjgj2xxeu#1!H=1?An2E_dkFkvS%2z%AHKr~K^(i3CogT8>76(>`PNwLW8C)(U> zGhn#N^0T9VK&)#3CG{bmj@N++{A?!*;^o-GPWA(Wp%jp@i^%xD$nL`JNG%DpL#u>y zKaGQ}9I$eM8M@O9Ei^-G%+O*pRBeVlX6Sk|RAGj$F+){mXpR|LTTb0Xg-oCbkn44b z5!0r!BZPTnDw=Q}O#s!!W`lZ6g4F%XTL4PYJYe?HY?z7xK;tu=lYE5p&Z&_+4~%6ta%s$B z3$YafTNF0iOIM(}p(b!+z&IU}=)LDCb=>JthzIz1I32p32Y8pBR>}zi9@R7~_RuhZ ztS=`(_(&?{1SD{$!lK6G!Vn;>mCcksOCfZUTDIbusY+GY+zpK+R& zDlZ^{jXMcuD5dOLDa{wgX%i+{S;NFHy#S>fQ`5CTq+c zYY^eaG{jC#0K3qnJSn=&iP$AP_LXF;balIt=8G;okep!22_Aw`E9c~Uo6daM{KngR z$O|5ms%f0$?!Er74f}EPI35y$<^)aoIWWw{>EQx6ph9aRH&IyO6Q5x~X25vMYTkf0 zMe{z4f#kJ5)<~ODIA#Md#!3Kbl89jUqkGAbVz4_{MKa%i;Dvsi9-v3yZ=N22nnzFv z2#Oy69Td)v8vEyAG@4COAEIxZLQsr(4Igksq|8;@lLkl&E!0torHifY&5O9*@e{bx znwH0^0`ajU+L5}{T8x%tDYZqbT5N^a^wPXqzqtRt4A-eZw8Bn4b?|62%B6$Ca{1USuJ8E z31LD&rhV}Wkkec!;RwC`N^UE-4`*2b^ja_r{B`5rEVUKj3 zY9^~JjxD0)V^le8vy54!CNq#?ObK?k<9E(85SQ5=B{8W1I}sqM?RR;IN>1v{eI)+I zIBq5F^)I1{IOKIEs2;R|h1?g#mb(B5b>{>|1uXecf-=pBmni}x0Ah!`Q;02p1r3^q zi4)aHGR1l6(P*TdG67eaYJ zQ2b7X zR9{z1|Kj(9R5&`FUx6BvD3P!XGNh%hwq1_ptq-T$fvdi3`f|zcDW|1+1FMZjr~n*P zqcmS@-9@%!8EBY_z-UhpE_jcvBlj`u@5y}(q_08UiS$xF0u>Y>;-p+hCWVONY%Xw` zOPguFf8FI%`2_<;AXX`|N*begwuo(G20bW$)n@Tx3=?k=B^C6~0s@^H?XC`H&Q0ee0 zbE2?}P79V|sf14-<_1pcIJPGSef(>JL@T0dWi z(?ufF13p$VomRRym7uk&J8bF>ySl^C{=Rcudvu5M`RAX1iIf2JEr5$(KTIq5U3r#P zr{@-VF#6yO1P=*3&W^a7<-wFNYVMnk0XJr7;6NvX%HT7$*l;N9q(|Uh)HFR3;azR5 zE&QGgkGr$s{I1Af0ooBE`CHi1CY3~=`UDZ;zGLD(tNYm2NyY6RU-YpYN)H#_%I==V zd1}`(3l4*{w8^K@U0di17i29;}uB& zOp&7iAsAQ*b1l1q0~Hb79`;f(1MLgB{DazhSijXIV`ronX#N!yb{(J3zqQ9HCfbrqnXFyW+X|J7Q?_O|t;n6>jMfzD zIm#DPwmK+S7_I4Pb?Vj*9H(%<(a@1{oy>&OBKIF#1UbyU(TC}6BRES-?B<7umT!_~ zC_C>Gq{-UW5SY`BN%Jg*3$#>rJ%D4-5B~$+m!^KWHG~ZPIOrd`l9_ z?VG;TI!2BI^%ag`R`NZE4jNz^&>xWG19VHru$-&K*l*F1*htxp%AjG`dOy&F#)>Wf zNR{*UDs3g@{rGJ7u-RZ=k_?vs*=*41Ww9lMZ*hMo)>aNwk(l3)n5dWepm)=tps4E* z#Ybp#*>vp1KUx5OJ#_e<0Y!x6aCLesgtlrS-h*#feh}3?23w7dXR?c&W#o&jtq-Bk*?kzibeMOUO>7BJR}^B4-7tP zN2)!MkLHnzztce#pFtxWcci2ig&>ijm!PuGa_0qoE^G*LVe>_^xwUK$okm4XwcT+!vqGF5|4hA2p&s!<>Re^xChu5`Z_uNZ9++qDN@LA~fqR7|?Jd=WV~g|r8W zVu)CW^GvsC4-&}`nv4+4qiMgxpxZ~e*gr!lR2@54=a6nFaAE*{mD3~lGg+7M#*;S>Hj+Ji*@ z@@>>x)5?BAb)xD{_CVV1qa;=ZK-~DSW2A3)nteN7%S7$Rp%O56%pst%^+Ry4Uv3+X zc2Km^$-BDK&%T71z>Qid&pPxmoojVt0RpaA=+{czgVMZ!x`>5osME5@&;E)}n3#jG zmke`zM<#Y7iG{V!b$m(6-G{c3-1&JgCg5I-X55d*C*aCW(A;)l0-nxZqv%a{C1+tj zRRpu}OUOaCta*@Frp>IBY%5B~U49lse~`Et@yg<3@DQLcW0YI&H5uXn9dl9o^5|%b z*zyoaR*Mrjj%alsdkDp7a-Vi{9$fujmGjZiXw~6*<-(M$wtA(l5ZnFwP5fL;*uqc7 z%%qj>p%Xxli3*2gg3s;jk9?lINoiTW-!cW^7j>4w*81NCLq zABZivkTAHR&D}1x(Cs}MuA;EP{%nmMB1r5Ky5HTNroCInotGNFcen_pa$nyQfaX_; z)Fl0TqpdtgCJgu2ByfBv$IkTgI_9MADb}j8g1~8xP$|6m(8fOUPaUj`hzIKqxx$8K09fogw(tn(1 z#<_6s&@Q31()KkkX|aWdJ2^>v6Sn0BPHSA;{s`Q_&k+hvHri-3aGC^VXEfbxYtrw7 zKXfykXVb$2tM%;YGH&ru+CE23_yR7W;JTF?FlLrOpGnruH5dFRs7v@IYQW;rvy_BY zw&BzMwK_=)P#-;;z&hzpJ!6@2(JDS1!k5AO9Ct%PO@hf`4Nj|Iiq{7?6VYZH@#f(p z;OImUHo|X|rO(48xMdb}&pc#_KFF|Aa+{G>QV#lQj{3dn;WvT=D+lw?;$>VnphfNf z7+35oxRRLOSPITcfLjcCL7CSf{SRx_{xxiLG>;ltd;=jgs|JkD|0%|UCPuhs{Dj2O zWVmp-&R}y5_U}#z8rqNxTi2_NJ??Tkv)#B-8|1zXWz%1Pww-jV5Pj_9(*P#Uz;Tsc z#mL(}&vb!EIYrQBC66J`iC-K7Fb~0VV!6IMr7@&zX{X;K5ocj{{TXm$r?5(gcC6`r ztLseDg*4go3(_s6GHm{11GE@M;2jGBaPW8t7mdK@xTT6O0O7AH!e<#S%c9crCAlnT z(rHEIRbxFeD)lz({H)VrDfvz_B?K<)_od*_pnkQVZ3mx0wqfH5tThWqJ_Qeo&GWOF zD9Fe9QBDvRzG-bF+Q~CCFLZ!t`Rco%rMVk-7LD0PjlmYiC4MfXDsV!OpUWa?ohEQU z6+fEsVmsi2(DKz)Ln&Iq+&0jz-~{C=yNvU{-=>-o(Px6_`joOpyPQWWO!UXq$t2mD z1uwhCAqLqcRO&4*2=|^;NBG%6UI@GtXf1582>^mSGj0j(#W5uBS+)Xgpq}{C`zVP% zW)a?$kp6o|30nV{(&^Yq&n3;^7n84hLt++jO z^vFQ+d;#_)Iv8-#H#|^6W^pr<(Qo zZ;l828ybY!e&l$-V4(~GXXm)mKYHEqlW{&k<2rf&7eF5I{cLHpN4y}2*}Coh)f<0sKJ^7^dD7VzJ4^| zf>}sXSA-{5q-_W05#YggJ!Uks6%=908r*XU*_i|<$9>0^39xt3Swbnxg9RPTT@9aJ zVoN4Fa7`4R7sbbv_eE>_wBzI2gYnyH={mk-Y-TF90w6sr=jH?w51Wa`wndPy+@yD0APUPe=k1 zKmoC(iLm2-l_j`f7ni5pTu_|25jV5AFYcHT0Norcv5ds7{-ytb{wnHPU65LPE=WK{LG`CexMDy9o(4;rMz%jZEX$v!>xia=Loc5;_JC6 zbyu~$)viy%W+yH#we#ZCk>bi4hv4l&@($(EF+x7^@`=)%-b`_q&;Ibv2=C8?+8_Ud zHwi9xV#_D^e9j|AKBRXVrheW4e#TNcMh8Vq+CgN_LDvQKbW}>sFt!vJTj05V0kbcp z@prMrB69_ulNVbwphEq{mLK2)Zt*{mYjDjIK~k$q{48dE4@*V3J9Zxe@B{ZJ9l_bp z5eBV-M5oN)`XrHdd2B^LSo{MylkVjx#CmQAKZybj76)A}J)q)5cjX#4+r)jArE0F8 zM|(6%5AG^+W}#;=C4gGw_(N8IrEj{nik}b)53g3eed?-SFvK*rA5IENAxwvOkGi%u z!i)vZbD!I8cXQpOVHS%5LM>pMM*!I?(6LcO{ANINFZ%#o+f#1tbdqt`iV_=iI-Fqe znVGL0$*hN($%46a>&-au>V8vf$p8`veKGQ-jSlxYq|#j#B}Hj%U5Qrjuz0AgDr^f% zQ>tL7Ix^TrLqhq}u)4|#a~54j{CzW4p29wOn^*G$UP-5pd{k4vRy%SMZgWl?YQ;Un z5CKm1FSJSB4b`9@YTr!uQ=Wrt&+KRXlcpMK-aV+0dGiu!DF5pgG*(nAa_510)s?vm zG|~F{z*1Y47L&fe>&En^3)#4Egl>Ae3m5k^H4Y1{<1{h44BI$lAw4HTDYsXiaA$gm9vO=3$gs)o9zi7n(c05g1c zlRH~ZZ?fBTYg6Gxt*)O=?Z(tPI2oRIcZvtPoC+ZCIAl*J-Tw3eYF%C#6PzUF4ucu=X z8MZ1Z56+9((n}rI94&KKwb8mFBVC{CuIraGc*4`@CnL;nMEC^0cjzG=Z3Fx=RERD^ z`avbwPS4je&9-}}k!gDRE(sMX?jV>Sqhbk?V2d=`@MKbr65ko=P+_#FfUKhzmKaSWt+8I z_h{lk#WiTs+-0pRuSv%eVtdxEiJI8DGI#DWT1BKnmoF>s)+Y>hKLM9Yh($ZgH(Lhf zrns*EBqLD?XXbuv=ZxMXNmpRB$qQ4LdG(Svf>PZFkIsHfYvd)-_ZviE2N6@P7}3!E zpif*e-`Zp>Ph&W*VTF651|68WuPLQB6-8BQYcn7pnF62n#>(y~| zl~r3BdOp4vv9wTbAI5@mCS9PYlx1U+kd~*;a5ld@fS9O-a(kV)Y>snD8r{Hs32%?# zk~N%5R;9RP9&W5oWJ|w>S8=^+B~D2Yr_jd*e9YA{J1R0R&(^OX&dD@^Bb;@HiNG)3 z#97CT&oYsq{wW5UN(?jwV_M3!4P+1l<)-Ob^_qaP0ESM1NQ?gn>WE4HaQZr&beqh| z-b{&DwiKUgNjyv{OX6-ZavObY>=WW^@sV5sVlC4{`u9zMA^8wm(gx*~!t6hn&8@mQClA8vF=S zXO)uI-PE!lT|lw?+@e02eS5U*TTMJ;&-Rj>B?re}Bgs6ww1Lo?lNB_kJgi=@)34t_ z#}aW9G$yCHwm;iyY*mi>oW{#8xeQbFu3-srid0U~0(4jb*Tt-~?1W zhBr%4&-o(JM= z6Ye8|LjmwcsVK6=l({y-JwgI#9aU|nE`izVV%L}+*Q;?16Y>-7gngnAq8^K85_=}c z(FzVLJ%^9!$i9^CdvWEkPLpCUkPv~z6P@y9@kOSo-w z5^VJd7~B2w|AgCWS=V8z-{0b;0U8o1UK)l!im9Ej470Gm#Y^=_GI^6a zGFk+>L@j-&$*+p(*Si23W znXv4D*|A`B0|+K{BFk^FJ$0}RDYP{Zc?BP|X-LB4<7~`u1MXqz z4RQZubuUAbx|c5GRrem{&*$j*cn_ZS?$ct+Gk}L@uJwX?@M*-A@f_mA+YlYSp{HI+ ztllb$`;UnGn!4g1LFo~RJ2j5$du>_bzLt`H#E0$e%(hOAP!V*M{w+k+M5g#q4)7R7 zk@GvrG^RwUxoFc*@KPgYdrdl+6fh}66o~g=ZH01il1r*mm{nR>+#wagZ#WMDF|rS- zS$hdQz8{}Tls;|o=SRLR@qfj4GmodSAAgi`@L)WG&wAyHE97Dg65p2U9I6Nu2DN?! ziEZ#Hij1#B46YN#=l9yO#r?mB>rofZ)=^R!0Y6L465>~;@XoyiFC`LQIs%iVKs=3O zq?EB3DIEV0iYqldaidhDBtnu$N!%r2mA)0H)sSR1iA=ijgLvRl^1I~m)(gpKtSRC@ zN3=;0XZ)ul--Yo<@Xc?wyjGrqE11(3$`fGTO=bj*;&&5p!eyp@(@cFffjSvGQLkHg z>IUpG@{c>kmU8}auh_DXf5>7>G5^>mw#?=qtHqWn^zkgQ1t|CyUbjX$hjm7%m!Yo+ z=H2!2ei-F>vp0x8ye19bEr;>sXZq-TAD!u2DmlRbx0w#)V&r`+Ig}%Xot&EplgZT@ zXEKujp6J0L6vHpMQ4jXxQ{|UaL!DM10s77ek(~D3;_o6j7@^jdpvq$8I3i6Xh4F*< z9!--olkwU?%1weh{V)*;yfnZu6q+ohtr=3EqC&-%3y>99ri|PDG5x}i044DV>0;2THdX=Y{5N0Dy(G$NGbr>@y(2{RyRW|6P zE|aXp&f;M~jS?-S2~QLs8Rd`or&#VN&r*ej_=or&LqlBJKLezRcM(Wplla5GfDgo$ z*YH#l8^wnY@%ZnGk9_zg$)h`^dz8dIQjwClSB(4&X(l;VM5)%C;_c6FVaW2)4HDB0+xEe)c3bs5LIh zgKC7tI_T;gOLv^3&o+@!M$Kw^%PKKod=%i?vLQ9{7(SAnZtVRD0^*?~#$IAIXb=h&uESShaEl~1l+W1@(_9DCSilYdgUO|;Jdg7 z@yu9=su75$>#vl@Cwl(M822BgE zBcloR4L~J(*Q7oqBWS)Ikl_+6DJZ{r#gfZeK8k&&x{B@GktV`>shzp z=OY9u!`hCGsB^_UJKfVye5V{F*@8}Z4qdBp=?Wuj@h`{&13x%%rJf68k}X`UXTT_! z7cLCet5ND&{5k}l01~u=-S{fz0<-ua#j2bYpL57X`b=|D3KyEQ(k<*Ec%dl=XOHABa>=riv ztJwdf9OQyc{+{*}H5Xf}cW8W~x>#chu^uFVVC2ls7xb%?C~uZN*BsGiiwxe2sdn)O{RSCv+Yu*%u-%nxkaR_|L0==; zO2A)AGUecNC>E!LjlJ~2uHOTQXL(#u<7%eH6=G;3*oWfWNS6aYPb&>eB5`pv(PD;3VvYFj<~m(=kOz(}+a07ZN%yLuF2+XzGq5CN_RxZm57 z&&G|ytOQK_he*b@5qS_k|11-#K=5!IR*(#7Z z>0;Qa!`M7bDTqs6LO$yJki3OljF34nNt;q&O44S>zo%%^f^_U5phoW8Ay@nqdp=*_BdwEF9AU7nR zR=yDX!gPVMuNIzT?qDiAyi_GYd#hmo)^V+bq&-{5B#x zf-J~DKi#&}AMi0@Kaq)C;cvuj7G1c5Zts+ThcjiU4*TbSMe1Do6yP@4nNF8dk@&<7 zZ8(37lb%#AlQ|T9l5Jgwm#L5bv6;{F-zb1b!#uKP^uqx8DH(v)#p=s)@pEMOWtK9# zoJhX=Yl}OgtJ5(3yz?%a#l0eOkhh5Pc4A*BhO-##4lpvAgFYD9BceSNMVg6yl&RR& zVGIMlx!y4dA%R+|87g*sDs8DP6R?3MG%wJHuHx{_zdZ@J zfudLn>2Crwvy#?K^5^_$W6E1IomBucMjBl)WR5htNR#huEH=m4p7FpFl`($UrSzf->eQiDyKT34H2&D1`_<+`0@ zvd4*KJN!j)(%NgcsS_csnwHF#=^jGw&~Ikr*P|+F$9J)j3Dc#0S4L|Zd^sGuW{Ue_ zzDkyHy-CiAMkX1%U`?ua?8-2_j#f)03P5o!XK>h>uC)C{)5St5z3F0>{I9@d>$m~l z05JWbnPN*E)u5h}Y>Ttxj7t67&HA5tLKhNf@<0XgV+2$|r(wYrnRHQ2<>%r>(sK4LUA=N^JoHNUL}q z?Wn>{i?gKV_!*jVY&-e@JcnJj#B5~Ft_(EKY@C59FV#{#hYgpTAl6DF6G^Kam2p2L zDzayGqzObZ%HWLWA`&fGw+6j#RSE^eGU6=g;1|S}%^?3^@b(ed`ppwiCGht0*S5}B zh?|md0t!NIH?h20Du5p_vyiQFQGsm5rCHjlA=)UZt&KLGXW5w7Xs$l$C`YN+Z~ivz zyIe3f-=HPhKTM0-MC^uM>tl~&(;O!%aYAW+GP`v+;3ovfX$im)RPE^nSE;28PnhM& z%M8vKW2&B#+}*GpzH44WSYPH!O74=R@k4$kXaIh;v^eHJneg~({eEmRnX_hx zvqi|X(xvqQQ9zk`ZN6F+GSD4I0MOKgahJV6lh5bikT5+B@&U$x}l$*D7?p>gvn z{RSp6T5aI)%^!GPei>2*w**Q#5&Y!9VAmeH-AdmGM@7TZqmc@H(4dYsQVPt#!j{U82)_g7!u5D@9V4TK5(%Z*gM%?R|^JXltDj^`7;y zStcurk#}KrIzWbih}S7k81y;?PbS!=%zIX{HB}o;IA5joSc_vXA#>Yr@o18kRY~)z zq(XKCIw>v&&NbMx_%gRuKG}n=?ufq&K(+e3J`Ht)P$0Ad(Ds=Zz<6*xVbyu~)`XpO z6~lG-y8?eR@aI&RM}D?!)pmd;iso& zK()J!Rgw}_D5x{pe0+5ZIJ<&l8~DUeYTRzh2CcjT+(o-P{heHe!Y?*Qy(cgX`Y;l( z=R<>~2iP`YJd>|`+ni(ARW3%CS){qm8?l@+cJl1Vg}h(Sc%63b-`fuwPVE`Lun&Wb zwcyDw6^g^31U2eOIlsyk|5qIJ188Bw!n19FDuhY;-`O>Y>J)NNZ~bZ0bGF(T@tmzT z>;!!+t9%9pXJ|M8J8Sgvbn=x6V&A{%xTSSP8txtaN;<#9IjyLvu&K5B%chNAR<%|e z^3H+wCb8u?a1RKSCT)TP67c`H7x+mu;u@DJ?1jD11Q#i&ljK9W zqAv*^uvw!M{+!;kb2{bptZJNZ%knzGgmXIG?NSA15{n?shf;~xY=qLx5MC6rVYP)c zTst(g!#ixz3oxx5po{M~7i1$YO}F7GBnPk9@=Nfz%RoIm@I@3OPaz1|#RbEhc3>1d z=1G3~Y?AJS&v@j14#V*4#t+_uPxR9kT-a;dQjEhmVq^`X#6#X;mr*6Q%tW9{j4a2C zZb}}e?V$Jsgs_IdPlm9K3y3(*aYv*RxK0%jD-pqczu;rg@(8FLw({SqzLwRTNm5O0 z*+SG$q)B1;LWmKvALCcrK6&}DAg`uYbH6R}Z$|}RLn1)M2k!*qqmtr70emD&|FAe& zy4XT~re+OJnUQmjpav0AJL8#rs_dN$tAkKJjE6iGHN6$9k|1mPKkR)8Tvb)O{$f&8 z6iiJV%A?{?m|~8I!y!O{Kv7h*G(rIZ5fILCD3zl?iAPMEXEU{I{IndJ%rU3RAsfsF zt*katNoi_DuK)9_z4zgOXjb>T_jmvITkxK>_8Q;!UGJKwmyId}uK|=NgRns)(%vR1 z%M*U$zjWce9nGa;|6oODFWsf$VX%dmXL;R>9VWXI$|48hN$kDpJ$K~Wfi+rz-KkxXWFa-D5)a?VJuqXge5pDgVzT?ZnhWi|I{}2m( z?d?@<-iD#-xb)oH;cKZ;lgv{!$t+i~HS3Zr94Eq=im20IlPrYU51ZprRiP?!Z8e$w zk}9`#r(-z}vVY(}wtNK!U8q6!SKq*{--}x6-2^?3@-dhwSI4L|@5j)0#b#s+m!}6K zcC{H9ONjPB|DMmfX3wW(7A1KAyHKGPKC&5Zj`gy z_F+G<>lqbHd{72)FlE9y<|p1@Ic{zzZUF(oc`iib#WqtSEnLci^h4*KuyqZcdmMKN z==nkB9Itv!Xd`h_6u@M7-?%hBvS`|`~=ynf-4 zj_zXP^e|7H8NpG*?Vc6iz|wzH!{BW-w=eLyWQ={suo}wPbGH>$wy%~QCd5QEe7L9X z!u!Xr$L53P&giOMd$gCF>i)3+XF}Ie&V-;*T631HoxT@bKZX<#Dqu_kEdL#+c#E2}4Jeuu)J@vzh1r6-&A1M?s5$*!E{zNF<27n?UPgu1 zQolzn@?~EwhD@g+8HS2Y+>&8jxd&!}7Tg?^>SQA#=Fj#f4p=iE>E|5f7dq0{?(+&t zso0S?^7R0;6{d+xAd|WRzmqtzhmwbLbIxtfLteYW&d>10%kc}I z02X-i4XEU|HFu6QOB!4Bt$)!s{$b~DNw)ix&*_ato!#un*qdXA2=<9!(4K$Isns&* zzNPnBF`e-m9gE7n^Re02%WDr7!&lvld<`ml0?tdJ2T@-SyW;?Fd~`g7QCfYReO)-r zW6@AgM7wYp?m+b_+N~mg#}zr|I$eI1FAtnl#Y=@m;VGA|rMjP@T^>Xb8(iSJ(B+Ca z?nIh4KsF#1FaaU`MSEbiElN*vmuK}zF>|xv(OC|5!v6K|Mn|1098{k-jBVdQ=7jN-amCXsQGV&m( zIu9EEacXrH((U#DQjxe=EvW3%`*GR^^TS4-{Ho_kF!Lk?PVhm`ORX@c0u}=n4fX1H zXyGugq8}CaPAcxb+gOBbL5nalr9stue!!AMG&I;>G&TvRMYNyMym233(V&4C>f@B2W}lle0o!9_ zi}%re)(>e1pjL4Xio8`F{!eQPFD;-uc68RCoyQy!h>pMVwN1ER& z<6uJV7m#sIQ!ygU%4pcF;19MB>kGf=oDK_ZOux1v@PXx7x}M{6yO`_hhAES-YG%7t zS^TFXvv3Zxa%7eVu4hEd_0HguWIF~(7%o{vMXwdaB`iv_U4w|=-a#J3u5=h$tsqu( z!9_}R!Fb?%M9ne#)wDuoSW+dW6vPlKv&gAcL!E%k1QhL^3d>*oILytzM>F&euGpH+!s zP8aJ!&GFh0U*dQVFL8`fFL9vF!uvXy4$@!ZXr^7`LZ;we)o1xkUrS0a^{hCE=ETIx z6PM?2$Ma$KKPYUt~?diNK$)vjf;|UtWxN=l&cG1W?fzMtLHqN@$j-Y zU%^}DC+<*MX=D9EOGZ$mSgyIpD3*q>2e=9Qm_Rkb6?S-DJM_ey`(pYB;_@4u&OKAK zS32=-Y;@T6xgOTis6fnxgiZ{yH$wT~mC4u{9OUf7H5Q(I>WcLfdm#FCTn_Vo3#9?) z*X==&Lfm&yiQyb4$w$H3e1-BX1_ykFa)|2{%6>TKTl*EtzJT~QF=*{Q)*o8xC+!}ryX*>Jy98qGT?g5hNCqGmxK>BrQYI>sty|`w`hys}pVlH_K(Bm!S=tG9Bjc-jy{nbXca<~TZo>XEmL>!4faKV_VvdY48S#>7 zs=#7H>em?O6zvSEv1VwL)*A1g@~JE(1#R7>pl!7jSSSU}l@tV2OF>&o0YrdXhYRNo zoG&XeP?_1=J@3QzU6}Wi@4SG0xDUhjTABBdge;M$eamgvJN?KXQbGwpN?>DCh(rQx zF%Vh>@dVcrwU%glbY@jQH#*Ky2eZCHO$9b7W*HCgm~5)x=yzw^y4b`$qFh3nj5ZB7 z{b(H-3l_85DBVwMrgS`&qV(pPm(l~Z-;3a{uXdW+42$-?(t|Xda>aL7?Ng<9)81El zi1v=sduuzD-d1}<>HW3!N*|~_54~uoRnD+#E0k5F_K?z}wPi|=(@K?|pv_nMXl=IA z$7$1*K0(V=`mI`u(o?nZO3%Y%u7OSzHabv}v^KQe zSWIJpGA^XiM;RB>_}c<{SW4qbWxSWh6Uz7?jUOxHqcrYU#wTdpp^U3&d_@`8(D;Hf zs!JuFRK~5eeLxv^(zsX|_s}?B8Bth;HUmb5@+;ORuDx-zQdCC|>V}UYur7=Sp zyU{pN8AE6srHs949Hxx@X+&8D_5*3`sf<<{J1b)(jct@Mn#KSa70Pk^@>C89G@eB< zlp9CW_`NcYqwx!6oIvA;%6Kb{Z^MY8rnwrd7dzW{XT2~Vb?XSu(5!)%@#=B?;1~!H8urcUjQaSI6m@hxE1F=w|n?M=N*J=!!Zf6SHd2>`9<}V(=HGHmEJ)G zKjQT1PK){2CwgM&g}L>(HZ3>1e;#bmc2)GkoGTWUycc>_e2LCg@+XDFkKw~OmbCaMZyTnz7x{=Kj9y!b$;=Kv3TcOcbyK#GUGQ$xH`xJ?Tf z5bkMj1?F?lR(tJ0mE`hmlK*zRKdZz2B8=nGaX)VcQ#=YKAPe@>|w=Z7)9V%$$=lfKX2B7Sv^g{^tm=LG@5r^aRpuVabYN%XeR?(>L@d9%VRCvcoxOK;(Rbc5qJ2qpFj zl$P}Vn)?I$tKSg(hGM3l9nu%EIE70b+G$b13-{~jJ zIAhJm6Hd|CmCIL{u#qCc=_PyDcm5<>IFM1i$;Q9!Hzq2^zlfN$BNn6mJg zVu=cjySYlbktsMNct=N!zDrB2_*_&%da!Z5WC{wvqDIaQq_WpmoO$JHVo6(kIqP}t zE}Dg1o-Gz7^jvfgw}h``Uamt2!NA|irNIMEuY4YcoO9lV4Z%CCpq2_-kd6FXBnl%Yg=gv zWhZn4+2p_Y3_5v5n@PXGu5<{CD^9LTRY$rj>U8585wBAL8HtDg;DaIK7RBG!-(Qr5i|JX&F;CJdTpePTOw*lheZ#C;dxen2w6n z)4^MGenw6&|Ed#|E`;s7lX&!LNTnNPXe%Y_h1Cj^)D9{=J<|N+bRI zm!E_*_1a6(>`&2LfltR~$_#e=6H)B$1x31~h2n(s9e==w^X*<|f|VeYl|;i6jy@N3 zUepXnlpkZJIex>bWF3!PqOo--F8Lff|GaF5$=VN`m3ok1oT@D==?dS-LlsHg*%-m( zls^x}3!GqD97ekx!Ky;QiAw(k*&w^TlM8hmb!UdUAsr33qSY)Az+K0jB1_zFA@ULa zo0@rj?zLaXzX$0^V*{hmf743?ymrmsOpEiR?3KStStiO& zZOT$;=T6x$Qg);Ash4$C#+eUxT9)zCAk2-dUk$RtocAeV-*knCl6tTGBn?jjk*JH3 zvj!Df{?=Y+#*WPx)0n4SDl1SR%gUk=ZSXc606B!?!rSnsn|>&oV_Lo&>0kT+nC{9| zkg+SFthf&Y*Oj$4Kd%kU{;$$Qk1dlf+OV16RK;7*V!hm|jBW&WR15(w49PS3 zas$~Sd-pdBK3=m>(o(dV(u){bCThlCq}mW+&o0`m{MfF;IpR=N1aY6j5BIZrZvaxX zUtlZ^sTg7u&tLI5zM`jD+psdXV&zMTp`(9mH8Kv;UQprNGW-S@i!5rtn4eQ260E8U z4)gI!{Vm#~(>Zp>Y*?L&*78M=QVLQfgRgD9pqYQ8TT;4PXI^}Gce|n@Eh}o$a)nmla@O8J->Bl~MIU#p=gr3*_a|x<7=gQJsE5aGdM0W)w8K84 zIS?rHKpPpN1!8c0uhYB z3z9M3vl=;@F7!l8fICqAu&E6v!ctyE`n;wDH!Ib{@mGDq^b)6E2b-r~Log|~h=*UD zZ)-qG;$3$feYH2?$ya~p+iQoYldtOF>jyOszN*gJ{O=v8<*FwI^=GowsaNM*&aIS{ zJ&&fKbi+aZZa%@^k~QkLQvLF!=+Y8R{l24qSE=8f_|=vb;O7vgAaUvy-{_qNYuoW@ z^n@A}@)*D?a8ajTd8?^;>NTYi`bT)!)Q%ha8qWo9UgM25yvC&sZb-nMAl&%V&RMzb zybs>4_VU}ntM{hEIV(>4qcf_YL*?1b!FZcM`wF@A((Mgd<-OrH^gJXQ=Y*zqk}uI9EH6r)uA< zeX6#Mk?5yteceyh(we7gPhwgrtNwU&*zU9-9xPkk@;Z8OTXC`jKESob&`L{mj_RD& zd93rEJTCth#T+TuJXafyt2xvGs=aV+uz}vo--NNKj7IPBmt1C#@~2>)uk0NtT;&hA zoIJ~&FgtLrwj1`p>Y48>tSa41OfZ98n(gw6gSE6QzX>+Z5*m37_D$npt#TSd&#N^! ziSk}Xyq#;tOGn1rT*b>T^g&dNG`q*h@A4mfiCv6sjN`WqTcqPRoT_#FhEug4z+NXv zz*N4A-omo&S4J3?Sn|;Gu>3hV=`0B-U+ywn%I|@Bk=MY!_NyJYd-S#kq9bO61&fTZ zx$rZvm-2DF?qfB1D+`fhNz9$qo^ClYX{INsL5S#}VHG9`xEBiOyM$jcB-o;ba)3N@9x zkJ<21{yKK}QC803OztLh1^kQ0u#dxcHn}6w7N^eSLU@7zzR}o4v<8C$2hZeE5)ne^ zg`qqV;m($jVEuIM<8X50IZww_JKGypJ2{nTW7n(Q2UVUdgaqgw138te zKaQbmqZRsTGg{)X8-90}kU>PKd@uZ{6SM5j0`Eeentd5g#GiW;ovPZZBOzOe|E6J8 z3F@x(vXaw?Frlo3r9VOQZ;42G8rIfsw<>>3s-oGVVO0y2$KA>wE%ksn^n`HbvzZ(& zoiIuZf)CWs#rDyOq(G{3vGi?guDV5Tr1T~!de)bBh1ob6OV0_~_Aim|<-A*8os8{^ z9KgA3m47%HE7|cshm)}{11Fx0oyC)}*Q%4TU%~B+$}ES@3%!oBWgFRoI4W)}Dmj5< zyq!vO=HbZ{lst}!V$~U0X0=6~k^K}VuFd&6OK8LkS1tyX4~DoH>{c}jPRf#>sN2x( zWE5w&2?z2146O4y?;Li{nN(HY00`6wh0|y7E6N^Yp6G|YA0rcR(ExsVe3I_yaf*s8 zds7F_*iP21R4yfjDrcUeq__DhvX$^WZ;*3?ve~7dx9#>kN{y=Aao+X`ctw8U44z79 z15{bnY7vN+Fjh>09Hj#0C;D3?w;5~9z z$@_>fWMRn%&~}%+gJ0yNC~pcs$Y=!cFKNm6cjMYIi!D%R$eC@p0K|XGFm=XuSk*%n z&A>-m8s}?OY2|laXKPLJjN-HuIJ?f)D(;!Wp(FukYn9L$XKU%flnS1l<=I*yU1mRp zqlYj^RXMpItflno2Wuy@cILraT`*h+YspjnU~SYXb*fgO2tMFK2{_>>I(}`FAzJmF z`yHVnwsEqIR!;T1%Ok{EVU1DeW$WWK6&9I)4ptI)=v+ltRrNiAd0Aa3^{TI;evAY2 zEnd9FUSH!YxB^#yVpo;!hI*d- zAn){6JXp~XtZendcV?R(u0T6iag}@Pveq&}3;YEcy_q$FROf7u$qkGPr&9U**g^c3 zDS1I1OJ7=R1keSH=WM&{MsGyEnH;WYr8jNp!G?^`UO!zk@~?1|6rO-3d2F-e$n12d z;xtae!v^OpWf=_#S@k$CQ&zH&AJ|Q$^}(?pRkPdshALZIce#PCH853S6q*GpX~u;s z8|+V2bSx@UL{_xc1E72}I}M_6a)SMM#RoCxdV?q|HtR%Pz_l+=)g04<2viup!j;u!eC`Szvw3P@mzT&{eHqHNm^d}KwMAnqAxsbyArgyGk~i5h#5=E#_~Jox<6w5 zh?C#APIt`lidNc6tk~<^(4K=4$muAXn_oFSkB#ciF~_xfK!)3`v{#vgK4R3L%T^Bw zY4NLJjU6MU;k;D7aZ!w)@9ywG=1xUZe0Z0IH-{6fSZO=MeT!0XYq5uM@shzJf9(nv zLfi$5$BRv_T%mE)Zs2OgV5;JCbF^jbxW%B$|4r<=Ejn&BV#Uq`x3MPoX>yR4 zY3q@Nde^c(PWvD;CgK3)+{$?&xH@#!6;9mJIp{R5lx$*LBiaNk9CRA5vkb=mBsE1~ z+cPX|ZsnYV>ByrBOVLp8^RpT|u}j-Gz0{+qo@Yg4UW1PS8Au3^B$ykqQj=N875j0) zDwYs@#$jg{4`LdxOYu=0W(hAEwY3PH7+?$Ne>LB=@x?YAecuue0OOFEDxsCy%cwPQ z?mcu|bNki0r+WSyn_zd7`@1)o@2_~9bo+0tm!RzgKh?!Ib9rEX;q&+``qg7zCrlF0 zvGjTmt3m$vZ65`GjU1cRK<457ChjsS*$Us>B^3~+g5+EJ-{OHy-VTOGV*bVHXmyMe z@8vhatWCf^1O19ecVsw&6b5H*TjEai1f+zhvpj01=3g=Zo+@5b6&N?$t8F?cXdmc> zwOW|5B*$$w&rCv-vk{x4;wzn{dw>+q|A%*CPq(feBa9J+7D{%~FU*0!CE)BgUWf9Vgu&lT-+cct_?^*UcrYB=j1I!13^4h^?e3MB^WPQk8&Qy4sE!3gvZ){+g8Cah{^j# z`?;IS$AH6G4P}d25TTX4C(w2BTis_k4=2=dk>6t0l6aEd8HL-f)eY5w+AL+qm#0v1 z;{95CAiZ*15wG;KA-;+$o%@6L;B^AeaTSelyWd{_hqjhQ3Xket1L}NzMNkrDOuOw( z*77{6AKmr8Gyrw&RxMi=g`;NcFyzc5yn&fT~VpGrFggz2Q3a@ z8)RH)eXPK5^S0u8Z2Q@<)+}#qI$MrHfR|-)5)(6RzF7^l*~y^I$pg(Tg3l*tZ(~HK z-m-Lh_rp|z{fDB?XiKWNUt7hG3IOGJEU%J3jVm$(HEv%p=IWBCf&vsD=3pYO631-| zVV~R5vIZq;?Is{yEZ5?Wx-ntLY$LICGjyh>I(K+(1t|*isluz< zbJ4g1($))Ch4j$w+5$Iqa{=%1$Hn7GS}SF+4cC?wns@*Ob+ljW_Y zJPt}%GDbvpv@|4CvESYdPD7QGo~mt2X^2zZxB%o|4(5Rq++>MuirUcgiioiD{)_(r ziJ`sxi+_P$*86pA(i(9K>x}W-Ca8`+p-#nx+-O-ndYvH!GqXHz#;&s}Ep9W=@Y<1} zU5P{up4{3SX>UwKO5lR63FCedU&y-gpbpo@9wjZqy@!=H0s5i!?5DWnMh@{W z8V)VX8}~So8=4<*R6>bS9UN4~ln29vXzj?&xt?c_l@0U6k*>uhh;fh}$89hsWO*BL z?0HPZ!O6@Nri$avey@}^EuHR7_Vm=_{1`4cU_5rLwmSon0N?Wz8HF#F;)5B`xWWa6 zg%#>J(1QvUr#Mb88q>UZw8vHUtJS5UxDwv2itUJ-i}kxT@e-l6&broH)wXzy?_s1| zv@^g}cL(CoOs`L{zKo3X#ii5OSgOUM4~M&gC7~I7xZR2@AI*V|3xHuy;oW+X|-A0wRqP9EA-Va~c+Uhn>pzcJ4smW*4dvNRh8r|CnMpQS18< zQ=e6@@Gy$|0VlVVV*S8ZJA}x2zkU@+H&M73DD?V7U6-sSBHg0?KK4dhUxf@N7Dds1 zi9%noIqdhs>2r{5!Bh}!)OcDi3?j_S;r)vv!AK?(h8lrOCfSHue~vc#q0*?zj@xl0 z8R*%s(LTDJv@&|_7>wqY5j+%Quk2_)jU!0@#k^M(N#P`|#z^;IJXD<&1qT8`O$ms( zI-&agWzF?184dMbx7Yqf;kchX$$#T)Z>*{4lPZVK&Hr6kG5Ae@?tp#+bc}{=ovC{Y z+tt)@(rJ(*#@pd+SQghaXi-zgm-8L_JQg;s=u*>mfn%R%h2}`{F05!=?c!+fDBZmDVx_ohbmERA=PuRC z`j>1Is2UCxeNnjWyZW}Yih5;_zyeKWZau(oG_|>7E%>>GO>KR^2v`*+!KyGBR=Md` z{NyCyXU47gnU@ELDX=TdgSAl`yt1@q8D6(6^p3$43YKKNYz=s@XXvmP``K}~;GwYB zP!vS)!Qg!(o!dskSL8l-91?=u?19lcr4(m?E(x?TV9 zD)N=8hAf=XOzSwCnQ}{Mh&C-1sO+jh%OA)p>8)}2RJ~pQlBFODDK&o;-FK0W7X|yG z$Lx>j8ztfO+nA?S5!H^&GOKItT^OC}Ey)@eGa*#xu-|7|v=`u>)q$y=MW>ow))EY1 zxfoUseB{DQV8kKAW zaC={)h)L-0Yj_&(YXrZI2R88HkMY391IHElsJknM8}C!F6~u83HUXFSz($KiZtohY z6`ZWD*>Gha(w&F_TVTai+%i>#>fO(Yd;MWGu}W*_N;ecQZ8UPRt)jkjMH`l$_U zwZm9OZ6m;?P^t=D4`Imj$nqSk9U22<^+WZxc5uTbOmAb`i{2CU#*RHd{Y-BNa!lRS zF>!}FKbeT3R-?VPcx>6lI7FW*8{pgf>=ziLB%b}k7$#xJ zk)G#OmWKZ(CmVt z`DtkadSaSwY)ZCWnTNTV!?UwR3;MZGrlx&#Ayo$K8f>Nj)X005N7OKe-|uc8rg5Wm1-+Qa1T?o#GRD znF&8>z}X_YiXO1dMr_yMD;@FW;G5haPPCyEke?}l3ptgeaHRAwlrAs&Z*|B>g;P9Y zAYR>7?lQ;C{J!3m-#LhZ97uyda%&1`wIGE&gq^IYPB+rXhOSdfUNBzWWg2{%*qbtI zrqk1vPTg|FSZd}s<2Lyn0enZ}oB2ZC>n=Kn$t&X5{of)Nwdn|P(P83b@~tikQfu-1 zdekju`C@LTs8XTR!_rk(92O;Wlv@**>ioN2^mD~$;&FNTHxp^qo#KUg=$>BRzmXnG z63gh{Nw1G9y*$XIp7%2lS3csjgMZoJ+Jz;@EQ{3~)8+7b(c2Z@S}IM&z&xPR>F8NY zj))CoVm+YOEv%;~GncOKd%DRF@w+gdY2Y$zIZ~dX_@AQcF1-$z`ls>#9eJslQmW#2 ziopew{_1i_?z2{~p+03jngRc8c_x7xlec=!OwO2jq{kEDmOqy-4~$ipLCOW&Y_{Hd z%x1jR<^1yFO#u~Cz;83g0vEPszK5Wf!F1R@rz2l-6>nH;ur1BQH_fcY**dYM(>cS| zL$BTSFqE!pUQn*shgy3ScZfhA2OU%V=sa4H7W!=;<6aTyw?fCR2O*$eLHi?C(Tw)c z1EE)bWEHKTKLNcp^bqK6pl|)qD%wKNgMKybp|^vc@qrbXLP2j2E#R;fa*TfNdsejA z=)Xe04f=ZM=w^!Np>w8WG4yy$O6J2*#fUC5Dns3D$d8aWG8+ zr^#)mB0!_wzv_-QgfB}C1m76*6y=NUFKcQ&G~=48xH%KQgH`z2DMTTh-hXSa;!da$ z+W=-ryc2wbp9*G=g z-NAkr`;%0|K@v5`Be6v4fnptm9g)6?Xe?uI} z-^nPAc-R;2trmgEaMmoeqPuon_Oq2eY z4&!01%@&09iH`eFd}X?Qj|R5%QQ&5mg!EGp1N(bs$kFiS{v8j#vKMN`n+W%s-%Oi0 zF+KLfmAZF1VQNogv>hv&|4nMX{v<QYtK;`8J?G)sq!!- zf3nKIv`P8)lziP!N{%uj9f9}-;$@ryaWNi1j)+g0Ef5Fvd@(d_l88;o5s4`_dwwb$ zpoZpWD%0o;dwzjomz0*8lV*I3w(F+&+#KbaXgBl}8^a2O6YwwKPr#3WyYTSz^7g4$ z-?u@-Mt+T(_y;t-qFM76SGEjn)w)gFtFCTmY2Tq^P^Zpax?Xc_aJTEa_Xz2EeXrhq z`u6J|Iv{M|put0|;WtD?MhzVn9TR(FT>S762_r`(jvg~MY25gmZk{mlmgHMgCQVLF zOP`XFnKd^!x&wea6gLvv0e7&fIy0B{l`PUWgvHn-nzV5GRv@n(Apdm6?Oo z7kE_vd3s#lpBer_>i??EpOpZn)Es|iiu|fJ2jDuhzoKgUzdUNIeFcbWvu;vX&I`x< z1x3Xrcig$Kbdhs$*^;}KF1!1ld+)pdfd?OY_>o5+dwls5E1q1rYV}i3uX*O#=bnGz z#ec0`_tMMjH*DPW%B!!v{>J7vw`|?EeaFtXcJ1D?ci-FZyu1Iv!9(vIe*c3HKRWX9 z(N8}8?DJ#CzxeX26JLMxtycbB#rHq_c(U@RpHH3s<;>Z0zy9`n)gQRw^`ABb7q93q zt0DNGrvHCB{eR5=KWm6D?yef*|7rStFxGvDoIzQ@hX*EYOQw~W82e-JC0$ccGTjq?kgxoxPp0d-w^=L#qX4+Gxq}`A^D+%-D ziE3uN_MCWE^lCYB$i_IGs%wrtJ6ku3dIJ9*7y}BgdZM0ZfOk|>ln+&(5R7f;+0s8@ zTzy~BFC-)>0q4&w7DcY_tr@pM2{9{g7L+f1i2B0U7n(2r_^DJqhvN>%dGlCY( zv!|#r0moDNXl`hVEhXC$m7kxRZ^_KD#HHACCTF03pO29i)zFm8?6g#iE!UEpmzHBm zo0T@%ZcCYz%?|#U92)4B4jHhd$W$bo;j7(|4|RC}Ue$im^2yl?B2n0LE$G78 z+sWWQXWck@=4=e-05}Hc_+DQ*F=uMJh)yU41)>W^{}#h6#N^x@TYhe~B_ky#H9IZe zQk%Z&Je`teLzZURER%Cn(=55^mOOKZmSZ#h*Tgq1e_Cb^QyT zB{{cpsJLwKu@3%&U5YNfJiGI|MqZ_+sVsMQx7Z8Fj4`8!Ue~{dUzK8)j$JG%2KJN` z_mFkTL6`Pjz)CDl&SazvT`T+Rz`bS;)=1$38A-{XVrS+SSh}XoK+TkyZb_S#XPbS^ zrPG-NkuoZ+6t0`5AjeICrBGU?rA^Dl6h#N4G<9&5D@z@Am|LMx{Y_Qu87`ivv0Ueh!fuy#f2HT8-FNh=>At5{`V0H$?gDCOZ>uoztc}M#{cFZk+r8d^OS?yh)pS2t z3y(DeYr5kyEyYjb(`Yc}rvX$Zezn7gM$~k#jbBl8P4^>i@gIZRSGC-0=hHi}7Y`4# z#DchL-Ys)8yQf2ck;AL~CAgVu<9j;6O7AXu-Q#&=lvTV4aCfgAzR$Rt?zoB9#ZQK- zkG&mKCO>P3cP7_#ug!03YEAdr@$XC1-I0X2A7(S1+VP}LuNhBm_q7Ez-D{`Q^6r}M zwZk8J;nMEUzF5<}cKiXGt>XLB!lhEr!FUjL0rn)B>OB+mY_{z<4S`?`y@OmFDk8UG4?BDWEO3Abh&CO3llb)TX#}+k9Tq(i}3NokU z7%_~_txihZ;sO5{0vh8Nj8KjdZxRxLKBo~xh~}QKjn7TBXQvIt@L+h#G!P_KdyQn@ z-3^QCsHb?v+p}$%H_W!Bjm}NVOihc(z&gQX#)H9VzRjM;U`e8cHlxuu(AgsHGw5~2 z6pm7$hf39n#wsSiIaXBzBlJ}GOc)bOY{ zb0nB!;I9vuqcBeH<(ZI{Hnp0=oxO~Fipj~d+hQ;V!2UtcgxmtRT$o7wTtS|~dQSny z46}_<_?X0~QD%BhLB@?jw`hjSnnZN?lSGt9qAef)F~D|!@&Qpq2c5Z=7#)`so)Du3 zu7Tv7p07GJaNoz(C1!qZW)8Zm;(%v#T1uYU<|f`&W_?TBk0Ofh5g2}DPEN^A1baBe zAVR(3(o$xmU0|Q7=VCsjlUzqihrP$-WGF#SjhZzXOI8SvOktv8HFdkU+1(bRfP8Z+8*jN$JUWA;{Fqei zo_7z8>^4Jp@<~E=DnSzOD(dvw2fG(lJPD*!WY8QQksw4r=IMy2c$ym`Pk?1+s;W6K zOC)lMi!N6>3&l&`iP>pbN4(A}E+Rf94-yJ#0R3CNMgcPxNFmZ0ibhiaMT)8sqpF9D zdbollag>OE%+TjfHaG)W@ufM(4WfC-Jmik0qq#V|0nZ@#HjxF2wL2#xgo{ z@>B!=ZEoB&-M&#g;Xlb^Xtuo|gAv_ePfy2~13PiSaRZCo{Gn(i?D-INy)>j^f9$lpl>9Uo zkCVt(H(rfR$vCb#k;t(BCCb_bnGQu=U%4<4 z4={8$jeBD}+`elY=}!2M`VR*#mjjd+zFNDk)fSBOb@{pyx+zPXTcFt+5D4%AGzMUv zT+QcW23*bObAH>;u%q4(KsT;Im~M=hVX6BA7%#<~c1;0S7(n~>0NVEf@SCNC-<-AO zH>w~NW)yVVCmK3SKI0z`VA|OLx=#aG0H`X|9xycE3V+f;{|*3go^R+2pmXn85rFQ+ z0LHTnz@>u6jqerEiO(tk(|Z~~f13cLX+MDO9|7nd2&Rxf1oDN-L)Too@#*?D-7jW; zG55df-;Br9&G7$|I)?8`t$)BOE(iX-xCUHQ>FHW7s{Xxr{ddKF@kMDJgNrYU{&!*c z?@#BVB4D)G7Zm}^zaO{%#uWaSi$a1A`dgmfzN^r{-MV1*g7yaMo;s!*R;KME03z$<{YfHi<801pC|0vv#Bz^#DM0Q!#x34YvbC#Np%_tUx3E1k=Ng1Z#>dI-U#dN zUtu3Sl!G0o|D)>9_PTl2QeK8K*+ssN0v}Cf@wum!X{OG;qr2*k4?+m?CIPo>{23G) zsyFr&mj zcNfEk4HHR8Ng^{dQ`qfx;h;x{1OE>3;DZl}r=NaWy!z^^V(Zqe;-il~66epKXPvKn zDbM(Tym3H#*E8Kf_aHpT&0-(m$|EeIpUZe~jrXbr$L4=8*$jB&8kkt2*%O zF?^k&2ZjHFszvWqy>o_f@caCz2{G_cm5uoE?eoUo=GQ#>&H<2+PX72Fd0~DtG63ov zzyBz?zG>V$2jF8dyd(Z+9`4y+_n^Mdy?bC)hv(l>e(8>I--i#B=MY@YB>?~ZD@VU` zuIhkeE8W2#`NxdkDimtS@EAyXu31~s~a1S=*}vBg&QMhdfOe8{9ssZa{!Gq$ z_wJ1|N;ma^Me!Y_M4?p}+eEs#;E;-NRw9Q(~8?D_` zpOSui-tBT@`W8{R<>Z$1skx#MS(Ls77yoamNQNX#E&TD98Tvha?%uD* zj2W{fJ+Ak2(37XeP9GuVhGaRfw9A&8$0UnFxpK>fF^uokC5*pN${)_2T`QCn-;Vn* z+O?Ab_1j6|WdLXg>*@y65B(GTbv}_tR>db&OqWodI&~7k!NJ&v8X^V_8YIHQaaTi3 zjN;wMks}3eyu(FoFEDIzN?OH7+KP2}g}Tpj93b>W&z~K_o@5EQX zN>N!^DbAift7L_2_3VKbJOOi~5E|d5m`_{_;Xz?;6tm@Y@t|BL zHpq3@H+9IYPepTt?~s7LU7iqwmI@KK7W0@0Kcy0V0ohb6Lik4!{zZh}itz6t{0X=4 zoe|!eAjD01LfDpKPxo3Oo6#Wm=|t|Io|f@GX5mGz>?I-B?Gf_OF}Ls*gzt;+aR@&N;b$TI5`5)>LnJ&fIWm5dQPKw_T zNmuwb2!9>I4?*}*2tOI&XCVASgny{16i@Y(V*N-dwojMhz%nU5T_;7wq3ZCy2u}{Q zK=?KY-yY#RBYZc6AKX-maXqD&K2nOs(-GG)DYmSW;^?93@HMN3WL>#iMnv2YenWVq zvWmO5Yp0+N9Xbzlc?iEDHYO%AGB#q!knqUl>$-O7(kW=zu#U-whsYQ><39$5$jId2 zYv^IvFpJ?H8y^uBI|R{3MT8HzAw0PoJ#^~Sp}pZA6K@TV4UdS7KzL%-y<2ebU;{^b ziH(mn)zCJ9Et9*$17is4(B9G!NX9V!*w~mMvB_68YZVB0c<5?)=$wr3L&6zBL~L@K zX3bjZ?h41C4i+F8S@bK%s{Cz@(B*!Pm$3(^JSfUEiRZK+h8zOpmdo&zw zIFMH{k*KZ=_vFwX0S)STcr=X$hD0$wb_fKi+C98qpO9V+ynL^Sfn&rCkmcUJBOHU;-Qq_^ z$Ak~485-rIri!l-IqFxrweXz3W5{uIF17+3I{cIVTp{A94YIDjoI?z$)t|d`KgI0N zjT$vd^+)EV4RiH9o}M*WEX<4&59UXR^$ViJ+K1aBFOP{Yzx-01IB`N$R8)xXzyDtR{L@L*H~8h3U&J4O{2`W|m0}(G3Wt7ot7m(( zM?=>S4IRqm(#dG(W}~6I3k}^~velNlwbG0-7>8F5w|LLdvuk5GrJ{PLi zty`lI3DHW;mbMP;)T2j_YiVz3-8!&!`)k_;G-+}*`opa{bnVosOQ#-91N^UPjPKU% zJ9g;;zfA+$^$6|}EZTOswrh{88un-k4^0|3zPfGuPF;I6YS{H^!@^?edTkG1U%##h zbIlb^8n+H?d2NqIzP=3``1tr;d^PIWut9@hj04(tYU9-wt_X4!zL9=#+vZ(52KVR@+y(d}{cD4RgMx$G2P^v8 zLUBd0eS7sO3jJ{}OnrDnUs-_%^tu%7O+WOHaH1WKFG552T-*xq5ElIYBjt(E=&=j* z*j?ZQGgJQWP#2^AQfU+4Mt~OW+O=yBoe%`*+@L`NjDT=VM{x>WXlyG6GzOR)hw;Be zkw1(Vqnpc88I;<@80di`b6-+fde7=%zd?mhw)%^rSk2s@Q-=ThWU!lojZ4gPF``E`f^m@%{SjX zq%Raax4}H(T^L8pEnBw8Z@>LkqCJ(Eci{w;Ja+7u#Q0m%9W+Rc!9UY9tsJy|@!osy zJ-%(*w!#~3xS6@T=nB+_yL@i&2dHGz3z0`VuWsGDYf6HGd&6CV?RvoryDE=@4)O#ScR zzhlRa#mL7Fkcnc_vVHq@MFZsn^G%X@fO#e*FT{~$0%cg~hYuf?1eOiv2X&SYmK}z9 z`|Y5|NZ;-?@T!+Fb^+bCRXut+$it7qA9cMnf%uzX=7p*MopQo*KzT{} zT*_fMbQkdf_)i*;2Yug`@_Nva^AXlNsxaSu2(M(msl=-Ca`DGJDP?(auU@@6Ko*Kg z2l7GDW70vLyrdkF|8>zpzLV$7BgzfspY<-rYzm=*8l4@kg5>&HA76kM>9s%>1BE{7pHh{4+l&SCkEt7M5|!8Red3!_-+W zs1m=BayV#+h5Qc%ze&R&9PSH!SEnHaWdZZ#vg;P*o%QJDs8+-ub@4LH@%KSKEMYlg z-BK4Fly~<$G3AOn`A>JY3k=J8#$Am)fig-OK9e#AG(>@hwLiG~xTqNq8_0(*LQJb) zfBjXWov8t&!32|zy7I)N#hs4dfB#(`di626dQPl-c=`}|f38&_cGEXfj`>Q;k;kQs zCk-DPXduRb!|FK`J${-mX5u%UOqi@pj>GmBp)vrtY{zs6U*@?gh4~XF)8DKQ#5FBm1ojm zl;`fOlTfF2LY>qeG_-p~uUiq#{8}_9{5y2$;Hv-8#C!=#0I!1lmBPfS{<6Mxo|8|H`07jF-f z&w_^4pkakg$Dhw)+*$z|G`u(h8d#oLC&i*pGRre*Fv~M(Fv~ORq^_?k{Lj|LpXH40 z3;J0uAPpwero${N?sU*h8mKlEhRT=b43ID07ABvW1sY}ylD|}bCqF`QCJo7;0c&hB z$*nxIPGWfuM_FK<)E{*c+h?;*>aqn-g6R0yu9sR7fAsGc_vzE81Ntb%q=WS$b;=Cs zV4sINX`vn4TC-n9H@3IzGf=(e2$dV>h01lH;RVpJ1~k0!P_8_E62fyCsvLAqL!R_! z`wSY)K1P=}^}x0H&-%iY{{aIAbY@WZtUdcc3Swh^27j@!9yjdQ|XERS&$Gi8B*&iZ}l>Z$I2g}W%;T6!ZelBQ0 zSzvi44J^;BlO967N*b1uhO8Upof)7ZJyOm~jZ!oaPxdj`KAU}vK4{;dE|7oL8EnJY zk07jBvqnDm+;fusQWMPlpnj=xf_Yha@bMJ6t*D=TV?Jm=S$G*V{L3iMtdmyQ2g}Fu z2g?WZhRAz!tn#kxaOngMcYuZkpkXd(psL-+xCLbc>Vo=*_(K+y{6nsbNy{B~+##QT z{&_`@NdxtZ(LtIhTMVlmdRcBS?kBf`hSx!ZD$k&Sb&^@0pFo}TX#NoSK%Q0J0~(fq zhDD&E1adS#Em9%MIw{<(kMT0fJ=6vDKk+x^KP)V)GjSlE*cIZUf%)Q2$E9fb1Lw$8# z%C~FDK0jMA&(Z!a!#;-CoSd9}#FgcdWnkXCd5Q*i`KnDz?L6T(>jajCKT{v=e9_g% zV0kVx%5$x7m+b!#f98F3bTsopKJ&~os_(@<4dw^rj2SarG+c^~OXUgiVV$&|b<&@e zXV5@Z2e0e0YDGR_ugx~pow7@pE;2beSz>R7WWTPUpg`JeHo185VpXm&<)i8y_J!)A zg}i6mz`BZkA@)Z(9-v}*KJb)XR{e(Y#>yG0eRl6-JYzjbs=loVXnd-ef`n+ zR`_3c-F1DjwI>HxAXlItt@7c?C!drfMvRcyTO`ZM$|Tm5< zP_76Z!;l8nr<6msh2+srXQX`ZY2trI?prmZx{rafz&-}cGwY;>XT=l!KOKKz?ynR} zq4Oy}ko9F4_xHg*nCDT3CEO(Ls*@-alHWJpc%$m~U_XqiKZ!eWWgd|R6KF?%Q}#H{ zVc(8?ckm*;mjEoVRQ5tG-K(nCW-@5P=TH4nnHjj}AUN0IMv zO3Z1=Yp%IQqHnEmAs*~+xC3c0!K8ya<0DX}%(z*%zWdlD`9_Hq?X%v;VEg>s+z7ep zo+Qc&zx;9-`F+{*57!LOe)zy9j{5931FeFAfo$8Nv< z_VdIO`$iS8Oq(=Zd+oInd)HJxu+5;%v+rZlL41inWuA0$Y(Smmfn|i{!ORotltK1Q z%(jPPZ;qcKFMnzNlVywY4_R7){bKL4oMJ^>&Y3eudje&N^Ub7*xN*)I zd+${FjfjYlR;yKFcZ$jfx-*PP19elb%ses63Cjm@H+9Mp#|)G!_5+!B=KKcm=W?4L z;Bu6zKSB3mECF-?4~tozH*emoXdr($Z;0}tXh=y(k#TWxO17{juka_Y$#c>|yjc!d z|InUe1j-Nl+FMW#SO!=o7%%H!;C>$Q6bA+dT9NNhV%|vu(p>Z5y3XY&)qgN$ko_N% zuf*rrv11A!y^9dg&$k;)^e;Ht=8n z`j-mFIRfxWL)|tJZR8x_z8!XV0%@*$T<-c!E8@%k59@!F$0ht`d81BTnD49?Ag8J? zfprp9x1y}8_KkH7<(o1`{8Orni((ii21?x9Q3XR-mEvdPI$RW z;cv<*b$1yi4JHsb(nT3!S-A7gJ0nKx!1g6lez zd&&}d&N75L<3Zr@cW`&%?=JtWBi!?&t~?=KoMWFbVS>cITqWNo&)s$UqbyO@Y0ox* zxSQ)E7$ZIQ4{%rbGYxb6i?(M8<&td>>0lWopICpeu48-To+sq(#*G{0!w)~KpCl1`{roCyWDoqE$SUF@_;+ z#Fw(Q1$8HBF>y!#^r^oo?>g4iziR#mlc;<0`rD; z%m>z;ET_yf)Wb4->GM+F|KJ+_?z;NzCvg6iEybrVgH`}AJWBjIRa&i z`mSBORJ}_cu)I>i=FAq{Lh*?(dEM>$}7#I}<> z=9rVbXFjkmVCDnAS?9B^Wj%&5g<97D&HvT7lMW^S?y^x^&dqPL+`8+Ob$-(i^MW!@ zK9feuI^^g)`Uo2GitQ@*Sp1c?iTM4Qx&j`!2jSldOoMwLxKHCBE9pSvvSsGXDp6ma zA2M_1ah%Vo)ODED_kW%4WyI%U=s5j?^q~HsZpLTE?}oR7(c^oop&$PzdZB@*)O8O- z_cHYQhVF0Z?F@a0p%)su)O8Q)+^1y$SOI@?pO!a*vVTjUJYTf0h@74ez$~~t18`UT z=88(~`9MThr(#-x7z>7=&5un>OB;#)ekA7n!(kr+V4u4Mz$K@Q`?GUW&cIqv^oRNy z8|Q+#rf@yhb|zqM_`{zSN|(Zcw6?`9{rxbun~pMlj`bP(oWG#HEk|4MJ?f>S=$}7{ zd9p0@fg|C+C!hoR8z-k=jf3lCoC~#L{+4UrTrYnAl#~ZBD~Iz)R6oN1#ne@(!&f5B zbF4pEM{>MG90=wbhSBFgk9zeK>fFPqH(z7KTr=f*BiFgOzQQ?it`B{1TFQf<{W8{i z+p(U;yg~}*p2iXf_MJHPWc$c^oox~8YW8K>PoW#lR5xR-iff)+YvURZ_b+gbit9UE z_vacL)y0U1eLIc;Fb2)Rcp;1JFWWVabD1vt(d3Cizv?^bG3viuFS`kIw_NYzTG{$a zch@@2T*Pvh2bDg@gX|*^hy#K3JApi5`}M=uN9EH+W7WC@=fkNc{ebnZ@AP%kMBu=6 zU+#h6+&7$dh(#$1(4cgY$P;Y?}!t z4(xM~C+u6lI4?r2^>KZM^N3VTo4~bKt{-#F&s`q5mxXIIT|INgOAvmwhxxkf}&*Yjf&eF;GC}Zw8P#(wDl1J>{S7m~GX(*4i*6G?Y zeXOUXU|wOYJ047%a!#F!>up>k;d&w0sWv{4_or)y-~A?K{xPh10tfErVVU5XEtN?> z`xST#FQ>4uFpGUqf{6#`O~?x>&aZQ=iEA8OE8{v7*EhIM#x*9cZE%f@>q~Pc>u~>q zOi3J+JYwC|T>EBx?&-4*Ah2&kaL0qVF#osRIYe^3>m}g8IZe)ubB%@a$aOBRuW+qV zt#KLY&rKc5q*R$O<#7=B0OiVm_RX*kk%DuVV_6q)ywCnQ=_W4Z0rmG*W~y~Vu2*sG zmTQJwdtPp=7qU!neS~X;4y;j`JYZt(bu`y*pvy6*-u1nMOX`b=O_0 z-ebMX_K)>HWr6&lEHZ84Ld7!ib3ta{r2{^3|enwHLsY$0uhG zl`q|wCo4{%b5bp9HP|qC@ZesU@10FLu#TBKY0{+KIKM5YPMxaefw4zY&0UydAM%|1 zApbeOqb!gg#J{#;obdM^WXrv+t&u)Iur4+RITS>kIBn#9a6a#LKb5@Raoh5dHW@F)_!+_Z_GO5c=c@|8e52uzRd5$;G(bp!XR zl6J}*^NYMD-K>)__wv+VOk1VTbWqo*`oAtb%sw#A97vpZRCC4b7jn*t^7s$ZR_T*o zv;CzkkzU40V4cS@$Ffa2DP!Ef!@Ut5D<%xByQ zLHYXu^I@fkgYzeUSMjV#z~2OxuRp8bE{a!GJDl0|aGlp}=KwDN9sqF}K!0YKb_hZk z0y`55VJ1jN9e1!eE;zSq5f@X~tHrqMRFKDr<;$0^#~RHU)KNcTU&!50J@r(LdIxI& zClN>Pv(G-O?BU0I<;s;Yn9qLmg%@5>`DwOc%xBc;AG#;T^)&2%<~-}~h~qfq?=;IH z$HtV`7cmA&M8A&v8i!zP^$5m+P@Bv+=$A6hKAhQ~G0PO|vSf^#IA-D;!h7h}^v1qU zD6@YoxPHL2Sk_oC5h$+=OO=A*3CF;j^e&mQGk$)7zL9kk%Mo#9-+{7y@Qqb+S+3qU zoNSEWIDX{#m16~tRYEXUdI)%Nt(9YP;!gQzy3fpuQGJ|K7=t|moEZnl;v9Q%E`sAe zjywBf+{rm=_Njn$pdVK|0*`M&9rak#4rRI!}X;XDGzY~&yFiER-3K~%5b5vBTD z9Di`^!Lbkfx*Tsj|7fXX92|#70}tjO?w(QW+^oaMhvPd}$c>IcYCOrlJNxY%H*oAU zH*J_oBk`D&YcQ_GId555Sg7`ha9xdgNqI5(uRP=D;I_4@-#-^)A48GY4dfr%1yyfx zO^*8q7}k`zb@K+x?~Wf<{Nxzw|Fw7R;Z+n@{02e=U!({Eg_KJOe1c%+u{%3EGdr7L zfPev_Am*!p2_XrA5Fj@|q^J?GJPak!D6s|%5;Z`?sKCcdL5hlqZKTM{d_2Slz5pYY zAXs|lLU?HV+5Xo**!%6>-8-){zd3Wx+`V_t@9~^)`==W9$LOB1^~Ua)v4m&W!fI@!;7Z*HI3!r*_H5G&DbxaH^y$8HJ2F=V^6P?#he>o z-dNTgP5#F5H`q0LIWWFbux{X~1-~Y&!<&B*-a+`V#7LXpEPsV4P`$?v( z`JQcjH~bcJRasNd!`D?OM8O_tdT|fH@jva2c}#w@w={Vp;6`RJ2zT_pSn46b z%a|YLLCl8Qav(x^Ce)l4$O4weK%jRx4+?O&UFyPaK^z(oJ}>~5BM}h&d;&x=p9su> zdBATu2#({!k^4;i^PF&ssV(?3=F1@PM1~+GKP=Bkc(gU*Qrn5}c?e?77?~!5Y&p{;2F*sgb{-jCm`e0BMJ1W5*d$J}79dG}({L;drnOc_4bqYAT$VRby)~6wS~Ls1@pjx}n=q zJW4?$(P%Ud6{1JbO!PEbjy9pQs0|*93-B!bGG32Az-6R?w4nFXa#~H-)1&kRJx}kn z23o0Bx;4$3WzDyqv?{ITR*kjAddJ#peP_kmkJ^M~vA5W*4t6}Jx0C9mJK0W=Q|v5u zmN`|<`_574dfu5kJexnp=keuyBj3Sm`5u0rw{|jHh1$#INr{FZ4 zg{R^gya6A^pW_J9oKSLr947T7mln`Dw3M!~M%wf2KiSXON9@n-2o}YnS$F2Lcs7{b z&&IG~wuDu)H`#maTNdk3M>%QEd}lJhPJO7pQPk_>b=7fN>9KmE{=F{JOLdiAqc=iq zGh>vu!66xKL1}mw{uFp4hYom44 zYGX&+_uHpg(23=hyqdqx-{nWRbUzkj<%{wa`L3*&u_{?@P>0lU^}TB9we&i8ojvMF zudg@HTj-U0-*^w`Og&Cd(o^+AdZvCtFVs)#3jLy9rPt~=^xJxu{zxCzpXrnOjE?l9 z{5F19zlV=}<|q3@{84@&9(Wl+_d4Ob@kBfy*W)(CA-zc@AaI zw#<{$WRWbE3*|F%sazq~%1xkIJLDc&C%=&2$uqL4>Z*iFQx)n3Rjc->I?%K0J>;$M z-uL!;Ep=O+rnB^P{ivR!=j*3*xn8E1>sRzT{kncj|5YE*hx8}yOqZ z>r?An%dtJXpIv9SXNXleuQ*>h4Nemt#oO~P{60R4=kmw-eEuANoBzm(+Xrym<#rHr z#d7gm*+Y7AupBG%0k;K!*W2=M@1UC;m9! z1O+LAzVt=8C?A!hBj_0V5hdb5_(8k?tj^zYQ__aqNwP>Td5SzsR+5j&SL8H7)TMo( zFHg`#v<7tK0FAJ2wr;UHTj#7!b`N`?U2fm%_|8X8yxY&cSLBK&lFD@|&nxtLYN=n< zn{}zb#Du*IC}>}!>1Y+&gQB3FWuyl5@JpCai8Rf+%g(T8*(H3p+fv>mAC?tzj(5s$ z@Xz^1@Yzr{fFe?&K zR^O>sUaaSM{k=Kfau3=s2^gBpz{8*k`%wS~aSxmTc4`i0WE1I3d(r3VX1bmJKnGaU zty1e5YnfGLRfCn@Z=JWIVP@TC_q361*&OCrygk=0u}keTK(GnBiQUHHn8i3#Yy_Ld z*0U{a8{5uyvRbyA?PGPUo72-lj^%K$<*S^bd@7&8XT$tk%vbTXd=qHPPO#;5{4;)n z{{Zu`In2jsH`UE|i`^*MRz}MNu-jdrSL4AxcQ<%aPu&2aMKira zUJKn_KcI8;unRW7#;i!-Pp!y9OVN6C2%ViI}HN@jsh=YdvF0lhvU z&&f85stIb5>g+x4Re4*zqh2#TNH5X}VBcV7Lcr-jU^pB`A_}rUMplr6AaM;?$uaOR zQM4yTG=)wC`%yz{X&r5#?VvZQR-siEUQ$Pd*A)Sn4OeSaqMc+X+l6kSm=3mfrkE{? zMTsaCWujbEh)PiY~7RSx4&t!mV2wN7nP0UfD1_~&??sFQTE wPSHbksvfS#=v?sF1-cMyei8V_+29u|jW%D~t|4#@folj{L*N<${}%}S3sXxjq5uE@ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe b/backend/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe new file mode 100644 index 0000000000000000000000000000000000000000..951d5817c9e6d81c94a173a0d9fead7f1f143331 GIT binary patch literal 168448 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/distlib/w64.exe b/backend/venv/Lib/site-packages/pip/_vendor/distlib/w64.exe new file mode 100644 index 0000000000000000000000000000000000000000..5763076d2878093971a0ef9870e1cde7f556b18b GIT binary patch literal 101888 zcmeFadwf*YwZK2gWXKQ_&Y%ng1RW(P8XvLInmD2vn2|FwQLLg=QPF6m6)O!hf)zD* zk~YI}TKcfpwzjp;YhSmmw^tIhm=GX@hXhm%;seFU8AmiICgFL0-?h&q1nTYY{{H{* z(VTPkbM3X)UVFXvp6Z)cxZEz6E06ze+vRHJDgUa}-+%w7hwPE3ts3e2$M7wuH|NB* zoPPcMuPq8Jth?{-y4&v!)ZG4!Z`>CT+;LZ+F7b`P*S--5UvpjH-uv#n>-?gkf|6|0 ze|zHfzwAHo%+Z1W?_PP%(a-t*v5go8j)Mza&?pPjFVb;B~PDv zugZ~!yyv=H9{Iz+fu~9YdB5J4Lr&GQflArBlyn*ycu3uBioCiiPRnu4l9v@ZuKm~X ztj}@fjgW-wzn&b|od8h(naed{AnpJ1>~XogGO_>5zw_gFEs2xY@+yA>AQ`(5!H|Ce zmuuenb$8w#zuo0}w2}03OYA49_9|s$8zt^A|b= z)fgG8tB?Zc{7bp2^XnGX)sUrd0&ZN_^YP^`DtFg{`zUyoj1^p|F)aU=a?{BD|Nngf z1{yoH#xwMM8>BZH_nStwW)R%pvdtENw^!#d4j!Q3Jt0x;u%1DWs8&?UI zqp9h|dMZ{@7EVpG%WXXwE(usu&!)lC$@Y(yGD**Q*#aX};&qE0cH-v7~&5!7}DrTmchEEO&=>CP%XgXD05h;H+mb|ON zDuZu?%*~ChO7`3WWE|Tw}j30R?cY)kTc(|}~R^fFp9 z*8PyyYwT$05#4<#{T-;{IoMjBxykyEF;2g93WGS*2y{Ki`n^5dZ`f>)ny-R4>xZXG z`4^>884KfMbYlbojMMDa9&fXLbc8X|yKcS|Y8F0cUFmc$^-7NdffYU3M|x>LW8GWoj5TJir%y&^okpKdN3R@I9Z4_e(@RKO8FAGHJ+G0R@Kl@cWoo6h z)PE@aZD$-WgFowM|I*@?i32SfPK#O4cOJIwt5b7J?dsqgb>p>_o_extLzV7$L3Qa{ zBrf_ig*eY zP|IKh=DyU8=Lv+fwla8l>Z5W->3&I`2&=Ky5g+)>^sWv1xK1*~L$!!DPru~lnm z0G%($s?IzF;k|!A>R(?nUl`3CE5kT-Q$9^T&2H{^?QAsk3qBLl1v~7PtzKuIe=BU53)L-4D z!yBuh8JnC67k|p+&lLF+U>ZHo^h?A3b{;e>U0LkoDp&Of#XDU>Dz<+ud5WpMBrnU> z3Ya$oG%&-CbaSWe|0d&MQYRVxxd~5iyE`$?8J)Q)Y_^(R!eDOJ?a3Q=9vgN*n%K;K zNNFjdXd&ImG6{ZW+hZYw{^CYFweSEC0M#)+wqh1 z;32JH22-X7`?Utp52_ET^tZHz3sicy)^Mgu?^o#^TEkeC-mW!_ldRvLB+m`jr{_SJKamds@Lj$l<-O71k+>%sd?Vp2-=1yr z9VE7D^W$jnu;je1a-<8}zd_}^uLqCDJ$mp>l_TBR{{JE;YSP-?YAsCFk9bh-W44Ok z>c+kC2~p#S9UlWvvi*Og>|kdJX|nNMDR5X7*lhcgP64OS>-o?dd*c&y<0u8-gtmXa zQ^4uETnezLs&sQfi7s2wEZtmMGDpb7;U!F{%;Dhtsl7-~J>5?aER-GubawEQPhqKv zG}5@6Wfe2uc9zXQkYnK}DgS4m3m~oR!=r*ZE@7na^~t0c!#clgPqhMd;N!Ktq`$O3&?ITT*3G`t5)AA+A zgJNy}E@@cyrEY5pOq@P$clsEnfZA%^;iTTfR?=CyBr5 z$%mTtF0(s?D|Koz^#Gs!jiGK*Eg8 z;$i!LO4(ZDp6=C3SPgY{7eKhfI`xUHwA2>9(@-RSUAq3#vgmrd2s z#IA}Q=3X^FyQ{^+*lho0KxJ>3>gHo{0m48R{E#Hzc)CB-+w_-=5x^oP{CidwpP!1i}CLx^sn)d=yVC@Ctet(@ttW#=lbH4dB+pByrG zSbz7cIUPscky1A`(`)-5Q{*Rg5}QSc9}#uGshfT2t5Z*1vqNOVxe&9ST3oEH94TFnlFq_(rlfcpb~|-O(J3{o^Q5@3J~vyuP>TB<*eu6LW_+Bsa)hKG8LeP0U27m$7`*#j*Z9k~J?qt}2q)U0JkpF%%@g#>DiM@~H> zKJHjUK8n$aG;}Qu0imEl;e4tC<~V6QqcI|F z)M27?Z_Dyf*7rh)VM*~Zc|P@Y1%wG7eJWoj$+O8nz(-fWf^7exZ7@Z4T32mlMI6R= zG?TBb+^QR`dD_ZtvM>D@$*sIMoT~K-5e$!|&YRogs5bL+Gbe}4mj&d+$!hE)qsF>i zM|h>|9#C`*CS8W=8N*#EWix2wGDM(dlbL$%}4S z?7kg}&PZC)M_e%Ut)gwJRzj=G^h@vGrh(dIeCaG5-DOs7B^z5D5@!-$wrbhNA%)>^mE79OOA;2eHA#(Nvvkjz z(5WpGuCRBBQ=AF!V8Zj&gj3^mRbyke#+acsJYP^lm`0WGHJCw_^%i_f)n7w>MeDl- z>aHFUMwXUTnJ-o=e7q#hld+PF=M*WYiZ0nFXh1W1*=mMqFqKQ$GQW0_Fs9Tz(7j5q zW6e38mYoFKf6sQ8D|Ow;=oHtNoSHZ%%5E1(-Sn|_W3C_%#Qzkk0S*{G`K*&W~UNN@hJ4r+j>N_%`g9O9Wzzzz(xA_fl2VyU9@ zC;@Gt@qyTw=q<72o!C2WFQNfBUI>=58J;`EdXNnlo_zej+FI>2(QGIjEV}lj99LqL z-qz-;?Q65`MDAzpdRwP2{r!@xTzrg;&!)*TU3!X`yB+O6Qoc82u0z?-9&cqr##(2h z!gjdE(6;s5NrI&GGTv30?W#=tbv|H<=Qv+4TGt~}3jc?yXUSSFvfe?l>Tt2!xiT+M z^8CaZ)>f4y&4M6@u``p_TzXrvqP#V88YYK`%%RenPd`hV>=&GV8_7x+hB_DF4l!?@ zXiuUmVr>}EAEG8accV!DjhzX8@!ZB~13i)^Cl)mS$+Z+70F0W$;Rv)(9E zt%|hvWA(bp`cQOX@bhr?`y1J3E?TzmEE!As6=_fpZd`PpG5}>2B&x^GIt^+rHbqr zg3rN=6%X^u;6Ijx$s~ZdT(*A7yaX<-hd~Zq-Ng6Si}?N)fArME{}eo@rasLhGxCcD zU`+iDExN>*Q}k15JLPnyAq$mvhFIjb|54IqOec(0*~Y?0HF0JupMQKGYdO{y#f{_Mfb(BFQTElOg z+}CDG?z@{Lw_jO1V`i^FF$Eb@zAJR&6EEGVb+_rJX8V7u z>UUeuOJ*|PhMyEQsg{>JIeafv-{0ap7W^#Xi3P3r^D*-?p@=EE^DGk486%n*J&B2aKbj!wf6K8gKa!z%S;$(bqwlI*bRy(|m zr|sX-DP+kMER+?!1X`^cumG{DWwN%XYq6GXmUpHtCq0KR(acbLa?&$Z)@CIYlVq+* zS4xUwOJHr?{bfjQljVYHsNZ6PaB0Lk*{LVgdx^3;#LPDE^HeDmvEBC1+o<-WvDPHT zeXv@r22MnkO=rSN+*$50uqM$>s@O@;YpfsApCbS#PN^gz?zeVRMOeZJYX@(L*HuZc z*ccoRGtdU>aDAwlg4+|1SYK09INhh4D_Vs_lB~3*X7x6c1?t~7F2@xgW7cmVsnPS_ z$Xf}o<(eiX5kx${9?dpdIo%sSMK`DW%qCT==rJia+!|gf#ij$obYHJ(AvZDFP-Sx0 zPcP0vIP>Lxrah7~6vi*Kfv|&AA@xV0QDr?2nQN&+^`Wiowr=EGiPhO!1yai+ zwKgMQYAf4I+rky-rJ}mwd@z0`csnAri9KP#z?Oq#Ghb2ZT$s4*%jIl1+hgX=O3(7M z!SG^m5dT(o{Or5g4fIjWxMZdqW(UI|b&A@wM8@HQLI~(hU%Lv~%?6Q9`^Ve(g~=NSb}wG)m?9fH zbuDrLa{v1j2!)vnSXY#zEMY5lS+B5psC8o9EK{&pNc= z_U!ugG+&wHdTun0(PMtII7l;|V7nG;*K0Pcl6^Aid7L8F)6<2hJr9V4PtlUpEa-bv za^e!nG@Z=3+06Xr@l?#*uZ%A@(wm+foueCT*zelBy1faR+Vor?O2hlG40zu)l!>Ht zchuYvOZh#>s0bN)TffJ6`?RQ;w?@CGb56`0of9<<+GwxFL5yS7tm9!Fxy*+hwOgh2 zsNI?PC+(?aujIK8u5`KTr@mgymJ#<@4}=A`MbBOgK+I?QcBJcLHc@!*pOJ|5;Lf_s zK~kAl-n$onNyNtHKmAetJ4Y|wruTiQw;hBDY}DJ*SEOR2d{&%AsI9uESj%>unyGen zF`y>b!F&houCEyfMn812(dM(Jomk_l!5TM84VfqZL

                                                  # pre-release
        +            [-_\.]?
        +            (?Palpha|a|beta|b|preview|pre|c|rc)
        +            [-_\.]?
        +            (?P[0-9]+)?
        +        )?
        +        (?P                                         # post release
        +            (?:-(?P[0-9]+))
        +            |
        +            (?:
        +                [-_\.]?
        +                (?Ppost|rev|r)
        +                [-_\.]?
        +                (?P[0-9]+)?
        +            )
        +        )?
        +        (?P                                          # dev release
        +            [-_\.]?
        +            (?Pdev)
        +            [-_\.]?
        +            (?P[0-9]+)?
        +        )?
        +    )
        +    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
        +"""
        +
        +VERSION_PATTERN = _VERSION_PATTERN
        +"""
        +A string containing the regular expression used to match a valid version.
        +
        +The pattern is not anchored at either end, and is intended for embedding in larger
        +expressions (for example, matching a version number as part of a file name). The
        +regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE``
        +flags set.
        +
        +:meta hide-value:
        +"""
        +
        +
        +class Version(_BaseVersion):
        +    """This class abstracts handling of a project's versions.
        +
        +    A :class:`Version` instance is comparison aware and can be compared and
        +    sorted using the standard Python interfaces.
        +
        +    >>> v1 = Version("1.0a5")
        +    >>> v2 = Version("1.0")
        +    >>> v1
        +    
        +    >>> v2
        +    
        +    >>> v1 < v2
        +    True
        +    >>> v1 == v2
        +    False
        +    >>> v1 > v2
        +    False
        +    >>> v1 >= v2
        +    False
        +    >>> v1 <= v2
        +    True
        +    """
        +
        +    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
        +    _key: CmpKey
        +
        +    def __init__(self, version: str) -> None:
        +        """Initialize a Version object.
        +
        +        :param version:
        +            The string representation of a version which will be parsed and normalized
        +            before use.
        +        :raises InvalidVersion:
        +            If the ``version`` does not conform to PEP 440 in any way then this
        +            exception will be raised.
        +        """
        +
        +        # Validate the version and parse it into pieces
        +        match = self._regex.search(version)
        +        if not match:
        +            raise InvalidVersion(f"Invalid version: {version!r}")
        +
        +        # Store the parsed out pieces of the version
        +        self._version = _Version(
        +            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
        +            release=tuple(int(i) for i in match.group("release").split(".")),
        +            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
        +            post=_parse_letter_version(
        +                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
        +            ),
        +            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
        +            local=_parse_local_version(match.group("local")),
        +        )
        +
        +        # Generate a key which will be used for sorting
        +        self._key = _cmpkey(
        +            self._version.epoch,
        +            self._version.release,
        +            self._version.pre,
        +            self._version.post,
        +            self._version.dev,
        +            self._version.local,
        +        )
        +
        +    def __repr__(self) -> str:
        +        """A representation of the Version that shows all internal state.
        +
        +        >>> Version('1.0.0')
        +        
        +        """
        +        return f""
        +
        +    def __str__(self) -> str:
        +        """A string representation of the version that can be round-tripped.
        +
        +        >>> str(Version("1.0a5"))
        +        '1.0a5'
        +        """
        +        parts = []
        +
        +        # Epoch
        +        if self.epoch != 0:
        +            parts.append(f"{self.epoch}!")
        +
        +        # Release segment
        +        parts.append(".".join(str(x) for x in self.release))
        +
        +        # Pre-release
        +        if self.pre is not None:
        +            parts.append("".join(str(x) for x in self.pre))
        +
        +        # Post-release
        +        if self.post is not None:
        +            parts.append(f".post{self.post}")
        +
        +        # Development release
        +        if self.dev is not None:
        +            parts.append(f".dev{self.dev}")
        +
        +        # Local version segment
        +        if self.local is not None:
        +            parts.append(f"+{self.local}")
        +
        +        return "".join(parts)
        +
        +    @property
        +    def epoch(self) -> int:
        +        """The epoch of the version.
        +
        +        >>> Version("2.0.0").epoch
        +        0
        +        >>> Version("1!2.0.0").epoch
        +        1
        +        """
        +        return self._version.epoch
        +
        +    @property
        +    def release(self) -> tuple[int, ...]:
        +        """The components of the "release" segment of the version.
        +
        +        >>> Version("1.2.3").release
        +        (1, 2, 3)
        +        >>> Version("2.0.0").release
        +        (2, 0, 0)
        +        >>> Version("1!2.0.0.post0").release
        +        (2, 0, 0)
        +
        +        Includes trailing zeroes but not the epoch or any pre-release / development /
        +        post-release suffixes.
        +        """
        +        return self._version.release
        +
        +    @property
        +    def pre(self) -> tuple[str, int] | None:
        +        """The pre-release segment of the version.
        +
        +        >>> print(Version("1.2.3").pre)
        +        None
        +        >>> Version("1.2.3a1").pre
        +        ('a', 1)
        +        >>> Version("1.2.3b1").pre
        +        ('b', 1)
        +        >>> Version("1.2.3rc1").pre
        +        ('rc', 1)
        +        """
        +        return self._version.pre
        +
        +    @property
        +    def post(self) -> int | None:
        +        """The post-release number of the version.
        +
        +        >>> print(Version("1.2.3").post)
        +        None
        +        >>> Version("1.2.3.post1").post
        +        1
        +        """
        +        return self._version.post[1] if self._version.post else None
        +
        +    @property
        +    def dev(self) -> int | None:
        +        """The development number of the version.
        +
        +        >>> print(Version("1.2.3").dev)
        +        None
        +        >>> Version("1.2.3.dev1").dev
        +        1
        +        """
        +        return self._version.dev[1] if self._version.dev else None
        +
        +    @property
        +    def local(self) -> str | None:
        +        """The local version segment of the version.
        +
        +        >>> print(Version("1.2.3").local)
        +        None
        +        >>> Version("1.2.3+abc").local
        +        'abc'
        +        """
        +        if self._version.local:
        +            return ".".join(str(x) for x in self._version.local)
        +        else:
        +            return None
        +
        +    @property
        +    def public(self) -> str:
        +        """The public portion of the version.
        +
        +        >>> Version("1.2.3").public
        +        '1.2.3'
        +        >>> Version("1.2.3+abc").public
        +        '1.2.3'
        +        >>> Version("1!1.2.3dev1+abc").public
        +        '1!1.2.3.dev1'
        +        """
        +        return str(self).split("+", 1)[0]
        +
        +    @property
        +    def base_version(self) -> str:
        +        """The "base version" of the version.
        +
        +        >>> Version("1.2.3").base_version
        +        '1.2.3'
        +        >>> Version("1.2.3+abc").base_version
        +        '1.2.3'
        +        >>> Version("1!1.2.3dev1+abc").base_version
        +        '1!1.2.3'
        +
        +        The "base version" is the public version of the project without any pre or post
        +        release markers.
        +        """
        +        parts = []
        +
        +        # Epoch
        +        if self.epoch != 0:
        +            parts.append(f"{self.epoch}!")
        +
        +        # Release segment
        +        parts.append(".".join(str(x) for x in self.release))
        +
        +        return "".join(parts)
        +
        +    @property
        +    def is_prerelease(self) -> bool:
        +        """Whether this version is a pre-release.
        +
        +        >>> Version("1.2.3").is_prerelease
        +        False
        +        >>> Version("1.2.3a1").is_prerelease
        +        True
        +        >>> Version("1.2.3b1").is_prerelease
        +        True
        +        >>> Version("1.2.3rc1").is_prerelease
        +        True
        +        >>> Version("1.2.3dev1").is_prerelease
        +        True
        +        """
        +        return self.dev is not None or self.pre is not None
        +
        +    @property
        +    def is_postrelease(self) -> bool:
        +        """Whether this version is a post-release.
        +
        +        >>> Version("1.2.3").is_postrelease
        +        False
        +        >>> Version("1.2.3.post1").is_postrelease
        +        True
        +        """
        +        return self.post is not None
        +
        +    @property
        +    def is_devrelease(self) -> bool:
        +        """Whether this version is a development release.
        +
        +        >>> Version("1.2.3").is_devrelease
        +        False
        +        >>> Version("1.2.3.dev1").is_devrelease
        +        True
        +        """
        +        return self.dev is not None
        +
        +    @property
        +    def major(self) -> int:
        +        """The first item of :attr:`release` or ``0`` if unavailable.
        +
        +        >>> Version("1.2.3").major
        +        1
        +        """
        +        return self.release[0] if len(self.release) >= 1 else 0
        +
        +    @property
        +    def minor(self) -> int:
        +        """The second item of :attr:`release` or ``0`` if unavailable.
        +
        +        >>> Version("1.2.3").minor
        +        2
        +        >>> Version("1").minor
        +        0
        +        """
        +        return self.release[1] if len(self.release) >= 2 else 0
        +
        +    @property
        +    def micro(self) -> int:
        +        """The third item of :attr:`release` or ``0`` if unavailable.
        +
        +        >>> Version("1.2.3").micro
        +        3
        +        >>> Version("1").micro
        +        0
        +        """
        +        return self.release[2] if len(self.release) >= 3 else 0
        +
        +
        +class _TrimmedRelease(Version):
        +    @property
        +    def release(self) -> tuple[int, ...]:
        +        """
        +        Release segment without any trailing zeros.
        +
        +        >>> _TrimmedRelease('1.0.0').release
        +        (1,)
        +        >>> _TrimmedRelease('0.0').release
        +        (0,)
        +        """
        +        rel = super().release
        +        nonzeros = (index for index, val in enumerate(rel) if val)
        +        last_nonzero = max(nonzeros, default=0)
        +        return rel[: last_nonzero + 1]
        +
        +
        +def _parse_letter_version(
        +    letter: str | None, number: str | bytes | SupportsInt | None
        +) -> tuple[str, int] | None:
        +    if letter:
        +        # We consider there to be an implicit 0 in a pre-release if there is
        +        # not a numeral associated with it.
        +        if number is None:
        +            number = 0
        +
        +        # We normalize any letters to their lower case form
        +        letter = letter.lower()
        +
        +        # We consider some words to be alternate spellings of other words and
        +        # in those cases we want to normalize the spellings to our preferred
        +        # spelling.
        +        if letter == "alpha":
        +            letter = "a"
        +        elif letter == "beta":
        +            letter = "b"
        +        elif letter in ["c", "pre", "preview"]:
        +            letter = "rc"
        +        elif letter in ["rev", "r"]:
        +            letter = "post"
        +
        +        return letter, int(number)
        +
        +    assert not letter
        +    if number:
        +        # We assume if we are given a number, but we are not given a letter
        +        # then this is using the implicit post release syntax (e.g. 1.0-1)
        +        letter = "post"
        +
        +        return letter, int(number)
        +
        +    return None
        +
        +
        +_local_version_separators = re.compile(r"[\._-]")
        +
        +
        +def _parse_local_version(local: str | None) -> LocalType | None:
        +    """
        +    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
        +    """
        +    if local is not None:
        +        return tuple(
        +            part.lower() if not part.isdigit() else int(part)
        +            for part in _local_version_separators.split(local)
        +        )
        +    return None
        +
        +
        +def _cmpkey(
        +    epoch: int,
        +    release: tuple[int, ...],
        +    pre: tuple[str, int] | None,
        +    post: tuple[str, int] | None,
        +    dev: tuple[str, int] | None,
        +    local: LocalType | None,
        +) -> CmpKey:
        +    # When we compare a release version, we want to compare it with all of the
        +    # trailing zeros removed. So we'll use a reverse the list, drop all the now
        +    # leading zeros until we come to something non zero, then take the rest
        +    # re-reverse it back into the correct order and make it a tuple and use
        +    # that for our sorting key.
        +    _release = tuple(
        +        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
        +    )
        +
        +    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
        +    # We'll do this by abusing the pre segment, but we _only_ want to do this
        +    # if there is not a pre or a post segment. If we have one of those then
        +    # the normal sorting rules will handle this case correctly.
        +    if pre is None and post is None and dev is not None:
        +        _pre: CmpPrePostDevType = NegativeInfinity
        +    # Versions without a pre-release (except as noted above) should sort after
        +    # those with one.
        +    elif pre is None:
        +        _pre = Infinity
        +    else:
        +        _pre = pre
        +
        +    # Versions without a post segment should sort before those with one.
        +    if post is None:
        +        _post: CmpPrePostDevType = NegativeInfinity
        +
        +    else:
        +        _post = post
        +
        +    # Versions without a development segment should sort after those with one.
        +    if dev is None:
        +        _dev: CmpPrePostDevType = Infinity
        +
        +    else:
        +        _dev = dev
        +
        +    if local is None:
        +        # Versions without a local segment should sort before those with one.
        +        _local: CmpLocalType = NegativeInfinity
        +    else:
        +        # Versions with a local segment need that segment parsed to implement
        +        # the sorting rules in PEP440.
        +        # - Alpha numeric segments sort before numeric segments
        +        # - Alpha numeric segments sort lexicographically
        +        # - Numeric segments sort numerically
        +        # - Shorter versions sort before longer versions when the prefixes
        +        #   match exactly
        +        _local = tuple(
        +            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
        +        )
        +
        +    return epoch, _release, _pre, _post, _dev, _local
        diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py
        new file mode 100644
        index 0000000..57ce7f1
        --- /dev/null
        +++ b/backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py
        @@ -0,0 +1,3676 @@
        +# TODO: Add Generic type annotations to initialized collections.
        +# For now we'd simply use implicit Any/Unknown which would add redundant annotations
        +# mypy: disable-error-code="var-annotated"
        +"""
        +Package resource API
        +--------------------
        +
        +A resource is a logical file contained within a package, or a logical
        +subdirectory thereof.  The package resource API expects resource names
        +to have their path parts separated with ``/``, *not* whatever the local
        +path separator is.  Do not use os.path operations to manipulate resource
        +names being passed into the API.
        +
        +The package resource API is designed to work with normal filesystem packages,
        +.egg files, and unpacked .egg files.  It can also work in a limited way with
        +.zip files and with custom PEP 302 loaders that support the ``get_data()``
        +method.
        +
        +This module is deprecated. Users are directed to :mod:`importlib.resources`,
        +:mod:`importlib.metadata` and :pypi:`packaging` instead.
        +"""
        +
        +from __future__ import annotations
        +
        +import sys
        +
        +if sys.version_info < (3, 8):  # noqa: UP036 # Check for unsupported versions
        +    raise RuntimeError("Python 3.8 or later is required")
        +
        +import os
        +import io
        +import time
        +import re
        +import types
        +from typing import (
        +    Any,
        +    Literal,
        +    Dict,
        +    Iterator,
        +    Mapping,
        +    MutableSequence,
        +    NamedTuple,
        +    NoReturn,
        +    Tuple,
        +    Union,
        +    TYPE_CHECKING,
        +    Protocol,
        +    Callable,
        +    Iterable,
        +    TypeVar,
        +    overload,
        +)
        +import zipfile
        +import zipimport
        +import warnings
        +import stat
        +import functools
        +import pkgutil
        +import operator
        +import platform
        +import collections
        +import plistlib
        +import email.parser
        +import errno
        +import tempfile
        +import textwrap
        +import inspect
        +import ntpath
        +import posixpath
        +import importlib
        +import importlib.abc
        +import importlib.machinery
        +from pkgutil import get_importer
        +
        +import _imp
        +
        +# capture these to bypass sandboxing
        +from os import utime
        +from os import open as os_open
        +from os.path import isdir, split
        +
        +try:
        +    from os import mkdir, rename, unlink
        +
        +    WRITE_SUPPORT = True
        +except ImportError:
        +    # no write support, probably under GAE
        +    WRITE_SUPPORT = False
        +
        +from pip._internal.utils._jaraco_text import (
        +    yield_lines,
        +    drop_comment,
        +    join_continuation,
        +)
        +from pip._vendor.packaging import markers as _packaging_markers
        +from pip._vendor.packaging import requirements as _packaging_requirements
        +from pip._vendor.packaging import utils as _packaging_utils
        +from pip._vendor.packaging import version as _packaging_version
        +from pip._vendor.platformdirs import user_cache_dir as _user_cache_dir
        +
        +if TYPE_CHECKING:
        +    from _typeshed import BytesPath, StrPath, StrOrBytesPath
        +    from pip._vendor.typing_extensions import Self
        +
        +
        +# Patch: Remove deprecation warning from vendored pkg_resources.
        +# Setting PYTHONWARNINGS=error to verify builds produce no warnings
        +# causes immediate exceptions.
        +# See https://github.com/pypa/pip/issues/12243
        +
        +
        +_T = TypeVar("_T")
        +_DistributionT = TypeVar("_DistributionT", bound="Distribution")
        +# Type aliases
        +_NestedStr = Union[str, Iterable[Union[str, Iterable["_NestedStr"]]]]
        +_InstallerTypeT = Callable[["Requirement"], "_DistributionT"]
        +_InstallerType = Callable[["Requirement"], Union["Distribution", None]]
        +_PkgReqType = Union[str, "Requirement"]
        +_EPDistType = Union["Distribution", _PkgReqType]
        +_MetadataType = Union["IResourceProvider", None]
        +_ResolvedEntryPoint = Any  # Can be any attribute in the module
        +_ResourceStream = Any  # TODO / Incomplete: A readable file-like object
        +# Any object works, but let's indicate we expect something like a module (optionally has __loader__ or __file__)
        +_ModuleLike = Union[object, types.ModuleType]
        +# Any: Should be _ModuleLike but we end up with issues where _ModuleLike doesn't have _ZipLoaderModule's __loader__
        +_ProviderFactoryType = Callable[[Any], "IResourceProvider"]
        +_DistFinderType = Callable[[_T, str, bool], Iterable["Distribution"]]
        +_NSHandlerType = Callable[[_T, str, str, types.ModuleType], Union[str, None]]
        +_AdapterT = TypeVar(
        +    "_AdapterT", _DistFinderType[Any], _ProviderFactoryType, _NSHandlerType[Any]
        +)
        +
        +
        +# Use _typeshed.importlib.LoaderProtocol once available https://github.com/python/typeshed/pull/11890
        +class _LoaderProtocol(Protocol):
        +    def load_module(self, fullname: str, /) -> types.ModuleType: ...
        +
        +
        +class _ZipLoaderModule(Protocol):
        +    __loader__: zipimport.zipimporter
        +
        +
        +_PEP440_FALLBACK = re.compile(r"^v?(?P(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I)
        +
        +
        +class PEP440Warning(RuntimeWarning):
        +    """
        +    Used when there is an issue with a version or specifier not complying with
        +    PEP 440.
        +    """
        +
        +
        +parse_version = _packaging_version.Version
        +
        +
        +_state_vars: dict[str, str] = {}
        +
        +
        +def _declare_state(vartype: str, varname: str, initial_value: _T) -> _T:
        +    _state_vars[varname] = vartype
        +    return initial_value
        +
        +
        +def __getstate__() -> dict[str, Any]:
        +    state = {}
        +    g = globals()
        +    for k, v in _state_vars.items():
        +        state[k] = g['_sget_' + v](g[k])
        +    return state
        +
        +
        +def __setstate__(state: dict[str, Any]) -> dict[str, Any]:
        +    g = globals()
        +    for k, v in state.items():
        +        g['_sset_' + _state_vars[k]](k, g[k], v)
        +    return state
        +
        +
        +def _sget_dict(val):
        +    return val.copy()
        +
        +
        +def _sset_dict(key, ob, state):
        +    ob.clear()
        +    ob.update(state)
        +
        +
        +def _sget_object(val):
        +    return val.__getstate__()
        +
        +
        +def _sset_object(key, ob, state):
        +    ob.__setstate__(state)
        +
        +
        +_sget_none = _sset_none = lambda *args: None
        +
        +
        +def get_supported_platform():
        +    """Return this platform's maximum compatible version.
        +
        +    distutils.util.get_platform() normally reports the minimum version
        +    of macOS that would be required to *use* extensions produced by
        +    distutils.  But what we want when checking compatibility is to know the
        +    version of macOS that we are *running*.  To allow usage of packages that
        +    explicitly require a newer version of macOS, we must also know the
        +    current version of the OS.
        +
        +    If this condition occurs for any other platform with a version in its
        +    platform strings, this function should be extended accordingly.
        +    """
        +    plat = get_build_platform()
        +    m = macosVersionString.match(plat)
        +    if m is not None and sys.platform == "darwin":
        +        try:
        +            plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
        +        except ValueError:
        +            # not macOS
        +            pass
        +    return plat
        +
        +
        +__all__ = [
        +    # Basic resource access and distribution/entry point discovery
        +    'require',
        +    'run_script',
        +    'get_provider',
        +    'get_distribution',
        +    'load_entry_point',
        +    'get_entry_map',
        +    'get_entry_info',
        +    'iter_entry_points',
        +    'resource_string',
        +    'resource_stream',
        +    'resource_filename',
        +    'resource_listdir',
        +    'resource_exists',
        +    'resource_isdir',
        +    # Environmental control
        +    'declare_namespace',
        +    'working_set',
        +    'add_activation_listener',
        +    'find_distributions',
        +    'set_extraction_path',
        +    'cleanup_resources',
        +    'get_default_cache',
        +    # Primary implementation classes
        +    'Environment',
        +    'WorkingSet',
        +    'ResourceManager',
        +    'Distribution',
        +    'Requirement',
        +    'EntryPoint',
        +    # Exceptions
        +    'ResolutionError',
        +    'VersionConflict',
        +    'DistributionNotFound',
        +    'UnknownExtra',
        +    'ExtractionError',
        +    # Warnings
        +    'PEP440Warning',
        +    # Parsing functions and string utilities
        +    'parse_requirements',
        +    'parse_version',
        +    'safe_name',
        +    'safe_version',
        +    'get_platform',
        +    'compatible_platforms',
        +    'yield_lines',
        +    'split_sections',
        +    'safe_extra',
        +    'to_filename',
        +    'invalid_marker',
        +    'evaluate_marker',
        +    # filesystem utilities
        +    'ensure_directory',
        +    'normalize_path',
        +    # Distribution "precedence" constants
        +    'EGG_DIST',
        +    'BINARY_DIST',
        +    'SOURCE_DIST',
        +    'CHECKOUT_DIST',
        +    'DEVELOP_DIST',
        +    # "Provider" interfaces, implementations, and registration/lookup APIs
        +    'IMetadataProvider',
        +    'IResourceProvider',
        +    'FileMetadata',
        +    'PathMetadata',
        +    'EggMetadata',
        +    'EmptyProvider',
        +    'empty_provider',
        +    'NullProvider',
        +    'EggProvider',
        +    'DefaultProvider',
        +    'ZipProvider',
        +    'register_finder',
        +    'register_namespace_handler',
        +    'register_loader_type',
        +    'fixup_namespace_packages',
        +    'get_importer',
        +    # Warnings
        +    'PkgResourcesDeprecationWarning',
        +    # Deprecated/backward compatibility only
        +    'run_main',
        +    'AvailableDistributions',
        +]
        +
        +
        +class ResolutionError(Exception):
        +    """Abstract base for dependency resolution errors"""
        +
        +    def __repr__(self):
        +        return self.__class__.__name__ + repr(self.args)
        +
        +
        +class VersionConflict(ResolutionError):
        +    """
        +    An already-installed version conflicts with the requested version.
        +
        +    Should be initialized with the installed Distribution and the requested
        +    Requirement.
        +    """
        +
        +    _template = "{self.dist} is installed but {self.req} is required"
        +
        +    @property
        +    def dist(self) -> Distribution:
        +        return self.args[0]
        +
        +    @property
        +    def req(self) -> Requirement:
        +        return self.args[1]
        +
        +    def report(self):
        +        return self._template.format(**locals())
        +
        +    def with_context(self, required_by: set[Distribution | str]):
        +        """
        +        If required_by is non-empty, return a version of self that is a
        +        ContextualVersionConflict.
        +        """
        +        if not required_by:
        +            return self
        +        args = self.args + (required_by,)
        +        return ContextualVersionConflict(*args)
        +
        +
        +class ContextualVersionConflict(VersionConflict):
        +    """
        +    A VersionConflict that accepts a third parameter, the set of the
        +    requirements that required the installed Distribution.
        +    """
        +
        +    _template = VersionConflict._template + ' by {self.required_by}'
        +
        +    @property
        +    def required_by(self) -> set[str]:
        +        return self.args[2]
        +
        +
        +class DistributionNotFound(ResolutionError):
        +    """A requested distribution was not found"""
        +
        +    _template = (
        +        "The '{self.req}' distribution was not found "
        +        "and is required by {self.requirers_str}"
        +    )
        +
        +    @property
        +    def req(self) -> Requirement:
        +        return self.args[0]
        +
        +    @property
        +    def requirers(self) -> set[str] | None:
        +        return self.args[1]
        +
        +    @property
        +    def requirers_str(self):
        +        if not self.requirers:
        +            return 'the application'
        +        return ', '.join(self.requirers)
        +
        +    def report(self):
        +        return self._template.format(**locals())
        +
        +    def __str__(self):
        +        return self.report()
        +
        +
        +class UnknownExtra(ResolutionError):
        +    """Distribution doesn't have an "extra feature" of the given name"""
        +
        +
        +_provider_factories: dict[type[_ModuleLike], _ProviderFactoryType] = {}
        +
        +PY_MAJOR = '{}.{}'.format(*sys.version_info)
        +EGG_DIST = 3
        +BINARY_DIST = 2
        +SOURCE_DIST = 1
        +CHECKOUT_DIST = 0
        +DEVELOP_DIST = -1
        +
        +
        +def register_loader_type(
        +    loader_type: type[_ModuleLike], provider_factory: _ProviderFactoryType
        +):
        +    """Register `provider_factory` to make providers for `loader_type`
        +
        +    `loader_type` is the type or class of a PEP 302 ``module.__loader__``,
        +    and `provider_factory` is a function that, passed a *module* object,
        +    returns an ``IResourceProvider`` for that module.
        +    """
        +    _provider_factories[loader_type] = provider_factory
        +
        +
        +@overload
        +def get_provider(moduleOrReq: str) -> IResourceProvider: ...
        +@overload
        +def get_provider(moduleOrReq: Requirement) -> Distribution: ...
        +def get_provider(moduleOrReq: str | Requirement) -> IResourceProvider | Distribution:
        +    """Return an IResourceProvider for the named module or requirement"""
        +    if isinstance(moduleOrReq, Requirement):
        +        return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
        +    try:
        +        module = sys.modules[moduleOrReq]
        +    except KeyError:
        +        __import__(moduleOrReq)
        +        module = sys.modules[moduleOrReq]
        +    loader = getattr(module, '__loader__', None)
        +    return _find_adapter(_provider_factories, loader)(module)
        +
        +
        +@functools.lru_cache(maxsize=None)
        +def _macos_vers():
        +    version = platform.mac_ver()[0]
        +    # fallback for MacPorts
        +    if version == '':
        +        plist = '/System/Library/CoreServices/SystemVersion.plist'
        +        if os.path.exists(plist):
        +            with open(plist, 'rb') as fh:
        +                plist_content = plistlib.load(fh)
        +            if 'ProductVersion' in plist_content:
        +                version = plist_content['ProductVersion']
        +    return version.split('.')
        +
        +
        +def _macos_arch(machine):
        +    return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
        +
        +
        +def get_build_platform():
        +    """Return this platform's string for platform-specific distributions
        +
        +    XXX Currently this is the same as ``distutils.util.get_platform()``, but it
        +    needs some hacks for Linux and macOS.
        +    """
        +    from sysconfig import get_platform
        +
        +    plat = get_platform()
        +    if sys.platform == "darwin" and not plat.startswith('macosx-'):
        +        try:
        +            version = _macos_vers()
        +            machine = os.uname()[4].replace(" ", "_")
        +            return "macosx-%d.%d-%s" % (
        +                int(version[0]),
        +                int(version[1]),
        +                _macos_arch(machine),
        +            )
        +        except ValueError:
        +            # if someone is running a non-Mac darwin system, this will fall
        +            # through to the default implementation
        +            pass
        +    return plat
        +
        +
        +macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
        +darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
        +# XXX backward compat
        +get_platform = get_build_platform
        +
        +
        +def compatible_platforms(provided: str | None, required: str | None):
        +    """Can code for the `provided` platform run on the `required` platform?
        +
        +    Returns true if either platform is ``None``, or the platforms are equal.
        +
        +    XXX Needs compatibility checks for Linux and other unixy OSes.
        +    """
        +    if provided is None or required is None or provided == required:
        +        # easy case
        +        return True
        +
        +    # macOS special cases
        +    reqMac = macosVersionString.match(required)
        +    if reqMac:
        +        provMac = macosVersionString.match(provided)
        +
        +        # is this a Mac package?
        +        if not provMac:
        +            # this is backwards compatibility for packages built before
        +            # setuptools 0.6. All packages built after this point will
        +            # use the new macOS designation.
        +            provDarwin = darwinVersionString.match(provided)
        +            if provDarwin:
        +                dversion = int(provDarwin.group(1))
        +                macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
        +                if (
        +                    dversion == 7
        +                    and macosversion >= "10.3"
        +                    or dversion == 8
        +                    and macosversion >= "10.4"
        +                ):
        +                    return True
        +            # egg isn't macOS or legacy darwin
        +            return False
        +
        +        # are they the same major version and machine type?
        +        if provMac.group(1) != reqMac.group(1) or provMac.group(3) != reqMac.group(3):
        +            return False
        +
        +        # is the required OS major update >= the provided one?
        +        if int(provMac.group(2)) > int(reqMac.group(2)):
        +            return False
        +
        +        return True
        +
        +    # XXX Linux and other platforms' special cases should go here
        +    return False
        +
        +
        +@overload
        +def get_distribution(dist: _DistributionT) -> _DistributionT: ...
        +@overload
        +def get_distribution(dist: _PkgReqType) -> Distribution: ...
        +def get_distribution(dist: Distribution | _PkgReqType) -> Distribution:
        +    """Return a current distribution object for a Requirement or string"""
        +    if isinstance(dist, str):
        +        dist = Requirement.parse(dist)
        +    if isinstance(dist, Requirement):
        +        # Bad type narrowing, dist has to be a Requirement here, so get_provider has to return Distribution
        +        dist = get_provider(dist)  # type: ignore[assignment]
        +    if not isinstance(dist, Distribution):
        +        raise TypeError("Expected str, Requirement, or Distribution", dist)
        +    return dist
        +
        +
        +def load_entry_point(dist: _EPDistType, group: str, name: str) -> _ResolvedEntryPoint:
        +    """Return `name` entry point of `group` for `dist` or raise ImportError"""
        +    return get_distribution(dist).load_entry_point(group, name)
        +
        +
        +@overload
        +def get_entry_map(
        +    dist: _EPDistType, group: None = None
        +) -> dict[str, dict[str, EntryPoint]]: ...
        +@overload
        +def get_entry_map(dist: _EPDistType, group: str) -> dict[str, EntryPoint]: ...
        +def get_entry_map(dist: _EPDistType, group: str | None = None):
        +    """Return the entry point map for `group`, or the full entry map"""
        +    return get_distribution(dist).get_entry_map(group)
        +
        +
        +def get_entry_info(dist: _EPDistType, group: str, name: str):
        +    """Return the EntryPoint object for `group`+`name`, or ``None``"""
        +    return get_distribution(dist).get_entry_info(group, name)
        +
        +
        +class IMetadataProvider(Protocol):
        +    def has_metadata(self, name: str) -> bool:
        +        """Does the package's distribution contain the named metadata?"""
        +
        +    def get_metadata(self, name: str) -> str:
        +        """The named metadata resource as a string"""
        +
        +    def get_metadata_lines(self, name: str) -> Iterator[str]:
        +        """Yield named metadata resource as list of non-blank non-comment lines
        +
        +        Leading and trailing whitespace is stripped from each line, and lines
        +        with ``#`` as the first non-blank character are omitted."""
        +
        +    def metadata_isdir(self, name: str) -> bool:
        +        """Is the named metadata a directory?  (like ``os.path.isdir()``)"""
        +
        +    def metadata_listdir(self, name: str) -> list[str]:
        +        """List of metadata names in the directory (like ``os.listdir()``)"""
        +
        +    def run_script(self, script_name: str, namespace: dict[str, Any]) -> None:
        +        """Execute the named script in the supplied namespace dictionary"""
        +
        +
        +class IResourceProvider(IMetadataProvider, Protocol):
        +    """An object that provides access to package resources"""
        +
        +    def get_resource_filename(
        +        self, manager: ResourceManager, resource_name: str
        +    ) -> str:
        +        """Return a true filesystem path for `resource_name`
        +
        +        `manager` must be a ``ResourceManager``"""
        +
        +    def get_resource_stream(
        +        self, manager: ResourceManager, resource_name: str
        +    ) -> _ResourceStream:
        +        """Return a readable file-like object for `resource_name`
        +
        +        `manager` must be a ``ResourceManager``"""
        +
        +    def get_resource_string(
        +        self, manager: ResourceManager, resource_name: str
        +    ) -> bytes:
        +        """Return the contents of `resource_name` as :obj:`bytes`
        +
        +        `manager` must be a ``ResourceManager``"""
        +
        +    def has_resource(self, resource_name: str) -> bool:
        +        """Does the package contain the named resource?"""
        +
        +    def resource_isdir(self, resource_name: str) -> bool:
        +        """Is the named resource a directory?  (like ``os.path.isdir()``)"""
        +
        +    def resource_listdir(self, resource_name: str) -> list[str]:
        +        """List of resource names in the directory (like ``os.listdir()``)"""
        +
        +
        +class WorkingSet:
        +    """A collection of active distributions on sys.path (or a similar list)"""
        +
        +    def __init__(self, entries: Iterable[str] | None = None):
        +        """Create working set from list of path entries (default=sys.path)"""
        +        self.entries: list[str] = []
        +        self.entry_keys = {}
        +        self.by_key = {}
        +        self.normalized_to_canonical_keys = {}
        +        self.callbacks = []
        +
        +        if entries is None:
        +            entries = sys.path
        +
        +        for entry in entries:
        +            self.add_entry(entry)
        +
        +    @classmethod
        +    def _build_master(cls):
        +        """
        +        Prepare the master working set.
        +        """
        +        ws = cls()
        +        try:
        +            from __main__ import __requires__
        +        except ImportError:
        +            # The main program does not list any requirements
        +            return ws
        +
        +        # ensure the requirements are met
        +        try:
        +            ws.require(__requires__)
        +        except VersionConflict:
        +            return cls._build_from_requirements(__requires__)
        +
        +        return ws
        +
        +    @classmethod
        +    def _build_from_requirements(cls, req_spec):
        +        """
        +        Build a working set from a requirement spec. Rewrites sys.path.
        +        """
        +        # try it without defaults already on sys.path
        +        # by starting with an empty path
        +        ws = cls([])
        +        reqs = parse_requirements(req_spec)
        +        dists = ws.resolve(reqs, Environment())
        +        for dist in dists:
        +            ws.add(dist)
        +
        +        # add any missing entries from sys.path
        +        for entry in sys.path:
        +            if entry not in ws.entries:
        +                ws.add_entry(entry)
        +
        +        # then copy back to sys.path
        +        sys.path[:] = ws.entries
        +        return ws
        +
        +    def add_entry(self, entry: str):
        +        """Add a path item to ``.entries``, finding any distributions on it
        +
        +        ``find_distributions(entry, True)`` is used to find distributions
        +        corresponding to the path entry, and they are added.  `entry` is
        +        always appended to ``.entries``, even if it is already present.
        +        (This is because ``sys.path`` can contain the same value more than
        +        once, and the ``.entries`` of the ``sys.path`` WorkingSet should always
        +        equal ``sys.path``.)
        +        """
        +        self.entry_keys.setdefault(entry, [])
        +        self.entries.append(entry)
        +        for dist in find_distributions(entry, True):
        +            self.add(dist, entry, False)
        +
        +    def __contains__(self, dist: Distribution) -> bool:
        +        """True if `dist` is the active distribution for its project"""
        +        return self.by_key.get(dist.key) == dist
        +
        +    def find(self, req: Requirement) -> Distribution | None:
        +        """Find a distribution matching requirement `req`
        +
        +        If there is an active distribution for the requested project, this
        +        returns it as long as it meets the version requirement specified by
        +        `req`.  But, if there is an active distribution for the project and it
        +        does *not* meet the `req` requirement, ``VersionConflict`` is raised.
        +        If there is no active distribution for the requested project, ``None``
        +        is returned.
        +        """
        +        dist = self.by_key.get(req.key)
        +
        +        if dist is None:
        +            canonical_key = self.normalized_to_canonical_keys.get(req.key)
        +
        +            if canonical_key is not None:
        +                req.key = canonical_key
        +                dist = self.by_key.get(canonical_key)
        +
        +        if dist is not None and dist not in req:
        +            # XXX add more info
        +            raise VersionConflict(dist, req)
        +        return dist
        +
        +    def iter_entry_points(self, group: str, name: str | None = None):
        +        """Yield entry point objects from `group` matching `name`
        +
        +        If `name` is None, yields all entry points in `group` from all
        +        distributions in the working set, otherwise only ones matching
        +        both `group` and `name` are yielded (in distribution order).
        +        """
        +        return (
        +            entry
        +            for dist in self
        +            for entry in dist.get_entry_map(group).values()
        +            if name is None or name == entry.name
        +        )
        +
        +    def run_script(self, requires: str, script_name: str):
        +        """Locate distribution for `requires` and run `script_name` script"""
        +        ns = sys._getframe(1).f_globals
        +        name = ns['__name__']
        +        ns.clear()
        +        ns['__name__'] = name
        +        self.require(requires)[0].run_script(script_name, ns)
        +
        +    def __iter__(self) -> Iterator[Distribution]:
        +        """Yield distributions for non-duplicate projects in the working set
        +
        +        The yield order is the order in which the items' path entries were
        +        added to the working set.
        +        """
        +        seen = set()
        +        for item in self.entries:
        +            if item not in self.entry_keys:
        +                # workaround a cache issue
        +                continue
        +
        +            for key in self.entry_keys[item]:
        +                if key not in seen:
        +                    seen.add(key)
        +                    yield self.by_key[key]
        +
        +    def add(
        +        self,
        +        dist: Distribution,
        +        entry: str | None = None,
        +        insert: bool = True,
        +        replace: bool = False,
        +    ):
        +        """Add `dist` to working set, associated with `entry`
        +
        +        If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
        +        On exit from this routine, `entry` is added to the end of the working
        +        set's ``.entries`` (if it wasn't already present).
        +
        +        `dist` is only added to the working set if it's for a project that
        +        doesn't already have a distribution in the set, unless `replace=True`.
        +        If it's added, any callbacks registered with the ``subscribe()`` method
        +        will be called.
        +        """
        +        if insert:
        +            dist.insert_on(self.entries, entry, replace=replace)
        +
        +        if entry is None:
        +            entry = dist.location
        +        keys = self.entry_keys.setdefault(entry, [])
        +        keys2 = self.entry_keys.setdefault(dist.location, [])
        +        if not replace and dist.key in self.by_key:
        +            # ignore hidden distros
        +            return
        +
        +        self.by_key[dist.key] = dist
        +        normalized_name = _packaging_utils.canonicalize_name(dist.key)
        +        self.normalized_to_canonical_keys[normalized_name] = dist.key
        +        if dist.key not in keys:
        +            keys.append(dist.key)
        +        if dist.key not in keys2:
        +            keys2.append(dist.key)
        +        self._added_new(dist)
        +
        +    @overload
        +    def resolve(
        +        self,
        +        requirements: Iterable[Requirement],
        +        env: Environment | None,
        +        installer: _InstallerTypeT[_DistributionT],
        +        replace_conflicting: bool = False,
        +        extras: tuple[str, ...] | None = None,
        +    ) -> list[_DistributionT]: ...
        +    @overload
        +    def resolve(
        +        self,
        +        requirements: Iterable[Requirement],
        +        env: Environment | None = None,
        +        *,
        +        installer: _InstallerTypeT[_DistributionT],
        +        replace_conflicting: bool = False,
        +        extras: tuple[str, ...] | None = None,
        +    ) -> list[_DistributionT]: ...
        +    @overload
        +    def resolve(
        +        self,
        +        requirements: Iterable[Requirement],
        +        env: Environment | None = None,
        +        installer: _InstallerType | None = None,
        +        replace_conflicting: bool = False,
        +        extras: tuple[str, ...] | None = None,
        +    ) -> list[Distribution]: ...
        +    def resolve(
        +        self,
        +        requirements: Iterable[Requirement],
        +        env: Environment | None = None,
        +        installer: _InstallerType | None | _InstallerTypeT[_DistributionT] = None,
        +        replace_conflicting: bool = False,
        +        extras: tuple[str, ...] | None = None,
        +    ) -> list[Distribution] | list[_DistributionT]:
        +        """List all distributions needed to (recursively) meet `requirements`
        +
        +        `requirements` must be a sequence of ``Requirement`` objects.  `env`,
        +        if supplied, should be an ``Environment`` instance.  If
        +        not supplied, it defaults to all distributions available within any
        +        entry or distribution in the working set.  `installer`, if supplied,
        +        will be invoked with each requirement that cannot be met by an
        +        already-installed distribution; it should return a ``Distribution`` or
        +        ``None``.
        +
        +        Unless `replace_conflicting=True`, raises a VersionConflict exception
        +        if
        +        any requirements are found on the path that have the correct name but
        +        the wrong version.  Otherwise, if an `installer` is supplied it will be
        +        invoked to obtain the correct version of the requirement and activate
        +        it.
        +
        +        `extras` is a list of the extras to be used with these requirements.
        +        This is important because extra requirements may look like `my_req;
        +        extra = "my_extra"`, which would otherwise be interpreted as a purely
        +        optional requirement.  Instead, we want to be able to assert that these
        +        requirements are truly required.
        +        """
        +
        +        # set up the stack
        +        requirements = list(requirements)[::-1]
        +        # set of processed requirements
        +        processed = set()
        +        # key -> dist
        +        best = {}
        +        to_activate = []
        +
        +        req_extras = _ReqExtras()
        +
        +        # Mapping of requirement to set of distributions that required it;
        +        # useful for reporting info about conflicts.
        +        required_by = collections.defaultdict(set)
        +
        +        while requirements:
        +            # process dependencies breadth-first
        +            req = requirements.pop(0)
        +            if req in processed:
        +                # Ignore cyclic or redundant dependencies
        +                continue
        +
        +            if not req_extras.markers_pass(req, extras):
        +                continue
        +
        +            dist = self._resolve_dist(
        +                req, best, replace_conflicting, env, installer, required_by, to_activate
        +            )
        +
        +            # push the new requirements onto the stack
        +            new_requirements = dist.requires(req.extras)[::-1]
        +            requirements.extend(new_requirements)
        +
        +            # Register the new requirements needed by req
        +            for new_requirement in new_requirements:
        +                required_by[new_requirement].add(req.project_name)
        +                req_extras[new_requirement] = req.extras
        +
        +            processed.add(req)
        +
        +        # return list of distros to activate
        +        return to_activate
        +
        +    def _resolve_dist(
        +        self, req, best, replace_conflicting, env, installer, required_by, to_activate
        +    ) -> Distribution:
        +        dist = best.get(req.key)
        +        if dist is None:
        +            # Find the best distribution and add it to the map
        +            dist = self.by_key.get(req.key)
        +            if dist is None or (dist not in req and replace_conflicting):
        +                ws = self
        +                if env is None:
        +                    if dist is None:
        +                        env = Environment(self.entries)
        +                    else:
        +                        # Use an empty environment and workingset to avoid
        +                        # any further conflicts with the conflicting
        +                        # distribution
        +                        env = Environment([])
        +                        ws = WorkingSet([])
        +                dist = best[req.key] = env.best_match(
        +                    req, ws, installer, replace_conflicting=replace_conflicting
        +                )
        +                if dist is None:
        +                    requirers = required_by.get(req, None)
        +                    raise DistributionNotFound(req, requirers)
        +            to_activate.append(dist)
        +        if dist not in req:
        +            # Oops, the "best" so far conflicts with a dependency
        +            dependent_req = required_by[req]
        +            raise VersionConflict(dist, req).with_context(dependent_req)
        +        return dist
        +
        +    @overload
        +    def find_plugins(
        +        self,
        +        plugin_env: Environment,
        +        full_env: Environment | None,
        +        installer: _InstallerTypeT[_DistributionT],
        +        fallback: bool = True,
        +    ) -> tuple[list[_DistributionT], dict[Distribution, Exception]]: ...
        +    @overload
        +    def find_plugins(
        +        self,
        +        plugin_env: Environment,
        +        full_env: Environment | None = None,
        +        *,
        +        installer: _InstallerTypeT[_DistributionT],
        +        fallback: bool = True,
        +    ) -> tuple[list[_DistributionT], dict[Distribution, Exception]]: ...
        +    @overload
        +    def find_plugins(
        +        self,
        +        plugin_env: Environment,
        +        full_env: Environment | None = None,
        +        installer: _InstallerType | None = None,
        +        fallback: bool = True,
        +    ) -> tuple[list[Distribution], dict[Distribution, Exception]]: ...
        +    def find_plugins(
        +        self,
        +        plugin_env: Environment,
        +        full_env: Environment | None = None,
        +        installer: _InstallerType | None | _InstallerTypeT[_DistributionT] = None,
        +        fallback: bool = True,
        +    ) -> tuple[
        +        list[Distribution] | list[_DistributionT],
        +        dict[Distribution, Exception],
        +    ]:
        +        """Find all activatable distributions in `plugin_env`
        +
        +        Example usage::
        +
        +            distributions, errors = working_set.find_plugins(
        +                Environment(plugin_dirlist)
        +            )
        +            # add plugins+libs to sys.path
        +            map(working_set.add, distributions)
        +            # display errors
        +            print('Could not load', errors)
        +
        +        The `plugin_env` should be an ``Environment`` instance that contains
        +        only distributions that are in the project's "plugin directory" or
        +        directories. The `full_env`, if supplied, should be an ``Environment``
        +        contains all currently-available distributions.  If `full_env` is not
        +        supplied, one is created automatically from the ``WorkingSet`` this
        +        method is called on, which will typically mean that every directory on
        +        ``sys.path`` will be scanned for distributions.
        +
        +        `installer` is a standard installer callback as used by the
        +        ``resolve()`` method. The `fallback` flag indicates whether we should
        +        attempt to resolve older versions of a plugin if the newest version
        +        cannot be resolved.
        +
        +        This method returns a 2-tuple: (`distributions`, `error_info`), where
        +        `distributions` is a list of the distributions found in `plugin_env`
        +        that were loadable, along with any other distributions that are needed
        +        to resolve their dependencies.  `error_info` is a dictionary mapping
        +        unloadable plugin distributions to an exception instance describing the
        +        error that occurred. Usually this will be a ``DistributionNotFound`` or
        +        ``VersionConflict`` instance.
        +        """
        +
        +        plugin_projects = list(plugin_env)
        +        # scan project names in alphabetic order
        +        plugin_projects.sort()
        +
        +        error_info: dict[Distribution, Exception] = {}
        +        distributions: dict[Distribution, Exception | None] = {}
        +
        +        if full_env is None:
        +            env = Environment(self.entries)
        +            env += plugin_env
        +        else:
        +            env = full_env + plugin_env
        +
        +        shadow_set = self.__class__([])
        +        # put all our entries in shadow_set
        +        list(map(shadow_set.add, self))
        +
        +        for project_name in plugin_projects:
        +            for dist in plugin_env[project_name]:
        +                req = [dist.as_requirement()]
        +
        +                try:
        +                    resolvees = shadow_set.resolve(req, env, installer)
        +
        +                except ResolutionError as v:
        +                    # save error info
        +                    error_info[dist] = v
        +                    if fallback:
        +                        # try the next older version of project
        +                        continue
        +                    else:
        +                        # give up on this project, keep going
        +                        break
        +
        +                else:
        +                    list(map(shadow_set.add, resolvees))
        +                    distributions.update(dict.fromkeys(resolvees))
        +
        +                    # success, no need to try any more versions of this project
        +                    break
        +
        +        sorted_distributions = list(distributions)
        +        sorted_distributions.sort()
        +
        +        return sorted_distributions, error_info
        +
        +    def require(self, *requirements: _NestedStr):
        +        """Ensure that distributions matching `requirements` are activated
        +
        +        `requirements` must be a string or a (possibly-nested) sequence
        +        thereof, specifying the distributions and versions required.  The
        +        return value is a sequence of the distributions that needed to be
        +        activated to fulfill the requirements; all relevant distributions are
        +        included, even if they were already activated in this working set.
        +        """
        +        needed = self.resolve(parse_requirements(requirements))
        +
        +        for dist in needed:
        +            self.add(dist)
        +
        +        return needed
        +
        +    def subscribe(
        +        self, callback: Callable[[Distribution], object], existing: bool = True
        +    ):
        +        """Invoke `callback` for all distributions
        +
        +        If `existing=True` (default),
        +        call on all existing ones, as well.
        +        """
        +        if callback in self.callbacks:
        +            return
        +        self.callbacks.append(callback)
        +        if not existing:
        +            return
        +        for dist in self:
        +            callback(dist)
        +
        +    def _added_new(self, dist):
        +        for callback in self.callbacks:
        +            callback(dist)
        +
        +    def __getstate__(self):
        +        return (
        +            self.entries[:],
        +            self.entry_keys.copy(),
        +            self.by_key.copy(),
        +            self.normalized_to_canonical_keys.copy(),
        +            self.callbacks[:],
        +        )
        +
        +    def __setstate__(self, e_k_b_n_c):
        +        entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c
        +        self.entries = entries[:]
        +        self.entry_keys = keys.copy()
        +        self.by_key = by_key.copy()
        +        self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy()
        +        self.callbacks = callbacks[:]
        +
        +
        +class _ReqExtras(Dict["Requirement", Tuple[str, ...]]):
        +    """
        +    Map each requirement to the extras that demanded it.
        +    """
        +
        +    def markers_pass(self, req: Requirement, extras: tuple[str, ...] | None = None):
        +        """
        +        Evaluate markers for req against each extra that
        +        demanded it.
        +
        +        Return False if the req has a marker and fails
        +        evaluation. Otherwise, return True.
        +        """
        +        extra_evals = (
        +            req.marker.evaluate({'extra': extra})
        +            for extra in self.get(req, ()) + (extras or (None,))
        +        )
        +        return not req.marker or any(extra_evals)
        +
        +
        +class Environment:
        +    """Searchable snapshot of distributions on a search path"""
        +
        +    def __init__(
        +        self,
        +        search_path: Iterable[str] | None = None,
        +        platform: str | None = get_supported_platform(),
        +        python: str | None = PY_MAJOR,
        +    ):
        +        """Snapshot distributions available on a search path
        +
        +        Any distributions found on `search_path` are added to the environment.
        +        `search_path` should be a sequence of ``sys.path`` items.  If not
        +        supplied, ``sys.path`` is used.
        +
        +        `platform` is an optional string specifying the name of the platform
        +        that platform-specific distributions must be compatible with.  If
        +        unspecified, it defaults to the current platform.  `python` is an
        +        optional string naming the desired version of Python (e.g. ``'3.6'``);
        +        it defaults to the current version.
        +
        +        You may explicitly set `platform` (and/or `python`) to ``None`` if you
        +        wish to map *all* distributions, not just those compatible with the
        +        running platform or Python version.
        +        """
        +        self._distmap = {}
        +        self.platform = platform
        +        self.python = python
        +        self.scan(search_path)
        +
        +    def can_add(self, dist: Distribution):
        +        """Is distribution `dist` acceptable for this environment?
        +
        +        The distribution must match the platform and python version
        +        requirements specified when this environment was created, or False
        +        is returned.
        +        """
        +        py_compat = (
        +            self.python is None
        +            or dist.py_version is None
        +            or dist.py_version == self.python
        +        )
        +        return py_compat and compatible_platforms(dist.platform, self.platform)
        +
        +    def remove(self, dist: Distribution):
        +        """Remove `dist` from the environment"""
        +        self._distmap[dist.key].remove(dist)
        +
        +    def scan(self, search_path: Iterable[str] | None = None):
        +        """Scan `search_path` for distributions usable in this environment
        +
        +        Any distributions found are added to the environment.
        +        `search_path` should be a sequence of ``sys.path`` items.  If not
        +        supplied, ``sys.path`` is used.  Only distributions conforming to
        +        the platform/python version defined at initialization are added.
        +        """
        +        if search_path is None:
        +            search_path = sys.path
        +
        +        for item in search_path:
        +            for dist in find_distributions(item):
        +                self.add(dist)
        +
        +    def __getitem__(self, project_name: str) -> list[Distribution]:
        +        """Return a newest-to-oldest list of distributions for `project_name`
        +
        +        Uses case-insensitive `project_name` comparison, assuming all the
        +        project's distributions use their project's name converted to all
        +        lowercase as their key.
        +
        +        """
        +        distribution_key = project_name.lower()
        +        return self._distmap.get(distribution_key, [])
        +
        +    def add(self, dist: Distribution):
        +        """Add `dist` if we ``can_add()`` it and it has not already been added"""
        +        if self.can_add(dist) and dist.has_version():
        +            dists = self._distmap.setdefault(dist.key, [])
        +            if dist not in dists:
        +                dists.append(dist)
        +                dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)
        +
        +    @overload
        +    def best_match(
        +        self,
        +        req: Requirement,
        +        working_set: WorkingSet,
        +        installer: _InstallerTypeT[_DistributionT],
        +        replace_conflicting: bool = False,
        +    ) -> _DistributionT: ...
        +    @overload
        +    def best_match(
        +        self,
        +        req: Requirement,
        +        working_set: WorkingSet,
        +        installer: _InstallerType | None = None,
        +        replace_conflicting: bool = False,
        +    ) -> Distribution | None: ...
        +    def best_match(
        +        self,
        +        req: Requirement,
        +        working_set: WorkingSet,
        +        installer: _InstallerType | None | _InstallerTypeT[_DistributionT] = None,
        +        replace_conflicting: bool = False,
        +    ) -> Distribution | None:
        +        """Find distribution best matching `req` and usable on `working_set`
        +
        +        This calls the ``find(req)`` method of the `working_set` to see if a
        +        suitable distribution is already active.  (This may raise
        +        ``VersionConflict`` if an unsuitable version of the project is already
        +        active in the specified `working_set`.)  If a suitable distribution
        +        isn't active, this method returns the newest distribution in the
        +        environment that meets the ``Requirement`` in `req`.  If no suitable
        +        distribution is found, and `installer` is supplied, then the result of
        +        calling the environment's ``obtain(req, installer)`` method will be
        +        returned.
        +        """
        +        try:
        +            dist = working_set.find(req)
        +        except VersionConflict:
        +            if not replace_conflicting:
        +                raise
        +            dist = None
        +        if dist is not None:
        +            return dist
        +        for dist in self[req.key]:
        +            if dist in req:
        +                return dist
        +        # try to download/install
        +        return self.obtain(req, installer)
        +
        +    @overload
        +    def obtain(
        +        self,
        +        requirement: Requirement,
        +        installer: _InstallerTypeT[_DistributionT],
        +    ) -> _DistributionT: ...
        +    @overload
        +    def obtain(
        +        self,
        +        requirement: Requirement,
        +        installer: Callable[[Requirement], None] | None = None,
        +    ) -> None: ...
        +    @overload
        +    def obtain(
        +        self,
        +        requirement: Requirement,
        +        installer: _InstallerType | None = None,
        +    ) -> Distribution | None: ...
        +    def obtain(
        +        self,
        +        requirement: Requirement,
        +        installer: Callable[[Requirement], None]
        +        | _InstallerType
        +        | None
        +        | _InstallerTypeT[_DistributionT] = None,
        +    ) -> Distribution | None:
        +        """Obtain a distribution matching `requirement` (e.g. via download)
        +
        +        Obtain a distro that matches requirement (e.g. via download).  In the
        +        base ``Environment`` class, this routine just returns
        +        ``installer(requirement)``, unless `installer` is None, in which case
        +        None is returned instead.  This method is a hook that allows subclasses
        +        to attempt other ways of obtaining a distribution before falling back
        +        to the `installer` argument."""
        +        return installer(requirement) if installer else None
        +
        +    def __iter__(self) -> Iterator[str]:
        +        """Yield the unique project names of the available distributions"""
        +        for key in self._distmap.keys():
        +            if self[key]:
        +                yield key
        +
        +    def __iadd__(self, other: Distribution | Environment):
        +        """In-place addition of a distribution or environment"""
        +        if isinstance(other, Distribution):
        +            self.add(other)
        +        elif isinstance(other, Environment):
        +            for project in other:
        +                for dist in other[project]:
        +                    self.add(dist)
        +        else:
        +            raise TypeError("Can't add %r to environment" % (other,))
        +        return self
        +
        +    def __add__(self, other: Distribution | Environment):
        +        """Add an environment or distribution to an environment"""
        +        new = self.__class__([], platform=None, python=None)
        +        for env in self, other:
        +            new += env
        +        return new
        +
        +
        +# XXX backward compatibility
        +AvailableDistributions = Environment
        +
        +
        +class ExtractionError(RuntimeError):
        +    """An error occurred extracting a resource
        +
        +    The following attributes are available from instances of this exception:
        +
        +    manager
        +        The resource manager that raised this exception
        +
        +    cache_path
        +        The base directory for resource extraction
        +
        +    original_error
        +        The exception instance that caused extraction to fail
        +    """
        +
        +    manager: ResourceManager
        +    cache_path: str
        +    original_error: BaseException | None
        +
        +
        +class ResourceManager:
        +    """Manage resource extraction and packages"""
        +
        +    extraction_path: str | None = None
        +
        +    def __init__(self):
        +        self.cached_files = {}
        +
        +    def resource_exists(self, package_or_requirement: _PkgReqType, resource_name: str):
        +        """Does the named resource exist?"""
        +        return get_provider(package_or_requirement).has_resource(resource_name)
        +
        +    def resource_isdir(self, package_or_requirement: _PkgReqType, resource_name: str):
        +        """Is the named resource an existing directory?"""
        +        return get_provider(package_or_requirement).resource_isdir(resource_name)
        +
        +    def resource_filename(
        +        self, package_or_requirement: _PkgReqType, resource_name: str
        +    ):
        +        """Return a true filesystem path for specified resource"""
        +        return get_provider(package_or_requirement).get_resource_filename(
        +            self, resource_name
        +        )
        +
        +    def resource_stream(self, package_or_requirement: _PkgReqType, resource_name: str):
        +        """Return a readable file-like object for specified resource"""
        +        return get_provider(package_or_requirement).get_resource_stream(
        +            self, resource_name
        +        )
        +
        +    def resource_string(
        +        self, package_or_requirement: _PkgReqType, resource_name: str
        +    ) -> bytes:
        +        """Return specified resource as :obj:`bytes`"""
        +        return get_provider(package_or_requirement).get_resource_string(
        +            self, resource_name
        +        )
        +
        +    def resource_listdir(self, package_or_requirement: _PkgReqType, resource_name: str):
        +        """List the contents of the named resource directory"""
        +        return get_provider(package_or_requirement).resource_listdir(resource_name)
        +
        +    def extraction_error(self) -> NoReturn:
        +        """Give an error message for problems extracting file(s)"""
        +
        +        old_exc = sys.exc_info()[1]
        +        cache_path = self.extraction_path or get_default_cache()
        +
        +        tmpl = textwrap.dedent(
        +            """
        +            Can't extract file(s) to egg cache
        +
        +            The following error occurred while trying to extract file(s)
        +            to the Python egg cache:
        +
        +              {old_exc}
        +
        +            The Python egg cache directory is currently set to:
        +
        +              {cache_path}
        +
        +            Perhaps your account does not have write access to this directory?
        +            You can change the cache directory by setting the PYTHON_EGG_CACHE
        +            environment variable to point to an accessible directory.
        +            """
        +        ).lstrip()
        +        err = ExtractionError(tmpl.format(**locals()))
        +        err.manager = self
        +        err.cache_path = cache_path
        +        err.original_error = old_exc
        +        raise err
        +
        +    def get_cache_path(self, archive_name: str, names: Iterable[StrPath] = ()):
        +        """Return absolute location in cache for `archive_name` and `names`
        +
        +        The parent directory of the resulting path will be created if it does
        +        not already exist.  `archive_name` should be the base filename of the
        +        enclosing egg (which may not be the name of the enclosing zipfile!),
        +        including its ".egg" extension.  `names`, if provided, should be a
        +        sequence of path name parts "under" the egg's extraction location.
        +
        +        This method should only be called by resource providers that need to
        +        obtain an extraction location, and only for names they intend to
        +        extract, as it tracks the generated names for possible cleanup later.
        +        """
        +        extract_path = self.extraction_path or get_default_cache()
        +        target_path = os.path.join(extract_path, archive_name + '-tmp', *names)
        +        try:
        +            _bypass_ensure_directory(target_path)
        +        except Exception:
        +            self.extraction_error()
        +
        +        self._warn_unsafe_extraction_path(extract_path)
        +
        +        self.cached_files[target_path] = True
        +        return target_path
        +
        +    @staticmethod
        +    def _warn_unsafe_extraction_path(path):
        +        """
        +        If the default extraction path is overridden and set to an insecure
        +        location, such as /tmp, it opens up an opportunity for an attacker to
        +        replace an extracted file with an unauthorized payload. Warn the user
        +        if a known insecure location is used.
        +
        +        See Distribute #375 for more details.
        +        """
        +        if os.name == 'nt' and not path.startswith(os.environ['windir']):
        +            # On Windows, permissions are generally restrictive by default
        +            #  and temp directories are not writable by other users, so
        +            #  bypass the warning.
        +            return
        +        mode = os.stat(path).st_mode
        +        if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
        +            msg = (
        +                "Extraction path is writable by group/others "
        +                "and vulnerable to attack when "
        +                "used with get_resource_filename ({path}). "
        +                "Consider a more secure "
        +                "location (set with .set_extraction_path or the "
        +                "PYTHON_EGG_CACHE environment variable)."
        +            ).format(**locals())
        +            warnings.warn(msg, UserWarning)
        +
        +    def postprocess(self, tempname: StrOrBytesPath, filename: StrOrBytesPath):
        +        """Perform any platform-specific postprocessing of `tempname`
        +
        +        This is where Mac header rewrites should be done; other platforms don't
        +        have anything special they should do.
        +
        +        Resource providers should call this method ONLY after successfully
        +        extracting a compressed resource.  They must NOT call it on resources
        +        that are already in the filesystem.
        +
        +        `tempname` is the current (temporary) name of the file, and `filename`
        +        is the name it will be renamed to by the caller after this routine
        +        returns.
        +        """
        +
        +        if os.name == 'posix':
        +            # Make the resource executable
        +            mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777
        +            os.chmod(tempname, mode)
        +
        +    def set_extraction_path(self, path: str):
        +        """Set the base path where resources will be extracted to, if needed.
        +
        +        If you do not call this routine before any extractions take place, the
        +        path defaults to the return value of ``get_default_cache()``.  (Which
        +        is based on the ``PYTHON_EGG_CACHE`` environment variable, with various
        +        platform-specific fallbacks.  See that routine's documentation for more
        +        details.)
        +
        +        Resources are extracted to subdirectories of this path based upon
        +        information given by the ``IResourceProvider``.  You may set this to a
        +        temporary directory, but then you must call ``cleanup_resources()`` to
        +        delete the extracted files when done.  There is no guarantee that
        +        ``cleanup_resources()`` will be able to remove all extracted files.
        +
        +        (Note: you may not change the extraction path for a given resource
        +        manager once resources have been extracted, unless you first call
        +        ``cleanup_resources()``.)
        +        """
        +        if self.cached_files:
        +            raise ValueError("Can't change extraction path, files already extracted")
        +
        +        self.extraction_path = path
        +
        +    def cleanup_resources(self, force: bool = False) -> list[str]:
        +        """
        +        Delete all extracted resource files and directories, returning a list
        +        of the file and directory names that could not be successfully removed.
        +        This function does not have any concurrency protection, so it should
        +        generally only be called when the extraction path is a temporary
        +        directory exclusive to a single process.  This method is not
        +        automatically called; you must call it explicitly or register it as an
        +        ``atexit`` function if you wish to ensure cleanup of a temporary
        +        directory used for extractions.
        +        """
        +        # XXX
        +        return []
        +
        +
        +def get_default_cache() -> str:
        +    """
        +    Return the ``PYTHON_EGG_CACHE`` environment variable
        +    or a platform-relevant user cache dir for an app
        +    named "Python-Eggs".
        +    """
        +    return os.environ.get('PYTHON_EGG_CACHE') or _user_cache_dir(appname='Python-Eggs')
        +
        +
        +def safe_name(name: str):
        +    """Convert an arbitrary string to a standard distribution name
        +
        +    Any runs of non-alphanumeric/. characters are replaced with a single '-'.
        +    """
        +    return re.sub('[^A-Za-z0-9.]+', '-', name)
        +
        +
        +def safe_version(version: str):
        +    """
        +    Convert an arbitrary string to a standard version string
        +    """
        +    try:
        +        # normalize the version
        +        return str(_packaging_version.Version(version))
        +    except _packaging_version.InvalidVersion:
        +        version = version.replace(' ', '.')
        +        return re.sub('[^A-Za-z0-9.]+', '-', version)
        +
        +
        +def _forgiving_version(version):
        +    """Fallback when ``safe_version`` is not safe enough
        +    >>> parse_version(_forgiving_version('0.23ubuntu1'))
        +    
        +    >>> parse_version(_forgiving_version('0.23-'))
        +    
        +    >>> parse_version(_forgiving_version('0.-_'))
        +    
        +    >>> parse_version(_forgiving_version('42.+?1'))
        +    
        +    >>> parse_version(_forgiving_version('hello world'))
        +    
        +    """
        +    version = version.replace(' ', '.')
        +    match = _PEP440_FALLBACK.search(version)
        +    if match:
        +        safe = match["safe"]
        +        rest = version[len(safe) :]
        +    else:
        +        safe = "0"
        +        rest = version
        +    local = f"sanitized.{_safe_segment(rest)}".strip(".")
        +    return f"{safe}.dev0+{local}"
        +
        +
        +def _safe_segment(segment):
        +    """Convert an arbitrary string into a safe segment"""
        +    segment = re.sub('[^A-Za-z0-9.]+', '-', segment)
        +    segment = re.sub('-[^A-Za-z0-9]+', '-', segment)
        +    return re.sub(r'\.[^A-Za-z0-9]+', '.', segment).strip(".-")
        +
        +
        +def safe_extra(extra: str):
        +    """Convert an arbitrary string to a standard 'extra' name
        +
        +    Any runs of non-alphanumeric characters are replaced with a single '_',
        +    and the result is always lowercased.
        +    """
        +    return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower()
        +
        +
        +def to_filename(name: str):
        +    """Convert a project or version name to its filename-escaped form
        +
        +    Any '-' characters are currently replaced with '_'.
        +    """
        +    return name.replace('-', '_')
        +
        +
        +def invalid_marker(text: str):
        +    """
        +    Validate text as a PEP 508 environment marker; return an exception
        +    if invalid or False otherwise.
        +    """
        +    try:
        +        evaluate_marker(text)
        +    except SyntaxError as e:
        +        e.filename = None
        +        e.lineno = None
        +        return e
        +    return False
        +
        +
        +def evaluate_marker(text: str, extra: str | None = None) -> bool:
        +    """
        +    Evaluate a PEP 508 environment marker.
        +    Return a boolean indicating the marker result in this environment.
        +    Raise SyntaxError if marker is invalid.
        +
        +    This implementation uses the 'pyparsing' module.
        +    """
        +    try:
        +        marker = _packaging_markers.Marker(text)
        +        return marker.evaluate()
        +    except _packaging_markers.InvalidMarker as e:
        +        raise SyntaxError(e) from e
        +
        +
        +class NullProvider:
        +    """Try to implement resources and metadata for arbitrary PEP 302 loaders"""
        +
        +    egg_name: str | None = None
        +    egg_info: str | None = None
        +    loader: _LoaderProtocol | None = None
        +
        +    def __init__(self, module: _ModuleLike):
        +        self.loader = getattr(module, '__loader__', None)
        +        self.module_path = os.path.dirname(getattr(module, '__file__', ''))
        +
        +    def get_resource_filename(self, manager: ResourceManager, resource_name: str):
        +        return self._fn(self.module_path, resource_name)
        +
        +    def get_resource_stream(self, manager: ResourceManager, resource_name: str):
        +        return io.BytesIO(self.get_resource_string(manager, resource_name))
        +
        +    def get_resource_string(
        +        self, manager: ResourceManager, resource_name: str
        +    ) -> bytes:
        +        return self._get(self._fn(self.module_path, resource_name))
        +
        +    def has_resource(self, resource_name: str):
        +        return self._has(self._fn(self.module_path, resource_name))
        +
        +    def _get_metadata_path(self, name):
        +        return self._fn(self.egg_info, name)
        +
        +    def has_metadata(self, name: str) -> bool:
        +        if not self.egg_info:
        +            return False
        +
        +        path = self._get_metadata_path(name)
        +        return self._has(path)
        +
        +    def get_metadata(self, name: str):
        +        if not self.egg_info:
        +            return ""
        +        path = self._get_metadata_path(name)
        +        value = self._get(path)
        +        try:
        +            return value.decode('utf-8')
        +        except UnicodeDecodeError as exc:
        +            # Include the path in the error message to simplify
        +            # troubleshooting, and without changing the exception type.
        +            exc.reason += ' in {} file at path: {}'.format(name, path)
        +            raise
        +
        +    def get_metadata_lines(self, name: str) -> Iterator[str]:
        +        return yield_lines(self.get_metadata(name))
        +
        +    def resource_isdir(self, resource_name: str):
        +        return self._isdir(self._fn(self.module_path, resource_name))
        +
        +    def metadata_isdir(self, name: str) -> bool:
        +        return bool(self.egg_info and self._isdir(self._fn(self.egg_info, name)))
        +
        +    def resource_listdir(self, resource_name: str):
        +        return self._listdir(self._fn(self.module_path, resource_name))
        +
        +    def metadata_listdir(self, name: str) -> list[str]:
        +        if self.egg_info:
        +            return self._listdir(self._fn(self.egg_info, name))
        +        return []
        +
        +    def run_script(self, script_name: str, namespace: dict[str, Any]):
        +        script = 'scripts/' + script_name
        +        if not self.has_metadata(script):
        +            raise ResolutionError(
        +                "Script {script!r} not found in metadata at {self.egg_info!r}".format(
        +                    **locals()
        +                ),
        +            )
        +
        +        script_text = self.get_metadata(script).replace('\r\n', '\n')
        +        script_text = script_text.replace('\r', '\n')
        +        script_filename = self._fn(self.egg_info, script)
        +        namespace['__file__'] = script_filename
        +        if os.path.exists(script_filename):
        +            source = _read_utf8_with_fallback(script_filename)
        +            code = compile(source, script_filename, 'exec')
        +            exec(code, namespace, namespace)
        +        else:
        +            from linecache import cache
        +
        +            cache[script_filename] = (
        +                len(script_text),
        +                0,
        +                script_text.split('\n'),
        +                script_filename,
        +            )
        +            script_code = compile(script_text, script_filename, 'exec')
        +            exec(script_code, namespace, namespace)
        +
        +    def _has(self, path) -> bool:
        +        raise NotImplementedError(
        +            "Can't perform this operation for unregistered loader type"
        +        )
        +
        +    def _isdir(self, path) -> bool:
        +        raise NotImplementedError(
        +            "Can't perform this operation for unregistered loader type"
        +        )
        +
        +    def _listdir(self, path) -> list[str]:
        +        raise NotImplementedError(
        +            "Can't perform this operation for unregistered loader type"
        +        )
        +
        +    def _fn(self, base: str | None, resource_name: str):
        +        if base is None:
        +            raise TypeError(
        +                "`base` parameter in `_fn` is `None`. Either override this method or check the parameter first."
        +            )
        +        self._validate_resource_path(resource_name)
        +        if resource_name:
        +            return os.path.join(base, *resource_name.split('/'))
        +        return base
        +
        +    @staticmethod
        +    def _validate_resource_path(path):
        +        """
        +        Validate the resource paths according to the docs.
        +        https://setuptools.pypa.io/en/latest/pkg_resources.html#basic-resource-access
        +
        +        >>> warned = getfixture('recwarn')
        +        >>> warnings.simplefilter('always')
        +        >>> vrp = NullProvider._validate_resource_path
        +        >>> vrp('foo/bar.txt')
        +        >>> bool(warned)
        +        False
        +        >>> vrp('../foo/bar.txt')
        +        >>> bool(warned)
        +        True
        +        >>> warned.clear()
        +        >>> vrp('/foo/bar.txt')
        +        >>> bool(warned)
        +        True
        +        >>> vrp('foo/../../bar.txt')
        +        >>> bool(warned)
        +        True
        +        >>> warned.clear()
        +        >>> vrp('foo/f../bar.txt')
        +        >>> bool(warned)
        +        False
        +
        +        Windows path separators are straight-up disallowed.
        +        >>> vrp(r'\\foo/bar.txt')
        +        Traceback (most recent call last):
        +        ...
        +        ValueError: Use of .. or absolute path in a resource path \
        +is not allowed.
        +
        +        >>> vrp(r'C:\\foo/bar.txt')
        +        Traceback (most recent call last):
        +        ...
        +        ValueError: Use of .. or absolute path in a resource path \
        +is not allowed.
        +
        +        Blank values are allowed
        +
        +        >>> vrp('')
        +        >>> bool(warned)
        +        False
        +
        +        Non-string values are not.
        +
        +        >>> vrp(None)
        +        Traceback (most recent call last):
        +        ...
        +        AttributeError: ...
        +        """
        +        invalid = (
        +            os.path.pardir in path.split(posixpath.sep)
        +            or posixpath.isabs(path)
        +            or ntpath.isabs(path)
        +            or path.startswith("\\")
        +        )
        +        if not invalid:
        +            return
        +
        +        msg = "Use of .. or absolute path in a resource path is not allowed."
        +
        +        # Aggressively disallow Windows absolute paths
        +        if (path.startswith("\\") or ntpath.isabs(path)) and not posixpath.isabs(path):
        +            raise ValueError(msg)
        +
        +        # for compatibility, warn; in future
        +        # raise ValueError(msg)
        +        issue_warning(
        +            msg[:-1] + " and will raise exceptions in a future release.",
        +            DeprecationWarning,
        +        )
        +
        +    def _get(self, path) -> bytes:
        +        if hasattr(self.loader, 'get_data') and self.loader:
        +            # Already checked get_data exists
        +            return self.loader.get_data(path)  # type: ignore[attr-defined]
        +        raise NotImplementedError(
        +            "Can't perform this operation for loaders without 'get_data()'"
        +        )
        +
        +
        +register_loader_type(object, NullProvider)
        +
        +
        +def _parents(path):
        +    """
        +    yield all parents of path including path
        +    """
        +    last = None
        +    while path != last:
        +        yield path
        +        last = path
        +        path, _ = os.path.split(path)
        +
        +
        +class EggProvider(NullProvider):
        +    """Provider based on a virtual filesystem"""
        +
        +    def __init__(self, module: _ModuleLike):
        +        super().__init__(module)
        +        self._setup_prefix()
        +
        +    def _setup_prefix(self):
        +        # Assume that metadata may be nested inside a "basket"
        +        # of multiple eggs and use module_path instead of .archive.
        +        eggs = filter(_is_egg_path, _parents(self.module_path))
        +        egg = next(eggs, None)
        +        egg and self._set_egg(egg)
        +
        +    def _set_egg(self, path: str):
        +        self.egg_name = os.path.basename(path)
        +        self.egg_info = os.path.join(path, 'EGG-INFO')
        +        self.egg_root = path
        +
        +
        +class DefaultProvider(EggProvider):
        +    """Provides access to package resources in the filesystem"""
        +
        +    def _has(self, path) -> bool:
        +        return os.path.exists(path)
        +
        +    def _isdir(self, path) -> bool:
        +        return os.path.isdir(path)
        +
        +    def _listdir(self, path):
        +        return os.listdir(path)
        +
        +    def get_resource_stream(self, manager: object, resource_name: str):
        +        return open(self._fn(self.module_path, resource_name), 'rb')
        +
        +    def _get(self, path) -> bytes:
        +        with open(path, 'rb') as stream:
        +            return stream.read()
        +
        +    @classmethod
        +    def _register(cls):
        +        loader_names = (
        +            'SourceFileLoader',
        +            'SourcelessFileLoader',
        +        )
        +        for name in loader_names:
        +            loader_cls = getattr(importlib.machinery, name, type(None))
        +            register_loader_type(loader_cls, cls)
        +
        +
        +DefaultProvider._register()
        +
        +
        +class EmptyProvider(NullProvider):
        +    """Provider that returns nothing for all requests"""
        +
        +    # A special case, we don't want all Providers inheriting from NullProvider to have a potentially None module_path
        +    module_path: str | None = None  # type: ignore[assignment]
        +
        +    _isdir = _has = lambda self, path: False
        +
        +    def _get(self, path) -> bytes:
        +        return b''
        +
        +    def _listdir(self, path):
        +        return []
        +
        +    def __init__(self):
        +        pass
        +
        +
        +empty_provider = EmptyProvider()
        +
        +
        +class ZipManifests(Dict[str, "MemoizedZipManifests.manifest_mod"]):
        +    """
        +    zip manifest builder
        +    """
        +
        +    # `path` could be `StrPath | IO[bytes]` but that violates the LSP for `MemoizedZipManifests.load`
        +    @classmethod
        +    def build(cls, path: str):
        +        """
        +        Build a dictionary similar to the zipimport directory
        +        caches, except instead of tuples, store ZipInfo objects.
        +
        +        Use a platform-specific path separator (os.sep) for the path keys
        +        for compatibility with pypy on Windows.
        +        """
        +        with zipfile.ZipFile(path) as zfile:
        +            items = (
        +                (
        +                    name.replace('/', os.sep),
        +                    zfile.getinfo(name),
        +                )
        +                for name in zfile.namelist()
        +            )
        +            return dict(items)
        +
        +    load = build
        +
        +
        +class MemoizedZipManifests(ZipManifests):
        +    """
        +    Memoized zipfile manifests.
        +    """
        +
        +    class manifest_mod(NamedTuple):
        +        manifest: dict[str, zipfile.ZipInfo]
        +        mtime: float
        +
        +    def load(self, path: str) -> dict[str, zipfile.ZipInfo]:  # type: ignore[override] # ZipManifests.load is a classmethod
        +        """
        +        Load a manifest at path or return a suitable manifest already loaded.
        +        """
        +        path = os.path.normpath(path)
        +        mtime = os.stat(path).st_mtime
        +
        +        if path not in self or self[path].mtime != mtime:
        +            manifest = self.build(path)
        +            self[path] = self.manifest_mod(manifest, mtime)
        +
        +        return self[path].manifest
        +
        +
        +class ZipProvider(EggProvider):
        +    """Resource support for zips and eggs"""
        +
        +    eagers: list[str] | None = None
        +    _zip_manifests = MemoizedZipManifests()
        +    # ZipProvider's loader should always be a zipimporter or equivalent
        +    loader: zipimport.zipimporter
        +
        +    def __init__(self, module: _ZipLoaderModule):
        +        super().__init__(module)
        +        self.zip_pre = self.loader.archive + os.sep
        +
        +    def _zipinfo_name(self, fspath):
        +        # Convert a virtual filename (full path to file) into a zipfile subpath
        +        # usable with the zipimport directory cache for our target archive
        +        fspath = fspath.rstrip(os.sep)
        +        if fspath == self.loader.archive:
        +            return ''
        +        if fspath.startswith(self.zip_pre):
        +            return fspath[len(self.zip_pre) :]
        +        raise AssertionError("%s is not a subpath of %s" % (fspath, self.zip_pre))
        +
        +    def _parts(self, zip_path):
        +        # Convert a zipfile subpath into an egg-relative path part list.
        +        # pseudo-fs path
        +        fspath = self.zip_pre + zip_path
        +        if fspath.startswith(self.egg_root + os.sep):
        +            return fspath[len(self.egg_root) + 1 :].split(os.sep)
        +        raise AssertionError("%s is not a subpath of %s" % (fspath, self.egg_root))
        +
        +    @property
        +    def zipinfo(self):
        +        return self._zip_manifests.load(self.loader.archive)
        +
        +    def get_resource_filename(self, manager: ResourceManager, resource_name: str):
        +        if not self.egg_name:
        +            raise NotImplementedError(
        +                "resource_filename() only supported for .egg, not .zip"
        +            )
        +        # no need to lock for extraction, since we use temp names
        +        zip_path = self._resource_to_zip(resource_name)
        +        eagers = self._get_eager_resources()
        +        if '/'.join(self._parts(zip_path)) in eagers:
        +            for name in eagers:
        +                self._extract_resource(manager, self._eager_to_zip(name))
        +        return self._extract_resource(manager, zip_path)
        +
        +    @staticmethod
        +    def _get_date_and_size(zip_stat):
        +        size = zip_stat.file_size
        +        # ymdhms+wday, yday, dst
        +        date_time = zip_stat.date_time + (0, 0, -1)
        +        # 1980 offset already done
        +        timestamp = time.mktime(date_time)
        +        return timestamp, size
        +
        +    # FIXME: 'ZipProvider._extract_resource' is too complex (12)
        +    def _extract_resource(self, manager: ResourceManager, zip_path) -> str:  # noqa: C901
        +        if zip_path in self._index():
        +            for name in self._index()[zip_path]:
        +                last = self._extract_resource(manager, os.path.join(zip_path, name))
        +            # return the extracted directory name
        +            return os.path.dirname(last)
        +
        +        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
        +
        +        if not WRITE_SUPPORT:
        +            raise OSError(
        +                '"os.rename" and "os.unlink" are not supported on this platform'
        +            )
        +        try:
        +            if not self.egg_name:
        +                raise OSError(
        +                    '"egg_name" is empty. This likely means no egg could be found from the "module_path".'
        +                )
        +            real_path = manager.get_cache_path(self.egg_name, self._parts(zip_path))
        +
        +            if self._is_current(real_path, zip_path):
        +                return real_path
        +
        +            outf, tmpnam = _mkstemp(
        +                ".$extract",
        +                dir=os.path.dirname(real_path),
        +            )
        +            os.write(outf, self.loader.get_data(zip_path))
        +            os.close(outf)
        +            utime(tmpnam, (timestamp, timestamp))
        +            manager.postprocess(tmpnam, real_path)
        +
        +            try:
        +                rename(tmpnam, real_path)
        +
        +            except OSError:
        +                if os.path.isfile(real_path):
        +                    if self._is_current(real_path, zip_path):
        +                        # the file became current since it was checked above,
        +                        #  so proceed.
        +                        return real_path
        +                    # Windows, del old file and retry
        +                    elif os.name == 'nt':
        +                        unlink(real_path)
        +                        rename(tmpnam, real_path)
        +                        return real_path
        +                raise
        +
        +        except OSError:
        +            # report a user-friendly error
        +            manager.extraction_error()
        +
        +        return real_path
        +
        +    def _is_current(self, file_path, zip_path):
        +        """
        +        Return True if the file_path is current for this zip_path
        +        """
        +        timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
        +        if not os.path.isfile(file_path):
        +            return False
        +        stat = os.stat(file_path)
        +        if stat.st_size != size or stat.st_mtime != timestamp:
        +            return False
        +        # check that the contents match
        +        zip_contents = self.loader.get_data(zip_path)
        +        with open(file_path, 'rb') as f:
        +            file_contents = f.read()
        +        return zip_contents == file_contents
        +
        +    def _get_eager_resources(self):
        +        if self.eagers is None:
        +            eagers = []
        +            for name in ('native_libs.txt', 'eager_resources.txt'):
        +                if self.has_metadata(name):
        +                    eagers.extend(self.get_metadata_lines(name))
        +            self.eagers = eagers
        +        return self.eagers
        +
        +    def _index(self):
        +        try:
        +            return self._dirindex
        +        except AttributeError:
        +            ind = {}
        +            for path in self.zipinfo:
        +                parts = path.split(os.sep)
        +                while parts:
        +                    parent = os.sep.join(parts[:-1])
        +                    if parent in ind:
        +                        ind[parent].append(parts[-1])
        +                        break
        +                    else:
        +                        ind[parent] = [parts.pop()]
        +            self._dirindex = ind
        +            return ind
        +
        +    def _has(self, fspath) -> bool:
        +        zip_path = self._zipinfo_name(fspath)
        +        return zip_path in self.zipinfo or zip_path in self._index()
        +
        +    def _isdir(self, fspath) -> bool:
        +        return self._zipinfo_name(fspath) in self._index()
        +
        +    def _listdir(self, fspath):
        +        return list(self._index().get(self._zipinfo_name(fspath), ()))
        +
        +    def _eager_to_zip(self, resource_name: str):
        +        return self._zipinfo_name(self._fn(self.egg_root, resource_name))
        +
        +    def _resource_to_zip(self, resource_name: str):
        +        return self._zipinfo_name(self._fn(self.module_path, resource_name))
        +
        +
        +register_loader_type(zipimport.zipimporter, ZipProvider)
        +
        +
        +class FileMetadata(EmptyProvider):
        +    """Metadata handler for standalone PKG-INFO files
        +
        +    Usage::
        +
        +        metadata = FileMetadata("/path/to/PKG-INFO")
        +
        +    This provider rejects all data and metadata requests except for PKG-INFO,
        +    which is treated as existing, and will be the contents of the file at
        +    the provided location.
        +    """
        +
        +    def __init__(self, path: StrPath):
        +        self.path = path
        +
        +    def _get_metadata_path(self, name):
        +        return self.path
        +
        +    def has_metadata(self, name: str) -> bool:
        +        return name == 'PKG-INFO' and os.path.isfile(self.path)
        +
        +    def get_metadata(self, name: str):
        +        if name != 'PKG-INFO':
        +            raise KeyError("No metadata except PKG-INFO is available")
        +
        +        with open(self.path, encoding='utf-8', errors="replace") as f:
        +            metadata = f.read()
        +        self._warn_on_replacement(metadata)
        +        return metadata
        +
        +    def _warn_on_replacement(self, metadata):
        +        replacement_char = '�'
        +        if replacement_char in metadata:
        +            tmpl = "{self.path} could not be properly decoded in UTF-8"
        +            msg = tmpl.format(**locals())
        +            warnings.warn(msg)
        +
        +    def get_metadata_lines(self, name: str) -> Iterator[str]:
        +        return yield_lines(self.get_metadata(name))
        +
        +
        +class PathMetadata(DefaultProvider):
        +    """Metadata provider for egg directories
        +
        +    Usage::
        +
        +        # Development eggs:
        +
        +        egg_info = "/path/to/PackageName.egg-info"
        +        base_dir = os.path.dirname(egg_info)
        +        metadata = PathMetadata(base_dir, egg_info)
        +        dist_name = os.path.splitext(os.path.basename(egg_info))[0]
        +        dist = Distribution(basedir, project_name=dist_name, metadata=metadata)
        +
        +        # Unpacked egg directories:
        +
        +        egg_path = "/path/to/PackageName-ver-pyver-etc.egg"
        +        metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO'))
        +        dist = Distribution.from_filename(egg_path, metadata=metadata)
        +    """
        +
        +    def __init__(self, path: str, egg_info: str):
        +        self.module_path = path
        +        self.egg_info = egg_info
        +
        +
        +class EggMetadata(ZipProvider):
        +    """Metadata provider for .egg files"""
        +
        +    def __init__(self, importer: zipimport.zipimporter):
        +        """Create a metadata provider from a zipimporter"""
        +
        +        self.zip_pre = importer.archive + os.sep
        +        self.loader = importer
        +        if importer.prefix:
        +            self.module_path = os.path.join(importer.archive, importer.prefix)
        +        else:
        +            self.module_path = importer.archive
        +        self._setup_prefix()
        +
        +
        +_distribution_finders: dict[type, _DistFinderType[Any]] = _declare_state(
        +    'dict', '_distribution_finders', {}
        +)
        +
        +
        +def register_finder(importer_type: type[_T], distribution_finder: _DistFinderType[_T]):
        +    """Register `distribution_finder` to find distributions in sys.path items
        +
        +    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
        +    handler), and `distribution_finder` is a callable that, passed a path
        +    item and the importer instance, yields ``Distribution`` instances found on
        +    that path item.  See ``pkg_resources.find_on_path`` for an example."""
        +    _distribution_finders[importer_type] = distribution_finder
        +
        +
        +def find_distributions(path_item: str, only: bool = False):
        +    """Yield distributions accessible via `path_item`"""
        +    importer = get_importer(path_item)
        +    finder = _find_adapter(_distribution_finders, importer)
        +    return finder(importer, path_item, only)
        +
        +
        +def find_eggs_in_zip(
        +    importer: zipimport.zipimporter, path_item: str, only: bool = False
        +) -> Iterator[Distribution]:
        +    """
        +    Find eggs in zip files; possibly multiple nested eggs.
        +    """
        +    if importer.archive.endswith('.whl'):
        +        # wheels are not supported with this finder
        +        # they don't have PKG-INFO metadata, and won't ever contain eggs
        +        return
        +    metadata = EggMetadata(importer)
        +    if metadata.has_metadata('PKG-INFO'):
        +        yield Distribution.from_filename(path_item, metadata=metadata)
        +    if only:
        +        # don't yield nested distros
        +        return
        +    for subitem in metadata.resource_listdir(''):
        +        if _is_egg_path(subitem):
        +            subpath = os.path.join(path_item, subitem)
        +            dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath)
        +            yield from dists
        +        elif subitem.lower().endswith(('.dist-info', '.egg-info')):
        +            subpath = os.path.join(path_item, subitem)
        +            submeta = EggMetadata(zipimport.zipimporter(subpath))
        +            submeta.egg_info = subpath
        +            yield Distribution.from_location(path_item, subitem, submeta)
        +
        +
        +register_finder(zipimport.zipimporter, find_eggs_in_zip)
        +
        +
        +def find_nothing(
        +    importer: object | None, path_item: str | None, only: bool | None = False
        +):
        +    return ()
        +
        +
        +register_finder(object, find_nothing)
        +
        +
        +def find_on_path(importer: object | None, path_item, only=False):
        +    """Yield distributions accessible on a sys.path directory"""
        +    path_item = _normalize_cached(path_item)
        +
        +    if _is_unpacked_egg(path_item):
        +        yield Distribution.from_filename(
        +            path_item,
        +            metadata=PathMetadata(path_item, os.path.join(path_item, 'EGG-INFO')),
        +        )
        +        return
        +
        +    entries = (os.path.join(path_item, child) for child in safe_listdir(path_item))
        +
        +    # scan for .egg and .egg-info in directory
        +    for entry in sorted(entries):
        +        fullpath = os.path.join(path_item, entry)
        +        factory = dist_factory(path_item, entry, only)
        +        yield from factory(fullpath)
        +
        +
        +def dist_factory(path_item, entry, only):
        +    """Return a dist_factory for the given entry."""
        +    lower = entry.lower()
        +    is_egg_info = lower.endswith('.egg-info')
        +    is_dist_info = lower.endswith('.dist-info') and os.path.isdir(
        +        os.path.join(path_item, entry)
        +    )
        +    is_meta = is_egg_info or is_dist_info
        +    return (
        +        distributions_from_metadata
        +        if is_meta
        +        else find_distributions
        +        if not only and _is_egg_path(entry)
        +        else resolve_egg_link
        +        if not only and lower.endswith('.egg-link')
        +        else NoDists()
        +    )
        +
        +
        +class NoDists:
        +    """
        +    >>> bool(NoDists())
        +    False
        +
        +    >>> list(NoDists()('anything'))
        +    []
        +    """
        +
        +    def __bool__(self):
        +        return False
        +
        +    def __call__(self, fullpath):
        +        return iter(())
        +
        +
        +def safe_listdir(path: StrOrBytesPath):
        +    """
        +    Attempt to list contents of path, but suppress some exceptions.
        +    """
        +    try:
        +        return os.listdir(path)
        +    except (PermissionError, NotADirectoryError):
        +        pass
        +    except OSError as e:
        +        # Ignore the directory if does not exist, not a directory or
        +        # permission denied
        +        if e.errno not in (errno.ENOTDIR, errno.EACCES, errno.ENOENT):
        +            raise
        +    return ()
        +
        +
        +def distributions_from_metadata(path: str):
        +    root = os.path.dirname(path)
        +    if os.path.isdir(path):
        +        if len(os.listdir(path)) == 0:
        +            # empty metadata dir; skip
        +            return
        +        metadata: _MetadataType = PathMetadata(root, path)
        +    else:
        +        metadata = FileMetadata(path)
        +    entry = os.path.basename(path)
        +    yield Distribution.from_location(
        +        root,
        +        entry,
        +        metadata,
        +        precedence=DEVELOP_DIST,
        +    )
        +
        +
        +def non_empty_lines(path):
        +    """
        +    Yield non-empty lines from file at path
        +    """
        +    for line in _read_utf8_with_fallback(path).splitlines():
        +        line = line.strip()
        +        if line:
        +            yield line
        +
        +
        +def resolve_egg_link(path):
        +    """
        +    Given a path to an .egg-link, resolve distributions
        +    present in the referenced path.
        +    """
        +    referenced_paths = non_empty_lines(path)
        +    resolved_paths = (
        +        os.path.join(os.path.dirname(path), ref) for ref in referenced_paths
        +    )
        +    dist_groups = map(find_distributions, resolved_paths)
        +    return next(dist_groups, ())
        +
        +
        +if hasattr(pkgutil, 'ImpImporter'):
        +    register_finder(pkgutil.ImpImporter, find_on_path)
        +
        +register_finder(importlib.machinery.FileFinder, find_on_path)
        +
        +_namespace_handlers: dict[type, _NSHandlerType[Any]] = _declare_state(
        +    'dict', '_namespace_handlers', {}
        +)
        +_namespace_packages: dict[str | None, list[str]] = _declare_state(
        +    'dict', '_namespace_packages', {}
        +)
        +
        +
        +def register_namespace_handler(
        +    importer_type: type[_T], namespace_handler: _NSHandlerType[_T]
        +):
        +    """Register `namespace_handler` to declare namespace packages
        +
        +    `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
        +    handler), and `namespace_handler` is a callable like this::
        +
        +        def namespace_handler(importer, path_entry, moduleName, module):
        +            # return a path_entry to use for child packages
        +
        +    Namespace handlers are only called if the importer object has already
        +    agreed that it can handle the relevant path item, and they should only
        +    return a subpath if the module __path__ does not already contain an
        +    equivalent subpath.  For an example namespace handler, see
        +    ``pkg_resources.file_ns_handler``.
        +    """
        +    _namespace_handlers[importer_type] = namespace_handler
        +
        +
        +def _handle_ns(packageName, path_item):
        +    """Ensure that named package includes a subpath of path_item (if needed)"""
        +
        +    importer = get_importer(path_item)
        +    if importer is None:
        +        return None
        +
        +    # use find_spec (PEP 451) and fall-back to find_module (PEP 302)
        +    try:
        +        spec = importer.find_spec(packageName)
        +    except AttributeError:
        +        # capture warnings due to #1111
        +        with warnings.catch_warnings():
        +            warnings.simplefilter("ignore")
        +            loader = importer.find_module(packageName)
        +    else:
        +        loader = spec.loader if spec else None
        +
        +    if loader is None:
        +        return None
        +    module = sys.modules.get(packageName)
        +    if module is None:
        +        module = sys.modules[packageName] = types.ModuleType(packageName)
        +        module.__path__ = []
        +        _set_parent_ns(packageName)
        +    elif not hasattr(module, '__path__'):
        +        raise TypeError("Not a package:", packageName)
        +    handler = _find_adapter(_namespace_handlers, importer)
        +    subpath = handler(importer, path_item, packageName, module)
        +    if subpath is not None:
        +        path = module.__path__
        +        path.append(subpath)
        +        importlib.import_module(packageName)
        +        _rebuild_mod_path(path, packageName, module)
        +    return subpath
        +
        +
        +def _rebuild_mod_path(orig_path, package_name, module: types.ModuleType):
        +    """
        +    Rebuild module.__path__ ensuring that all entries are ordered
        +    corresponding to their sys.path order
        +    """
        +    sys_path = [_normalize_cached(p) for p in sys.path]
        +
        +    def safe_sys_path_index(entry):
        +        """
        +        Workaround for #520 and #513.
        +        """
        +        try:
        +            return sys_path.index(entry)
        +        except ValueError:
        +            return float('inf')
        +
        +    def position_in_sys_path(path):
        +        """
        +        Return the ordinal of the path based on its position in sys.path
        +        """
        +        path_parts = path.split(os.sep)
        +        module_parts = package_name.count('.') + 1
        +        parts = path_parts[:-module_parts]
        +        return safe_sys_path_index(_normalize_cached(os.sep.join(parts)))
        +
        +    new_path = sorted(orig_path, key=position_in_sys_path)
        +    new_path = [_normalize_cached(p) for p in new_path]
        +
        +    if isinstance(module.__path__, list):
        +        module.__path__[:] = new_path
        +    else:
        +        module.__path__ = new_path
        +
        +
        +def declare_namespace(packageName: str):
        +    """Declare that package 'packageName' is a namespace package"""
        +
        +    msg = (
        +        f"Deprecated call to `pkg_resources.declare_namespace({packageName!r})`.\n"
        +        "Implementing implicit namespace packages (as specified in PEP 420) "
        +        "is preferred to `pkg_resources.declare_namespace`. "
        +        "See https://setuptools.pypa.io/en/latest/references/"
        +        "keywords.html#keyword-namespace-packages"
        +    )
        +    warnings.warn(msg, DeprecationWarning, stacklevel=2)
        +
        +    _imp.acquire_lock()
        +    try:
        +        if packageName in _namespace_packages:
        +            return
        +
        +        path: MutableSequence[str] = sys.path
        +        parent, _, _ = packageName.rpartition('.')
        +
        +        if parent:
        +            declare_namespace(parent)
        +            if parent not in _namespace_packages:
        +                __import__(parent)
        +            try:
        +                path = sys.modules[parent].__path__
        +            except AttributeError as e:
        +                raise TypeError("Not a package:", parent) from e
        +
        +        # Track what packages are namespaces, so when new path items are added,
        +        # they can be updated
        +        _namespace_packages.setdefault(parent or None, []).append(packageName)
        +        _namespace_packages.setdefault(packageName, [])
        +
        +        for path_item in path:
        +            # Ensure all the parent's path items are reflected in the child,
        +            # if they apply
        +            _handle_ns(packageName, path_item)
        +
        +    finally:
        +        _imp.release_lock()
        +
        +
        +def fixup_namespace_packages(path_item: str, parent: str | None = None):
        +    """Ensure that previously-declared namespace packages include path_item"""
        +    _imp.acquire_lock()
        +    try:
        +        for package in _namespace_packages.get(parent, ()):
        +            subpath = _handle_ns(package, path_item)
        +            if subpath:
        +                fixup_namespace_packages(subpath, package)
        +    finally:
        +        _imp.release_lock()
        +
        +
        +def file_ns_handler(
        +    importer: object,
        +    path_item: StrPath,
        +    packageName: str,
        +    module: types.ModuleType,
        +):
        +    """Compute an ns-package subpath for a filesystem or zipfile importer"""
        +
        +    subpath = os.path.join(path_item, packageName.split('.')[-1])
        +    normalized = _normalize_cached(subpath)
        +    for item in module.__path__:
        +        if _normalize_cached(item) == normalized:
        +            break
        +    else:
        +        # Only return the path if it's not already there
        +        return subpath
        +
        +
        +if hasattr(pkgutil, 'ImpImporter'):
        +    register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)
        +
        +register_namespace_handler(zipimport.zipimporter, file_ns_handler)
        +register_namespace_handler(importlib.machinery.FileFinder, file_ns_handler)
        +
        +
        +def null_ns_handler(
        +    importer: object,
        +    path_item: str | None,
        +    packageName: str | None,
        +    module: _ModuleLike | None,
        +):
        +    return None
        +
        +
        +register_namespace_handler(object, null_ns_handler)
        +
        +
        +@overload
        +def normalize_path(filename: StrPath) -> str: ...
        +@overload
        +def normalize_path(filename: BytesPath) -> bytes: ...
        +def normalize_path(filename: StrOrBytesPath):
        +    """Normalize a file/dir name for comparison purposes"""
        +    return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename))))
        +
        +
        +def _cygwin_patch(filename: StrOrBytesPath):  # pragma: nocover
        +    """
        +    Contrary to POSIX 2008, on Cygwin, getcwd (3) contains
        +    symlink components. Using
        +    os.path.abspath() works around this limitation. A fix in os.getcwd()
        +    would probably better, in Cygwin even more so, except
        +    that this seems to be by design...
        +    """
        +    return os.path.abspath(filename) if sys.platform == 'cygwin' else filename
        +
        +
        +if TYPE_CHECKING:
        +    # https://github.com/python/mypy/issues/16261
        +    # https://github.com/python/typeshed/issues/6347
        +    @overload
        +    def _normalize_cached(filename: StrPath) -> str: ...
        +    @overload
        +    def _normalize_cached(filename: BytesPath) -> bytes: ...
        +    def _normalize_cached(filename: StrOrBytesPath) -> str | bytes: ...
        +else:
        +
        +    @functools.lru_cache(maxsize=None)
        +    def _normalize_cached(filename):
        +        return normalize_path(filename)
        +
        +
        +def _is_egg_path(path):
        +    """
        +    Determine if given path appears to be an egg.
        +    """
        +    return _is_zip_egg(path) or _is_unpacked_egg(path)
        +
        +
        +def _is_zip_egg(path):
        +    return (
        +        path.lower().endswith('.egg')
        +        and os.path.isfile(path)
        +        and zipfile.is_zipfile(path)
        +    )
        +
        +
        +def _is_unpacked_egg(path):
        +    """
        +    Determine if given path appears to be an unpacked egg.
        +    """
        +    return path.lower().endswith('.egg') and os.path.isfile(
        +        os.path.join(path, 'EGG-INFO', 'PKG-INFO')
        +    )
        +
        +
        +def _set_parent_ns(packageName):
        +    parts = packageName.split('.')
        +    name = parts.pop()
        +    if parts:
        +        parent = '.'.join(parts)
        +        setattr(sys.modules[parent], name, sys.modules[packageName])
        +
        +
        +MODULE = re.compile(r"\w+(\.\w+)*$").match
        +EGG_NAME = re.compile(
        +    r"""
        +    (?P[^-]+) (
        +        -(?P[^-]+) (
        +            -py(?P[^-]+) (
        +                -(?P.+)
        +            )?
        +        )?
        +    )?
        +    """,
        +    re.VERBOSE | re.IGNORECASE,
        +).match
        +
        +
        +class EntryPoint:
        +    """Object representing an advertised importable object"""
        +
        +    def __init__(
        +        self,
        +        name: str,
        +        module_name: str,
        +        attrs: Iterable[str] = (),
        +        extras: Iterable[str] = (),
        +        dist: Distribution | None = None,
        +    ):
        +        if not MODULE(module_name):
        +            raise ValueError("Invalid module name", module_name)
        +        self.name = name
        +        self.module_name = module_name
        +        self.attrs = tuple(attrs)
        +        self.extras = tuple(extras)
        +        self.dist = dist
        +
        +    def __str__(self):
        +        s = "%s = %s" % (self.name, self.module_name)
        +        if self.attrs:
        +            s += ':' + '.'.join(self.attrs)
        +        if self.extras:
        +            s += ' [%s]' % ','.join(self.extras)
        +        return s
        +
        +    def __repr__(self):
        +        return "EntryPoint.parse(%r)" % str(self)
        +
        +    @overload
        +    def load(
        +        self,
        +        require: Literal[True] = True,
        +        env: Environment | None = None,
        +        installer: _InstallerType | None = None,
        +    ) -> _ResolvedEntryPoint: ...
        +    @overload
        +    def load(
        +        self,
        +        require: Literal[False],
        +        *args: Any,
        +        **kwargs: Any,
        +    ) -> _ResolvedEntryPoint: ...
        +    def load(
        +        self,
        +        require: bool = True,
        +        *args: Environment | _InstallerType | None,
        +        **kwargs: Environment | _InstallerType | None,
        +    ) -> _ResolvedEntryPoint:
        +        """
        +        Require packages for this EntryPoint, then resolve it.
        +        """
        +        if not require or args or kwargs:
        +            warnings.warn(
        +                "Parameters to load are deprecated.  Call .resolve and "
        +                ".require separately.",
        +                PkgResourcesDeprecationWarning,
        +                stacklevel=2,
        +            )
        +        if require:
        +            # We could pass `env` and `installer` directly,
        +            # but keeping `*args` and `**kwargs` for backwards compatibility
        +            self.require(*args, **kwargs)  # type: ignore
        +        return self.resolve()
        +
        +    def resolve(self) -> _ResolvedEntryPoint:
        +        """
        +        Resolve the entry point from its module and attrs.
        +        """
        +        module = __import__(self.module_name, fromlist=['__name__'], level=0)
        +        try:
        +            return functools.reduce(getattr, self.attrs, module)
        +        except AttributeError as exc:
        +            raise ImportError(str(exc)) from exc
        +
        +    def require(
        +        self,
        +        env: Environment | None = None,
        +        installer: _InstallerType | None = None,
        +    ):
        +        if not self.dist:
        +            error_cls = UnknownExtra if self.extras else AttributeError
        +            raise error_cls("Can't require() without a distribution", self)
        +
        +        # Get the requirements for this entry point with all its extras and
        +        # then resolve them. We have to pass `extras` along when resolving so
        +        # that the working set knows what extras we want. Otherwise, for
        +        # dist-info distributions, the working set will assume that the
        +        # requirements for that extra are purely optional and skip over them.
        +        reqs = self.dist.requires(self.extras)
        +        items = working_set.resolve(reqs, env, installer, extras=self.extras)
        +        list(map(working_set.add, items))
        +
        +    pattern = re.compile(
        +        r'\s*'
        +        r'(?P.+?)\s*'
        +        r'=\s*'
        +        r'(?P[\w.]+)\s*'
        +        r'(:\s*(?P[\w.]+))?\s*'
        +        r'(?P\[.*\])?\s*$'
        +    )
        +
        +    @classmethod
        +    def parse(cls, src: str, dist: Distribution | None = None):
        +        """Parse a single entry point from string `src`
        +
        +        Entry point syntax follows the form::
        +
        +            name = some.module:some.attr [extra1, extra2]
        +
        +        The entry name and module name are required, but the ``:attrs`` and
        +        ``[extras]`` parts are optional
        +        """
        +        m = cls.pattern.match(src)
        +        if not m:
        +            msg = "EntryPoint must be in 'name=module:attrs [extras]' format"
        +            raise ValueError(msg, src)
        +        res = m.groupdict()
        +        extras = cls._parse_extras(res['extras'])
        +        attrs = res['attr'].split('.') if res['attr'] else ()
        +        return cls(res['name'], res['module'], attrs, extras, dist)
        +
        +    @classmethod
        +    def _parse_extras(cls, extras_spec):
        +        if not extras_spec:
        +            return ()
        +        req = Requirement.parse('x' + extras_spec)
        +        if req.specs:
        +            raise ValueError
        +        return req.extras
        +
        +    @classmethod
        +    def parse_group(
        +        cls,
        +        group: str,
        +        lines: _NestedStr,
        +        dist: Distribution | None = None,
        +    ):
        +        """Parse an entry point group"""
        +        if not MODULE(group):
        +            raise ValueError("Invalid group name", group)
        +        this: dict[str, Self] = {}
        +        for line in yield_lines(lines):
        +            ep = cls.parse(line, dist)
        +            if ep.name in this:
        +                raise ValueError("Duplicate entry point", group, ep.name)
        +            this[ep.name] = ep
        +        return this
        +
        +    @classmethod
        +    def parse_map(
        +        cls,
        +        data: str | Iterable[str] | dict[str, str | Iterable[str]],
        +        dist: Distribution | None = None,
        +    ):
        +        """Parse a map of entry point groups"""
        +        _data: Iterable[tuple[str | None, str | Iterable[str]]]
        +        if isinstance(data, dict):
        +            _data = data.items()
        +        else:
        +            _data = split_sections(data)
        +        maps: dict[str, dict[str, Self]] = {}
        +        for group, lines in _data:
        +            if group is None:
        +                if not lines:
        +                    continue
        +                raise ValueError("Entry points must be listed in groups")
        +            group = group.strip()
        +            if group in maps:
        +                raise ValueError("Duplicate group name", group)
        +            maps[group] = cls.parse_group(group, lines, dist)
        +        return maps
        +
        +
        +def _version_from_file(lines):
        +    """
        +    Given an iterable of lines from a Metadata file, return
        +    the value of the Version field, if present, or None otherwise.
        +    """
        +
        +    def is_version_line(line):
        +        return line.lower().startswith('version:')
        +
        +    version_lines = filter(is_version_line, lines)
        +    line = next(iter(version_lines), '')
        +    _, _, value = line.partition(':')
        +    return safe_version(value.strip()) or None
        +
        +
        +class Distribution:
        +    """Wrap an actual or potential sys.path entry w/metadata"""
        +
        +    PKG_INFO = 'PKG-INFO'
        +
        +    def __init__(
        +        self,
        +        location: str | None = None,
        +        metadata: _MetadataType = None,
        +        project_name: str | None = None,
        +        version: str | None = None,
        +        py_version: str | None = PY_MAJOR,
        +        platform: str | None = None,
        +        precedence: int = EGG_DIST,
        +    ):
        +        self.project_name = safe_name(project_name or 'Unknown')
        +        if version is not None:
        +            self._version = safe_version(version)
        +        self.py_version = py_version
        +        self.platform = platform
        +        self.location = location
        +        self.precedence = precedence
        +        self._provider = metadata or empty_provider
        +
        +    @classmethod
        +    def from_location(
        +        cls,
        +        location: str,
        +        basename: StrPath,
        +        metadata: _MetadataType = None,
        +        **kw: int,  # We could set `precedence` explicitly, but keeping this as `**kw` for full backwards and subclassing compatibility
        +    ) -> Distribution:
        +        project_name, version, py_version, platform = [None] * 4
        +        basename, ext = os.path.splitext(basename)
        +        if ext.lower() in _distributionImpl:
        +            cls = _distributionImpl[ext.lower()]
        +
        +            match = EGG_NAME(basename)
        +            if match:
        +                project_name, version, py_version, platform = match.group(
        +                    'name', 'ver', 'pyver', 'plat'
        +                )
        +        return cls(
        +            location,
        +            metadata,
        +            project_name=project_name,
        +            version=version,
        +            py_version=py_version,
        +            platform=platform,
        +            **kw,
        +        )._reload_version()
        +
        +    def _reload_version(self):
        +        return self
        +
        +    @property
        +    def hashcmp(self):
        +        return (
        +            self._forgiving_parsed_version,
        +            self.precedence,
        +            self.key,
        +            self.location,
        +            self.py_version or '',
        +            self.platform or '',
        +        )
        +
        +    def __hash__(self):
        +        return hash(self.hashcmp)
        +
        +    def __lt__(self, other: Distribution):
        +        return self.hashcmp < other.hashcmp
        +
        +    def __le__(self, other: Distribution):
        +        return self.hashcmp <= other.hashcmp
        +
        +    def __gt__(self, other: Distribution):
        +        return self.hashcmp > other.hashcmp
        +
        +    def __ge__(self, other: Distribution):
        +        return self.hashcmp >= other.hashcmp
        +
        +    def __eq__(self, other: object):
        +        if not isinstance(other, self.__class__):
        +            # It's not a Distribution, so they are not equal
        +            return False
        +        return self.hashcmp == other.hashcmp
        +
        +    def __ne__(self, other: object):
        +        return not self == other
        +
        +    # These properties have to be lazy so that we don't have to load any
        +    # metadata until/unless it's actually needed.  (i.e., some distributions
        +    # may not know their name or version without loading PKG-INFO)
        +
        +    @property
        +    def key(self):
        +        try:
        +            return self._key
        +        except AttributeError:
        +            self._key = key = self.project_name.lower()
        +            return key
        +
        +    @property
        +    def parsed_version(self):
        +        if not hasattr(self, "_parsed_version"):
        +            try:
        +                self._parsed_version = parse_version(self.version)
        +            except _packaging_version.InvalidVersion as ex:
        +                info = f"(package: {self.project_name})"
        +                if hasattr(ex, "add_note"):
        +                    ex.add_note(info)  # PEP 678
        +                    raise
        +                raise _packaging_version.InvalidVersion(f"{str(ex)} {info}") from None
        +
        +        return self._parsed_version
        +
        +    @property
        +    def _forgiving_parsed_version(self):
        +        try:
        +            return self.parsed_version
        +        except _packaging_version.InvalidVersion as ex:
        +            self._parsed_version = parse_version(_forgiving_version(self.version))
        +
        +            notes = "\n".join(getattr(ex, "__notes__", []))  # PEP 678
        +            msg = f"""!!\n\n
        +            *************************************************************************
        +            {str(ex)}\n{notes}
        +
        +            This is a long overdue deprecation.
        +            For the time being, `pkg_resources` will use `{self._parsed_version}`
        +            as a replacement to avoid breaking existing environments,
        +            but no future compatibility is guaranteed.
        +
        +            If you maintain package {self.project_name} you should implement
        +            the relevant changes to adequate the project to PEP 440 immediately.
        +            *************************************************************************
        +            \n\n!!
        +            """
        +            warnings.warn(msg, DeprecationWarning)
        +
        +            return self._parsed_version
        +
        +    @property
        +    def version(self):
        +        try:
        +            return self._version
        +        except AttributeError as e:
        +            version = self._get_version()
        +            if version is None:
        +                path = self._get_metadata_path_for_display(self.PKG_INFO)
        +                msg = ("Missing 'Version:' header and/or {} file at path: {}").format(
        +                    self.PKG_INFO, path
        +                )
        +                raise ValueError(msg, self) from e
        +
        +            return version
        +
        +    @property
        +    def _dep_map(self):
        +        """
        +        A map of extra to its list of (direct) requirements
        +        for this distribution, including the null extra.
        +        """
        +        try:
        +            return self.__dep_map
        +        except AttributeError:
        +            self.__dep_map = self._filter_extras(self._build_dep_map())
        +        return self.__dep_map
        +
        +    @staticmethod
        +    def _filter_extras(dm: dict[str | None, list[Requirement]]):
        +        """
        +        Given a mapping of extras to dependencies, strip off
        +        environment markers and filter out any dependencies
        +        not matching the markers.
        +        """
        +        for extra in list(filter(None, dm)):
        +            new_extra: str | None = extra
        +            reqs = dm.pop(extra)
        +            new_extra, _, marker = extra.partition(':')
        +            fails_marker = marker and (
        +                invalid_marker(marker) or not evaluate_marker(marker)
        +            )
        +            if fails_marker:
        +                reqs = []
        +            new_extra = safe_extra(new_extra) or None
        +
        +            dm.setdefault(new_extra, []).extend(reqs)
        +        return dm
        +
        +    def _build_dep_map(self):
        +        dm = {}
        +        for name in 'requires.txt', 'depends.txt':
        +            for extra, reqs in split_sections(self._get_metadata(name)):
        +                dm.setdefault(extra, []).extend(parse_requirements(reqs))
        +        return dm
        +
        +    def requires(self, extras: Iterable[str] = ()):
        +        """List of Requirements needed for this distro if `extras` are used"""
        +        dm = self._dep_map
        +        deps: list[Requirement] = []
        +        deps.extend(dm.get(None, ()))
        +        for ext in extras:
        +            try:
        +                deps.extend(dm[safe_extra(ext)])
        +            except KeyError as e:
        +                raise UnknownExtra(
        +                    "%s has no such extra feature %r" % (self, ext)
        +                ) from e
        +        return deps
        +
        +    def _get_metadata_path_for_display(self, name):
        +        """
        +        Return the path to the given metadata file, if available.
        +        """
        +        try:
        +            # We need to access _get_metadata_path() on the provider object
        +            # directly rather than through this class's __getattr__()
        +            # since _get_metadata_path() is marked private.
        +            path = self._provider._get_metadata_path(name)
        +
        +        # Handle exceptions e.g. in case the distribution's metadata
        +        # provider doesn't support _get_metadata_path().
        +        except Exception:
        +            return '[could not detect]'
        +
        +        return path
        +
        +    def _get_metadata(self, name):
        +        if self.has_metadata(name):
        +            yield from self.get_metadata_lines(name)
        +
        +    def _get_version(self):
        +        lines = self._get_metadata(self.PKG_INFO)
        +        return _version_from_file(lines)
        +
        +    def activate(self, path: list[str] | None = None, replace: bool = False):
        +        """Ensure distribution is importable on `path` (default=sys.path)"""
        +        if path is None:
        +            path = sys.path
        +        self.insert_on(path, replace=replace)
        +        if path is sys.path and self.location is not None:
        +            fixup_namespace_packages(self.location)
        +            for pkg in self._get_metadata('namespace_packages.txt'):
        +                if pkg in sys.modules:
        +                    declare_namespace(pkg)
        +
        +    def egg_name(self):
        +        """Return what this distribution's standard .egg filename should be"""
        +        filename = "%s-%s-py%s" % (
        +            to_filename(self.project_name),
        +            to_filename(self.version),
        +            self.py_version or PY_MAJOR,
        +        )
        +
        +        if self.platform:
        +            filename += '-' + self.platform
        +        return filename
        +
        +    def __repr__(self):
        +        if self.location:
        +            return "%s (%s)" % (self, self.location)
        +        else:
        +            return str(self)
        +
        +    def __str__(self):
        +        try:
        +            version = getattr(self, 'version', None)
        +        except ValueError:
        +            version = None
        +        version = version or "[unknown version]"
        +        return "%s %s" % (self.project_name, version)
        +
        +    def __getattr__(self, attr):
        +        """Delegate all unrecognized public attributes to .metadata provider"""
        +        if attr.startswith('_'):
        +            raise AttributeError(attr)
        +        return getattr(self._provider, attr)
        +
        +    def __dir__(self):
        +        return list(
        +            set(super().__dir__())
        +            | set(attr for attr in self._provider.__dir__() if not attr.startswith('_'))
        +        )
        +
        +    @classmethod
        +    def from_filename(
        +        cls,
        +        filename: StrPath,
        +        metadata: _MetadataType = None,
        +        **kw: int,  # We could set `precedence` explicitly, but keeping this as `**kw` for full backwards and subclassing compatibility
        +    ):
        +        return cls.from_location(
        +            _normalize_cached(filename), os.path.basename(filename), metadata, **kw
        +        )
        +
        +    def as_requirement(self):
        +        """Return a ``Requirement`` that matches this distribution exactly"""
        +        if isinstance(self.parsed_version, _packaging_version.Version):
        +            spec = "%s==%s" % (self.project_name, self.parsed_version)
        +        else:
        +            spec = "%s===%s" % (self.project_name, self.parsed_version)
        +
        +        return Requirement.parse(spec)
        +
        +    def load_entry_point(self, group: str, name: str) -> _ResolvedEntryPoint:
        +        """Return the `name` entry point of `group` or raise ImportError"""
        +        ep = self.get_entry_info(group, name)
        +        if ep is None:
        +            raise ImportError("Entry point %r not found" % ((group, name),))
        +        return ep.load()
        +
        +    @overload
        +    def get_entry_map(self, group: None = None) -> dict[str, dict[str, EntryPoint]]: ...
        +    @overload
        +    def get_entry_map(self, group: str) -> dict[str, EntryPoint]: ...
        +    def get_entry_map(self, group: str | None = None):
        +        """Return the entry point map for `group`, or the full entry map"""
        +        if not hasattr(self, "_ep_map"):
        +            self._ep_map = EntryPoint.parse_map(
        +                self._get_metadata('entry_points.txt'), self
        +            )
        +        if group is not None:
        +            return self._ep_map.get(group, {})
        +        return self._ep_map
        +
        +    def get_entry_info(self, group: str, name: str):
        +        """Return the EntryPoint object for `group`+`name`, or ``None``"""
        +        return self.get_entry_map(group).get(name)
        +
        +    # FIXME: 'Distribution.insert_on' is too complex (13)
        +    def insert_on(  # noqa: C901
        +        self,
        +        path: list[str],
        +        loc=None,
        +        replace: bool = False,
        +    ):
        +        """Ensure self.location is on path
        +
        +        If replace=False (default):
        +            - If location is already in path anywhere, do nothing.
        +            - Else:
        +              - If it's an egg and its parent directory is on path,
        +                insert just ahead of the parent.
        +              - Else: add to the end of path.
        +        If replace=True:
        +            - If location is already on path anywhere (not eggs)
        +              or higher priority than its parent (eggs)
        +              do nothing.
        +            - Else:
        +              - If it's an egg and its parent directory is on path,
        +                insert just ahead of the parent,
        +                removing any lower-priority entries.
        +              - Else: add it to the front of path.
        +        """
        +
        +        loc = loc or self.location
        +        if not loc:
        +            return
        +
        +        nloc = _normalize_cached(loc)
        +        bdir = os.path.dirname(nloc)
        +        npath = [(p and _normalize_cached(p) or p) for p in path]
        +
        +        for p, item in enumerate(npath):
        +            if item == nloc:
        +                if replace:
        +                    break
        +                else:
        +                    # don't modify path (even removing duplicates) if
        +                    # found and not replace
        +                    return
        +            elif item == bdir and self.precedence == EGG_DIST:
        +                # if it's an .egg, give it precedence over its directory
        +                # UNLESS it's already been added to sys.path and replace=False
        +                if (not replace) and nloc in npath[p:]:
        +                    return
        +                if path is sys.path:
        +                    self.check_version_conflict()
        +                path.insert(p, loc)
        +                npath.insert(p, nloc)
        +                break
        +        else:
        +            if path is sys.path:
        +                self.check_version_conflict()
        +            if replace:
        +                path.insert(0, loc)
        +            else:
        +                path.append(loc)
        +            return
        +
        +        # p is the spot where we found or inserted loc; now remove duplicates
        +        while True:
        +            try:
        +                np = npath.index(nloc, p + 1)
        +            except ValueError:
        +                break
        +            else:
        +                del npath[np], path[np]
        +                # ha!
        +                p = np
        +
        +        return
        +
        +    def check_version_conflict(self):
        +        if self.key == 'setuptools':
        +            # ignore the inevitable setuptools self-conflicts  :(
        +            return
        +
        +        nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
        +        loc = normalize_path(self.location)
        +        for modname in self._get_metadata('top_level.txt'):
        +            if (
        +                modname not in sys.modules
        +                or modname in nsp
        +                or modname in _namespace_packages
        +            ):
        +                continue
        +            if modname in ('pkg_resources', 'setuptools', 'site'):
        +                continue
        +            fn = getattr(sys.modules[modname], '__file__', None)
        +            if fn and (
        +                normalize_path(fn).startswith(loc) or fn.startswith(self.location)
        +            ):
        +                continue
        +            issue_warning(
        +                "Module %s was already imported from %s, but %s is being added"
        +                " to sys.path" % (modname, fn, self.location),
        +            )
        +
        +    def has_version(self):
        +        try:
        +            self.version
        +        except ValueError:
        +            issue_warning("Unbuilt egg for " + repr(self))
        +            return False
        +        except SystemError:
        +            # TODO: remove this except clause when python/cpython#103632 is fixed.
        +            return False
        +        return True
        +
        +    def clone(self, **kw: str | int | IResourceProvider | None):
        +        """Copy this distribution, substituting in any changed keyword args"""
        +        names = 'project_name version py_version platform location precedence'
        +        for attr in names.split():
        +            kw.setdefault(attr, getattr(self, attr, None))
        +        kw.setdefault('metadata', self._provider)
        +        # Unsafely unpacking. But keeping **kw for backwards and subclassing compatibility
        +        return self.__class__(**kw)  # type:ignore[arg-type]
        +
        +    @property
        +    def extras(self):
        +        return [dep for dep in self._dep_map if dep]
        +
        +
        +class EggInfoDistribution(Distribution):
        +    def _reload_version(self):
        +        """
        +        Packages installed by distutils (e.g. numpy or scipy),
        +        which uses an old safe_version, and so
        +        their version numbers can get mangled when
        +        converted to filenames (e.g., 1.11.0.dev0+2329eae to
        +        1.11.0.dev0_2329eae). These distributions will not be
        +        parsed properly
        +        downstream by Distribution and safe_version, so
        +        take an extra step and try to get the version number from
        +        the metadata file itself instead of the filename.
        +        """
        +        md_version = self._get_version()
        +        if md_version:
        +            self._version = md_version
        +        return self
        +
        +
        +class DistInfoDistribution(Distribution):
        +    """
        +    Wrap an actual or potential sys.path entry
        +    w/metadata, .dist-info style.
        +    """
        +
        +    PKG_INFO = 'METADATA'
        +    EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
        +
        +    @property
        +    def _parsed_pkg_info(self):
        +        """Parse and cache metadata"""
        +        try:
        +            return self._pkg_info
        +        except AttributeError:
        +            metadata = self.get_metadata(self.PKG_INFO)
        +            self._pkg_info = email.parser.Parser().parsestr(metadata)
        +            return self._pkg_info
        +
        +    @property
        +    def _dep_map(self):
        +        try:
        +            return self.__dep_map
        +        except AttributeError:
        +            self.__dep_map = self._compute_dependencies()
        +            return self.__dep_map
        +
        +    def _compute_dependencies(self) -> dict[str | None, list[Requirement]]:
        +        """Recompute this distribution's dependencies."""
        +        self.__dep_map: dict[str | None, list[Requirement]] = {None: []}
        +
        +        reqs: list[Requirement] = []
        +        # Including any condition expressions
        +        for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
        +            reqs.extend(parse_requirements(req))
        +
        +        def reqs_for_extra(extra):
        +            for req in reqs:
        +                if not req.marker or req.marker.evaluate({'extra': extra}):
        +                    yield req
        +
        +        common = types.MappingProxyType(dict.fromkeys(reqs_for_extra(None)))
        +        self.__dep_map[None].extend(common)
        +
        +        for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
        +            s_extra = safe_extra(extra.strip())
        +            self.__dep_map[s_extra] = [
        +                r for r in reqs_for_extra(extra) if r not in common
        +            ]
        +
        +        return self.__dep_map
        +
        +
        +_distributionImpl = {
        +    '.egg': Distribution,
        +    '.egg-info': EggInfoDistribution,
        +    '.dist-info': DistInfoDistribution,
        +}
        +
        +
        +def issue_warning(*args, **kw):
        +    level = 1
        +    g = globals()
        +    try:
        +        # find the first stack frame that is *not* code in
        +        # the pkg_resources module, to use for the warning
        +        while sys._getframe(level).f_globals is g:
        +            level += 1
        +    except ValueError:
        +        pass
        +    warnings.warn(stacklevel=level + 1, *args, **kw)
        +
        +
        +def parse_requirements(strs: _NestedStr):
        +    """
        +    Yield ``Requirement`` objects for each specification in `strs`.
        +
        +    `strs` must be a string, or a (possibly-nested) iterable thereof.
        +    """
        +    return map(Requirement, join_continuation(map(drop_comment, yield_lines(strs))))
        +
        +
        +class RequirementParseError(_packaging_requirements.InvalidRequirement):
        +    "Compatibility wrapper for InvalidRequirement"
        +
        +
        +class Requirement(_packaging_requirements.Requirement):
        +    def __init__(self, requirement_string: str):
        +        """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
        +        super().__init__(requirement_string)
        +        self.unsafe_name = self.name
        +        project_name = safe_name(self.name)
        +        self.project_name, self.key = project_name, project_name.lower()
        +        self.specs = [(spec.operator, spec.version) for spec in self.specifier]
        +        # packaging.requirements.Requirement uses a set for its extras. We use a variable-length tuple
        +        self.extras: tuple[str] = tuple(map(safe_extra, self.extras))
        +        self.hashCmp = (
        +            self.key,
        +            self.url,
        +            self.specifier,
        +            frozenset(self.extras),
        +            str(self.marker) if self.marker else None,
        +        )
        +        self.__hash = hash(self.hashCmp)
        +
        +    def __eq__(self, other: object):
        +        return isinstance(other, Requirement) and self.hashCmp == other.hashCmp
        +
        +    def __ne__(self, other):
        +        return not self == other
        +
        +    def __contains__(self, item: Distribution | str | tuple[str, ...]) -> bool:
        +        if isinstance(item, Distribution):
        +            if item.key != self.key:
        +                return False
        +
        +            item = item.version
        +
        +        # Allow prereleases always in order to match the previous behavior of
        +        # this method. In the future this should be smarter and follow PEP 440
        +        # more accurately.
        +        return self.specifier.contains(item, prereleases=True)
        +
        +    def __hash__(self):
        +        return self.__hash
        +
        +    def __repr__(self):
        +        return "Requirement.parse(%r)" % str(self)
        +
        +    @staticmethod
        +    def parse(s: str | Iterable[str]):
        +        (req,) = parse_requirements(s)
        +        return req
        +
        +
        +def _always_object(classes):
        +    """
        +    Ensure object appears in the mro even
        +    for old-style classes.
        +    """
        +    if object not in classes:
        +        return classes + (object,)
        +    return classes
        +
        +
        +def _find_adapter(registry: Mapping[type, _AdapterT], ob: object) -> _AdapterT:
        +    """Return an adapter factory for `ob` from `registry`"""
        +    types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob))))
        +    for t in types:
        +        if t in registry:
        +            return registry[t]
        +    # _find_adapter would previously return None, and immediately be called.
        +    # So we're raising a TypeError to keep backward compatibility if anyone depended on that behaviour.
        +    raise TypeError(f"Could not find adapter for {registry} and {ob}")
        +
        +
        +def ensure_directory(path: StrOrBytesPath):
        +    """Ensure that the parent directory of `path` exists"""
        +    dirname = os.path.dirname(path)
        +    os.makedirs(dirname, exist_ok=True)
        +
        +
        +def _bypass_ensure_directory(path):
        +    """Sandbox-bypassing version of ensure_directory()"""
        +    if not WRITE_SUPPORT:
        +        raise OSError('"os.mkdir" not supported on this platform.')
        +    dirname, filename = split(path)
        +    if dirname and filename and not isdir(dirname):
        +        _bypass_ensure_directory(dirname)
        +        try:
        +            mkdir(dirname, 0o755)
        +        except FileExistsError:
        +            pass
        +
        +
        +def split_sections(s: _NestedStr) -> Iterator[tuple[str | None, list[str]]]:
        +    """Split a string or iterable thereof into (section, content) pairs
        +
        +    Each ``section`` is a stripped version of the section header ("[section]")
        +    and each ``content`` is a list of stripped lines excluding blank lines and
        +    comment-only lines.  If there are any such lines before the first section
        +    header, they're returned in a first ``section`` of ``None``.
        +    """
        +    section = None
        +    content = []
        +    for line in yield_lines(s):
        +        if line.startswith("["):
        +            if line.endswith("]"):
        +                if section or content:
        +                    yield section, content
        +                section = line[1:-1].strip()
        +                content = []
        +            else:
        +                raise ValueError("Invalid section heading", line)
        +        else:
        +            content.append(line)
        +
        +    # wrap up last segment
        +    yield section, content
        +
        +
        +def _mkstemp(*args, **kw):
        +    old_open = os.open
        +    try:
        +        # temporarily bypass sandboxing
        +        os.open = os_open
        +        return tempfile.mkstemp(*args, **kw)
        +    finally:
        +        # and then put it back
        +        os.open = old_open
        +
        +
        +# Silence the PEP440Warning by default, so that end users don't get hit by it
        +# randomly just because they use pkg_resources. We want to append the rule
        +# because we want earlier uses of filterwarnings to take precedence over this
        +# one.
        +warnings.filterwarnings("ignore", category=PEP440Warning, append=True)
        +
        +
        +class PkgResourcesDeprecationWarning(Warning):
        +    """
        +    Base class for warning about deprecations in ``pkg_resources``
        +
        +    This class is not derived from ``DeprecationWarning``, and as such is
        +    visible by default.
        +    """
        +
        +
        +# Ported from ``setuptools`` to avoid introducing an import inter-dependency:
        +_LOCALE_ENCODING = "locale" if sys.version_info >= (3, 10) else None
        +
        +
        +def _read_utf8_with_fallback(file: str, fallback_encoding=_LOCALE_ENCODING) -> str:
        +    """See setuptools.unicode_utils._read_utf8_with_fallback"""
        +    try:
        +        with open(file, "r", encoding="utf-8") as f:
        +            return f.read()
        +    except UnicodeDecodeError:  # pragma: no cover
        +        msg = f"""\
        +        ********************************************************************************
        +        `encoding="utf-8"` fails with {file!r}, trying `encoding={fallback_encoding!r}`.
        +
        +        This fallback behaviour is considered **deprecated** and future versions of
        +        `setuptools/pkg_resources` may not implement it.
        +
        +        Please encode {file!r} with "utf-8" to ensure future builds will succeed.
        +
        +        If this file was produced by `setuptools` itself, cleaning up the cached files
        +        and re-building/re-installing the package with a newer version of `setuptools`
        +        (e.g. by updating `build-system.requires` in its `pyproject.toml`)
        +        might solve the problem.
        +        ********************************************************************************
        +        """
        +        # TODO: Add a deadline?
        +        #       See comment in setuptools.unicode_utils._Utf8EncodingNeeded
        +        warnings.warn(msg, PkgResourcesDeprecationWarning, stacklevel=2)
        +        with open(file, "r", encoding=fallback_encoding) as f:
        +            return f.read()
        +
        +
        +# from jaraco.functools 1.3
        +def _call_aside(f, *args, **kwargs):
        +    f(*args, **kwargs)
        +    return f
        +
        +
        +@_call_aside
        +def _initialize(g=globals()):
        +    "Set up global resource manager (deliberately not state-saved)"
        +    manager = ResourceManager()
        +    g['_manager'] = manager
        +    g.update(
        +        (name, getattr(manager, name))
        +        for name in dir(manager)
        +        if not name.startswith('_')
        +    )
        +
        +
        +@_call_aside
        +def _initialize_master_working_set():
        +    """
        +    Prepare the master working set and make the ``require()``
        +    API available.
        +
        +    This function has explicit effects on the global state
        +    of pkg_resources. It is intended to be invoked once at
        +    the initialization of this module.
        +
        +    Invocation by other packages is unsupported and done
        +    at their own risk.
        +    """
        +    working_set = _declare_state('object', 'working_set', WorkingSet._build_master())
        +
        +    require = working_set.require
        +    iter_entry_points = working_set.iter_entry_points
        +    add_activation_listener = working_set.subscribe
        +    run_script = working_set.run_script
        +    # backward compatibility
        +    run_main = run_script
        +    # Activate all distributions already on sys.path with replace=False and
        +    # ensure that all distributions added to the working set in the future
        +    # (e.g. by calling ``require()``) will get activated as well,
        +    # with higher priority (replace=True).
        +    tuple(dist.activate(replace=False) for dist in working_set)
        +    add_activation_listener(
        +        lambda dist: dist.activate(replace=True),
        +        existing=False,
        +    )
        +    working_set.entries = []
        +    # match order
        +    list(map(working_set.add_entry, sys.path))
        +    globals().update(locals())
        +
        +
        +if TYPE_CHECKING:
        +    # All of these are set by the @_call_aside methods above
        +    __resource_manager = ResourceManager()  # Won't exist at runtime
        +    resource_exists = __resource_manager.resource_exists
        +    resource_isdir = __resource_manager.resource_isdir
        +    resource_filename = __resource_manager.resource_filename
        +    resource_stream = __resource_manager.resource_stream
        +    resource_string = __resource_manager.resource_string
        +    resource_listdir = __resource_manager.resource_listdir
        +    set_extraction_path = __resource_manager.set_extraction_path
        +    cleanup_resources = __resource_manager.cleanup_resources
        +
        +    working_set = WorkingSet()
        +    require = working_set.require
        +    iter_entry_points = working_set.iter_entry_points
        +    add_activation_listener = working_set.subscribe
        +    run_script = working_set.run_script
        +    run_main = run_script
        diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc
        new file mode 100644
        index 0000000000000000000000000000000000000000..1338eabf7565fc6dcaf360f28fdb4fab261f6d80
        GIT binary patch
        literal 161266
        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

        ' : '\U0001d4ab', + '\\' : '\U0001d4ac', + '\\' : '\U0000211b', + '\\' : '\U0001d4ae', + '\\' : '\U0001d4af', + '\\' : '\U0001d4b0', + '\\' : '\U0001d4b1', + '\\' : '\U0001d4b2', + '\\' : '\U0001d4b3', + '\\' : '\U0001d4b4', + '\\' : '\U0001d4b5', + '\\' : '\U0001d5ba', + '\\' : '\U0001d5bb', + '\\' : '\U0001d5bc', + '\\' : '\U0001d5bd', + '\\' : '\U0001d5be', + '\\' : '\U0001d5bf', + '\\' : '\U0001d5c0', + '\\' : '\U0001d5c1', + '\\' : '\U0001d5c2', + '\\' : '\U0001d5c3', + '\\' : '\U0001d5c4', + '\\' : '\U0001d5c5', + '\\' : '\U0001d5c6', + '\\' : '\U0001d5c7', + '\\' : '\U0001d5c8', + '\\

        ' : '\U0001d5c9', + '\\' : '\U0001d5ca', + '\\' : '\U0001d5cb', + '\\' : '\U0001d5cc', + '\\' : '\U0001d5cd', + '\\' : '\U0001d5ce', + '\\' : '\U0001d5cf', + '\\' : '\U0001d5d0', + '\\' : '\U0001d5d1', + '\\' : '\U0001d5d2', + '\\' : '\U0001d5d3', + '\\' : '\U0001d504', + '\\' : '\U0001d505', + '\\' : '\U0000212d', + '\\

        ' : '\U0001d507', + '\\' : '\U0001d508', + '\\' : '\U0001d509', + '\\' : '\U0001d50a', + '\\' : '\U0000210c', + '\\' : '\U00002111', + '\\' : '\U0001d50d', + '\\' : '\U0001d50e', + '\\' : '\U0001d50f', + '\\' : '\U0001d510', + '\\' : '\U0001d511', + '\\' : '\U0001d512', + '\\' : '\U0001d513', + '\\' : '\U0001d514', + '\\' : '\U0000211c', + '\\' : '\U0001d516', + '\\' : '\U0001d517', + '\\' : '\U0001d518', + '\\' : '\U0001d519', + '\\' : '\U0001d51a', + '\\' : '\U0001d51b', + '\\' : '\U0001d51c', + '\\' : '\U00002128', + '\\' : '\U0001d51e', + '\\' : '\U0001d51f', + '\\' : '\U0001d520', + '\\

        yGenP|Mee()}DT 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py new file mode 100644 index 0000000..edc21fa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py @@ -0,0 +1,631 @@ +""" +Utilities for determining application-specific dirs. + +See for details and usage. + +""" + +from __future__ import annotations + +import os +import sys +from typing import TYPE_CHECKING + +from .api import PlatformDirsABC +from .version import __version__ +from .version import __version_tuple__ as __version_info__ + +if TYPE_CHECKING: + from pathlib import Path + from typing import Literal + +if sys.platform == "win32": + from pip._vendor.platformdirs.windows import Windows as _Result +elif sys.platform == "darwin": + from pip._vendor.platformdirs.macos import MacOS as _Result +else: + from pip._vendor.platformdirs.unix import Unix as _Result + + +def _set_platform_dir_class() -> type[PlatformDirsABC]: + if os.getenv("ANDROID_DATA") == "/data" and os.getenv("ANDROID_ROOT") == "/system": + if os.getenv("SHELL") or os.getenv("PREFIX"): + return _Result + + from pip._vendor.platformdirs.android import _android_folder # noqa: PLC0415 + + if _android_folder() is not None: + from pip._vendor.platformdirs.android import Android # noqa: PLC0415 + + return Android # return to avoid redefinition of a result + + return _Result + + +if TYPE_CHECKING: + # Work around mypy issue: https://github.com/python/mypy/issues/10962 + PlatformDirs = _Result +else: + PlatformDirs = _set_platform_dir_class() #: Currently active platform +AppDirs = PlatformDirs #: Backwards compatibility with appdirs + + +def user_data_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: data directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_data_dir + + +def site_data_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + multipath: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param multipath: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: data directory shared by users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + multipath=multipath, + ensure_exists=ensure_exists, + ).site_data_dir + + +def user_config_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: config directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_config_dir + + +def site_config_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + multipath: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param multipath: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: config directory shared by the users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + multipath=multipath, + ensure_exists=ensure_exists, + ).site_config_dir + + +def user_cache_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: cache directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_cache_dir + + +def site_cache_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: cache directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).site_cache_dir + + +def user_state_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: state directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_state_dir + + +def user_log_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: log directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_log_dir + + +def user_documents_dir() -> str: + """:returns: documents directory tied to the user""" + return PlatformDirs().user_documents_dir + + +def user_downloads_dir() -> str: + """:returns: downloads directory tied to the user""" + return PlatformDirs().user_downloads_dir + + +def user_pictures_dir() -> str: + """:returns: pictures directory tied to the user""" + return PlatformDirs().user_pictures_dir + + +def user_videos_dir() -> str: + """:returns: videos directory tied to the user""" + return PlatformDirs().user_videos_dir + + +def user_music_dir() -> str: + """:returns: music directory tied to the user""" + return PlatformDirs().user_music_dir + + +def user_desktop_dir() -> str: + """:returns: desktop directory tied to the user""" + return PlatformDirs().user_desktop_dir + + +def user_runtime_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: runtime directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_runtime_dir + + +def site_runtime_dir( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> str: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: runtime directory shared by users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).site_runtime_dir + + +def user_data_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: data path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_data_path + + +def site_data_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + multipath: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param multipath: See `multipath `. + :param ensure_exists: See `ensure_exists `. + :returns: data path shared by users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + multipath=multipath, + ensure_exists=ensure_exists, + ).site_data_path + + +def user_config_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: config path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_config_path + + +def site_config_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + multipath: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param multipath: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: config path shared by the users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + multipath=multipath, + ensure_exists=ensure_exists, + ).site_config_path + + +def site_cache_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: cache directory tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).site_cache_path + + +def user_cache_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: cache path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_cache_path + + +def user_state_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param roaming: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: state path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + roaming=roaming, + ensure_exists=ensure_exists, + ).user_state_path + + +def user_log_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `roaming `. + :param ensure_exists: See `ensure_exists `. + :returns: log path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_log_path + + +def user_documents_path() -> Path: + """:returns: documents a path tied to the user""" + return PlatformDirs().user_documents_path + + +def user_downloads_path() -> Path: + """:returns: downloads path tied to the user""" + return PlatformDirs().user_downloads_path + + +def user_pictures_path() -> Path: + """:returns: pictures path tied to the user""" + return PlatformDirs().user_pictures_path + + +def user_videos_path() -> Path: + """:returns: videos path tied to the user""" + return PlatformDirs().user_videos_path + + +def user_music_path() -> Path: + """:returns: music path tied to the user""" + return PlatformDirs().user_music_path + + +def user_desktop_path() -> Path: + """:returns: desktop path tied to the user""" + return PlatformDirs().user_desktop_path + + +def user_runtime_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: runtime path tied to the user + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).user_runtime_path + + +def site_runtime_path( + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 +) -> Path: + """ + :param appname: See `appname `. + :param appauthor: See `appauthor `. + :param version: See `version `. + :param opinion: See `opinion `. + :param ensure_exists: See `ensure_exists `. + :returns: runtime path shared by users + """ + return PlatformDirs( + appname=appname, + appauthor=appauthor, + version=version, + opinion=opinion, + ensure_exists=ensure_exists, + ).site_runtime_path + + +__all__ = [ + "AppDirs", + "PlatformDirs", + "PlatformDirsABC", + "__version__", + "__version_info__", + "site_cache_dir", + "site_cache_path", + "site_config_dir", + "site_config_path", + "site_data_dir", + "site_data_path", + "site_runtime_dir", + "site_runtime_path", + "user_cache_dir", + "user_cache_path", + "user_config_dir", + "user_config_path", + "user_data_dir", + "user_data_path", + "user_desktop_dir", + "user_desktop_path", + "user_documents_dir", + "user_documents_path", + "user_downloads_dir", + "user_downloads_path", + "user_log_dir", + "user_log_path", + "user_music_dir", + "user_music_path", + "user_pictures_dir", + "user_pictures_path", + "user_runtime_dir", + "user_runtime_path", + "user_state_dir", + "user_state_path", + "user_videos_dir", + "user_videos_path", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py new file mode 100644 index 0000000..fa8a677 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py @@ -0,0 +1,55 @@ +"""Main entry point.""" + +from __future__ import annotations + +from pip._vendor.platformdirs import PlatformDirs, __version__ + +PROPS = ( + "user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "user_documents_dir", + "user_downloads_dir", + "user_pictures_dir", + "user_videos_dir", + "user_music_dir", + "user_runtime_dir", + "site_data_dir", + "site_config_dir", + "site_cache_dir", + "site_runtime_dir", +) + + +def main() -> None: + """Run the main entry point.""" + app_name = "MyApp" + app_author = "MyCompany" + + print(f"-- platformdirs {__version__} --") # noqa: T201 + + print("-- app dirs (with optional 'version')") # noqa: T201 + dirs = PlatformDirs(app_name, app_author, version="1.0") + for prop in PROPS: + print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201 + + print("\n-- app dirs (without optional 'version')") # noqa: T201 + dirs = PlatformDirs(app_name, app_author) + for prop in PROPS: + print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201 + + print("\n-- app dirs (without optional 'appauthor')") # noqa: T201 + dirs = PlatformDirs(app_name) + for prop in PROPS: + print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201 + + print("\n-- app dirs (with disabled 'appauthor')") # noqa: T201 + dirs = PlatformDirs(app_name, appauthor=False) + for prop in PROPS: + print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201 + + +if __name__ == "__main__": + main() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6218edcc563c3563a30c55409cd893bf7271a039 GIT binary patch literal 19852 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e91d68f18a975521487c0e80550e3bd934f9417c GIT binary patch literal 1953 zcmcIl&uiR96dp;VUF|P>-KKV&nxZ7Mw%Y7E2{cVZ2$Z;?gxWRkZM$WVC3#n5r4b{^ zW|uYWp@kfJ@U4NQ;A4tI>HpEoQg5LVfwVNC^ycE8dg>cV>xw2NU16n7LaE2r)%OR(>z_D4=e>o7W1xsb$@ERm%-nSM{jv2K7I{McfQZMhw)n+Y}*>v^^jgv?5ygn838Et&ucvlIHZ z5&NmeHY{`l+ex@9zRjaJiai#yu_wS$?A2J#crenO#;*cAC4_{-X{Z@gO4vrGxGe<2 zSjm)vw3-Org-U%R?WJb|%4o?M6mCPZ`lv6Mxd-_@VBl+8406d1p(XVB93axaKKc^) zR{|bUy!v8a+Dp0bqAc%MZ{RF<;s3bD*2lzKd_M0OJto%D*gxbylWDX3pmH4F+nvxR zd$Vhys|IaLb^hCZk-Xgf!1JQQa`!rQJl*Z~s06`!%CVenk@cV46lA?RVyrVO|io>hkM ze0{xRnd*E-^9DpzIFeU1Ig&jF!-w$#Fbt1KUS0cS_0uTdvS3OCOv8}^2E^4JD=P9` z!Wv=z{So#U^?Yuq!uq>?{Yn#%7SkQac3aIYN)75b7BehjyPGgoDC;)Yb>o)hnoW>5 zn;+ZjP2Slx4^X{j`AyIE7GcV{CS{A+{4Wy1%SK4u>qeMw*%=@{1wX$Gy*xm_Oim9z z`gv+@aPtW+49j!(KD)Dg|J7l!Ho|p|6fcbM#Yd%?JIe0c-&>>7)xpx^>T9?0Bc-x) zVkft=es5;?#BQ)Zdv18LHk_#cq%0mtXlnYe9FmK};-wLOFSXt;)n3l_@(8~l+wPZ6 zzntZ}BYY{gy#L{-bn(TufAWYAAt@+Q#u;0IKaw1?U|zcsUZJj~6{0*LCN&6&iiB*0 ze3TQy_<)N}LIvt+1?t%f#5W|lE3boMoPJKiF9#vtB6gOer(^1?4mHD$b&Z_^kxyE` y4vzy#5QK+l<|#V!JGyp&s|9f&AHFp!oIkjXaQSxcM``vUR=&IedB>+>fByi!Vhkt% literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..442cd647517baaaa50bae1ffa92d4864d24bb7db GIT binary patch literal 10702 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccb4a4dff4144d79cd53329cc40623e13b333471 GIT binary patch literal 13309 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..151153efcdf281c6beef7a33642be73b0a92636b GIT binary patch literal 14695 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..145e561d29b5e582f00f288b02f889c186d34398 GIT binary patch literal 602 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/android.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/android.py new file mode 100644 index 0000000..7004a85 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/android.py @@ -0,0 +1,249 @@ +"""Android.""" + +from __future__ import annotations + +import os +import re +import sys +from functools import lru_cache +from typing import TYPE_CHECKING, cast + +from .api import PlatformDirsABC + + +class Android(PlatformDirsABC): + """ + Follows the guidance `from here `_. + + Makes use of the `appname `, `version + `, `ensure_exists `. + + """ + + @property + def user_data_dir(self) -> str: + """:return: data directory tied to the user, e.g. ``/data/user///files/``""" + return self._append_app_name_and_version(cast(str, _android_folder()), "files") + + @property + def site_data_dir(self) -> str: + """:return: data directory shared by users, same as `user_data_dir`""" + return self.user_data_dir + + @property + def user_config_dir(self) -> str: + """ + :return: config directory tied to the user, e.g. \ + ``/data/user///shared_prefs/`` + """ + return self._append_app_name_and_version(cast(str, _android_folder()), "shared_prefs") + + @property + def site_config_dir(self) -> str: + """:return: config directory shared by the users, same as `user_config_dir`""" + return self.user_config_dir + + @property + def user_cache_dir(self) -> str: + """:return: cache directory tied to the user, e.g.,``/data/user///cache/``""" + return self._append_app_name_and_version(cast(str, _android_folder()), "cache") + + @property + def site_cache_dir(self) -> str: + """:return: cache directory shared by users, same as `user_cache_dir`""" + return self.user_cache_dir + + @property + def user_state_dir(self) -> str: + """:return: state directory tied to the user, same as `user_data_dir`""" + return self.user_data_dir + + @property + def user_log_dir(self) -> str: + """ + :return: log directory tied to the user, same as `user_cache_dir` if not opinionated else ``log`` in it, + e.g. ``/data/user///cache//log`` + """ + path = self.user_cache_dir + if self.opinion: + path = os.path.join(path, "log") # noqa: PTH118 + return path + + @property + def user_documents_dir(self) -> str: + """:return: documents directory tied to the user e.g. ``/storage/emulated/0/Documents``""" + return _android_documents_folder() + + @property + def user_downloads_dir(self) -> str: + """:return: downloads directory tied to the user e.g. ``/storage/emulated/0/Downloads``""" + return _android_downloads_folder() + + @property + def user_pictures_dir(self) -> str: + """:return: pictures directory tied to the user e.g. ``/storage/emulated/0/Pictures``""" + return _android_pictures_folder() + + @property + def user_videos_dir(self) -> str: + """:return: videos directory tied to the user e.g. ``/storage/emulated/0/DCIM/Camera``""" + return _android_videos_folder() + + @property + def user_music_dir(self) -> str: + """:return: music directory tied to the user e.g. ``/storage/emulated/0/Music``""" + return _android_music_folder() + + @property + def user_desktop_dir(self) -> str: + """:return: desktop directory tied to the user e.g. ``/storage/emulated/0/Desktop``""" + return "/storage/emulated/0/Desktop" + + @property + def user_runtime_dir(self) -> str: + """ + :return: runtime directory tied to the user, same as `user_cache_dir` if not opinionated else ``tmp`` in it, + e.g. ``/data/user///cache//tmp`` + """ + path = self.user_cache_dir + if self.opinion: + path = os.path.join(path, "tmp") # noqa: PTH118 + return path + + @property + def site_runtime_dir(self) -> str: + """:return: runtime directory shared by users, same as `user_runtime_dir`""" + return self.user_runtime_dir + + +@lru_cache(maxsize=1) +def _android_folder() -> str | None: # noqa: C901 + """:return: base folder for the Android OS or None if it cannot be found""" + result: str | None = None + # type checker isn't happy with our "import android", just don't do this when type checking see + # https://stackoverflow.com/a/61394121 + if not TYPE_CHECKING: + try: + # First try to get a path to android app using python4android (if available)... + from android import mActivity # noqa: PLC0415 + + context = cast("android.content.Context", mActivity.getApplicationContext()) # noqa: F821 + result = context.getFilesDir().getParentFile().getAbsolutePath() + except Exception: # noqa: BLE001 + result = None + if result is None: + try: + # ...and fall back to using plain pyjnius, if python4android isn't available or doesn't deliver any useful + # result... + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + result = context.getFilesDir().getParentFile().getAbsolutePath() + except Exception: # noqa: BLE001 + result = None + if result is None: + # and if that fails, too, find an android folder looking at path on the sys.path + # warning: only works for apps installed under /data, not adopted storage etc. + pattern = re.compile(r"/data/(data|user/\d+)/(.+)/files") + for path in sys.path: + if pattern.match(path): + result = path.split("/files")[0] + break + else: + result = None + if result is None: + # one last try: find an android folder looking at path on the sys.path taking adopted storage paths into + # account + pattern = re.compile(r"/mnt/expand/[a-fA-F0-9-]{36}/(data|user/\d+)/(.+)/files") + for path in sys.path: + if pattern.match(path): + result = path.split("/files")[0] + break + else: + result = None + return result + + +@lru_cache(maxsize=1) +def _android_documents_folder() -> str: + """:return: documents folder for the Android OS""" + # Get directories with pyjnius + try: + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + environment = autoclass("android.os.Environment") + documents_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + except Exception: # noqa: BLE001 + documents_dir = "/storage/emulated/0/Documents" + + return documents_dir + + +@lru_cache(maxsize=1) +def _android_downloads_folder() -> str: + """:return: downloads folder for the Android OS""" + # Get directories with pyjnius + try: + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + environment = autoclass("android.os.Environment") + downloads_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + except Exception: # noqa: BLE001 + downloads_dir = "/storage/emulated/0/Downloads" + + return downloads_dir + + +@lru_cache(maxsize=1) +def _android_pictures_folder() -> str: + """:return: pictures folder for the Android OS""" + # Get directories with pyjnius + try: + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + environment = autoclass("android.os.Environment") + pictures_dir: str = context.getExternalFilesDir(environment.DIRECTORY_PICTURES).getAbsolutePath() + except Exception: # noqa: BLE001 + pictures_dir = "/storage/emulated/0/Pictures" + + return pictures_dir + + +@lru_cache(maxsize=1) +def _android_videos_folder() -> str: + """:return: videos folder for the Android OS""" + # Get directories with pyjnius + try: + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + environment = autoclass("android.os.Environment") + videos_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DCIM).getAbsolutePath() + except Exception: # noqa: BLE001 + videos_dir = "/storage/emulated/0/DCIM/Camera" + + return videos_dir + + +@lru_cache(maxsize=1) +def _android_music_folder() -> str: + """:return: music folder for the Android OS""" + # Get directories with pyjnius + try: + from jnius import autoclass # noqa: PLC0415 + + context = autoclass("android.content.Context") + environment = autoclass("android.os.Environment") + music_dir: str = context.getExternalFilesDir(environment.DIRECTORY_MUSIC).getAbsolutePath() + except Exception: # noqa: BLE001 + music_dir = "/storage/emulated/0/Music" + + return music_dir + + +__all__ = [ + "Android", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/api.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/api.py new file mode 100644 index 0000000..18d660e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/api.py @@ -0,0 +1,298 @@ +"""Base API.""" + +from __future__ import annotations + +import os +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Iterator, Literal + + +class PlatformDirsABC(ABC): # noqa: PLR0904 + """Abstract base class for platform directories.""" + + def __init__( # noqa: PLR0913, PLR0917 + self, + appname: str | None = None, + appauthor: str | None | Literal[False] = None, + version: str | None = None, + roaming: bool = False, # noqa: FBT001, FBT002 + multipath: bool = False, # noqa: FBT001, FBT002 + opinion: bool = True, # noqa: FBT001, FBT002 + ensure_exists: bool = False, # noqa: FBT001, FBT002 + ) -> None: + """ + Create a new platform directory. + + :param appname: See `appname`. + :param appauthor: See `appauthor`. + :param version: See `version`. + :param roaming: See `roaming`. + :param multipath: See `multipath`. + :param opinion: See `opinion`. + :param ensure_exists: See `ensure_exists`. + + """ + self.appname = appname #: The name of application. + self.appauthor = appauthor + """ + The name of the app author or distributing body for this application. + + Typically, it is the owning company name. Defaults to `appname`. You may pass ``False`` to disable it. + + """ + self.version = version + """ + An optional version path element to append to the path. + + You might want to use this if you want multiple versions of your app to be able to run independently. If used, + this would typically be ``.``. + + """ + self.roaming = roaming + """ + Whether to use the roaming appdata directory on Windows. + + That means that for users on a Windows network setup for roaming profiles, this user data will be synced on + login (see + `here `_). + + """ + self.multipath = multipath + """ + An optional parameter which indicates that the entire list of data dirs should be returned. + + By default, the first item would only be returned. + + """ + self.opinion = opinion #: A flag to indicating to use opinionated values. + self.ensure_exists = ensure_exists + """ + Optionally create the directory (and any missing parents) upon access if it does not exist. + + By default, no directories are created. + + """ + + def _append_app_name_and_version(self, *base: str) -> str: + params = list(base[1:]) + if self.appname: + params.append(self.appname) + if self.version: + params.append(self.version) + path = os.path.join(base[0], *params) # noqa: PTH118 + self._optionally_create_directory(path) + return path + + def _optionally_create_directory(self, path: str) -> None: + if self.ensure_exists: + Path(path).mkdir(parents=True, exist_ok=True) + + def _first_item_as_path_if_multipath(self, directory: str) -> Path: + if self.multipath: + # If multipath is True, the first path is returned. + directory = directory.split(os.pathsep)[0] + return Path(directory) + + @property + @abstractmethod + def user_data_dir(self) -> str: + """:return: data directory tied to the user""" + + @property + @abstractmethod + def site_data_dir(self) -> str: + """:return: data directory shared by users""" + + @property + @abstractmethod + def user_config_dir(self) -> str: + """:return: config directory tied to the user""" + + @property + @abstractmethod + def site_config_dir(self) -> str: + """:return: config directory shared by the users""" + + @property + @abstractmethod + def user_cache_dir(self) -> str: + """:return: cache directory tied to the user""" + + @property + @abstractmethod + def site_cache_dir(self) -> str: + """:return: cache directory shared by users""" + + @property + @abstractmethod + def user_state_dir(self) -> str: + """:return: state directory tied to the user""" + + @property + @abstractmethod + def user_log_dir(self) -> str: + """:return: log directory tied to the user""" + + @property + @abstractmethod + def user_documents_dir(self) -> str: + """:return: documents directory tied to the user""" + + @property + @abstractmethod + def user_downloads_dir(self) -> str: + """:return: downloads directory tied to the user""" + + @property + @abstractmethod + def user_pictures_dir(self) -> str: + """:return: pictures directory tied to the user""" + + @property + @abstractmethod + def user_videos_dir(self) -> str: + """:return: videos directory tied to the user""" + + @property + @abstractmethod + def user_music_dir(self) -> str: + """:return: music directory tied to the user""" + + @property + @abstractmethod + def user_desktop_dir(self) -> str: + """:return: desktop directory tied to the user""" + + @property + @abstractmethod + def user_runtime_dir(self) -> str: + """:return: runtime directory tied to the user""" + + @property + @abstractmethod + def site_runtime_dir(self) -> str: + """:return: runtime directory shared by users""" + + @property + def user_data_path(self) -> Path: + """:return: data path tied to the user""" + return Path(self.user_data_dir) + + @property + def site_data_path(self) -> Path: + """:return: data path shared by users""" + return Path(self.site_data_dir) + + @property + def user_config_path(self) -> Path: + """:return: config path tied to the user""" + return Path(self.user_config_dir) + + @property + def site_config_path(self) -> Path: + """:return: config path shared by the users""" + return Path(self.site_config_dir) + + @property + def user_cache_path(self) -> Path: + """:return: cache path tied to the user""" + return Path(self.user_cache_dir) + + @property + def site_cache_path(self) -> Path: + """:return: cache path shared by users""" + return Path(self.site_cache_dir) + + @property + def user_state_path(self) -> Path: + """:return: state path tied to the user""" + return Path(self.user_state_dir) + + @property + def user_log_path(self) -> Path: + """:return: log path tied to the user""" + return Path(self.user_log_dir) + + @property + def user_documents_path(self) -> Path: + """:return: documents a path tied to the user""" + return Path(self.user_documents_dir) + + @property + def user_downloads_path(self) -> Path: + """:return: downloads path tied to the user""" + return Path(self.user_downloads_dir) + + @property + def user_pictures_path(self) -> Path: + """:return: pictures path tied to the user""" + return Path(self.user_pictures_dir) + + @property + def user_videos_path(self) -> Path: + """:return: videos path tied to the user""" + return Path(self.user_videos_dir) + + @property + def user_music_path(self) -> Path: + """:return: music path tied to the user""" + return Path(self.user_music_dir) + + @property + def user_desktop_path(self) -> Path: + """:return: desktop path tied to the user""" + return Path(self.user_desktop_dir) + + @property + def user_runtime_path(self) -> Path: + """:return: runtime path tied to the user""" + return Path(self.user_runtime_dir) + + @property + def site_runtime_path(self) -> Path: + """:return: runtime path shared by users""" + return Path(self.site_runtime_dir) + + def iter_config_dirs(self) -> Iterator[str]: + """:yield: all user and site configuration directories.""" + yield self.user_config_dir + yield self.site_config_dir + + def iter_data_dirs(self) -> Iterator[str]: + """:yield: all user and site data directories.""" + yield self.user_data_dir + yield self.site_data_dir + + def iter_cache_dirs(self) -> Iterator[str]: + """:yield: all user and site cache directories.""" + yield self.user_cache_dir + yield self.site_cache_dir + + def iter_runtime_dirs(self) -> Iterator[str]: + """:yield: all user and site runtime directories.""" + yield self.user_runtime_dir + yield self.site_runtime_dir + + def iter_config_paths(self) -> Iterator[Path]: + """:yield: all user and site configuration paths.""" + for path in self.iter_config_dirs(): + yield Path(path) + + def iter_data_paths(self) -> Iterator[Path]: + """:yield: all user and site data paths.""" + for path in self.iter_data_dirs(): + yield Path(path) + + def iter_cache_paths(self) -> Iterator[Path]: + """:yield: all user and site cache paths.""" + for path in self.iter_cache_dirs(): + yield Path(path) + + def iter_runtime_paths(self) -> Iterator[Path]: + """:yield: all user and site runtime paths.""" + for path in self.iter_runtime_dirs(): + yield Path(path) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py new file mode 100644 index 0000000..e4b0391 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py @@ -0,0 +1,144 @@ +"""macOS.""" + +from __future__ import annotations + +import os.path +import sys +from typing import TYPE_CHECKING + +from .api import PlatformDirsABC + +if TYPE_CHECKING: + from pathlib import Path + + +class MacOS(PlatformDirsABC): + """ + Platform directories for the macOS operating system. + + Follows the guidance from + `Apple documentation `_. + Makes use of the `appname `, + `version `, + `ensure_exists `. + + """ + + @property + def user_data_dir(self) -> str: + """:return: data directory tied to the user, e.g. ``~/Library/Application Support/$appname/$version``""" + return self._append_app_name_and_version(os.path.expanduser("~/Library/Application Support")) # noqa: PTH111 + + @property + def site_data_dir(self) -> str: + """ + :return: data directory shared by users, e.g. ``/Library/Application Support/$appname/$version``. + If we're using a Python binary managed by `Homebrew `_, the directory + will be under the Homebrew prefix, e.g. ``/opt/homebrew/share/$appname/$version``. + If `multipath ` is enabled, and we're in Homebrew, + the response is a multi-path string separated by ":", e.g. + ``/opt/homebrew/share/$appname/$version:/Library/Application Support/$appname/$version`` + """ + is_homebrew = sys.prefix.startswith("/opt/homebrew") + path_list = [self._append_app_name_and_version("/opt/homebrew/share")] if is_homebrew else [] + path_list.append(self._append_app_name_and_version("/Library/Application Support")) + if self.multipath: + return os.pathsep.join(path_list) + return path_list[0] + + @property + def site_data_path(self) -> Path: + """:return: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``""" + return self._first_item_as_path_if_multipath(self.site_data_dir) + + @property + def user_config_dir(self) -> str: + """:return: config directory tied to the user, same as `user_data_dir`""" + return self.user_data_dir + + @property + def site_config_dir(self) -> str: + """:return: config directory shared by the users, same as `site_data_dir`""" + return self.site_data_dir + + @property + def user_cache_dir(self) -> str: + """:return: cache directory tied to the user, e.g. ``~/Library/Caches/$appname/$version``""" + return self._append_app_name_and_version(os.path.expanduser("~/Library/Caches")) # noqa: PTH111 + + @property + def site_cache_dir(self) -> str: + """ + :return: cache directory shared by users, e.g. ``/Library/Caches/$appname/$version``. + If we're using a Python binary managed by `Homebrew `_, the directory + will be under the Homebrew prefix, e.g. ``/opt/homebrew/var/cache/$appname/$version``. + If `multipath ` is enabled, and we're in Homebrew, + the response is a multi-path string separated by ":", e.g. + ``/opt/homebrew/var/cache/$appname/$version:/Library/Caches/$appname/$version`` + """ + is_homebrew = sys.prefix.startswith("/opt/homebrew") + path_list = [self._append_app_name_and_version("/opt/homebrew/var/cache")] if is_homebrew else [] + path_list.append(self._append_app_name_and_version("/Library/Caches")) + if self.multipath: + return os.pathsep.join(path_list) + return path_list[0] + + @property + def site_cache_path(self) -> Path: + """:return: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``""" + return self._first_item_as_path_if_multipath(self.site_cache_dir) + + @property + def user_state_dir(self) -> str: + """:return: state directory tied to the user, same as `user_data_dir`""" + return self.user_data_dir + + @property + def user_log_dir(self) -> str: + """:return: log directory tied to the user, e.g. ``~/Library/Logs/$appname/$version``""" + return self._append_app_name_and_version(os.path.expanduser("~/Library/Logs")) # noqa: PTH111 + + @property + def user_documents_dir(self) -> str: + """:return: documents directory tied to the user, e.g. ``~/Documents``""" + return os.path.expanduser("~/Documents") # noqa: PTH111 + + @property + def user_downloads_dir(self) -> str: + """:return: downloads directory tied to the user, e.g. ``~/Downloads``""" + return os.path.expanduser("~/Downloads") # noqa: PTH111 + + @property + def user_pictures_dir(self) -> str: + """:return: pictures directory tied to the user, e.g. ``~/Pictures``""" + return os.path.expanduser("~/Pictures") # noqa: PTH111 + + @property + def user_videos_dir(self) -> str: + """:return: videos directory tied to the user, e.g. ``~/Movies``""" + return os.path.expanduser("~/Movies") # noqa: PTH111 + + @property + def user_music_dir(self) -> str: + """:return: music directory tied to the user, e.g. ``~/Music``""" + return os.path.expanduser("~/Music") # noqa: PTH111 + + @property + def user_desktop_dir(self) -> str: + """:return: desktop directory tied to the user, e.g. ``~/Desktop``""" + return os.path.expanduser("~/Desktop") # noqa: PTH111 + + @property + def user_runtime_dir(self) -> str: + """:return: runtime directory tied to the user, e.g. ``~/Library/Caches/TemporaryItems/$appname/$version``""" + return self._append_app_name_and_version(os.path.expanduser("~/Library/Caches/TemporaryItems")) # noqa: PTH111 + + @property + def site_runtime_dir(self) -> str: + """:return: runtime directory shared by users, same as `user_runtime_dir`""" + return self.user_runtime_dir + + +__all__ = [ + "MacOS", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py new file mode 100644 index 0000000..f1942e9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py @@ -0,0 +1,269 @@ +"""Unix.""" + +from __future__ import annotations + +import os +import sys +from configparser import ConfigParser +from pathlib import Path +from typing import Iterator, NoReturn + +from .api import PlatformDirsABC + +if sys.platform == "win32": + + def getuid() -> NoReturn: + msg = "should only be used on Unix" + raise RuntimeError(msg) + +else: + from os import getuid + + +class Unix(PlatformDirsABC): # noqa: PLR0904 + """ + On Unix/Linux, we follow the `XDG Basedir Spec `_. + + The spec allows overriding directories with environment variables. The examples shown are the default values, + alongside the name of the environment variable that overrides them. Makes use of the `appname + `, `version `, `multipath + `, `opinion `, `ensure_exists + `. + + """ + + @property + def user_data_dir(self) -> str: + """ + :return: data directory tied to the user, e.g. ``~/.local/share/$appname/$version`` or + ``$XDG_DATA_HOME/$appname/$version`` + """ + path = os.environ.get("XDG_DATA_HOME", "") + if not path.strip(): + path = os.path.expanduser("~/.local/share") # noqa: PTH111 + return self._append_app_name_and_version(path) + + @property + def _site_data_dirs(self) -> list[str]: + path = os.environ.get("XDG_DATA_DIRS", "") + if not path.strip(): + path = f"/usr/local/share{os.pathsep}/usr/share" + return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)] + + @property + def site_data_dir(self) -> str: + """ + :return: data directories shared by users (if `multipath ` is + enabled and ``XDG_DATA_DIRS`` is set and a multi path the response is also a multi path separated by the + OS path separator), e.g. ``/usr/local/share/$appname/$version`` or ``/usr/share/$appname/$version`` + """ + # XDG default for $XDG_DATA_DIRS; only first, if multipath is False + dirs = self._site_data_dirs + if not self.multipath: + return dirs[0] + return os.pathsep.join(dirs) + + @property + def user_config_dir(self) -> str: + """ + :return: config directory tied to the user, e.g. ``~/.config/$appname/$version`` or + ``$XDG_CONFIG_HOME/$appname/$version`` + """ + path = os.environ.get("XDG_CONFIG_HOME", "") + if not path.strip(): + path = os.path.expanduser("~/.config") # noqa: PTH111 + return self._append_app_name_and_version(path) + + @property + def _site_config_dirs(self) -> list[str]: + path = os.environ.get("XDG_CONFIG_DIRS", "") + if not path.strip(): + path = "/etc/xdg" + return [self._append_app_name_and_version(p) for p in path.split(os.pathsep)] + + @property + def site_config_dir(self) -> str: + """ + :return: config directories shared by users (if `multipath ` + is enabled and ``XDG_CONFIG_DIRS`` is set and a multi path the response is also a multi path separated by + the OS path separator), e.g. ``/etc/xdg/$appname/$version`` + """ + # XDG default for $XDG_CONFIG_DIRS only first, if multipath is False + dirs = self._site_config_dirs + if not self.multipath: + return dirs[0] + return os.pathsep.join(dirs) + + @property + def user_cache_dir(self) -> str: + """ + :return: cache directory tied to the user, e.g. ``~/.cache/$appname/$version`` or + ``~/$XDG_CACHE_HOME/$appname/$version`` + """ + path = os.environ.get("XDG_CACHE_HOME", "") + if not path.strip(): + path = os.path.expanduser("~/.cache") # noqa: PTH111 + return self._append_app_name_and_version(path) + + @property + def site_cache_dir(self) -> str: + """:return: cache directory shared by users, e.g. ``/var/cache/$appname/$version``""" + return self._append_app_name_and_version("/var/cache") + + @property + def user_state_dir(self) -> str: + """ + :return: state directory tied to the user, e.g. ``~/.local/state/$appname/$version`` or + ``$XDG_STATE_HOME/$appname/$version`` + """ + path = os.environ.get("XDG_STATE_HOME", "") + if not path.strip(): + path = os.path.expanduser("~/.local/state") # noqa: PTH111 + return self._append_app_name_and_version(path) + + @property + def user_log_dir(self) -> str: + """:return: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it""" + path = self.user_state_dir + if self.opinion: + path = os.path.join(path, "log") # noqa: PTH118 + self._optionally_create_directory(path) + return path + + @property + def user_documents_dir(self) -> str: + """:return: documents directory tied to the user, e.g. ``~/Documents``""" + return _get_user_media_dir("XDG_DOCUMENTS_DIR", "~/Documents") + + @property + def user_downloads_dir(self) -> str: + """:return: downloads directory tied to the user, e.g. ``~/Downloads``""" + return _get_user_media_dir("XDG_DOWNLOAD_DIR", "~/Downloads") + + @property + def user_pictures_dir(self) -> str: + """:return: pictures directory tied to the user, e.g. ``~/Pictures``""" + return _get_user_media_dir("XDG_PICTURES_DIR", "~/Pictures") + + @property + def user_videos_dir(self) -> str: + """:return: videos directory tied to the user, e.g. ``~/Videos``""" + return _get_user_media_dir("XDG_VIDEOS_DIR", "~/Videos") + + @property + def user_music_dir(self) -> str: + """:return: music directory tied to the user, e.g. ``~/Music``""" + return _get_user_media_dir("XDG_MUSIC_DIR", "~/Music") + + @property + def user_desktop_dir(self) -> str: + """:return: desktop directory tied to the user, e.g. ``~/Desktop``""" + return _get_user_media_dir("XDG_DESKTOP_DIR", "~/Desktop") + + @property + def user_runtime_dir(self) -> str: + """ + :return: runtime directory tied to the user, e.g. ``/run/user/$(id -u)/$appname/$version`` or + ``$XDG_RUNTIME_DIR/$appname/$version``. + + For FreeBSD/OpenBSD/NetBSD, it would return ``/var/run/user/$(id -u)/$appname/$version`` if + exists, otherwise ``/tmp/runtime-$(id -u)/$appname/$version``, if``$XDG_RUNTIME_DIR`` + is not set. + """ + path = os.environ.get("XDG_RUNTIME_DIR", "") + if not path.strip(): + if sys.platform.startswith(("freebsd", "openbsd", "netbsd")): + path = f"/var/run/user/{getuid()}" + if not Path(path).exists(): + path = f"/tmp/runtime-{getuid()}" # noqa: S108 + else: + path = f"/run/user/{getuid()}" + return self._append_app_name_and_version(path) + + @property + def site_runtime_dir(self) -> str: + """ + :return: runtime directory shared by users, e.g. ``/run/$appname/$version`` or \ + ``$XDG_RUNTIME_DIR/$appname/$version``. + + Note that this behaves almost exactly like `user_runtime_dir` if ``$XDG_RUNTIME_DIR`` is set, but will + fall back to paths associated to the root user instead of a regular logged-in user if it's not set. + + If you wish to ensure that a logged-in root user path is returned e.g. ``/run/user/0``, use `user_runtime_dir` + instead. + + For FreeBSD/OpenBSD/NetBSD, it would return ``/var/run/$appname/$version`` if ``$XDG_RUNTIME_DIR`` is not set. + """ + path = os.environ.get("XDG_RUNTIME_DIR", "") + if not path.strip(): + if sys.platform.startswith(("freebsd", "openbsd", "netbsd")): + path = "/var/run" + else: + path = "/run" + return self._append_app_name_and_version(path) + + @property + def site_data_path(self) -> Path: + """:return: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``""" + return self._first_item_as_path_if_multipath(self.site_data_dir) + + @property + def site_config_path(self) -> Path: + """:return: config path shared by the users, returns the first item, even if ``multipath`` is set to ``True``""" + return self._first_item_as_path_if_multipath(self.site_config_dir) + + @property + def site_cache_path(self) -> Path: + """:return: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``""" + return self._first_item_as_path_if_multipath(self.site_cache_dir) + + def iter_config_dirs(self) -> Iterator[str]: + """:yield: all user and site configuration directories.""" + yield self.user_config_dir + yield from self._site_config_dirs + + def iter_data_dirs(self) -> Iterator[str]: + """:yield: all user and site data directories.""" + yield self.user_data_dir + yield from self._site_data_dirs + + +def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str: + media_dir = _get_user_dirs_folder(env_var) + if media_dir is None: + media_dir = os.environ.get(env_var, "").strip() + if not media_dir: + media_dir = os.path.expanduser(fallback_tilde_path) # noqa: PTH111 + + return media_dir + + +def _get_user_dirs_folder(key: str) -> str | None: + """ + Return directory from user-dirs.dirs config file. + + See https://freedesktop.org/wiki/Software/xdg-user-dirs/. + + """ + user_dirs_config_path = Path(Unix().user_config_dir) / "user-dirs.dirs" + if user_dirs_config_path.exists(): + parser = ConfigParser() + + with user_dirs_config_path.open() as stream: + # Add fake section header, so ConfigParser doesn't complain + parser.read_string(f"[top]\n{stream.read()}") + + if key not in parser["top"]: + return None + + path = parser["top"][key].strip('"') + # Handle relative home paths + return path.replace("$HOME", os.path.expanduser("~")) # noqa: PTH111 + + return None + + +__all__ = [ + "Unix", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/version.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/version.py new file mode 100644 index 0000000..afb4924 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/version.py @@ -0,0 +1,16 @@ +# file generated by setuptools_scm +# don't change, don't track in version control +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '4.3.6' +__version_tuple__ = version_tuple = (4, 3, 6) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py new file mode 100644 index 0000000..d7bc960 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py @@ -0,0 +1,272 @@ +"""Windows.""" + +from __future__ import annotations + +import os +import sys +from functools import lru_cache +from typing import TYPE_CHECKING + +from .api import PlatformDirsABC + +if TYPE_CHECKING: + from collections.abc import Callable + + +class Windows(PlatformDirsABC): + """ + `MSDN on where to store app data files `_. + + Makes use of the `appname `, `appauthor + `, `version `, `roaming + `, `opinion `, `ensure_exists + `. + + """ + + @property + def user_data_dir(self) -> str: + """ + :return: data directory tied to the user, e.g. + ``%USERPROFILE%\\AppData\\Local\\$appauthor\\$appname`` (not roaming) or + ``%USERPROFILE%\\AppData\\Roaming\\$appauthor\\$appname`` (roaming) + """ + const = "CSIDL_APPDATA" if self.roaming else "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(get_win_folder(const)) + return self._append_parts(path) + + def _append_parts(self, path: str, *, opinion_value: str | None = None) -> str: + params = [] + if self.appname: + if self.appauthor is not False: + author = self.appauthor or self.appname + params.append(author) + params.append(self.appname) + if opinion_value is not None and self.opinion: + params.append(opinion_value) + if self.version: + params.append(self.version) + path = os.path.join(path, *params) # noqa: PTH118 + self._optionally_create_directory(path) + return path + + @property + def site_data_dir(self) -> str: + """:return: data directory shared by users, e.g. ``C:\\ProgramData\\$appauthor\\$appname``""" + path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA")) + return self._append_parts(path) + + @property + def user_config_dir(self) -> str: + """:return: config directory tied to the user, same as `user_data_dir`""" + return self.user_data_dir + + @property + def site_config_dir(self) -> str: + """:return: config directory shared by the users, same as `site_data_dir`""" + return self.site_data_dir + + @property + def user_cache_dir(self) -> str: + """ + :return: cache directory tied to the user (if opinionated with ``Cache`` folder within ``$appname``) e.g. + ``%USERPROFILE%\\AppData\\Local\\$appauthor\\$appname\\Cache\\$version`` + """ + path = os.path.normpath(get_win_folder("CSIDL_LOCAL_APPDATA")) + return self._append_parts(path, opinion_value="Cache") + + @property + def site_cache_dir(self) -> str: + """:return: cache directory shared by users, e.g. ``C:\\ProgramData\\$appauthor\\$appname\\Cache\\$version``""" + path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA")) + return self._append_parts(path, opinion_value="Cache") + + @property + def user_state_dir(self) -> str: + """:return: state directory tied to the user, same as `user_data_dir`""" + return self.user_data_dir + + @property + def user_log_dir(self) -> str: + """:return: log directory tied to the user, same as `user_data_dir` if not opinionated else ``Logs`` in it""" + path = self.user_data_dir + if self.opinion: + path = os.path.join(path, "Logs") # noqa: PTH118 + self._optionally_create_directory(path) + return path + + @property + def user_documents_dir(self) -> str: + """:return: documents directory tied to the user e.g. ``%USERPROFILE%\\Documents``""" + return os.path.normpath(get_win_folder("CSIDL_PERSONAL")) + + @property + def user_downloads_dir(self) -> str: + """:return: downloads directory tied to the user e.g. ``%USERPROFILE%\\Downloads``""" + return os.path.normpath(get_win_folder("CSIDL_DOWNLOADS")) + + @property + def user_pictures_dir(self) -> str: + """:return: pictures directory tied to the user e.g. ``%USERPROFILE%\\Pictures``""" + return os.path.normpath(get_win_folder("CSIDL_MYPICTURES")) + + @property + def user_videos_dir(self) -> str: + """:return: videos directory tied to the user e.g. ``%USERPROFILE%\\Videos``""" + return os.path.normpath(get_win_folder("CSIDL_MYVIDEO")) + + @property + def user_music_dir(self) -> str: + """:return: music directory tied to the user e.g. ``%USERPROFILE%\\Music``""" + return os.path.normpath(get_win_folder("CSIDL_MYMUSIC")) + + @property + def user_desktop_dir(self) -> str: + """:return: desktop directory tied to the user, e.g. ``%USERPROFILE%\\Desktop``""" + return os.path.normpath(get_win_folder("CSIDL_DESKTOPDIRECTORY")) + + @property + def user_runtime_dir(self) -> str: + """ + :return: runtime directory tied to the user, e.g. + ``%USERPROFILE%\\AppData\\Local\\Temp\\$appauthor\\$appname`` + """ + path = os.path.normpath(os.path.join(get_win_folder("CSIDL_LOCAL_APPDATA"), "Temp")) # noqa: PTH118 + return self._append_parts(path) + + @property + def site_runtime_dir(self) -> str: + """:return: runtime directory shared by users, same as `user_runtime_dir`""" + return self.user_runtime_dir + + +def get_win_folder_from_env_vars(csidl_name: str) -> str: + """Get folder from environment variables.""" + result = get_win_folder_if_csidl_name_not_env_var(csidl_name) + if result is not None: + return result + + env_var_name = { + "CSIDL_APPDATA": "APPDATA", + "CSIDL_COMMON_APPDATA": "ALLUSERSPROFILE", + "CSIDL_LOCAL_APPDATA": "LOCALAPPDATA", + }.get(csidl_name) + if env_var_name is None: + msg = f"Unknown CSIDL name: {csidl_name}" + raise ValueError(msg) + result = os.environ.get(env_var_name) + if result is None: + msg = f"Unset environment variable: {env_var_name}" + raise ValueError(msg) + return result + + +def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None: + """Get a folder for a CSIDL name that does not exist as an environment variable.""" + if csidl_name == "CSIDL_PERSONAL": + return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Documents") # noqa: PTH118 + + if csidl_name == "CSIDL_DOWNLOADS": + return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Downloads") # noqa: PTH118 + + if csidl_name == "CSIDL_MYPICTURES": + return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Pictures") # noqa: PTH118 + + if csidl_name == "CSIDL_MYVIDEO": + return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Videos") # noqa: PTH118 + + if csidl_name == "CSIDL_MYMUSIC": + return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Music") # noqa: PTH118 + return None + + +def get_win_folder_from_registry(csidl_name: str) -> str: + """ + Get folder from the registry. + + This is a fallback technique at best. I'm not sure if using the registry for these guarantees us the correct answer + for all CSIDL_* names. + + """ + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + "CSIDL_PERSONAL": "Personal", + "CSIDL_DOWNLOADS": "{374DE290-123F-4565-9164-39C4925E467B}", + "CSIDL_MYPICTURES": "My Pictures", + "CSIDL_MYVIDEO": "My Video", + "CSIDL_MYMUSIC": "My Music", + }.get(csidl_name) + if shell_folder_name is None: + msg = f"Unknown CSIDL name: {csidl_name}" + raise ValueError(msg) + if sys.platform != "win32": # only needed for mypy type checker to know that this code runs only on Windows + raise NotImplementedError + import winreg # noqa: PLC0415 + + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") + directory, _ = winreg.QueryValueEx(key, shell_folder_name) + return str(directory) + + +def get_win_folder_via_ctypes(csidl_name: str) -> str: + """Get folder with ctypes.""" + # There is no 'CSIDL_DOWNLOADS'. + # Use 'CSIDL_PROFILE' (40) and append the default folder 'Downloads' instead. + # https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid + + import ctypes # noqa: PLC0415 + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + "CSIDL_PERSONAL": 5, + "CSIDL_MYPICTURES": 39, + "CSIDL_MYVIDEO": 14, + "CSIDL_MYMUSIC": 13, + "CSIDL_DOWNLOADS": 40, + "CSIDL_DESKTOPDIRECTORY": 16, + }.get(csidl_name) + if csidl_const is None: + msg = f"Unknown CSIDL name: {csidl_name}" + raise ValueError(msg) + + buf = ctypes.create_unicode_buffer(1024) + windll = getattr(ctypes, "windll") # noqa: B009 # using getattr to avoid false positive with mypy type checker + windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if it has high-bit chars. + if any(ord(c) > 255 for c in buf): # noqa: PLR2004 + buf2 = ctypes.create_unicode_buffer(1024) + if windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + if csidl_name == "CSIDL_DOWNLOADS": + return os.path.join(buf.value, "Downloads") # noqa: PTH118 + + return buf.value + + +def _pick_get_win_folder() -> Callable[[str], str]: + try: + import ctypes # noqa: PLC0415 + except ImportError: + pass + else: + if hasattr(ctypes, "windll"): + return get_win_folder_via_ctypes + try: + import winreg # noqa: PLC0415, F401 + except ImportError: + return get_win_folder_from_env_vars + else: + return get_win_folder_from_registry + + +get_win_folder = lru_cache(maxsize=None)(_pick_get_win_folder()) + +__all__ = [ + "Windows", +] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__init__.py new file mode 100644 index 0000000..60ae9bb --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__init__.py @@ -0,0 +1,82 @@ +""" + Pygments + ~~~~~~~~ + + Pygments is a syntax highlighting package written in Python. + + It is a generic syntax highlighter for general use in all kinds of software + such as forum systems, wikis or other applications that need to prettify + source code. Highlights are: + + * a wide range of common languages and markup formats is supported + * special attention is paid to details, increasing quality by a fair amount + * support for new languages and formats are added easily + * a number of output formats, presently HTML, LaTeX, RTF, SVG, all image + formats that PIL supports, and ANSI sequences + * it is usable as a command-line tool and as a library + * ... and it highlights even Brainfuck! + + The `Pygments master branch`_ is installable with ``easy_install Pygments==dev``. + + .. _Pygments master branch: + https://github.com/pygments/pygments/archive/master.zip#egg=Pygments-dev + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from io import StringIO, BytesIO + +__version__ = '2.18.0' +__docformat__ = 'restructuredtext' + +__all__ = ['lex', 'format', 'highlight'] + + +def lex(code, lexer): + """ + Lex `code` with the `lexer` (must be a `Lexer` instance) + and return an iterable of tokens. Currently, this only calls + `lexer.get_tokens()`. + """ + try: + return lexer.get_tokens(code) + except TypeError: + # Heuristic to catch a common mistake. + from pip._vendor.pygments.lexer import RegexLexer + if isinstance(lexer, type) and issubclass(lexer, RegexLexer): + raise TypeError('lex() argument must be a lexer instance, ' + 'not a class') + raise + + +def format(tokens, formatter, outfile=None): # pylint: disable=redefined-builtin + """ + Format ``tokens`` (an iterable of tokens) with the formatter ``formatter`` + (a `Formatter` instance). + + If ``outfile`` is given and a valid file object (an object with a + ``write`` method), the result will be written to it, otherwise it + is returned as a string. + """ + try: + if not outfile: + realoutfile = getattr(formatter, 'encoding', None) and BytesIO() or StringIO() + formatter.format(tokens, realoutfile) + return realoutfile.getvalue() + else: + formatter.format(tokens, outfile) + except TypeError: + # Heuristic to catch a common mistake. + from pip._vendor.pygments.formatter import Formatter + if isinstance(formatter, type) and issubclass(formatter, Formatter): + raise TypeError('format() argument must be a formatter instance, ' + 'not a class') + raise + + +def highlight(code, lexer, formatter, outfile=None): + """ + This is the most high-level highlighting function. It combines `lex` and + `format` in one function. + """ + return format(lex(code, lexer), formatter, outfile) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__main__.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__main__.py new file mode 100644 index 0000000..dcc6e5a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__main__.py @@ -0,0 +1,17 @@ +""" + pygments.__main__ + ~~~~~~~~~~~~~~~~~ + + Main entry point for ``python -m pygments``. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import sys +from pip._vendor.pygments.cmdline import main + +try: + sys.exit(main(sys.argv)) +except KeyboardInterrupt: + sys.exit(1) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7097f55d3336e4f871485f9cad216b1428819c40 GIT binary patch literal 3494 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba1583b93615acc1445be7e622953ccc9a6f688b GIT binary patch literal 26590 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15a305defb00465ac7474e9dfdb4df77b71bb1e8 GIT binary patch literal 2634 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef52b3cb5edf5b9b96ca334d9176bda7bca9341b GIT binary patch literal 4726 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5550c442ca45bf3662b8005be7032f54168a6120 GIT binary patch literal 1565 zcmZV;U2oe|^j_OZ+$8;GWsQn-#po0lmX->Th_+T;R|(LRp{DSVrHh>SCUxf6-nH8< zk&A*fL`x^N;-%%SkDDs(kML3`8pY}Z5>I_V3S>{bz_AmzQ#q2)J?EZt&-d|J zDWNAQ7gi!l_zBKM>YOAtUPcLkS+CTnZd<9Ep-@fLsek*`Wr+IMbHq|>rbbDiOiYsg)HwP38lVOixXHbYpsI`U6s|6MKb{&%1#To65EK zh(#%x`(o*ndyCnW?>nujC8}FAO>SrJbmVtGonOdg7f9J)M4`5n1IfnNcegSIcF}8l4Q2vuU!X5(iKXFnvrU;@#c9d242QmgJQQBF&Pt?>aT% zi^?`A1}1^D>Usy;viJHHNs{{y(s^t7T_QzGIA{W#&}jc_F9ETK>~m4olUxD^9d_St zU$*&tm$*9#RE75|gufbRtte!8*rH52k^1!d<@2bVTrP}m{3Ab{E zT6t47Ckr4`3^o}I(_|1s%B;I1|L=r1XDkjujKF6l0X5O7IQ*-a_(@Fczke*g)tvh+ zBA)aQ?5uCC?>^dY9EqbX9*I3|&_$*0SbH?`YU5S0{WG9FYDQHDD1H{0%<}vO8#b7@-Z`KJSOa2ld?$9Kpg*2OXirVU$Gzvd{bBU|3Lm*nI_7 z#=%O+3E7dZL*#IQore%L*cp1w2j_%5?}0|w)3pmvbzTx0ccb2-W=pc}FG^>O{h<%a zY!O*k2&48Y(=R4eEyF@mqFSK4swbAwD4h b9~QsOeVuDZ`2N9W?C&^_6R+a^xD)ArEDDM4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b90b7db855b0611a2465df2821edb850aefa4416 GIT binary patch literal 2614 zcmd5;&2Jk;6rZsj+i||##!Uqx3l(Y|QpZG9QJu6XO&k$noGLa_V_a5i@5EVHd##zx zhpmKGh(jWf%88T{y+#541pWaomRv>Ass|)4a7$w$5l+0BwVl|F0>_RtZ)e`Td2inD z{buZ6dwP5b+LfOdw5$iA-}$7`9Q8r%E(~^%ic(0$szb+lN6LYb>P$IRSIVV!q&if0 z%B_07LMe~x1?g2gL3XM>kUq5wWLK#>*rWUcE`1WTVkws=1(St}`bthK2;CR0%_o%i z>V}eSC}{GH0&pZE-A&Bc>#@1%Xgm=WII6@{ zG@XTffATvK#8x-3mzLzB0fc1bzBaOzFEkZR^iNyaD3<$AtVBvIi|bd8e_YU=&}*w8 zc97Xz+k-i8o7m**qHSOm@6|6X^>5(MIvOh{-wpJmW3TQdfxreXe0$qKIn?lzKtX5R zaxnU183 z)W}gKp9kip*9;?T={TE^5Uw z8P-&Tjy1p=v!8}gv1AQ^F_ll3hIT{rcc8OdAReLTJ(s`!^wI2dPw&?1x9iV5(xDsm z2Oe*3Z$6D|ZC3k26>sR!%T?v=@{^ILnQC9K;tkedGs<$&XdHtp&};WWe28#Mh0J;- z5NhB(gC1OjilGg3R%IF${SNP7jJ^rDPzn9yT*JFK9(0Nntbthcesn>O#*+(+^1b=F zc+zs|hNA9b%O?`HsmRMK(JqjdA07l%w!x9@N07o9(0kAsKl&f&ZvZ54_1U#s`+>-o z@1S?+v9WDbdxxvu;TKMHY2ui15`KAY1h?eQl_K{d4E|T{QayLRv#kLlXYjCr$daRu z$y*IfXdgHL67s@YgR}DsA5A5b?Z|Kf(gCobeh};wDuL6eoLo*i1a_0$b`-=3GPm~w zcbdpNDgW^B`-j!xaHTg~^@ce_?;qC$L^p1}st^q%l8dqEY2wgJkmA|sv~b3LrReKm zJ@qm&Eu1+6nTcb18Fsy*#PQG0#oAbN4lEa1NMpa%bQrRmeHoX?eqiD}#!T9{#Dm?I zN0wD1E6bK&%NGr5>RKk0hhG|1F%|L1(thwy16;hu#T#63;){zcI4jB{&a#VW4_^|O z-#cmlt+_+_MdkcwyoQHPjPVP{o7nZ&3`ThLw~KFA(7?ga^$Hq1u*ZW}E69K3?!+TU SLk=t*`5gFNA!>XiLi`I4l!X%j literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a9b186025218afe2083213f6be18c2454d49faf GIT binary patch literal 4083 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b09a9746fece2325cdabbdc6350084fe52f00c7d GIT binary patch literal 12104 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef9f15224d98a714f3deba3bbdc317f1d64c794a GIT binary patch literal 6699 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%0A*OfPy==s*YC}g%8Qnn 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dab6ed304a4cb46842f998e43a31441e12a5c22 GIT binary patch literal 14075 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 is one of "lexer", "formatter" or "filter".') + special_modes.add_argument( + '-V', action='store_true', + help='Print the package version.') + special_modes.add_argument( + '-h', '--help', action='store_true', + help='Print this help.') + special_modes_group.add_argument( + '-a', metavar='ARG', + help='Formatter-specific additional argument for the -S (print ' + 'style sheet) mode.') + + argns = parser.parse_args(args[1:]) + + try: + return main_inner(parser, argns) + except BrokenPipeError: + # someone closed our stdout, e.g. by quitting a pager. + return 0 + except Exception: + if argns.v: + print(file=sys.stderr) + print('*' * 65, file=sys.stderr) + print('An unhandled exception occurred while highlighting.', + file=sys.stderr) + print('Please report the whole traceback to the issue tracker at', + file=sys.stderr) + print('.', + file=sys.stderr) + print('*' * 65, file=sys.stderr) + print(file=sys.stderr) + raise + import traceback + info = traceback.format_exception(*sys.exc_info()) + msg = info[-1].strip() + if len(info) >= 3: + # extract relevant file and position info + msg += '\n (f{})'.format(info[-2].split('\n')[0].strip()[1:]) + print(file=sys.stderr) + print('*** Error while highlighting:', file=sys.stderr) + print(msg, file=sys.stderr) + print('*** If this is a bug you want to report, please rerun with -v.', + file=sys.stderr) + return 1 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/console.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/console.py new file mode 100644 index 0000000..4c1a062 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/console.py @@ -0,0 +1,70 @@ +""" + pygments.console + ~~~~~~~~~~~~~~~~ + + Format colored console output. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +esc = "\x1b[" + +codes = {} +codes[""] = "" +codes["reset"] = esc + "39;49;00m" + +codes["bold"] = esc + "01m" +codes["faint"] = esc + "02m" +codes["standout"] = esc + "03m" +codes["underline"] = esc + "04m" +codes["blink"] = esc + "05m" +codes["overline"] = esc + "06m" + +dark_colors = ["black", "red", "green", "yellow", "blue", + "magenta", "cyan", "gray"] +light_colors = ["brightblack", "brightred", "brightgreen", "brightyellow", "brightblue", + "brightmagenta", "brightcyan", "white"] + +x = 30 +for dark, light in zip(dark_colors, light_colors): + codes[dark] = esc + "%im" % x + codes[light] = esc + "%im" % (60 + x) + x += 1 + +del dark, light, x + +codes["white"] = codes["bold"] + + +def reset_color(): + return codes["reset"] + + +def colorize(color_key, text): + return codes[color_key] + text + codes["reset"] + + +def ansiformat(attr, text): + """ + Format ``text`` with a color and/or some attributes:: + + color normal color + *color* bold color + _color_ underlined color + +color+ blinking color + """ + result = [] + if attr[:1] == attr[-1:] == '+': + result.append(codes['blink']) + attr = attr[1:-1] + if attr[:1] == attr[-1:] == '*': + result.append(codes['bold']) + attr = attr[1:-1] + if attr[:1] == attr[-1:] == '_': + result.append(codes['underline']) + attr = attr[1:-1] + result.append(codes[attr]) + result.append(text) + result.append(codes['reset']) + return ''.join(result) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/filter.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/filter.py new file mode 100644 index 0000000..aa6f760 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/filter.py @@ -0,0 +1,70 @@ +""" + pygments.filter + ~~~~~~~~~~~~~~~ + + Module that implements the default filter. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + + +def apply_filters(stream, filters, lexer=None): + """ + Use this method to apply an iterable of filters to + a stream. If lexer is given it's forwarded to the + filter, otherwise the filter receives `None`. + """ + def _apply(filter_, stream): + yield from filter_.filter(lexer, stream) + for filter_ in filters: + stream = _apply(filter_, stream) + return stream + + +def simplefilter(f): + """ + Decorator that converts a function into a filter:: + + @simplefilter + def lowercase(self, lexer, stream, options): + for ttype, value in stream: + yield ttype, value.lower() + """ + return type(f.__name__, (FunctionFilter,), { + '__module__': getattr(f, '__module__'), + '__doc__': f.__doc__, + 'function': f, + }) + + +class Filter: + """ + Default filter. Subclass this class or use the `simplefilter` + decorator to create own filters. + """ + + def __init__(self, **options): + self.options = options + + def filter(self, lexer, stream): + raise NotImplementedError() + + +class FunctionFilter(Filter): + """ + Abstract class used by `simplefilter` to create simple + function filters on the fly. The `simplefilter` decorator + automatically creates subclasses of this class for + functions passed to it. + """ + function = None + + def __init__(self, **options): + if not hasattr(self, 'function'): + raise TypeError(f'{self.__class__.__name__!r} used without bound function') + Filter.__init__(self, **options) + + def filter(self, lexer, stream): + # pylint: disable=not-callable + yield from self.function(lexer, stream, self.options) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py new file mode 100644 index 0000000..9255ca2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py @@ -0,0 +1,940 @@ +""" + pygments.filters + ~~~~~~~~~~~~~~~~ + + Module containing filter lookup functions and default + filters. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re + +from pip._vendor.pygments.token import String, Comment, Keyword, Name, Error, Whitespace, \ + string_to_tokentype +from pip._vendor.pygments.filter import Filter +from pip._vendor.pygments.util import get_list_opt, get_int_opt, get_bool_opt, \ + get_choice_opt, ClassNotFound, OptionError +from pip._vendor.pygments.plugin import find_plugin_filters + + +def find_filter_class(filtername): + """Lookup a filter by name. Return None if not found.""" + if filtername in FILTERS: + return FILTERS[filtername] + for name, cls in find_plugin_filters(): + if name == filtername: + return cls + return None + + +def get_filter_by_name(filtername, **options): + """Return an instantiated filter. + + Options are passed to the filter initializer if wanted. + Raise a ClassNotFound if not found. + """ + cls = find_filter_class(filtername) + if cls: + return cls(**options) + else: + raise ClassNotFound(f'filter {filtername!r} not found') + + +def get_all_filters(): + """Return a generator of all filter names.""" + yield from FILTERS + for name, _ in find_plugin_filters(): + yield name + + +def _replace_special(ttype, value, regex, specialttype, + replacefunc=lambda x: x): + last = 0 + for match in regex.finditer(value): + start, end = match.start(), match.end() + if start != last: + yield ttype, value[last:start] + yield specialttype, replacefunc(value[start:end]) + last = end + if last != len(value): + yield ttype, value[last:] + + +class CodeTagFilter(Filter): + """Highlight special code tags in comments and docstrings. + + Options accepted: + + `codetags` : list of strings + A list of strings that are flagged as code tags. The default is to + highlight ``XXX``, ``TODO``, ``FIXME``, ``BUG`` and ``NOTE``. + + .. versionchanged:: 2.13 + Now recognizes ``FIXME`` by default. + """ + + def __init__(self, **options): + Filter.__init__(self, **options) + tags = get_list_opt(options, 'codetags', + ['XXX', 'TODO', 'FIXME', 'BUG', 'NOTE']) + self.tag_re = re.compile(r'\b({})\b'.format('|'.join([ + re.escape(tag) for tag in tags if tag + ]))) + + def filter(self, lexer, stream): + regex = self.tag_re + for ttype, value in stream: + if ttype in String.Doc or \ + ttype in Comment and \ + ttype not in Comment.Preproc: + yield from _replace_special(ttype, value, regex, Comment.Special) + else: + yield ttype, value + + +class SymbolFilter(Filter): + """Convert mathematical symbols such as \\ in Isabelle + or \\longrightarrow in LaTeX into Unicode characters. + + This is mostly useful for HTML or console output when you want to + approximate the source rendering you'd see in an IDE. + + Options accepted: + + `lang` : string + The symbol language. Must be one of ``'isabelle'`` or + ``'latex'``. The default is ``'isabelle'``. + """ + + latex_symbols = { + '\\alpha' : '\U000003b1', + '\\beta' : '\U000003b2', + '\\gamma' : '\U000003b3', + '\\delta' : '\U000003b4', + '\\varepsilon' : '\U000003b5', + '\\zeta' : '\U000003b6', + '\\eta' : '\U000003b7', + '\\vartheta' : '\U000003b8', + '\\iota' : '\U000003b9', + '\\kappa' : '\U000003ba', + '\\lambda' : '\U000003bb', + '\\mu' : '\U000003bc', + '\\nu' : '\U000003bd', + '\\xi' : '\U000003be', + '\\pi' : '\U000003c0', + '\\varrho' : '\U000003c1', + '\\sigma' : '\U000003c3', + '\\tau' : '\U000003c4', + '\\upsilon' : '\U000003c5', + '\\varphi' : '\U000003c6', + '\\chi' : '\U000003c7', + '\\psi' : '\U000003c8', + '\\omega' : '\U000003c9', + '\\Gamma' : '\U00000393', + '\\Delta' : '\U00000394', + '\\Theta' : '\U00000398', + '\\Lambda' : '\U0000039b', + '\\Xi' : '\U0000039e', + '\\Pi' : '\U000003a0', + '\\Sigma' : '\U000003a3', + '\\Upsilon' : '\U000003a5', + '\\Phi' : '\U000003a6', + '\\Psi' : '\U000003a8', + '\\Omega' : '\U000003a9', + '\\leftarrow' : '\U00002190', + '\\longleftarrow' : '\U000027f5', + '\\rightarrow' : '\U00002192', + '\\longrightarrow' : '\U000027f6', + '\\Leftarrow' : '\U000021d0', + '\\Longleftarrow' : '\U000027f8', + '\\Rightarrow' : '\U000021d2', + '\\Longrightarrow' : '\U000027f9', + '\\leftrightarrow' : '\U00002194', + '\\longleftrightarrow' : '\U000027f7', + '\\Leftrightarrow' : '\U000021d4', + '\\Longleftrightarrow' : '\U000027fa', + '\\mapsto' : '\U000021a6', + '\\longmapsto' : '\U000027fc', + '\\relbar' : '\U00002500', + '\\Relbar' : '\U00002550', + '\\hookleftarrow' : '\U000021a9', + '\\hookrightarrow' : '\U000021aa', + '\\leftharpoondown' : '\U000021bd', + '\\rightharpoondown' : '\U000021c1', + '\\leftharpoonup' : '\U000021bc', + '\\rightharpoonup' : '\U000021c0', + '\\rightleftharpoons' : '\U000021cc', + '\\leadsto' : '\U0000219d', + '\\downharpoonleft' : '\U000021c3', + '\\downharpoonright' : '\U000021c2', + '\\upharpoonleft' : '\U000021bf', + '\\upharpoonright' : '\U000021be', + '\\restriction' : '\U000021be', + '\\uparrow' : '\U00002191', + '\\Uparrow' : '\U000021d1', + '\\downarrow' : '\U00002193', + '\\Downarrow' : '\U000021d3', + '\\updownarrow' : '\U00002195', + '\\Updownarrow' : '\U000021d5', + '\\langle' : '\U000027e8', + '\\rangle' : '\U000027e9', + '\\lceil' : '\U00002308', + '\\rceil' : '\U00002309', + '\\lfloor' : '\U0000230a', + '\\rfloor' : '\U0000230b', + '\\flqq' : '\U000000ab', + '\\frqq' : '\U000000bb', + '\\bot' : '\U000022a5', + '\\top' : '\U000022a4', + '\\wedge' : '\U00002227', + '\\bigwedge' : '\U000022c0', + '\\vee' : '\U00002228', + '\\bigvee' : '\U000022c1', + '\\forall' : '\U00002200', + '\\exists' : '\U00002203', + '\\nexists' : '\U00002204', + '\\neg' : '\U000000ac', + '\\Box' : '\U000025a1', + '\\Diamond' : '\U000025c7', + '\\vdash' : '\U000022a2', + '\\models' : '\U000022a8', + '\\dashv' : '\U000022a3', + '\\surd' : '\U0000221a', + '\\le' : '\U00002264', + '\\ge' : '\U00002265', + '\\ll' : '\U0000226a', + '\\gg' : '\U0000226b', + '\\lesssim' : '\U00002272', + '\\gtrsim' : '\U00002273', + '\\lessapprox' : '\U00002a85', + '\\gtrapprox' : '\U00002a86', + '\\in' : '\U00002208', + '\\notin' : '\U00002209', + '\\subset' : '\U00002282', + '\\supset' : '\U00002283', + '\\subseteq' : '\U00002286', + '\\supseteq' : '\U00002287', + '\\sqsubset' : '\U0000228f', + '\\sqsupset' : '\U00002290', + '\\sqsubseteq' : '\U00002291', + '\\sqsupseteq' : '\U00002292', + '\\cap' : '\U00002229', + '\\bigcap' : '\U000022c2', + '\\cup' : '\U0000222a', + '\\bigcup' : '\U000022c3', + '\\sqcup' : '\U00002294', + '\\bigsqcup' : '\U00002a06', + '\\sqcap' : '\U00002293', + '\\Bigsqcap' : '\U00002a05', + '\\setminus' : '\U00002216', + '\\propto' : '\U0000221d', + '\\uplus' : '\U0000228e', + '\\bigplus' : '\U00002a04', + '\\sim' : '\U0000223c', + '\\doteq' : '\U00002250', + '\\simeq' : '\U00002243', + '\\approx' : '\U00002248', + '\\asymp' : '\U0000224d', + '\\cong' : '\U00002245', + '\\equiv' : '\U00002261', + '\\Join' : '\U000022c8', + '\\bowtie' : '\U00002a1d', + '\\prec' : '\U0000227a', + '\\succ' : '\U0000227b', + '\\preceq' : '\U0000227c', + '\\succeq' : '\U0000227d', + '\\parallel' : '\U00002225', + '\\mid' : '\U000000a6', + '\\pm' : '\U000000b1', + '\\mp' : '\U00002213', + '\\times' : '\U000000d7', + '\\div' : '\U000000f7', + '\\cdot' : '\U000022c5', + '\\star' : '\U000022c6', + '\\circ' : '\U00002218', + '\\dagger' : '\U00002020', + '\\ddagger' : '\U00002021', + '\\lhd' : '\U000022b2', + '\\rhd' : '\U000022b3', + '\\unlhd' : '\U000022b4', + '\\unrhd' : '\U000022b5', + '\\triangleleft' : '\U000025c3', + '\\triangleright' : '\U000025b9', + '\\triangle' : '\U000025b3', + '\\triangleq' : '\U0000225c', + '\\oplus' : '\U00002295', + '\\bigoplus' : '\U00002a01', + '\\otimes' : '\U00002297', + '\\bigotimes' : '\U00002a02', + '\\odot' : '\U00002299', + '\\bigodot' : '\U00002a00', + '\\ominus' : '\U00002296', + '\\oslash' : '\U00002298', + '\\dots' : '\U00002026', + '\\cdots' : '\U000022ef', + '\\sum' : '\U00002211', + '\\prod' : '\U0000220f', + '\\coprod' : '\U00002210', + '\\infty' : '\U0000221e', + '\\int' : '\U0000222b', + '\\oint' : '\U0000222e', + '\\clubsuit' : '\U00002663', + '\\diamondsuit' : '\U00002662', + '\\heartsuit' : '\U00002661', + '\\spadesuit' : '\U00002660', + '\\aleph' : '\U00002135', + '\\emptyset' : '\U00002205', + '\\nabla' : '\U00002207', + '\\partial' : '\U00002202', + '\\flat' : '\U0000266d', + '\\natural' : '\U0000266e', + '\\sharp' : '\U0000266f', + '\\angle' : '\U00002220', + '\\copyright' : '\U000000a9', + '\\textregistered' : '\U000000ae', + '\\textonequarter' : '\U000000bc', + '\\textonehalf' : '\U000000bd', + '\\textthreequarters' : '\U000000be', + '\\textordfeminine' : '\U000000aa', + '\\textordmasculine' : '\U000000ba', + '\\euro' : '\U000020ac', + '\\pounds' : '\U000000a3', + '\\yen' : '\U000000a5', + '\\textcent' : '\U000000a2', + '\\textcurrency' : '\U000000a4', + '\\textdegree' : '\U000000b0', + } + + isabelle_symbols = { + '\\' : '\U0001d7ec', + '\\' : '\U0001d7ed', + '\\' : '\U0001d7ee', + '\\' : '\U0001d7ef', + '\\' : '\U0001d7f0', + '\\' : '\U0001d7f1', + '\\' : '\U0001d7f2', + '\\' : '\U0001d7f3', + '\\' : '\U0001d7f4', + '\\' : '\U0001d7f5', + '\\' : '\U0001d49c', + '\\' : '\U0000212c', + '\\' : '\U0001d49e', + '\\' : '\U0001d49f', + '\\' : '\U00002130', + '\\' : '\U00002131', + '\\' : '\U0001d4a2', + '\\' : '\U0000210b', + '\\' : '\U00002110', + '\\' : '\U0001d4a5', + '\\' : '\U0001d4a6', + '\\' : '\U00002112', + '\\' : '\U00002133', + '\\' : '\U0001d4a9', + '\\' : '\U0001d4aa', + '\\

        ' : '\U0001d521', + '\\' : '\U0001d522', + '\\' : '\U0001d523', + '\\' : '\U0001d524', + '\\' : '\U0001d525', + '\\' : '\U0001d526', + '\\' : '\U0001d527', + '\\' : '\U0001d528', + '\\' : '\U0001d529', + '\\' : '\U0001d52a', + '\\' : '\U0001d52b', + '\\' : '\U0001d52c', + '\\' : '\U0001d52d', + '\\' : '\U0001d52e', + '\\' : '\U0001d52f', + '\\' : '\U0001d530', + '\\' : '\U0001d531', + '\\' : '\U0001d532', + '\\' : '\U0001d533', + '\\' : '\U0001d534', + '\\' : '\U0001d535', + '\\' : '\U0001d536', + '\\' : '\U0001d537', + '\\' : '\U000003b1', + '\\' : '\U000003b2', + '\\' : '\U000003b3', + '\\' : '\U000003b4', + '\\' : '\U000003b5', + '\\' : '\U000003b6', + '\\' : '\U000003b7', + '\\' : '\U000003b8', + '\\' : '\U000003b9', + '\\' : '\U000003ba', + '\\' : '\U000003bb', + '\\' : '\U000003bc', + '\\' : '\U000003bd', + '\\' : '\U000003be', + '\\' : '\U000003c0', + '\\' : '\U000003c1', + '\\' : '\U000003c3', + '\\' : '\U000003c4', + '\\' : '\U000003c5', + '\\' : '\U000003c6', + '\\' : '\U000003c7', + '\\' : '\U000003c8', + '\\' : '\U000003c9', + '\\' : '\U00000393', + '\\' : '\U00000394', + '\\' : '\U00000398', + '\\' : '\U0000039b', + '\\' : '\U0000039e', + '\\' : '\U000003a0', + '\\' : '\U000003a3', + '\\' : '\U000003a5', + '\\' : '\U000003a6', + '\\' : '\U000003a8', + '\\' : '\U000003a9', + '\\' : '\U0001d539', + '\\' : '\U00002102', + '\\' : '\U00002115', + '\\' : '\U0000211a', + '\\' : '\U0000211d', + '\\' : '\U00002124', + '\\' : '\U00002190', + '\\' : '\U000027f5', + '\\' : '\U00002192', + '\\' : '\U000027f6', + '\\' : '\U000021d0', + '\\' : '\U000027f8', + '\\' : '\U000021d2', + '\\' : '\U000027f9', + '\\' : '\U00002194', + '\\' : '\U000027f7', + '\\' : '\U000021d4', + '\\' : '\U000027fa', + '\\' : '\U000021a6', + '\\' : '\U000027fc', + '\\' : '\U00002500', + '\\' : '\U00002550', + '\\' : '\U000021a9', + '\\' : '\U000021aa', + '\\' : '\U000021bd', + '\\' : '\U000021c1', + '\\' : '\U000021bc', + '\\' : '\U000021c0', + '\\' : '\U000021cc', + '\\' : '\U0000219d', + '\\' : '\U000021c3', + '\\' : '\U000021c2', + '\\' : '\U000021bf', + '\\' : '\U000021be', + '\\' : '\U000021be', + '\\' : '\U00002237', + '\\' : '\U00002191', + '\\' : '\U000021d1', + '\\' : '\U00002193', + '\\' : '\U000021d3', + '\\' : '\U00002195', + '\\' : '\U000021d5', + '\\' : '\U000027e8', + '\\' : '\U000027e9', + '\\' : '\U00002308', + '\\' : '\U00002309', + '\\' : '\U0000230a', + '\\' : '\U0000230b', + '\\' : '\U00002987', + '\\' : '\U00002988', + '\\' : '\U000027e6', + '\\' : '\U000027e7', + '\\' : '\U00002983', + '\\' : '\U00002984', + '\\' : '\U000000ab', + '\\' : '\U000000bb', + '\\' : '\U000022a5', + '\\' : '\U000022a4', + '\\' : '\U00002227', + '\\' : '\U000022c0', + '\\' : '\U00002228', + '\\' : '\U000022c1', + '\\' : '\U00002200', + '\\' : '\U00002203', + '\\' : '\U00002204', + '\\' : '\U000000ac', + '\\' : '\U000025a1', + '\\' : '\U000025c7', + '\\' : '\U000022a2', + '\\' : '\U000022a8', + '\\' : '\U000022a9', + '\\' : '\U000022ab', + '\\' : '\U000022a3', + '\\' : '\U0000221a', + '\\' : '\U00002264', + '\\' : '\U00002265', + '\\' : '\U0000226a', + '\\' : '\U0000226b', + '\\' : '\U00002272', + '\\' : '\U00002273', + '\\' : '\U00002a85', + '\\' : '\U00002a86', + '\\' : '\U00002208', + '\\' : '\U00002209', + '\\' : '\U00002282', + '\\' : '\U00002283', + '\\' : '\U00002286', + '\\' : '\U00002287', + '\\' : '\U0000228f', + '\\' : '\U00002290', + '\\' : '\U00002291', + '\\' : '\U00002292', + '\\' : '\U00002229', + '\\' : '\U000022c2', + '\\' : '\U0000222a', + '\\' : '\U000022c3', + '\\' : '\U00002294', + '\\' : '\U00002a06', + '\\' : '\U00002293', + '\\' : '\U00002a05', + '\\' : '\U00002216', + '\\' : '\U0000221d', + '\\' : '\U0000228e', + '\\' : '\U00002a04', + '\\' : '\U00002260', + '\\' : '\U0000223c', + '\\' : '\U00002250', + '\\' : '\U00002243', + '\\' : '\U00002248', + '\\' : '\U0000224d', + '\\' : '\U00002245', + '\\' : '\U00002323', + '\\' : '\U00002261', + '\\' : '\U00002322', + '\\' : '\U000022c8', + '\\' : '\U00002a1d', + '\\' : '\U0000227a', + '\\' : '\U0000227b', + '\\' : '\U0000227c', + '\\' : '\U0000227d', + '\\' : '\U00002225', + '\\' : '\U000000a6', + '\\' : '\U000000b1', + '\\' : '\U00002213', + '\\' : '\U000000d7', + '\\
        ' : '\U000000f7', + '\\' : '\U000022c5', + '\\' : '\U000022c6', + '\\' : '\U00002219', + '\\' : '\U00002218', + '\\' : '\U00002020', + '\\' : '\U00002021', + '\\' : '\U000022b2', + '\\' : '\U000022b3', + '\\' : '\U000022b4', + '\\' : '\U000022b5', + '\\' : '\U000025c3', + '\\' : '\U000025b9', + '\\' : '\U000025b3', + '\\' : '\U0000225c', + '\\' : '\U00002295', + '\\' : '\U00002a01', + '\\' : '\U00002297', + '\\' : '\U00002a02', + '\\' : '\U00002299', + '\\' : '\U00002a00', + '\\' : '\U00002296', + '\\' : '\U00002298', + '\\' : '\U00002026', + '\\' : '\U000022ef', + '\\' : '\U00002211', + '\\' : '\U0000220f', + '\\' : '\U00002210', + '\\' : '\U0000221e', + '\\' : '\U0000222b', + '\\' : '\U0000222e', + '\\' : '\U00002663', + '\\' : '\U00002662', + '\\' : '\U00002661', + '\\' : '\U00002660', + '\\' : '\U00002135', + '\\' : '\U00002205', + '\\' : '\U00002207', + '\\' : '\U00002202', + '\\' : '\U0000266d', + '\\' : '\U0000266e', + '\\' : '\U0000266f', + '\\' : '\U00002220', + '\\' : '\U000000a9', + '\\' : '\U000000ae', + '\\' : '\U000000ad', + '\\' : '\U000000af', + '\\' : '\U000000bc', + '\\' : '\U000000bd', + '\\' : '\U000000be', + '\\' : '\U000000aa', + '\\' : '\U000000ba', + '\\
        ' : '\U000000a7', + '\\' : '\U000000b6', + '\\' : '\U000000a1', + '\\' : '\U000000bf', + '\\' : '\U000020ac', + '\\' : '\U000000a3', + '\\' : '\U000000a5', + '\\' : '\U000000a2', + '\\' : '\U000000a4', + '\\' : '\U000000b0', + '\\' : '\U00002a3f', + '\\' : '\U00002127', + '\\' : '\U000025ca', + '\\' : '\U00002118', + '\\' : '\U00002240', + '\\' : '\U000022c4', + '\\' : '\U000000b4', + '\\' : '\U00000131', + '\\' : '\U000000a8', + '\\' : '\U000000b8', + '\\' : '\U000002dd', + '\\' : '\U000003f5', + '\\' : '\U000023ce', + '\\' : '\U00002039', + '\\' : '\U0000203a', + '\\' : '\U00002302', + '\\<^sub>' : '\U000021e9', + '\\<^sup>' : '\U000021e7', + '\\<^bold>' : '\U00002759', + '\\<^bsub>' : '\U000021d8', + '\\<^esub>' : '\U000021d9', + '\\<^bsup>' : '\U000021d7', + '\\<^esup>' : '\U000021d6', + } + + lang_map = {'isabelle' : isabelle_symbols, 'latex' : latex_symbols} + + def __init__(self, **options): + Filter.__init__(self, **options) + lang = get_choice_opt(options, 'lang', + ['isabelle', 'latex'], 'isabelle') + self.symbols = self.lang_map[lang] + + def filter(self, lexer, stream): + for ttype, value in stream: + if value in self.symbols: + yield ttype, self.symbols[value] + else: + yield ttype, value + + +class KeywordCaseFilter(Filter): + """Convert keywords to lowercase or uppercase or capitalize them, which + means first letter uppercase, rest lowercase. + + This can be useful e.g. if you highlight Pascal code and want to adapt the + code to your styleguide. + + Options accepted: + + `case` : string + The casing to convert keywords to. Must be one of ``'lower'``, + ``'upper'`` or ``'capitalize'``. The default is ``'lower'``. + """ + + def __init__(self, **options): + Filter.__init__(self, **options) + case = get_choice_opt(options, 'case', + ['lower', 'upper', 'capitalize'], 'lower') + self.convert = getattr(str, case) + + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype in Keyword: + yield ttype, self.convert(value) + else: + yield ttype, value + + +class NameHighlightFilter(Filter): + """Highlight a normal Name (and Name.*) token with a different token type. + + Example:: + + filter = NameHighlightFilter( + names=['foo', 'bar', 'baz'], + tokentype=Name.Function, + ) + + This would highlight the names "foo", "bar" and "baz" + as functions. `Name.Function` is the default token type. + + Options accepted: + + `names` : list of strings + A list of names that should be given the different token type. + There is no default. + `tokentype` : TokenType or string + A token type or a string containing a token type name that is + used for highlighting the strings in `names`. The default is + `Name.Function`. + """ + + def __init__(self, **options): + Filter.__init__(self, **options) + self.names = set(get_list_opt(options, 'names', [])) + tokentype = options.get('tokentype') + if tokentype: + self.tokentype = string_to_tokentype(tokentype) + else: + self.tokentype = Name.Function + + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype in Name and value in self.names: + yield self.tokentype, value + else: + yield ttype, value + + +class ErrorToken(Exception): + pass + + +class RaiseOnErrorTokenFilter(Filter): + """Raise an exception when the lexer generates an error token. + + Options accepted: + + `excclass` : Exception class + The exception class to raise. + The default is `pygments.filters.ErrorToken`. + + .. versionadded:: 0.8 + """ + + def __init__(self, **options): + Filter.__init__(self, **options) + self.exception = options.get('excclass', ErrorToken) + try: + # issubclass() will raise TypeError if first argument is not a class + if not issubclass(self.exception, Exception): + raise TypeError + except TypeError: + raise OptionError('excclass option is not an exception class') + + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype is Error: + raise self.exception(value) + yield ttype, value + + +class VisibleWhitespaceFilter(Filter): + """Convert tabs, newlines and/or spaces to visible characters. + + Options accepted: + + `spaces` : string or bool + If this is a one-character string, spaces will be replaces by this string. + If it is another true value, spaces will be replaced by ``·`` (unicode + MIDDLE DOT). If it is a false value, spaces will not be replaced. The + default is ``False``. + `tabs` : string or bool + The same as for `spaces`, but the default replacement character is ``»`` + (unicode RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK). The default value + is ``False``. Note: this will not work if the `tabsize` option for the + lexer is nonzero, as tabs will already have been expanded then. + `tabsize` : int + If tabs are to be replaced by this filter (see the `tabs` option), this + is the total number of characters that a tab should be expanded to. + The default is ``8``. + `newlines` : string or bool + The same as for `spaces`, but the default replacement character is ``¶`` + (unicode PILCROW SIGN). The default value is ``False``. + `wstokentype` : bool + If true, give whitespace the special `Whitespace` token type. This allows + styling the visible whitespace differently (e.g. greyed out), but it can + disrupt background colors. The default is ``True``. + + .. versionadded:: 0.8 + """ + + def __init__(self, **options): + Filter.__init__(self, **options) + for name, default in [('spaces', '·'), + ('tabs', '»'), + ('newlines', '¶')]: + opt = options.get(name, False) + if isinstance(opt, str) and len(opt) == 1: + setattr(self, name, opt) + else: + setattr(self, name, (opt and default or '')) + tabsize = get_int_opt(options, 'tabsize', 8) + if self.tabs: + self.tabs += ' ' * (tabsize - 1) + if self.newlines: + self.newlines += '\n' + self.wstt = get_bool_opt(options, 'wstokentype', True) + + def filter(self, lexer, stream): + if self.wstt: + spaces = self.spaces or ' ' + tabs = self.tabs or '\t' + newlines = self.newlines or '\n' + regex = re.compile(r'\s') + + def replacefunc(wschar): + if wschar == ' ': + return spaces + elif wschar == '\t': + return tabs + elif wschar == '\n': + return newlines + return wschar + + for ttype, value in stream: + yield from _replace_special(ttype, value, regex, Whitespace, + replacefunc) + else: + spaces, tabs, newlines = self.spaces, self.tabs, self.newlines + # simpler processing + for ttype, value in stream: + if spaces: + value = value.replace(' ', spaces) + if tabs: + value = value.replace('\t', tabs) + if newlines: + value = value.replace('\n', newlines) + yield ttype, value + + +class GobbleFilter(Filter): + """Gobbles source code lines (eats initial characters). + + This filter drops the first ``n`` characters off every line of code. This + may be useful when the source code fed to the lexer is indented by a fixed + amount of space that isn't desired in the output. + + Options accepted: + + `n` : int + The number of characters to gobble. + + .. versionadded:: 1.2 + """ + def __init__(self, **options): + Filter.__init__(self, **options) + self.n = get_int_opt(options, 'n', 0) + + def gobble(self, value, left): + if left < len(value): + return value[left:], 0 + else: + return '', left - len(value) + + def filter(self, lexer, stream): + n = self.n + left = n # How many characters left to gobble. + for ttype, value in stream: + # Remove ``left`` tokens from first line, ``n`` from all others. + parts = value.split('\n') + (parts[0], left) = self.gobble(parts[0], left) + for i in range(1, len(parts)): + (parts[i], left) = self.gobble(parts[i], n) + value = '\n'.join(parts) + + if value != '': + yield ttype, value + + +class TokenMergeFilter(Filter): + """Merges consecutive tokens with the same token type in the output + stream of a lexer. + + .. versionadded:: 1.2 + """ + def __init__(self, **options): + Filter.__init__(self, **options) + + def filter(self, lexer, stream): + current_type = None + current_value = None + for ttype, value in stream: + if ttype is current_type: + current_value += value + else: + if current_type is not None: + yield current_type, current_value + current_type = ttype + current_value = value + if current_type is not None: + yield current_type, current_value + + +FILTERS = { + 'codetagify': CodeTagFilter, + 'keywordcase': KeywordCaseFilter, + 'highlight': NameHighlightFilter, + 'raiseonerror': RaiseOnErrorTokenFilter, + 'whitespace': VisibleWhitespaceFilter, + 'gobble': GobbleFilter, + 'tokenmerge': TokenMergeFilter, + 'symbols': SymbolFilter, +} diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ce397a6f4e1744e082ca4e417f27f6287c9a3e5 GIT binary patch literal 37917 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 gYwp1K{DJX{`, + the `arg` is then given by the ``-a`` option. + """ + return '' + + def format(self, tokensource, outfile): + """ + This method must format the tokens from the `tokensource` iterable and + write the formatted version to the file object `outfile`. + + Formatter options can control how exactly the tokens are converted. + """ + if self.encoding: + # wrap the outfile in a StreamWriter + outfile = codecs.lookup(self.encoding)[3](outfile) + return self.format_unencoded(tokensource, outfile) + + # Allow writing Formatter[str] or Formatter[bytes]. That's equivalent to + # Formatter. This helps when using third-party type stubs from typeshed. + def __class_getitem__(cls, name): + return cls diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py new file mode 100644 index 0000000..f19e993 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py @@ -0,0 +1,157 @@ +""" + pygments.formatters + ~~~~~~~~~~~~~~~~~~~ + + Pygments formatters. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re +import sys +import types +import fnmatch +from os.path import basename + +from pip._vendor.pygments.formatters._mapping import FORMATTERS +from pip._vendor.pygments.plugin import find_plugin_formatters +from pip._vendor.pygments.util import ClassNotFound + +__all__ = ['get_formatter_by_name', 'get_formatter_for_filename', + 'get_all_formatters', 'load_formatter_from_file'] + list(FORMATTERS) + +_formatter_cache = {} # classes by name +_pattern_cache = {} + + +def _fn_matches(fn, glob): + """Return whether the supplied file name fn matches pattern filename.""" + if glob not in _pattern_cache: + pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob)) + return pattern.match(fn) + return _pattern_cache[glob].match(fn) + + +def _load_formatters(module_name): + """Load a formatter (and all others in the module too).""" + mod = __import__(module_name, None, None, ['__all__']) + for formatter_name in mod.__all__: + cls = getattr(mod, formatter_name) + _formatter_cache[cls.name] = cls + + +def get_all_formatters(): + """Return a generator for all formatter classes.""" + # NB: this returns formatter classes, not info like get_all_lexers(). + for info in FORMATTERS.values(): + if info[1] not in _formatter_cache: + _load_formatters(info[0]) + yield _formatter_cache[info[1]] + for _, formatter in find_plugin_formatters(): + yield formatter + + +def find_formatter_class(alias): + """Lookup a formatter by alias. + + Returns None if not found. + """ + for module_name, name, aliases, _, _ in FORMATTERS.values(): + if alias in aliases: + if name not in _formatter_cache: + _load_formatters(module_name) + return _formatter_cache[name] + for _, cls in find_plugin_formatters(): + if alias in cls.aliases: + return cls + + +def get_formatter_by_name(_alias, **options): + """ + Return an instance of a :class:`.Formatter` subclass that has `alias` in its + aliases list. The formatter is given the `options` at its instantiation. + + Will raise :exc:`pygments.util.ClassNotFound` if no formatter with that + alias is found. + """ + cls = find_formatter_class(_alias) + if cls is None: + raise ClassNotFound(f"no formatter found for name {_alias!r}") + return cls(**options) + + +def load_formatter_from_file(filename, formattername="CustomFormatter", **options): + """ + Return a `Formatter` subclass instance loaded from the provided file, relative + to the current directory. + + The file is expected to contain a Formatter class named ``formattername`` + (by default, CustomFormatter). Users should be very careful with the input, because + this method is equivalent to running ``eval()`` on the input file. The formatter is + given the `options` at its instantiation. + + :exc:`pygments.util.ClassNotFound` is raised if there are any errors loading + the formatter. + + .. versionadded:: 2.2 + """ + try: + # This empty dict will contain the namespace for the exec'd file + custom_namespace = {} + with open(filename, 'rb') as f: + exec(f.read(), custom_namespace) + # Retrieve the class `formattername` from that namespace + if formattername not in custom_namespace: + raise ClassNotFound(f'no valid {formattername} class found in {filename}') + formatter_class = custom_namespace[formattername] + # And finally instantiate it with the options + return formatter_class(**options) + except OSError as err: + raise ClassNotFound(f'cannot read {filename}: {err}') + except ClassNotFound: + raise + except Exception as err: + raise ClassNotFound(f'error when loading custom formatter: {err}') + + +def get_formatter_for_filename(fn, **options): + """ + Return a :class:`.Formatter` subclass instance that has a filename pattern + matching `fn`. The formatter is given the `options` at its instantiation. + + Will raise :exc:`pygments.util.ClassNotFound` if no formatter for that filename + is found. + """ + fn = basename(fn) + for modname, name, _, filenames, _ in FORMATTERS.values(): + for filename in filenames: + if _fn_matches(fn, filename): + if name not in _formatter_cache: + _load_formatters(modname) + return _formatter_cache[name](**options) + for _name, cls in find_plugin_formatters(): + for filename in cls.filenames: + if _fn_matches(fn, filename): + return cls(**options) + raise ClassNotFound(f"no formatter found for file name {fn!r}") + + +class _automodule(types.ModuleType): + """Automatically import formatters.""" + + def __getattr__(self, name): + info = FORMATTERS.get(name) + if info: + _load_formatters(info[0]) + cls = _formatter_cache[info[1]] + setattr(self, name, cls) + return cls + raise AttributeError(name) + + +oldmod = sys.modules[__name__] +newmod = _automodule(__name__) +newmod.__dict__.update(oldmod.__dict__) +sys.modules[__name__] = newmod +del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17ecd8daee90dc6af32da906437e01ee19ed89f9 GIT binary patch literal 6908 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 YU^TdJF7OY3f@RUX@+17~WgT<>4gOd|P5=M^ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6101369f7ff39bfd46f1e51b92a035c7c5fec414 GIT binary patch literal 7299 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 G!u}UdfoZe= literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10a7668afba0994efbe9dbe7528823a899c408f3 GIT binary patch literal 41032 zcmd753wT@CogauN34$O95_~@|-w%P;j9@%%0F+a2j-;BGK|8>ZeQ0 zVb50eIhQ@#)aN|*Y*(N2*|S4^F7TQ!6nl!t^S^cPA*=Qng0O2s0CWn%G#aN!J$&QsW^lg#Lg;X=X7x*M;| z>aH4J*3IhMDntL#D&U%)o0#(Wf&tgKUz&0UgB~g1x)_|AWRYKc%4KD-hm;%w@(M@J zojf7qEQ}bjHH~qMopqu(o zR`csKe!6WzvWA^|_l+5-rSe6iMSo8k5!}*+b(iG1B*(L#u>M2&?O9!$KGZi97;{g1 zgys&RuS4h;+yP#LNS2bbShyQb5D*Xj91)JLf-)RSpz}06b#IIgBS5+9`jH7r2w@`kctr|vSvM_ z-tjr91`pft7wAB6O&8C$ZDf~5vrCt=?q}Do?AmD98Ex3PHgvzCH=bX#V0)NfxcK7r zHzJk_sT3J9_w&1mxupxLFu0UFnGi=;Sf})6ULV$@M|$)~KabyQT_XA?8q1N2`WH4( zh#1`^6K>M3`QNCXYx)~qVLdOA!%dgacmDGK#non%vQc)z2%Jh}O}iz`Ai~FBaBkX@ zFpvA(Q}}VyPk=@gbcsXKF-%y_(Vz#Dh zL!V^Z7%by9`?aCCHGiQq?r<)8mJcj>m-1JdqK=jYbKFsU%eG`&Fh6kAY&hzpj{22d zF-O~ic{5v=>$u*zY0=pV7I$6WA2F4&kqG?{UG3HhkIy3kWkjM|D$VM<7z|Dadb`va z?($0$UH#TCOYdCP6P&tIR=bNEA&Vd=gH-cmTvwsPF9RI=}N^SJ&XVK~AZAT-&?5x`s~G6OFB>UZ4}Rv$L+* zovaJz&M*Y+=?Z|Djs;y}P^|B__SJQE{xdF>f-I{8}*BG)XE*nEyI)5>fZHVef0kS z1Jb0|cUh1;ll$u#Kmr#%o?yLjQSyxMuWxDv#Kygo9zb*}9KQtQLXN&J8Ln)!`mJN2 z4eCV%g{~(R0ProHM+fOpN0K0jW1%- zU9nhm-^*Ol77VM@6~)LGY7FY zsUATTkgraxLs&1?BWw^G5H^a92%F||+nObkr``Vu%nDOi5V(LN1W9HJkZi#uydGg> zq%Sb-_Vtg92toHmz$F}*6F`C7Gn2s%M!sbH5xfBb$TH~1mKwC5h<0A}0}AM`waeC?r{N#OJ4^BLXBeuiw|kCB$hbvlN-TAPatHmWp`Hmz^&=y^ zpITSE0oFmcD0-<`?#aoyq%H-#A|x_uAm}eAP%gkn8cS@-{`nqU3CcOirU<^dbmefN6T&5x!J}6)~ zjwC<_qWy#=DRHOVhi2;g$NhdevUSugwe==dPL-zQpwgxx_sAJil72zc(GjU10SWf_ zCG6nC-HO=mY|rllwX?J!8*DG2;mFqtOZk~cU9%wly7KoAK81^+mHeNZD5gqrq@ zdB?rTIzt)I5n%8is7spg9C&jJPja?hMb&L zbE?)MK%-^EDByv(3b9Wh4kdWU)xwC7&^x7BRP}@x`i=~_^A|lnVT33oPo)tOYRa@5 zT|>Xo6-t7-M9)=L2hl_-YX)Q!1HG95Lqa#WzD&SSc?sUJA(5>Xsv_%B0fH9r zNjQSL5d~G`aTEd!W#$OuWG2DN2K)1jL7fJKFS>)QJy4GX5T$9T&Kzje4#u-Q;I;!O z7$6xLpMtH%l?H?skYg8-DFA|%HS3?56w&PfxHC;?Dr($6Iq9Dzv`y;VQ$0P`X@z*$)pPR3Ju%0A3C&syD-n%KtxT;IyQx@O1i!5N=oN) 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77e0476ed83179cc2bd1e4a59f8636b1ea4d97ea GIT binary patch literal 6061 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

        $a^z^uu)SmGJ>mS+}BQ!v@C!tKA=d7 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..954c126d66ec848d7ead89487b70d4384ed94a3e GIT binary patch literal 13779 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..788604395c89157363d34c2da9a5070788c0f859 GIT binary patch literal 9145 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7769f1e2e7320ccb6588c0cd566b99f8ce9c8eb0 GIT binary patch literal 15124 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 tags. By default, the content is enclosed in a ``

        `` tag, itself wrapped in a ``
        `` tag (but see the `nowrap` option). The ``
        ``'s CSS class can be set by the `cssclass` option."), + 'IRCFormatter': ('pygments.formatters.irc', 'IRC', ('irc', 'IRC'), (), 'Format tokens with IRC color sequences'), + 'ImageFormatter': ('pygments.formatters.img', 'img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'JpgImageFormatter': ('pygments.formatters.img', 'img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'LatexFormatter': ('pygments.formatters.latex', 'LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'), + 'NullFormatter': ('pygments.formatters.other', 'Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'), + 'PangoMarkupFormatter': ('pygments.formatters.pangomarkup', 'Pango Markup', ('pango', 'pangomarkup'), (), 'Format tokens as Pango Markup code. It can then be rendered to an SVG.'), + 'RawTokenFormatter': ('pygments.formatters.other', 'Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'), + 'RtfFormatter': ('pygments.formatters.rtf', 'RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft(R) Word(R) documents.'), + 'SvgFormatter': ('pygments.formatters.svg', 'SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file. This formatter is still experimental. Each line of code is a ```` element with explicit ``x`` and ``y`` coordinates containing ```` elements with the individual token styles.'), + 'Terminal256Formatter': ('pygments.formatters.terminal256', 'Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TerminalFormatter': ('pygments.formatters.terminal', 'Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TerminalTrueColorFormatter': ('pygments.formatters.terminal256', 'TerminalTrueColor', ('terminal16m', 'console16m', '16m'), (), 'Format tokens with ANSI color sequences, for output in a true-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TestcaseFormatter': ('pygments.formatters.other', 'Testcase', ('testcase',), (), 'Format tokens as appropriate for a new testcase.'), +} diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py new file mode 100644 index 0000000..5a05bd9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py @@ -0,0 +1,108 @@ +""" + pygments.formatters.bbcode + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + BBcode formatter. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + + +from pip._vendor.pygments.formatter import Formatter +from pip._vendor.pygments.util import get_bool_opt + +__all__ = ['BBCodeFormatter'] + + +class BBCodeFormatter(Formatter): + """ + Format tokens with BBcodes. These formatting codes are used by many + bulletin boards, so you can highlight your sourcecode with pygments before + posting it there. + + This formatter has no support for background colors and borders, as there + are no common BBcode tags for that. + + Some board systems (e.g. phpBB) don't support colors in their [code] tag, + so you can't use the highlighting together with that tag. + Text in a [code] tag usually is shown with a monospace font (which this + formatter can do with the ``monofont`` option) and no spaces (which you + need for indentation) are removed. + + Additional options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + + `codetag` + If set to true, put the output into ``[code]`` tags (default: + ``false``) + + `monofont` + If set to true, add a tag to show the code with a monospace font + (default: ``false``). + """ + name = 'BBCode' + aliases = ['bbcode', 'bb'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self._code = get_bool_opt(options, 'codetag', False) + self._mono = get_bool_opt(options, 'monofont', False) + + self.styles = {} + self._make_styles() + + def _make_styles(self): + for ttype, ndef in self.style: + start = end = '' + if ndef['color']: + start += '[color=#{}]'.format(ndef['color']) + end = '[/color]' + end + if ndef['bold']: + start += '[b]' + end = '[/b]' + end + if ndef['italic']: + start += '[i]' + end = '[/i]' + end + if ndef['underline']: + start += '[u]' + end = '[/u]' + end + # there are no common BBcodes for background-color and border + + self.styles[ttype] = start, end + + def format_unencoded(self, tokensource, outfile): + if self._code: + outfile.write('[code]') + if self._mono: + outfile.write('[font=monospace]') + + lastval = '' + lasttype = None + + for ttype, value in tokensource: + while ttype not in self.styles: + ttype = ttype.parent + if ttype == lasttype: + lastval += value + else: + if lastval: + start, end = self.styles[lasttype] + outfile.write(''.join((start, lastval, end))) + lastval = value + lasttype = ttype + + if lastval: + start, end = self.styles[lasttype] + outfile.write(''.join((start, lastval, end))) + + if self._mono: + outfile.write('[/font]') + if self._code: + outfile.write('[/code]') + if self._code or self._mono: + outfile.write('\n') diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py new file mode 100644 index 0000000..5c8a958 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py @@ -0,0 +1,170 @@ +""" + pygments.formatters.groff + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for groff output. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import math +from pip._vendor.pygments.formatter import Formatter +from pip._vendor.pygments.util import get_bool_opt, get_int_opt + +__all__ = ['GroffFormatter'] + + +class GroffFormatter(Formatter): + """ + Format tokens with groff escapes to change their color and font style. + + .. versionadded:: 2.11 + + Additional options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + + `monospaced` + If set to true, monospace font will be used (default: ``true``). + + `linenos` + If set to true, print the line numbers (default: ``false``). + + `wrap` + Wrap lines to the specified number of characters. Disabled if set to 0 + (default: ``0``). + """ + + name = 'groff' + aliases = ['groff','troff','roff'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + + self.monospaced = get_bool_opt(options, 'monospaced', True) + self.linenos = get_bool_opt(options, 'linenos', False) + self._lineno = 0 + self.wrap = get_int_opt(options, 'wrap', 0) + self._linelen = 0 + + self.styles = {} + self._make_styles() + + + def _make_styles(self): + regular = '\\f[CR]' if self.monospaced else '\\f[R]' + bold = '\\f[CB]' if self.monospaced else '\\f[B]' + italic = '\\f[CI]' if self.monospaced else '\\f[I]' + + for ttype, ndef in self.style: + start = end = '' + if ndef['color']: + start += '\\m[{}]'.format(ndef['color']) + end = '\\m[]' + end + if ndef['bold']: + start += bold + end = regular + end + if ndef['italic']: + start += italic + end = regular + end + if ndef['bgcolor']: + start += '\\M[{}]'.format(ndef['bgcolor']) + end = '\\M[]' + end + + self.styles[ttype] = start, end + + + def _define_colors(self, outfile): + colors = set() + for _, ndef in self.style: + if ndef['color'] is not None: + colors.add(ndef['color']) + + for color in sorted(colors): + outfile.write('.defcolor ' + color + ' rgb #' + color + '\n') + + + def _write_lineno(self, outfile): + self._lineno += 1 + outfile.write("%s% 4d " % (self._lineno != 1 and '\n' or '', self._lineno)) + + + def _wrap_line(self, line): + length = len(line.rstrip('\n')) + space = ' ' if self.linenos else '' + newline = '' + + if length > self.wrap: + for i in range(0, math.floor(length / self.wrap)): + chunk = line[i*self.wrap:i*self.wrap+self.wrap] + newline += (chunk + '\n' + space) + remainder = length % self.wrap + if remainder > 0: + newline += line[-remainder-1:] + self._linelen = remainder + elif self._linelen + length > self.wrap: + newline = ('\n' + space) + line + self._linelen = length + else: + newline = line + self._linelen += length + + return newline + + + def _escape_chars(self, text): + text = text.replace('\\', '\\[u005C]'). \ + replace('.', '\\[char46]'). \ + replace('\'', '\\[u0027]'). \ + replace('`', '\\[u0060]'). \ + replace('~', '\\[u007E]') + copy = text + + for char in copy: + if len(char) != len(char.encode()): + uni = char.encode('unicode_escape') \ + .decode()[1:] \ + .replace('x', 'u00') \ + .upper() + text = text.replace(char, '\\[u' + uni[1:] + ']') + + return text + + + def format_unencoded(self, tokensource, outfile): + self._define_colors(outfile) + + outfile.write('.nf\n\\f[CR]\n') + + if self.linenos: + self._write_lineno(outfile) + + for ttype, value in tokensource: + while ttype not in self.styles: + ttype = ttype.parent + start, end = self.styles[ttype] + + for line in value.splitlines(True): + if self.wrap > 0: + line = self._wrap_line(line) + + if start and end: + text = self._escape_chars(line.rstrip('\n')) + if text != '': + outfile.write(''.join((start, text, end))) + else: + outfile.write(self._escape_chars(line.rstrip('\n'))) + + if line.endswith('\n'): + if self.linenos: + self._write_lineno(outfile) + self._linelen = 0 + else: + outfile.write('\n') + self._linelen = 0 + + outfile.write('\n.fi') diff --git a/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py new file mode 100644 index 0000000..7aa938f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py @@ -0,0 +1,987 @@ +""" + pygments.formatters.html + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for HTML output. + + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import functools +import os +import sys +import os.path +from io import StringIO + +from pip._vendor.pygments.formatter import Formatter +from pip._vendor.pygments.token import Token, Text, STANDARD_TYPES +from pip._vendor.pygments.util import get_bool_opt, get_int_opt, get_list_opt + +try: + import ctags +except ImportError: + ctags = None + +__all__ = ['HtmlFormatter'] + + +_escape_html_table = { + ord('&'): '&', + ord('<'): '<', + ord('>'): '>', + ord('"'): '"', + ord("'"): ''', +} + + +def escape_html(text, table=_escape_html_table): + """Escape &, <, > as well as single and double quotes for HTML.""" + return text.translate(table) + + +def webify(color): + if color.startswith('calc') or color.startswith('var'): + return color + else: + return '#' + color + + +def _get_ttype_class(ttype): + fname = STANDARD_TYPES.get(ttype) + if fname: + return fname + aname = '' + while fname is None: + aname = '-' + ttype[-1] + aname + ttype = ttype.parent + fname = STANDARD_TYPES.get(ttype) + return fname + aname + + +CSSFILE_TEMPLATE = '''\ +/* +generated by Pygments +Copyright 2006-2024 by the Pygments team. +Licensed under the BSD license, see LICENSE for details. +*/ +%(styledefs)s +''' + +DOC_HEADER = '''\ + + + + + %(title)s + + + + +

        %(title)s

        + +''' + +DOC_HEADER_EXTERNALCSS = '''\ + + + + + %(title)s + + + + +

        %(title)s

        + +''' + +DOC_FOOTER = '''\ + + +''' + + +class HtmlFormatter(Formatter): + r""" + Format tokens as HTML 4 ```` tags. By default, the content is enclosed + in a ``
        `` tag, itself wrapped in a ``
        `` tag (but see the `nowrap` option). + The ``
        ``'s CSS class can be set by the `cssclass` option. + + If the `linenos` option is set to ``"table"``, the ``
        `` is
        +    additionally wrapped inside a ```` which has one row and two
        +    cells: one containing the line numbers and one containing the code.
        +    Example:
        +
        +    .. sourcecode:: html
        +
        +        
        +
        + + +
        +
        1
        +            2
        +
        +
        def foo(bar):
        +              pass
        +            
        +
        + + (whitespace added to improve clarity). + + A list of lines can be specified using the `hl_lines` option to make these + lines highlighted (as of Pygments 0.11). + + With the `full` option, a complete HTML 4 document is output, including + the style definitions inside a `` + + +
        {code}
        + + +""" + +CONSOLE_SVG_FORMAT = """\ + + + + + + + + + {lines} + + + {chrome} + + {backgrounds} + + {matrix} + + + +""" + +_SVG_FONT_FAMILY = "Rich Fira Code" +_SVG_CLASSES_PREFIX = "rich-svg" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_extension.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_extension.py new file mode 100644 index 0000000..cbd6da9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_extension.py @@ -0,0 +1,10 @@ +from typing import Any + + +def load_ipython_extension(ip: Any) -> None: # pragma: no cover + # prevent circular import + from pip._vendor.rich.pretty import install + from pip._vendor.rich.traceback import install as tr_install + + install() + tr_install() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_fileno.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_fileno.py new file mode 100644 index 0000000..b17ee65 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_fileno.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import IO, Callable + + +def get_fileno(file_like: IO[str]) -> int | None: + """Get fileno() from a file, accounting for poorly implemented file-like objects. + + Args: + file_like (IO): A file-like object. + + Returns: + int | None: The result of fileno if available, or None if operation failed. + """ + fileno: Callable[[], int] | None = getattr(file_like, "fileno", None) + if fileno is not None: + try: + return fileno() + except Exception: + # `fileno` is documented as potentially raising a OSError + # Alas, from the issues, there are so many poorly implemented file-like objects, + # that `fileno()` can raise just about anything. + return None + return None diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_inspect.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_inspect.py new file mode 100644 index 0000000..e87698d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_inspect.py @@ -0,0 +1,268 @@ +import inspect +from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature +from typing import Any, Collection, Iterable, Optional, Tuple, Type, Union + +from .console import Group, RenderableType +from .control import escape_control_codes +from .highlighter import ReprHighlighter +from .jupyter import JupyterMixin +from .panel import Panel +from .pretty import Pretty +from .table import Table +from .text import Text, TextType + + +def _first_paragraph(doc: str) -> str: + """Get the first paragraph from a docstring.""" + paragraph, _, _ = doc.partition("\n\n") + return paragraph + + +class Inspect(JupyterMixin): + """A renderable to inspect any Python Object. + + Args: + obj (Any): An object to inspect. + title (str, optional): Title to display over inspect result, or None use type. Defaults to None. + help (bool, optional): Show full help text rather than just first paragraph. Defaults to False. + methods (bool, optional): Enable inspection of callables. Defaults to False. + docs (bool, optional): Also render doc strings. Defaults to True. + private (bool, optional): Show private attributes (beginning with underscore). Defaults to False. + dunder (bool, optional): Show attributes starting with double underscore. Defaults to False. + sort (bool, optional): Sort attributes alphabetically. Defaults to True. + all (bool, optional): Show all attributes. Defaults to False. + value (bool, optional): Pretty print value of object. Defaults to True. + """ + + def __init__( + self, + obj: Any, + *, + title: Optional[TextType] = None, + help: bool = False, + methods: bool = False, + docs: bool = True, + private: bool = False, + dunder: bool = False, + sort: bool = True, + all: bool = True, + value: bool = True, + ) -> None: + self.highlighter = ReprHighlighter() + self.obj = obj + self.title = title or self._make_title(obj) + if all: + methods = private = dunder = True + self.help = help + self.methods = methods + self.docs = docs or help + self.private = private or dunder + self.dunder = dunder + self.sort = sort + self.value = value + + def _make_title(self, obj: Any) -> Text: + """Make a default title.""" + title_str = ( + str(obj) + if (isclass(obj) or callable(obj) or ismodule(obj)) + else str(type(obj)) + ) + title_text = self.highlighter(title_str) + return title_text + + def __rich__(self) -> Panel: + return Panel.fit( + Group(*self._render()), + title=self.title, + border_style="scope.border", + padding=(0, 1), + ) + + def _get_signature(self, name: str, obj: Any) -> Optional[Text]: + """Get a signature for a callable.""" + try: + _signature = str(signature(obj)) + ":" + except ValueError: + _signature = "(...)" + except TypeError: + return None + + source_filename: Optional[str] = None + try: + source_filename = getfile(obj) + except (OSError, TypeError): + # OSError is raised if obj has no source file, e.g. when defined in REPL. + pass + + callable_name = Text(name, style="inspect.callable") + if source_filename: + callable_name.stylize(f"link file://{source_filename}") + signature_text = self.highlighter(_signature) + + qualname = name or getattr(obj, "__qualname__", name) + + # If obj is a module, there may be classes (which are callable) to display + if inspect.isclass(obj): + prefix = "class" + elif inspect.iscoroutinefunction(obj): + prefix = "async def" + else: + prefix = "def" + + qual_signature = Text.assemble( + (f"{prefix} ", f"inspect.{prefix.replace(' ', '_')}"), + (qualname, "inspect.callable"), + signature_text, + ) + + return qual_signature + + def _render(self) -> Iterable[RenderableType]: + """Render object.""" + + def sort_items(item: Tuple[str, Any]) -> Tuple[bool, str]: + key, (_error, value) = item + return (callable(value), key.strip("_").lower()) + + def safe_getattr(attr_name: str) -> Tuple[Any, Any]: + """Get attribute or any exception.""" + try: + return (None, getattr(obj, attr_name)) + except Exception as error: + return (error, None) + + obj = self.obj + keys = dir(obj) + total_items = len(keys) + if not self.dunder: + keys = [key for key in keys if not key.startswith("__")] + if not self.private: + keys = [key for key in keys if not key.startswith("_")] + not_shown_count = total_items - len(keys) + items = [(key, safe_getattr(key)) for key in keys] + if self.sort: + items.sort(key=sort_items) + + items_table = Table.grid(padding=(0, 1), expand=False) + items_table.add_column(justify="right") + add_row = items_table.add_row + highlighter = self.highlighter + + if callable(obj): + signature = self._get_signature("", obj) + if signature is not None: + yield signature + yield "" + + if self.docs: + _doc = self._get_formatted_doc(obj) + if _doc is not None: + doc_text = Text(_doc, style="inspect.help") + doc_text = highlighter(doc_text) + yield doc_text + yield "" + + if self.value and not (isclass(obj) or callable(obj) or ismodule(obj)): + yield Panel( + Pretty(obj, indent_guides=True, max_length=10, max_string=60), + border_style="inspect.value.border", + ) + yield "" + + for key, (error, value) in items: + key_text = Text.assemble( + ( + key, + "inspect.attr.dunder" if key.startswith("__") else "inspect.attr", + ), + (" =", "inspect.equals"), + ) + if error is not None: + warning = key_text.copy() + warning.stylize("inspect.error") + add_row(warning, highlighter(repr(error))) + continue + + if callable(value): + if not self.methods: + continue + + _signature_text = self._get_signature(key, value) + if _signature_text is None: + add_row(key_text, Pretty(value, highlighter=highlighter)) + else: + if self.docs: + docs = self._get_formatted_doc(value) + if docs is not None: + _signature_text.append("\n" if "\n" in docs else " ") + doc = highlighter(docs) + doc.stylize("inspect.doc") + _signature_text.append(doc) + + add_row(key_text, _signature_text) + else: + add_row(key_text, Pretty(value, highlighter=highlighter)) + if items_table.row_count: + yield items_table + elif not_shown_count: + yield Text.from_markup( + f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] " + f"Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options." + ) + + def _get_formatted_doc(self, object_: Any) -> Optional[str]: + """ + Extract the docstring of an object, process it and returns it. + The processing consists in cleaning up the doctring's indentation, + taking only its 1st paragraph if `self.help` is not True, + and escape its control codes. + + Args: + object_ (Any): the object to get the docstring from. + + Returns: + Optional[str]: the processed docstring, or None if no docstring was found. + """ + docs = getdoc(object_) + if docs is None: + return None + docs = cleandoc(docs).strip() + if not self.help: + docs = _first_paragraph(docs) + return escape_control_codes(docs) + + +def get_object_types_mro(obj: Union[object, Type[Any]]) -> Tuple[type, ...]: + """Returns the MRO of an object's class, or of the object itself if it's a class.""" + if not hasattr(obj, "__mro__"): + # N.B. we cannot use `if type(obj) is type` here because it doesn't work with + # some types of classes, such as the ones that use abc.ABCMeta. + obj = type(obj) + return getattr(obj, "__mro__", ()) + + +def get_object_types_mro_as_strings(obj: object) -> Collection[str]: + """ + Returns the MRO of an object's class as full qualified names, or of the object itself if it's a class. + + Examples: + `object_types_mro_as_strings(JSONDecoder)` will return `['json.decoder.JSONDecoder', 'builtins.object']` + """ + return [ + f'{getattr(type_, "__module__", "")}.{getattr(type_, "__qualname__", "")}' + for type_ in get_object_types_mro(obj) + ] + + +def is_object_one_of_types( + obj: object, fully_qualified_types_names: Collection[str] +) -> bool: + """ + Returns `True` if the given object's class (or the object itself, if it's a class) has one of the + fully qualified names in its MRO. + """ + for type_name in get_object_types_mro_as_strings(obj): + if type_name in fully_qualified_types_names: + return True + return False diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_log_render.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_log_render.py new file mode 100644 index 0000000..fc16c84 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_log_render.py @@ -0,0 +1,94 @@ +from datetime import datetime +from typing import Iterable, List, Optional, TYPE_CHECKING, Union, Callable + + +from .text import Text, TextType + +if TYPE_CHECKING: + from .console import Console, ConsoleRenderable, RenderableType + from .table import Table + +FormatTimeCallable = Callable[[datetime], Text] + + +class LogRender: + def __init__( + self, + show_time: bool = True, + show_level: bool = False, + show_path: bool = True, + time_format: Union[str, FormatTimeCallable] = "[%x %X]", + omit_repeated_times: bool = True, + level_width: Optional[int] = 8, + ) -> None: + self.show_time = show_time + self.show_level = show_level + self.show_path = show_path + self.time_format = time_format + self.omit_repeated_times = omit_repeated_times + self.level_width = level_width + self._last_time: Optional[Text] = None + + def __call__( + self, + console: "Console", + renderables: Iterable["ConsoleRenderable"], + log_time: Optional[datetime] = None, + time_format: Optional[Union[str, FormatTimeCallable]] = None, + level: TextType = "", + path: Optional[str] = None, + line_no: Optional[int] = None, + link_path: Optional[str] = None, + ) -> "Table": + from .containers import Renderables + from .table import Table + + output = Table.grid(padding=(0, 1)) + output.expand = True + if self.show_time: + output.add_column(style="log.time") + if self.show_level: + output.add_column(style="log.level", width=self.level_width) + output.add_column(ratio=1, style="log.message", overflow="fold") + if self.show_path and path: + output.add_column(style="log.path") + row: List["RenderableType"] = [] + if self.show_time: + log_time = log_time or console.get_datetime() + time_format = time_format or self.time_format + if callable(time_format): + log_time_display = time_format(log_time) + else: + log_time_display = Text(log_time.strftime(time_format)) + if log_time_display == self._last_time and self.omit_repeated_times: + row.append(Text(" " * len(log_time_display))) + else: + row.append(log_time_display) + self._last_time = log_time_display + if self.show_level: + row.append(level) + + row.append(Renderables(renderables)) + if self.show_path and path: + path_text = Text() + path_text.append( + path, style=f"link file://{link_path}" if link_path else "" + ) + if line_no: + path_text.append(":") + path_text.append( + f"{line_no}", + style=f"link file://{link_path}#{line_no}" if link_path else "", + ) + row.append(path_text) + + output.add_row(*row) + return output + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + + c = Console() + c.print("[on blue]Hello", justify="right") + c.log("[on blue]hello", justify="right") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_loop.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_loop.py new file mode 100644 index 0000000..01c6caf --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_loop.py @@ -0,0 +1,43 @@ +from typing import Iterable, Tuple, TypeVar + +T = TypeVar("T") + + +def loop_first(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for first value.""" + iter_values = iter(values) + try: + value = next(iter_values) + except StopIteration: + return + yield True, value + for value in iter_values: + yield False, value + + +def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value + + +def loop_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]: + """Iterate and generate a tuple with a flag for first and last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + first = True + for value in iter_values: + yield first, False, previous_value + first = False + previous_value = value + yield first, True, previous_value diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_null_file.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_null_file.py new file mode 100644 index 0000000..6ae05d3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_null_file.py @@ -0,0 +1,69 @@ +from types import TracebackType +from typing import IO, Iterable, Iterator, List, Optional, Type + + +class NullFile(IO[str]): + def close(self) -> None: + pass + + def isatty(self) -> bool: + return False + + def read(self, __n: int = 1) -> str: + return "" + + def readable(self) -> bool: + return False + + def readline(self, __limit: int = 1) -> str: + return "" + + def readlines(self, __hint: int = 1) -> List[str]: + return [] + + def seek(self, __offset: int, __whence: int = 1) -> int: + return 0 + + def seekable(self) -> bool: + return False + + def tell(self) -> int: + return 0 + + def truncate(self, __size: Optional[int] = 1) -> int: + return 0 + + def writable(self) -> bool: + return False + + def writelines(self, __lines: Iterable[str]) -> None: + pass + + def __next__(self) -> str: + return "" + + def __iter__(self) -> Iterator[str]: + return iter([""]) + + def __enter__(self) -> IO[str]: + return self + + def __exit__( + self, + __t: Optional[Type[BaseException]], + __value: Optional[BaseException], + __traceback: Optional[TracebackType], + ) -> None: + pass + + def write(self, text: str) -> int: + return 0 + + def flush(self) -> None: + pass + + def fileno(self) -> int: + return -1 + + +NULL_FILE = NullFile() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_palettes.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_palettes.py new file mode 100644 index 0000000..3c748d3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_palettes.py @@ -0,0 +1,309 @@ +from .palette import Palette + + +# Taken from https://en.wikipedia.org/wiki/ANSI_escape_code (Windows 10 column) +WINDOWS_PALETTE = Palette( + [ + (12, 12, 12), + (197, 15, 31), + (19, 161, 14), + (193, 156, 0), + (0, 55, 218), + (136, 23, 152), + (58, 150, 221), + (204, 204, 204), + (118, 118, 118), + (231, 72, 86), + (22, 198, 12), + (249, 241, 165), + (59, 120, 255), + (180, 0, 158), + (97, 214, 214), + (242, 242, 242), + ] +) + +# # The standard ansi colors (including bright variants) +STANDARD_PALETTE = Palette( + [ + (0, 0, 0), + (170, 0, 0), + (0, 170, 0), + (170, 85, 0), + (0, 0, 170), + (170, 0, 170), + (0, 170, 170), + (170, 170, 170), + (85, 85, 85), + (255, 85, 85), + (85, 255, 85), + (255, 255, 85), + (85, 85, 255), + (255, 85, 255), + (85, 255, 255), + (255, 255, 255), + ] +) + + +# The 256 color palette +EIGHT_BIT_PALETTE = Palette( + [ + (0, 0, 0), + (128, 0, 0), + (0, 128, 0), + (128, 128, 0), + (0, 0, 128), + (128, 0, 128), + (0, 128, 128), + (192, 192, 192), + (128, 128, 128), + (255, 0, 0), + (0, 255, 0), + (255, 255, 0), + (0, 0, 255), + (255, 0, 255), + (0, 255, 255), + (255, 255, 255), + (0, 0, 0), + (0, 0, 95), + (0, 0, 135), + (0, 0, 175), + (0, 0, 215), + (0, 0, 255), + (0, 95, 0), + (0, 95, 95), + (0, 95, 135), + (0, 95, 175), + (0, 95, 215), + (0, 95, 255), + (0, 135, 0), + (0, 135, 95), + (0, 135, 135), + (0, 135, 175), + (0, 135, 215), + (0, 135, 255), + (0, 175, 0), + (0, 175, 95), + (0, 175, 135), + (0, 175, 175), + (0, 175, 215), + (0, 175, 255), + (0, 215, 0), + (0, 215, 95), + (0, 215, 135), + (0, 215, 175), + (0, 215, 215), + (0, 215, 255), + (0, 255, 0), + (0, 255, 95), + (0, 255, 135), + (0, 255, 175), + (0, 255, 215), + (0, 255, 255), + (95, 0, 0), + (95, 0, 95), + (95, 0, 135), + (95, 0, 175), + (95, 0, 215), + (95, 0, 255), + (95, 95, 0), + (95, 95, 95), + (95, 95, 135), + (95, 95, 175), + (95, 95, 215), + (95, 95, 255), + (95, 135, 0), + (95, 135, 95), + (95, 135, 135), + (95, 135, 175), + (95, 135, 215), + (95, 135, 255), + (95, 175, 0), + (95, 175, 95), + (95, 175, 135), + (95, 175, 175), + (95, 175, 215), + (95, 175, 255), + (95, 215, 0), + (95, 215, 95), + (95, 215, 135), + (95, 215, 175), + (95, 215, 215), + (95, 215, 255), + (95, 255, 0), + (95, 255, 95), + (95, 255, 135), + (95, 255, 175), + (95, 255, 215), + (95, 255, 255), + (135, 0, 0), + (135, 0, 95), + (135, 0, 135), + (135, 0, 175), + (135, 0, 215), + (135, 0, 255), + (135, 95, 0), + (135, 95, 95), + (135, 95, 135), + (135, 95, 175), + (135, 95, 215), + (135, 95, 255), + (135, 135, 0), + (135, 135, 95), + (135, 135, 135), + (135, 135, 175), + (135, 135, 215), + (135, 135, 255), + (135, 175, 0), + (135, 175, 95), + (135, 175, 135), + (135, 175, 175), + (135, 175, 215), + (135, 175, 255), + (135, 215, 0), + (135, 215, 95), + (135, 215, 135), + (135, 215, 175), + (135, 215, 215), + (135, 215, 255), + (135, 255, 0), + (135, 255, 95), + (135, 255, 135), + (135, 255, 175), + (135, 255, 215), + (135, 255, 255), + (175, 0, 0), + (175, 0, 95), + (175, 0, 135), + (175, 0, 175), + (175, 0, 215), + (175, 0, 255), + (175, 95, 0), + (175, 95, 95), + (175, 95, 135), + (175, 95, 175), + (175, 95, 215), + (175, 95, 255), + (175, 135, 0), + (175, 135, 95), + (175, 135, 135), + (175, 135, 175), + (175, 135, 215), + (175, 135, 255), + (175, 175, 0), + (175, 175, 95), + (175, 175, 135), + (175, 175, 175), + (175, 175, 215), + (175, 175, 255), + (175, 215, 0), + (175, 215, 95), + (175, 215, 135), + (175, 215, 175), + (175, 215, 215), + (175, 215, 255), + (175, 255, 0), + (175, 255, 95), + (175, 255, 135), + (175, 255, 175), + (175, 255, 215), + (175, 255, 255), + (215, 0, 0), + (215, 0, 95), + (215, 0, 135), + (215, 0, 175), + (215, 0, 215), + (215, 0, 255), + (215, 95, 0), + (215, 95, 95), + (215, 95, 135), + (215, 95, 175), + (215, 95, 215), + (215, 95, 255), + (215, 135, 0), + (215, 135, 95), + (215, 135, 135), + (215, 135, 175), + (215, 135, 215), + (215, 135, 255), + (215, 175, 0), + (215, 175, 95), + (215, 175, 135), + (215, 175, 175), + (215, 175, 215), + (215, 175, 255), + (215, 215, 0), + (215, 215, 95), + (215, 215, 135), + (215, 215, 175), + (215, 215, 215), + (215, 215, 255), + (215, 255, 0), + (215, 255, 95), + (215, 255, 135), + (215, 255, 175), + (215, 255, 215), + (215, 255, 255), + (255, 0, 0), + (255, 0, 95), + (255, 0, 135), + (255, 0, 175), + (255, 0, 215), + (255, 0, 255), + (255, 95, 0), + (255, 95, 95), + (255, 95, 135), + (255, 95, 175), + (255, 95, 215), + (255, 95, 255), + (255, 135, 0), + (255, 135, 95), + (255, 135, 135), + (255, 135, 175), + (255, 135, 215), + (255, 135, 255), + (255, 175, 0), + (255, 175, 95), + (255, 175, 135), + (255, 175, 175), + (255, 175, 215), + (255, 175, 255), + (255, 215, 0), + (255, 215, 95), + (255, 215, 135), + (255, 215, 175), + (255, 215, 215), + (255, 215, 255), + (255, 255, 0), + (255, 255, 95), + (255, 255, 135), + (255, 255, 175), + (255, 255, 215), + (255, 255, 255), + (8, 8, 8), + (18, 18, 18), + (28, 28, 28), + (38, 38, 38), + (48, 48, 48), + (58, 58, 58), + (68, 68, 68), + (78, 78, 78), + (88, 88, 88), + (98, 98, 98), + (108, 108, 108), + (118, 118, 118), + (128, 128, 128), + (138, 138, 138), + (148, 148, 148), + (158, 158, 158), + (168, 168, 168), + (178, 178, 178), + (188, 188, 188), + (198, 198, 198), + (208, 208, 208), + (218, 218, 218), + (228, 228, 228), + (238, 238, 238), + ] +) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_pick.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_pick.py new file mode 100644 index 0000000..4f6d8b2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_pick.py @@ -0,0 +1,17 @@ +from typing import Optional + + +def pick_bool(*values: Optional[bool]) -> bool: + """Pick the first non-none bool or return the last value. + + Args: + *values (bool): Any number of boolean or None values. + + Returns: + bool: First non-none boolean. + """ + assert values, "1 or more values required" + for value in values: + if value is not None: + return value + return bool(value) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_ratio.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_ratio.py new file mode 100644 index 0000000..95267b0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_ratio.py @@ -0,0 +1,159 @@ +import sys +from fractions import Fraction +from math import ceil +from typing import cast, List, Optional, Sequence + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from pip._vendor.typing_extensions import Protocol # pragma: no cover + + +class Edge(Protocol): + """Any object that defines an edge (such as Layout).""" + + size: Optional[int] = None + ratio: int = 1 + minimum_size: int = 1 + + +def ratio_resolve(total: int, edges: Sequence[Edge]) -> List[int]: + """Divide total space to satisfy size, ratio, and minimum_size, constraints. + + The returned list of integers should add up to total in most cases, unless it is + impossible to satisfy all the constraints. For instance, if there are two edges + with a minimum size of 20 each and `total` is 30 then the returned list will be + greater than total. In practice, this would mean that a Layout object would + clip the rows that would overflow the screen height. + + Args: + total (int): Total number of characters. + edges (List[Edge]): Edges within total space. + + Returns: + List[int]: Number of characters for each edge. + """ + # Size of edge or None for yet to be determined + sizes = [(edge.size or None) for edge in edges] + + _Fraction = Fraction + + # While any edges haven't been calculated + while None in sizes: + # Get flexible edges and index to map these back on to sizes list + flexible_edges = [ + (index, edge) + for index, (size, edge) in enumerate(zip(sizes, edges)) + if size is None + ] + # Remaining space in total + remaining = total - sum(size or 0 for size in sizes) + if remaining <= 0: + # No room for flexible edges + return [ + ((edge.minimum_size or 1) if size is None else size) + for size, edge in zip(sizes, edges) + ] + # Calculate number of characters in a ratio portion + portion = _Fraction( + remaining, sum((edge.ratio or 1) for _, edge in flexible_edges) + ) + + # If any edges will be less than their minimum, replace size with the minimum + for index, edge in flexible_edges: + if portion * edge.ratio <= edge.minimum_size: + sizes[index] = edge.minimum_size + # New fixed size will invalidate calculations, so we need to repeat the process + break + else: + # Distribute flexible space and compensate for rounding error + # Since edge sizes can only be integers we need to add the remainder + # to the following line + remainder = _Fraction(0) + for index, edge in flexible_edges: + size, remainder = divmod(portion * edge.ratio + remainder, 1) + sizes[index] = size + break + # Sizes now contains integers only + return cast(List[int], sizes) + + +def ratio_reduce( + total: int, ratios: List[int], maximums: List[int], values: List[int] +) -> List[int]: + """Divide an integer total in to parts based on ratios. + + Args: + total (int): The total to divide. + ratios (List[int]): A list of integer ratios. + maximums (List[int]): List of maximums values for each slot. + values (List[int]): List of values + + Returns: + List[int]: A list of integers guaranteed to sum to total. + """ + ratios = [ratio if _max else 0 for ratio, _max in zip(ratios, maximums)] + total_ratio = sum(ratios) + if not total_ratio: + return values[:] + total_remaining = total + result: List[int] = [] + append = result.append + for ratio, maximum, value in zip(ratios, maximums, values): + if ratio and total_ratio > 0: + distributed = min(maximum, round(ratio * total_remaining / total_ratio)) + append(value - distributed) + total_remaining -= distributed + total_ratio -= ratio + else: + append(value) + return result + + +def ratio_distribute( + total: int, ratios: List[int], minimums: Optional[List[int]] = None +) -> List[int]: + """Distribute an integer total in to parts based on ratios. + + Args: + total (int): The total to divide. + ratios (List[int]): A list of integer ratios. + minimums (List[int]): List of minimum values for each slot. + + Returns: + List[int]: A list of integers guaranteed to sum to total. + """ + if minimums: + ratios = [ratio if _min else 0 for ratio, _min in zip(ratios, minimums)] + total_ratio = sum(ratios) + assert total_ratio > 0, "Sum of ratios must be > 0" + + total_remaining = total + distributed_total: List[int] = [] + append = distributed_total.append + if minimums is None: + _minimums = [0] * len(ratios) + else: + _minimums = minimums + for ratio, minimum in zip(ratios, _minimums): + if total_ratio > 0: + distributed = max(minimum, ceil(ratio * total_remaining / total_ratio)) + else: + distributed = total_remaining + append(distributed) + total_ratio -= ratio + total_remaining -= distributed + return distributed_total + + +if __name__ == "__main__": + from dataclasses import dataclass + + @dataclass + class E: + size: Optional[int] = None + ratio: int = 1 + minimum_size: int = 1 + + resolved = ratio_resolve(110, [E(None, 1, 1), E(None, 1, 1), E(None, 1, 1)]) + print(sum(resolved)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_spinners.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_spinners.py new file mode 100644 index 0000000..d0bb1fe --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_spinners.py @@ -0,0 +1,482 @@ +""" +Spinners are from: +* cli-spinners: + MIT License + Copyright (c) Sindre Sorhus (sindresorhus.com) + 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. +""" + +SPINNERS = { + "dots": { + "interval": 80, + "frames": "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏", + }, + "dots2": {"interval": 80, "frames": "⣾⣽⣻⢿⡿⣟⣯⣷"}, + "dots3": { + "interval": 80, + "frames": "⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓", + }, + "dots4": { + "interval": 80, + "frames": "⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆", + }, + "dots5": { + "interval": 80, + "frames": "⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋", + }, + "dots6": { + "interval": 80, + "frames": "⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁", + }, + "dots7": { + "interval": 80, + "frames": "⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈", + }, + "dots8": { + "interval": 80, + "frames": "⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈", + }, + "dots9": {"interval": 80, "frames": "⢹⢺⢼⣸⣇⡧⡗⡏"}, + "dots10": {"interval": 80, "frames": "⢄⢂⢁⡁⡈⡐⡠"}, + "dots11": {"interval": 100, "frames": "⠁⠂⠄⡀⢀⠠⠐⠈"}, + "dots12": { + "interval": 80, + "frames": [ + "⢀⠀", + "⡀⠀", + "⠄⠀", + "⢂⠀", + "⡂⠀", + "⠅⠀", + "⢃⠀", + "⡃⠀", + "⠍⠀", + "⢋⠀", + "⡋⠀", + "⠍⠁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⢈⠩", + "⡀⢙", + "⠄⡙", + "⢂⠩", + "⡂⢘", + "⠅⡘", + "⢃⠨", + "⡃⢐", + "⠍⡐", + "⢋⠠", + "⡋⢀", + "⠍⡁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⠈⠩", + "⠀⢙", + "⠀⡙", + "⠀⠩", + "⠀⢘", + "⠀⡘", + "⠀⠨", + "⠀⢐", + "⠀⡐", + "⠀⠠", + "⠀⢀", + "⠀⡀", + ], + }, + "dots8Bit": { + "interval": 80, + "frames": "⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙" + "⡚⡛⡜⡝⡞⡟⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻" + "⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕" + "⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷" + "⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿", + }, + "line": {"interval": 130, "frames": ["-", "\\", "|", "/"]}, + "line2": {"interval": 100, "frames": "⠂-–—–-"}, + "pipe": {"interval": 100, "frames": "┤┘┴└├┌┬┐"}, + "simpleDots": {"interval": 400, "frames": [". ", ".. ", "...", " "]}, + "simpleDotsScrolling": { + "interval": 200, + "frames": [". ", ".. ", "...", " ..", " .", " "], + }, + "star": {"interval": 70, "frames": "✶✸✹✺✹✷"}, + "star2": {"interval": 80, "frames": "+x*"}, + "flip": { + "interval": 70, + "frames": "___-``'´-___", + }, + "hamburger": {"interval": 100, "frames": "☱☲☴"}, + "growVertical": { + "interval": 120, + "frames": "▁▃▄▅▆▇▆▅▄▃", + }, + "growHorizontal": { + "interval": 120, + "frames": "▏▎▍▌▋▊▉▊▋▌▍▎", + }, + "balloon": {"interval": 140, "frames": " .oO@* "}, + "balloon2": {"interval": 120, "frames": ".oO°Oo."}, + "noise": {"interval": 100, "frames": "▓▒░"}, + "bounce": {"interval": 120, "frames": "⠁⠂⠄⠂"}, + "boxBounce": {"interval": 120, "frames": "▖▘▝▗"}, + "boxBounce2": {"interval": 100, "frames": "▌▀▐▄"}, + "triangle": {"interval": 50, "frames": "◢◣◤◥"}, + "arc": {"interval": 100, "frames": "◜◠◝◞◡◟"}, + "circle": {"interval": 120, "frames": "◡⊙◠"}, + "squareCorners": {"interval": 180, "frames": "◰◳◲◱"}, + "circleQuarters": {"interval": 120, "frames": "◴◷◶◵"}, + "circleHalves": {"interval": 50, "frames": "◐◓◑◒"}, + "squish": {"interval": 100, "frames": "╫╪"}, + "toggle": {"interval": 250, "frames": "⊶⊷"}, + "toggle2": {"interval": 80, "frames": "▫▪"}, + "toggle3": {"interval": 120, "frames": "□■"}, + "toggle4": {"interval": 100, "frames": "■□▪▫"}, + "toggle5": {"interval": 100, "frames": "▮▯"}, + "toggle6": {"interval": 300, "frames": "ဝ၀"}, + "toggle7": {"interval": 80, "frames": "⦾⦿"}, + "toggle8": {"interval": 100, "frames": "◍◌"}, + "toggle9": {"interval": 100, "frames": "◉◎"}, + "toggle10": {"interval": 100, "frames": "㊂㊀㊁"}, + "toggle11": {"interval": 50, "frames": "⧇⧆"}, + "toggle12": {"interval": 120, "frames": "☗☖"}, + "toggle13": {"interval": 80, "frames": "=*-"}, + "arrow": {"interval": 100, "frames": "←↖↑↗→↘↓↙"}, + "arrow2": { + "interval": 80, + "frames": ["⬆️ ", "↗️ ", "➡️ ", "↘️ ", "⬇️ ", "↙️ ", "⬅️ ", "↖️ "], + }, + "arrow3": { + "interval": 120, + "frames": ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"], + }, + "bouncingBar": { + "interval": 80, + "frames": [ + "[ ]", + "[= ]", + "[== ]", + "[=== ]", + "[ ===]", + "[ ==]", + "[ =]", + "[ ]", + "[ =]", + "[ ==]", + "[ ===]", + "[====]", + "[=== ]", + "[== ]", + "[= ]", + ], + }, + "bouncingBall": { + "interval": 80, + "frames": [ + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "( ●)", + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "(● )", + ], + }, + "smiley": {"interval": 200, "frames": ["😄 ", "😝 "]}, + "monkey": {"interval": 300, "frames": ["🙈 ", "🙈 ", "🙉 ", "🙊 "]}, + "hearts": {"interval": 100, "frames": ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "]}, + "clock": { + "interval": 100, + "frames": [ + "🕛 ", + "🕐 ", + "🕑 ", + "🕒 ", + "🕓 ", + "🕔 ", + "🕕 ", + "🕖 ", + "🕗 ", + "🕘 ", + "🕙 ", + "🕚 ", + ], + }, + "earth": {"interval": 180, "frames": ["🌍 ", "🌎 ", "🌏 "]}, + "material": { + "interval": 17, + "frames": [ + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "██████████▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "█████████████▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁██████████████▁▁▁▁", + "▁▁▁██████████████▁▁▁", + "▁▁▁▁█████████████▁▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁▁▁████████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁▁█████████████▁▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁▁███████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁▁█████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + ], + }, + "moon": { + "interval": 80, + "frames": ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "], + }, + "runner": {"interval": 140, "frames": ["🚶 ", "🏃 "]}, + "pong": { + "interval": 80, + "frames": [ + "▐⠂ ▌", + "▐⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂▌", + "▐ ⠠▌", + "▐ ⡀▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐⠠ ▌", + ], + }, + "shark": { + "interval": 120, + "frames": [ + "▐|\\____________▌", + "▐_|\\___________▌", + "▐__|\\__________▌", + "▐___|\\_________▌", + "▐____|\\________▌", + "▐_____|\\_______▌", + "▐______|\\______▌", + "▐_______|\\_____▌", + "▐________|\\____▌", + "▐_________|\\___▌", + "▐__________|\\__▌", + "▐___________|\\_▌", + "▐____________|\\▌", + "▐____________/|▌", + "▐___________/|_▌", + "▐__________/|__▌", + "▐_________/|___▌", + "▐________/|____▌", + "▐_______/|_____▌", + "▐______/|______▌", + "▐_____/|_______▌", + "▐____/|________▌", + "▐___/|_________▌", + "▐__/|__________▌", + "▐_/|___________▌", + "▐/|____________▌", + ], + }, + "dqpb": {"interval": 100, "frames": "dqpb"}, + "weather": { + "interval": 100, + "frames": [ + "☀️ ", + "☀️ ", + "☀️ ", + "🌤 ", + "⛅️ ", + "🌥 ", + "☁️ ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "⛈ ", + "🌨 ", + "🌧 ", + "🌨 ", + "☁️ ", + "🌥 ", + "⛅️ ", + "🌤 ", + "☀️ ", + "☀️ ", + ], + }, + "christmas": {"interval": 400, "frames": "🌲🎄"}, + "grenade": { + "interval": 80, + "frames": [ + "، ", + "′ ", + " ´ ", + " ‾ ", + " ⸌", + " ⸊", + " |", + " ⁎", + " ⁕", + " ෴ ", + " ⁓", + " ", + " ", + " ", + ], + }, + "point": {"interval": 125, "frames": ["∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"]}, + "layer": {"interval": 150, "frames": "-=≡"}, + "betaWave": { + "interval": 80, + "frames": [ + "ρββββββ", + "βρβββββ", + "ββρββββ", + "βββρβββ", + "ββββρββ", + "βββββρβ", + "ββββββρ", + ], + }, + "aesthetic": { + "interval": 80, + "frames": [ + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▰▱▱▱▱▱▱", + ], + }, +} diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_stack.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_stack.py new file mode 100644 index 0000000..194564e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_stack.py @@ -0,0 +1,16 @@ +from typing import List, TypeVar + +T = TypeVar("T") + + +class Stack(List[T]): + """A small shim over builtin list.""" + + @property + def top(self) -> T: + """Get top of stack.""" + return self[-1] + + def push(self, item: T) -> None: + """Push an item on to the stack (append in stack nomenclature).""" + self.append(item) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_timer.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_timer.py new file mode 100644 index 0000000..a2ca6be --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_timer.py @@ -0,0 +1,19 @@ +""" +Timer context manager, only used in debug. + +""" + +from time import time + +import contextlib +from typing import Generator + + +@contextlib.contextmanager +def timer(subject: str = "time") -> Generator[None, None, None]: + """print the elapsed time. (only used in debugging)""" + start = time() + yield + elapsed = time() - start + elapsed_ms = elapsed * 1000 + print(f"{subject} elapsed {elapsed_ms:.1f}ms") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py new file mode 100644 index 0000000..2eba1b9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py @@ -0,0 +1,661 @@ +"""Light wrapper around the Win32 Console API - this module should only be imported on Windows + +The API that this module wraps is documented at https://docs.microsoft.com/en-us/windows/console/console-functions +""" + +import ctypes +import sys +from typing import Any + +windll: Any = None +if sys.platform == "win32": + windll = ctypes.LibraryLoader(ctypes.WinDLL) +else: + raise ImportError(f"{__name__} can only be imported on Windows") + +import time +from ctypes import Structure, byref, wintypes +from typing import IO, NamedTuple, Type, cast + +from pip._vendor.rich.color import ColorSystem +from pip._vendor.rich.style import Style + +STDOUT = -11 +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 + +COORD = wintypes._COORD + + +class LegacyWindowsError(Exception): + pass + + +class WindowsCoordinates(NamedTuple): + """Coordinates in the Windows Console API are (y, x), not (x, y). + This class is intended to prevent that confusion. + Rows and columns are indexed from 0. + This class can be used in place of wintypes._COORD in arguments and argtypes. + """ + + row: int + col: int + + @classmethod + def from_param(cls, value: "WindowsCoordinates") -> COORD: + """Converts a WindowsCoordinates into a wintypes _COORD structure. + This classmethod is internally called by ctypes to perform the conversion. + + Args: + value (WindowsCoordinates): The input coordinates to convert. + + Returns: + wintypes._COORD: The converted coordinates struct. + """ + return COORD(value.col, value.row) + + +class CONSOLE_SCREEN_BUFFER_INFO(Structure): + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + + +class CONSOLE_CURSOR_INFO(ctypes.Structure): + _fields_ = [("dwSize", wintypes.DWORD), ("bVisible", wintypes.BOOL)] + + +_GetStdHandle = windll.kernel32.GetStdHandle +_GetStdHandle.argtypes = [ + wintypes.DWORD, +] +_GetStdHandle.restype = wintypes.HANDLE + + +def GetStdHandle(handle: int = STDOUT) -> wintypes.HANDLE: + """Retrieves a handle to the specified standard device (standard input, standard output, or standard error). + + Args: + handle (int): Integer identifier for the handle. Defaults to -11 (stdout). + + Returns: + wintypes.HANDLE: The handle + """ + return cast(wintypes.HANDLE, _GetStdHandle(handle)) + + +_GetConsoleMode = windll.kernel32.GetConsoleMode +_GetConsoleMode.argtypes = [wintypes.HANDLE, wintypes.LPDWORD] +_GetConsoleMode.restype = wintypes.BOOL + + +def GetConsoleMode(std_handle: wintypes.HANDLE) -> int: + """Retrieves the current input mode of a console's input buffer + or the current output mode of a console screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + + Raises: + LegacyWindowsError: If any error occurs while calling the Windows console API. + + Returns: + int: Value representing the current console mode as documented at + https://docs.microsoft.com/en-us/windows/console/getconsolemode#parameters + """ + + console_mode = wintypes.DWORD() + success = bool(_GetConsoleMode(std_handle, console_mode)) + if not success: + raise LegacyWindowsError("Unable to get legacy Windows Console Mode") + return console_mode.value + + +_FillConsoleOutputCharacterW = windll.kernel32.FillConsoleOutputCharacterW +_FillConsoleOutputCharacterW.argtypes = [ + wintypes.HANDLE, + ctypes.c_char, + wintypes.DWORD, + cast(Type[COORD], WindowsCoordinates), + ctypes.POINTER(wintypes.DWORD), +] +_FillConsoleOutputCharacterW.restype = wintypes.BOOL + + +def FillConsoleOutputCharacter( + std_handle: wintypes.HANDLE, + char: str, + length: int, + start: WindowsCoordinates, +) -> int: + """Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + char (str): The character to write. Must be a string of length 1. + length (int): The number of times to write the character. + start (WindowsCoordinates): The coordinates to start writing at. + + Returns: + int: The number of characters written. + """ + character = ctypes.c_char(char.encode()) + num_characters = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + _FillConsoleOutputCharacterW( + std_handle, + character, + num_characters, + start, + byref(num_written), + ) + return num_written.value + + +_FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute +_FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + cast(Type[COORD], WindowsCoordinates), + ctypes.POINTER(wintypes.DWORD), +] +_FillConsoleOutputAttribute.restype = wintypes.BOOL + + +def FillConsoleOutputAttribute( + std_handle: wintypes.HANDLE, + attributes: int, + length: int, + start: WindowsCoordinates, +) -> int: + """Sets the character attributes for a specified number of character cells, + beginning at the specified coordinates in a screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + attributes (int): Integer value representing the foreground and background colours of the cells. + length (int): The number of cells to set the output attribute of. + start (WindowsCoordinates): The coordinates of the first cell whose attributes are to be set. + + Returns: + int: The number of cells whose attributes were actually set. + """ + num_cells = wintypes.DWORD(length) + style_attrs = wintypes.WORD(attributes) + num_written = wintypes.DWORD(0) + _FillConsoleOutputAttribute( + std_handle, style_attrs, num_cells, start, byref(num_written) + ) + return num_written.value + + +_SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute +_SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, +] +_SetConsoleTextAttribute.restype = wintypes.BOOL + + +def SetConsoleTextAttribute( + std_handle: wintypes.HANDLE, attributes: wintypes.WORD +) -> bool: + """Set the colour attributes for all text written after this function is called. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + attributes (int): Integer value representing the foreground and background colours. + + + Returns: + bool: True if the attribute was set successfully, otherwise False. + """ + return bool(_SetConsoleTextAttribute(std_handle, attributes)) + + +_GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo +_GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_SCREEN_BUFFER_INFO), +] +_GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + +def GetConsoleScreenBufferInfo( + std_handle: wintypes.HANDLE, +) -> CONSOLE_SCREEN_BUFFER_INFO: + """Retrieves information about the specified console screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + + Returns: + CONSOLE_SCREEN_BUFFER_INFO: A CONSOLE_SCREEN_BUFFER_INFO ctype struct contain information about + screen size, cursor position, colour attributes, and more.""" + console_screen_buffer_info = CONSOLE_SCREEN_BUFFER_INFO() + _GetConsoleScreenBufferInfo(std_handle, byref(console_screen_buffer_info)) + return console_screen_buffer_info + + +_SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition +_SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + cast(Type[COORD], WindowsCoordinates), +] +_SetConsoleCursorPosition.restype = wintypes.BOOL + + +def SetConsoleCursorPosition( + std_handle: wintypes.HANDLE, coords: WindowsCoordinates +) -> bool: + """Set the position of the cursor in the console screen + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + coords (WindowsCoordinates): The coordinates to move the cursor to. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleCursorPosition(std_handle, coords)) + + +_GetConsoleCursorInfo = windll.kernel32.GetConsoleCursorInfo +_GetConsoleCursorInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_CURSOR_INFO), +] +_GetConsoleCursorInfo.restype = wintypes.BOOL + + +def GetConsoleCursorInfo( + std_handle: wintypes.HANDLE, cursor_info: CONSOLE_CURSOR_INFO +) -> bool: + """Get the cursor info - used to get cursor visibility and width + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + cursor_info (CONSOLE_CURSOR_INFO): CONSOLE_CURSOR_INFO ctype struct that receives information + about the console's cursor. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_GetConsoleCursorInfo(std_handle, byref(cursor_info))) + + +_SetConsoleCursorInfo = windll.kernel32.SetConsoleCursorInfo +_SetConsoleCursorInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_CURSOR_INFO), +] +_SetConsoleCursorInfo.restype = wintypes.BOOL + + +def SetConsoleCursorInfo( + std_handle: wintypes.HANDLE, cursor_info: CONSOLE_CURSOR_INFO +) -> bool: + """Set the cursor info - used for adjusting cursor visibility and width + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + cursor_info (CONSOLE_CURSOR_INFO): CONSOLE_CURSOR_INFO ctype struct containing the new cursor info. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleCursorInfo(std_handle, byref(cursor_info))) + + +_SetConsoleTitle = windll.kernel32.SetConsoleTitleW +_SetConsoleTitle.argtypes = [wintypes.LPCWSTR] +_SetConsoleTitle.restype = wintypes.BOOL + + +def SetConsoleTitle(title: str) -> bool: + """Sets the title of the current console window + + Args: + title (str): The new title of the console window. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleTitle(title)) + + +class LegacyWindowsTerm: + """This class allows interaction with the legacy Windows Console API. It should only be used in the context + of environments where virtual terminal processing is not available. However, if it is used in a Windows environment, + the entire API should work. + + Args: + file (IO[str]): The file which the Windows Console API HANDLE is retrieved from, defaults to sys.stdout. + """ + + BRIGHT_BIT = 8 + + # Indices are ANSI color numbers, values are the corresponding Windows Console API color numbers + ANSI_TO_WINDOWS = [ + 0, # black The Windows colours are defined in wincon.h as follows: + 4, # red define FOREGROUND_BLUE 0x0001 -- 0000 0001 + 2, # green define FOREGROUND_GREEN 0x0002 -- 0000 0010 + 6, # yellow define FOREGROUND_RED 0x0004 -- 0000 0100 + 1, # blue define FOREGROUND_INTENSITY 0x0008 -- 0000 1000 + 5, # magenta define BACKGROUND_BLUE 0x0010 -- 0001 0000 + 3, # cyan define BACKGROUND_GREEN 0x0020 -- 0010 0000 + 7, # white define BACKGROUND_RED 0x0040 -- 0100 0000 + 8, # bright black (grey) define BACKGROUND_INTENSITY 0x0080 -- 1000 0000 + 12, # bright red + 10, # bright green + 14, # bright yellow + 9, # bright blue + 13, # bright magenta + 11, # bright cyan + 15, # bright white + ] + + def __init__(self, file: "IO[str]") -> None: + handle = GetStdHandle(STDOUT) + self._handle = handle + default_text = GetConsoleScreenBufferInfo(handle).wAttributes + self._default_text = default_text + + self._default_fore = default_text & 7 + self._default_back = (default_text >> 4) & 7 + self._default_attrs = self._default_fore | (self._default_back << 4) + + self._file = file + self.write = file.write + self.flush = file.flush + + @property + def cursor_position(self) -> WindowsCoordinates: + """Returns the current position of the cursor (0-based) + + Returns: + WindowsCoordinates: The current cursor position. + """ + coord: COORD = GetConsoleScreenBufferInfo(self._handle).dwCursorPosition + return WindowsCoordinates(row=coord.Y, col=coord.X) + + @property + def screen_size(self) -> WindowsCoordinates: + """Returns the current size of the console screen buffer, in character columns and rows + + Returns: + WindowsCoordinates: The width and height of the screen as WindowsCoordinates. + """ + screen_size: COORD = GetConsoleScreenBufferInfo(self._handle).dwSize + return WindowsCoordinates(row=screen_size.Y, col=screen_size.X) + + def write_text(self, text: str) -> None: + """Write text directly to the terminal without any modification of styles + + Args: + text (str): The text to write to the console + """ + self.write(text) + self.flush() + + def write_styled(self, text: str, style: Style) -> None: + """Write styled text to the terminal. + + Args: + text (str): The text to write + style (Style): The style of the text + """ + color = style.color + bgcolor = style.bgcolor + if style.reverse: + color, bgcolor = bgcolor, color + + if color: + fore = color.downgrade(ColorSystem.WINDOWS).number + fore = fore if fore is not None else 7 # Default to ANSI 7: White + if style.bold: + fore = fore | self.BRIGHT_BIT + if style.dim: + fore = fore & ~self.BRIGHT_BIT + fore = self.ANSI_TO_WINDOWS[fore] + else: + fore = self._default_fore + + if bgcolor: + back = bgcolor.downgrade(ColorSystem.WINDOWS).number + back = back if back is not None else 0 # Default to ANSI 0: Black + back = self.ANSI_TO_WINDOWS[back] + else: + back = self._default_back + + assert fore is not None + assert back is not None + + SetConsoleTextAttribute( + self._handle, attributes=ctypes.c_ushort(fore | (back << 4)) + ) + self.write_text(text) + SetConsoleTextAttribute(self._handle, attributes=self._default_text) + + def move_cursor_to(self, new_position: WindowsCoordinates) -> None: + """Set the position of the cursor + + Args: + new_position (WindowsCoordinates): The WindowsCoordinates representing the new position of the cursor. + """ + if new_position.col < 0 or new_position.row < 0: + return + SetConsoleCursorPosition(self._handle, coords=new_position) + + def erase_line(self) -> None: + """Erase all content on the line the cursor is currently located at""" + screen_size = self.screen_size + cursor_position = self.cursor_position + cells_to_erase = screen_size.col + start_coordinates = WindowsCoordinates(row=cursor_position.row, col=0) + FillConsoleOutputCharacter( + self._handle, " ", length=cells_to_erase, start=start_coordinates + ) + FillConsoleOutputAttribute( + self._handle, + self._default_attrs, + length=cells_to_erase, + start=start_coordinates, + ) + + def erase_end_of_line(self) -> None: + """Erase all content from the cursor position to the end of that line""" + cursor_position = self.cursor_position + cells_to_erase = self.screen_size.col - cursor_position.col + FillConsoleOutputCharacter( + self._handle, " ", length=cells_to_erase, start=cursor_position + ) + FillConsoleOutputAttribute( + self._handle, + self._default_attrs, + length=cells_to_erase, + start=cursor_position, + ) + + def erase_start_of_line(self) -> None: + """Erase all content from the cursor position to the start of that line""" + row, col = self.cursor_position + start = WindowsCoordinates(row, 0) + FillConsoleOutputCharacter(self._handle, " ", length=col, start=start) + FillConsoleOutputAttribute( + self._handle, self._default_attrs, length=col, start=start + ) + + def move_cursor_up(self) -> None: + """Move the cursor up a single cell""" + cursor_position = self.cursor_position + SetConsoleCursorPosition( + self._handle, + coords=WindowsCoordinates( + row=cursor_position.row - 1, col=cursor_position.col + ), + ) + + def move_cursor_down(self) -> None: + """Move the cursor down a single cell""" + cursor_position = self.cursor_position + SetConsoleCursorPosition( + self._handle, + coords=WindowsCoordinates( + row=cursor_position.row + 1, + col=cursor_position.col, + ), + ) + + def move_cursor_forward(self) -> None: + """Move the cursor forward a single cell. Wrap to the next line if required.""" + row, col = self.cursor_position + if col == self.screen_size.col - 1: + row += 1 + col = 0 + else: + col += 1 + SetConsoleCursorPosition( + self._handle, coords=WindowsCoordinates(row=row, col=col) + ) + + def move_cursor_to_column(self, column: int) -> None: + """Move cursor to the column specified by the zero-based column index, staying on the same row + + Args: + column (int): The zero-based column index to move the cursor to. + """ + row, _ = self.cursor_position + SetConsoleCursorPosition(self._handle, coords=WindowsCoordinates(row, column)) + + def move_cursor_backward(self) -> None: + """Move the cursor backward a single cell. Wrap to the previous line if required.""" + row, col = self.cursor_position + if col == 0: + row -= 1 + col = self.screen_size.col - 1 + else: + col -= 1 + SetConsoleCursorPosition( + self._handle, coords=WindowsCoordinates(row=row, col=col) + ) + + def hide_cursor(self) -> None: + """Hide the cursor""" + current_cursor_size = self._get_cursor_size() + invisible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=0) + SetConsoleCursorInfo(self._handle, cursor_info=invisible_cursor) + + def show_cursor(self) -> None: + """Show the cursor""" + current_cursor_size = self._get_cursor_size() + visible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=1) + SetConsoleCursorInfo(self._handle, cursor_info=visible_cursor) + + def set_title(self, title: str) -> None: + """Set the title of the terminal window + + Args: + title (str): The new title of the console window + """ + assert len(title) < 255, "Console title must be less than 255 characters" + SetConsoleTitle(title) + + def _get_cursor_size(self) -> int: + """Get the percentage of the character cell that is filled by the cursor""" + cursor_info = CONSOLE_CURSOR_INFO() + GetConsoleCursorInfo(self._handle, cursor_info=cursor_info) + return int(cursor_info.dwSize) + + +if __name__ == "__main__": + handle = GetStdHandle() + + from pip._vendor.rich.console import Console + + console = Console() + + term = LegacyWindowsTerm(sys.stdout) + term.set_title("Win32 Console Examples") + + style = Style(color="black", bgcolor="red") + + heading = Style.parse("black on green") + + # Check colour output + console.rule("Checking colour output") + console.print("[on red]on red!") + console.print("[blue]blue!") + console.print("[yellow]yellow!") + console.print("[bold yellow]bold yellow!") + console.print("[bright_yellow]bright_yellow!") + console.print("[dim bright_yellow]dim bright_yellow!") + console.print("[italic cyan]italic cyan!") + console.print("[bold white on blue]bold white on blue!") + console.print("[reverse bold white on blue]reverse bold white on blue!") + console.print("[bold black on cyan]bold black on cyan!") + console.print("[black on green]black on green!") + console.print("[blue on green]blue on green!") + console.print("[white on black]white on black!") + console.print("[black on white]black on white!") + console.print("[#1BB152 on #DA812D]#1BB152 on #DA812D!") + + # Check cursor movement + console.rule("Checking cursor movement") + console.print() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("went back and wrapped to prev line") + time.sleep(1) + term.move_cursor_up() + term.write_text("we go up") + time.sleep(1) + term.move_cursor_down() + term.write_text("and down") + time.sleep(1) + term.move_cursor_up() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("we went up and back 2") + time.sleep(1) + term.move_cursor_down() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("we went down and back 2") + time.sleep(1) + + # Check erasing of lines + term.hide_cursor() + console.print() + console.rule("Checking line erasing") + console.print("\n...Deleting to the start of the line...") + term.write_text("The red arrow shows the cursor location, and direction of erase") + time.sleep(1) + term.move_cursor_to_column(16) + term.write_styled("<", Style.parse("black on red")) + term.move_cursor_backward() + time.sleep(1) + term.erase_start_of_line() + time.sleep(1) + + console.print("\n\n...And to the end of the line...") + term.write_text("The red arrow shows the cursor location, and direction of erase") + time.sleep(1) + + term.move_cursor_to_column(16) + term.write_styled(">", Style.parse("black on red")) + time.sleep(1) + term.erase_end_of_line() + time.sleep(1) + + console.print("\n\n...Now the whole line will be erased...") + term.write_styled("I'm going to disappear!", style=Style.parse("black on cyan")) + time.sleep(1) + term.erase_line() + + term.show_cursor() + print("\n") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows.py new file mode 100644 index 0000000..7520a9f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows.py @@ -0,0 +1,71 @@ +import sys +from dataclasses import dataclass + + +@dataclass +class WindowsConsoleFeatures: + """Windows features available.""" + + vt: bool = False + """The console supports VT codes.""" + truecolor: bool = False + """The console supports truecolor.""" + + +try: + import ctypes + from ctypes import LibraryLoader + + if sys.platform == "win32": + windll = LibraryLoader(ctypes.WinDLL) + else: + windll = None + raise ImportError("Not windows") + + from pip._vendor.rich._win32_console import ( + ENABLE_VIRTUAL_TERMINAL_PROCESSING, + GetConsoleMode, + GetStdHandle, + LegacyWindowsError, + ) + +except (AttributeError, ImportError, ValueError): + # Fallback if we can't load the Windows DLL + def get_windows_console_features() -> WindowsConsoleFeatures: + features = WindowsConsoleFeatures() + return features + +else: + + def get_windows_console_features() -> WindowsConsoleFeatures: + """Get windows console features. + + Returns: + WindowsConsoleFeatures: An instance of WindowsConsoleFeatures. + """ + handle = GetStdHandle() + try: + console_mode = GetConsoleMode(handle) + success = True + except LegacyWindowsError: + console_mode = 0 + success = False + vt = bool(success and console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) + truecolor = False + if vt: + win_version = sys.getwindowsversion() + truecolor = win_version.major > 10 or ( + win_version.major == 10 and win_version.build >= 15063 + ) + features = WindowsConsoleFeatures(vt=vt, truecolor=truecolor) + return features + + +if __name__ == "__main__": + import platform + + features = get_windows_console_features() + from pip._vendor.rich import print + + print(f'platform="{platform.system()}"') + print(repr(features)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py new file mode 100644 index 0000000..5ece056 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py @@ -0,0 +1,56 @@ +from typing import Iterable, Sequence, Tuple, cast + +from pip._vendor.rich._win32_console import LegacyWindowsTerm, WindowsCoordinates +from pip._vendor.rich.segment import ControlCode, ControlType, Segment + + +def legacy_windows_render(buffer: Iterable[Segment], term: LegacyWindowsTerm) -> None: + """Makes appropriate Windows Console API calls based on the segments in the buffer. + + Args: + buffer (Iterable[Segment]): Iterable of Segments to convert to Win32 API calls. + term (LegacyWindowsTerm): Used to call the Windows Console API. + """ + for text, style, control in buffer: + if not control: + if style: + term.write_styled(text, style) + else: + term.write_text(text) + else: + control_codes: Sequence[ControlCode] = control + for control_code in control_codes: + control_type = control_code[0] + if control_type == ControlType.CURSOR_MOVE_TO: + _, x, y = cast(Tuple[ControlType, int, int], control_code) + term.move_cursor_to(WindowsCoordinates(row=y - 1, col=x - 1)) + elif control_type == ControlType.CARRIAGE_RETURN: + term.write_text("\r") + elif control_type == ControlType.HOME: + term.move_cursor_to(WindowsCoordinates(0, 0)) + elif control_type == ControlType.CURSOR_UP: + term.move_cursor_up() + elif control_type == ControlType.CURSOR_DOWN: + term.move_cursor_down() + elif control_type == ControlType.CURSOR_FORWARD: + term.move_cursor_forward() + elif control_type == ControlType.CURSOR_BACKWARD: + term.move_cursor_backward() + elif control_type == ControlType.CURSOR_MOVE_TO_COLUMN: + _, column = cast(Tuple[ControlType, int], control_code) + term.move_cursor_to_column(column - 1) + elif control_type == ControlType.HIDE_CURSOR: + term.hide_cursor() + elif control_type == ControlType.SHOW_CURSOR: + term.show_cursor() + elif control_type == ControlType.ERASE_IN_LINE: + _, mode = cast(Tuple[ControlType, int], control_code) + if mode == 0: + term.erase_end_of_line() + elif mode == 1: + term.erase_start_of_line() + elif mode == 2: + term.erase_line() + elif control_type == ControlType.SET_WINDOW_TITLE: + _, title = cast(Tuple[ControlType, str], control_code) + term.set_title(title) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/_wrap.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/_wrap.py new file mode 100644 index 0000000..2e94ff6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/_wrap.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import re +from typing import Iterable + +from ._loop import loop_last +from .cells import cell_len, chop_cells + +re_word = re.compile(r"\s*\S+\s*") + + +def words(text: str) -> Iterable[tuple[int, int, str]]: + """Yields each word from the text as a tuple + containing (start_index, end_index, word). A "word" in this context may + include the actual word and any whitespace to the right. + """ + position = 0 + word_match = re_word.match(text, position) + while word_match is not None: + start, end = word_match.span() + word = word_match.group(0) + yield start, end, word + word_match = re_word.match(text, end) + + +def divide_line(text: str, width: int, fold: bool = True) -> list[int]: + """Given a string of text, and a width (measured in cells), return a list + of cell offsets which the string should be split at in order for it to fit + within the given width. + + Args: + text: The text to examine. + width: The available cell width. + fold: If True, words longer than `width` will be folded onto a new line. + + Returns: + A list of indices to break the line at. + """ + break_positions: list[int] = [] # offsets to insert the breaks at + append = break_positions.append + cell_offset = 0 + _cell_len = cell_len + + for start, _end, word in words(text): + word_length = _cell_len(word.rstrip()) + remaining_space = width - cell_offset + word_fits_remaining_space = remaining_space >= word_length + + if word_fits_remaining_space: + # Simplest case - the word fits within the remaining width for this line. + cell_offset += _cell_len(word) + else: + # Not enough space remaining for this word on the current line. + if word_length > width: + # The word doesn't fit on any line, so we can't simply + # place it on the next line... + if fold: + # Fold the word across multiple lines. + folded_word = chop_cells(word, width=width) + for last, line in loop_last(folded_word): + if start: + append(start) + if last: + cell_offset = _cell_len(line) + else: + start += len(line) + else: + # Folding isn't allowed, so crop the word. + if start: + append(start) + cell_offset = _cell_len(word) + elif cell_offset and start: + # The word doesn't fit within the remaining space on the current + # line, but it *can* fit on to the next (empty) line. + append(start) + cell_offset = _cell_len(word) + + return break_positions + + +if __name__ == "__main__": # pragma: no cover + from .console import Console + + console = Console(width=10) + console.print("12345 abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ 12345") + print(chop_cells("abcdefghijklmnopqrstuvwxyz", 10)) + + console = Console(width=20) + console.rule() + console.print("TextualはPythonの高速アプリケーション開発フレームワークです") + + console.rule() + console.print("アプリケーションは1670万色を使用でき") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/abc.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/abc.py new file mode 100644 index 0000000..e6e498e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/abc.py @@ -0,0 +1,33 @@ +from abc import ABC + + +class RichRenderable(ABC): + """An abstract base class for Rich renderables. + + Note that there is no need to extend this class, the intended use is to check if an + object supports the Rich renderable protocol. For example:: + + if isinstance(my_object, RichRenderable): + console.print(my_object) + + """ + + @classmethod + def __subclasshook__(cls, other: type) -> bool: + """Check if this class supports the rich render protocol.""" + return hasattr(other, "__rich_console__") or hasattr(other, "__rich__") + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.text import Text + + t = Text() + print(isinstance(Text, RichRenderable)) + print(isinstance(t, RichRenderable)) + + class Foo: + pass + + f = Foo() + print(isinstance(f, RichRenderable)) + print(isinstance("", RichRenderable)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/align.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/align.py new file mode 100644 index 0000000..330dcc5 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/align.py @@ -0,0 +1,312 @@ +import sys +from itertools import chain +from typing import TYPE_CHECKING, Iterable, Optional + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + +from .constrain import Constrain +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import StyleType + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType, RenderResult + +AlignMethod = Literal["left", "center", "right"] +VerticalAlignMethod = Literal["top", "middle", "bottom"] + + +class Align(JupyterMixin): + """Align a renderable by adding spaces if necessary. + + Args: + renderable (RenderableType): A console renderable. + align (AlignMethod): One of "left", "center", or "right"" + style (StyleType, optional): An optional style to apply to the background. + vertical (Optional[VerticalAlignMethod], optional): Optional vertical align, one of "top", "middle", or "bottom". Defaults to None. + pad (bool, optional): Pad the right with spaces. Defaults to True. + width (int, optional): Restrict contents to given width, or None to use default width. Defaults to None. + height (int, optional): Set height of align renderable, or None to fit to contents. Defaults to None. + + Raises: + ValueError: if ``align`` is not one of the expected values. + """ + + def __init__( + self, + renderable: "RenderableType", + align: AlignMethod = "left", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> None: + if align not in ("left", "center", "right"): + raise ValueError( + f'invalid value for align, expected "left", "center", or "right" (not {align!r})' + ) + if vertical is not None and vertical not in ("top", "middle", "bottom"): + raise ValueError( + f'invalid value for vertical, expected "top", "middle", or "bottom" (not {vertical!r})' + ) + self.renderable = renderable + self.align = align + self.style = style + self.vertical = vertical + self.pad = pad + self.width = width + self.height = height + + def __repr__(self) -> str: + return f"Align({self.renderable!r}, {self.align!r})" + + @classmethod + def left( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the left.""" + return cls( + renderable, + "left", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + @classmethod + def center( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the center.""" + return cls( + renderable, + "center", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + @classmethod + def right( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the right.""" + return cls( + renderable, + "right", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + align = self.align + width = console.measure(self.renderable, options=options).maximum + rendered = console.render( + Constrain( + self.renderable, width if self.width is None else min(width, self.width) + ), + options.update(height=None), + ) + lines = list(Segment.split_lines(rendered)) + width, height = Segment.get_shape(lines) + lines = Segment.set_shape(lines, width, height) + new_line = Segment.line() + excess_space = options.max_width - width + style = console.get_style(self.style) if self.style is not None else None + + def generate_segments() -> Iterable[Segment]: + if excess_space <= 0: + # Exact fit + for line in lines: + yield from line + yield new_line + + elif align == "left": + # Pad on the right + pad = Segment(" " * excess_space, style) if self.pad else None + for line in lines: + yield from line + if pad: + yield pad + yield new_line + + elif align == "center": + # Pad left and right + left = excess_space // 2 + pad = Segment(" " * left, style) + pad_right = ( + Segment(" " * (excess_space - left), style) if self.pad else None + ) + for line in lines: + if left: + yield pad + yield from line + if pad_right: + yield pad_right + yield new_line + + elif align == "right": + # Padding on left + pad = Segment(" " * excess_space, style) + for line in lines: + yield pad + yield from line + yield new_line + + blank_line = ( + Segment(f"{' ' * (self.width or options.max_width)}\n", style) + if self.pad + else Segment("\n") + ) + + def blank_lines(count: int) -> Iterable[Segment]: + if count > 0: + for _ in range(count): + yield blank_line + + vertical_height = self.height or options.height + iter_segments: Iterable[Segment] + if self.vertical and vertical_height is not None: + if self.vertical == "top": + bottom_space = vertical_height - height + iter_segments = chain(generate_segments(), blank_lines(bottom_space)) + elif self.vertical == "middle": + top_space = (vertical_height - height) // 2 + bottom_space = vertical_height - top_space - height + iter_segments = chain( + blank_lines(top_space), + generate_segments(), + blank_lines(bottom_space), + ) + else: # self.vertical == "bottom": + top_space = vertical_height - height + iter_segments = chain(blank_lines(top_space), generate_segments()) + else: + iter_segments = generate_segments() + if self.style: + style = console.get_style(self.style) + iter_segments = Segment.apply_style(iter_segments, style) + yield from iter_segments + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + measurement = Measurement.get(console, options, self.renderable) + return measurement + + +class VerticalCenter(JupyterMixin): + """Vertically aligns a renderable. + + Warn: + This class is deprecated and may be removed in a future version. Use Align class with + `vertical="middle"`. + + Args: + renderable (RenderableType): A renderable object. + style (StyleType, optional): An optional style to apply to the background. Defaults to None. + """ + + def __init__( + self, + renderable: "RenderableType", + style: Optional[StyleType] = None, + ) -> None: + self.renderable = renderable + self.style = style + + def __repr__(self) -> str: + return f"VerticalCenter({self.renderable!r})" + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + style = console.get_style(self.style) if self.style is not None else None + lines = console.render_lines( + self.renderable, options.update(height=None), pad=False + ) + width, _height = Segment.get_shape(lines) + new_line = Segment.line() + height = options.height or options.size.height + top_space = (height - len(lines)) // 2 + bottom_space = height - top_space - len(lines) + blank_line = Segment(f"{' ' * width}", style) + + def blank_lines(count: int) -> Iterable[Segment]: + for _ in range(count): + yield blank_line + yield new_line + + if top_space > 0: + yield from blank_lines(top_space) + for line in lines: + yield from line + yield new_line + if bottom_space > 0: + yield from blank_lines(bottom_space) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + measurement = Measurement.get(console, options, self.renderable) + return measurement + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console, Group + from pip._vendor.rich.highlighter import ReprHighlighter + from pip._vendor.rich.panel import Panel + + highlighter = ReprHighlighter() + console = Console() + + panel = Panel( + Group( + Align.left(highlighter("align='left'")), + Align.center(highlighter("align='center'")), + Align.right(highlighter("align='right'")), + ), + width=60, + style="on dark_blue", + title="Align", + ) + + console.print( + Align.center(panel, vertical="middle", style="on red", height=console.height) + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/ansi.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/ansi.py new file mode 100644 index 0000000..7de86ce --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/ansi.py @@ -0,0 +1,241 @@ +import re +import sys +from contextlib import suppress +from typing import Iterable, NamedTuple, Optional + +from .color import Color +from .style import Style +from .text import Text + +re_ansi = re.compile( + r""" +(?:\x1b[0-?])| +(?:\x1b\](.*?)\x1b\\)| +(?:\x1b([(@-Z\\-_]|\[[0-?]*[ -/]*[@-~])) +""", + re.VERBOSE, +) + + +class _AnsiToken(NamedTuple): + """Result of ansi tokenized string.""" + + plain: str = "" + sgr: Optional[str] = "" + osc: Optional[str] = "" + + +def _ansi_tokenize(ansi_text: str) -> Iterable[_AnsiToken]: + """Tokenize a string in to plain text and ANSI codes. + + Args: + ansi_text (str): A String containing ANSI codes. + + Yields: + AnsiToken: A named tuple of (plain, sgr, osc) + """ + + position = 0 + sgr: Optional[str] + osc: Optional[str] + for match in re_ansi.finditer(ansi_text): + start, end = match.span(0) + osc, sgr = match.groups() + if start > position: + yield _AnsiToken(ansi_text[position:start]) + if sgr: + if sgr == "(": + position = end + 1 + continue + if sgr.endswith("m"): + yield _AnsiToken("", sgr[1:-1], osc) + else: + yield _AnsiToken("", sgr, osc) + position = end + if position < len(ansi_text): + yield _AnsiToken(ansi_text[position:]) + + +SGR_STYLE_MAP = { + 1: "bold", + 2: "dim", + 3: "italic", + 4: "underline", + 5: "blink", + 6: "blink2", + 7: "reverse", + 8: "conceal", + 9: "strike", + 21: "underline2", + 22: "not dim not bold", + 23: "not italic", + 24: "not underline", + 25: "not blink", + 26: "not blink2", + 27: "not reverse", + 28: "not conceal", + 29: "not strike", + 30: "color(0)", + 31: "color(1)", + 32: "color(2)", + 33: "color(3)", + 34: "color(4)", + 35: "color(5)", + 36: "color(6)", + 37: "color(7)", + 39: "default", + 40: "on color(0)", + 41: "on color(1)", + 42: "on color(2)", + 43: "on color(3)", + 44: "on color(4)", + 45: "on color(5)", + 46: "on color(6)", + 47: "on color(7)", + 49: "on default", + 51: "frame", + 52: "encircle", + 53: "overline", + 54: "not frame not encircle", + 55: "not overline", + 90: "color(8)", + 91: "color(9)", + 92: "color(10)", + 93: "color(11)", + 94: "color(12)", + 95: "color(13)", + 96: "color(14)", + 97: "color(15)", + 100: "on color(8)", + 101: "on color(9)", + 102: "on color(10)", + 103: "on color(11)", + 104: "on color(12)", + 105: "on color(13)", + 106: "on color(14)", + 107: "on color(15)", +} + + +class AnsiDecoder: + """Translate ANSI code in to styled Text.""" + + def __init__(self) -> None: + self.style = Style.null() + + def decode(self, terminal_text: str) -> Iterable[Text]: + """Decode ANSI codes in an iterable of lines. + + Args: + lines (Iterable[str]): An iterable of lines of terminal output. + + Yields: + Text: Marked up Text. + """ + for line in terminal_text.splitlines(): + yield self.decode_line(line) + + def decode_line(self, line: str) -> Text: + """Decode a line containing ansi codes. + + Args: + line (str): A line of terminal output. + + Returns: + Text: A Text instance marked up according to ansi codes. + """ + from_ansi = Color.from_ansi + from_rgb = Color.from_rgb + _Style = Style + text = Text() + append = text.append + line = line.rsplit("\r", 1)[-1] + for plain_text, sgr, osc in _ansi_tokenize(line): + if plain_text: + append(plain_text, self.style or None) + elif osc is not None: + if osc.startswith("8;"): + _params, semicolon, link = osc[2:].partition(";") + if semicolon: + self.style = self.style.update_link(link or None) + elif sgr is not None: + # Translate in to semi-colon separated codes + # Ignore invalid codes, because we want to be lenient + codes = [ + min(255, int(_code) if _code else 0) + for _code in sgr.split(";") + if _code.isdigit() or _code == "" + ] + iter_codes = iter(codes) + for code in iter_codes: + if code == 0: + # reset + self.style = _Style.null() + elif code in SGR_STYLE_MAP: + # styles + self.style += _Style.parse(SGR_STYLE_MAP[code]) + elif code == 38: + #  Foreground + with suppress(StopIteration): + color_type = next(iter_codes) + if color_type == 5: + self.style += _Style.from_color( + from_ansi(next(iter_codes)) + ) + elif color_type == 2: + self.style += _Style.from_color( + from_rgb( + next(iter_codes), + next(iter_codes), + next(iter_codes), + ) + ) + elif code == 48: + # Background + with suppress(StopIteration): + color_type = next(iter_codes) + if color_type == 5: + self.style += _Style.from_color( + None, from_ansi(next(iter_codes)) + ) + elif color_type == 2: + self.style += _Style.from_color( + None, + from_rgb( + next(iter_codes), + next(iter_codes), + next(iter_codes), + ), + ) + + return text + + +if sys.platform != "win32" and __name__ == "__main__": # pragma: no cover + import io + import os + import pty + import sys + + decoder = AnsiDecoder() + + stdout = io.BytesIO() + + def read(fd: int) -> bytes: + data = os.read(fd, 1024) + stdout.write(data) + return data + + pty.spawn(sys.argv[1:], read) + + from .console import Console + + console = Console(record=True) + + stdout_result = stdout.getvalue().decode("utf-8") + print(stdout_result) + + for line in decoder.decode(stdout_result): + console.print(line) + + console.save_html("stdout.html") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/bar.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/bar.py new file mode 100644 index 0000000..022284b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/bar.py @@ -0,0 +1,93 @@ +from typing import Optional, Union + +from .color import Color +from .console import Console, ConsoleOptions, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style + +# There are left-aligned characters for 1/8 to 7/8, but +# the right-aligned characters exist only for 1/8 and 4/8. +BEGIN_BLOCK_ELEMENTS = ["█", "█", "█", "▐", "▐", "▐", "▕", "▕"] +END_BLOCK_ELEMENTS = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"] +FULL_BLOCK = "█" + + +class Bar(JupyterMixin): + """Renders a solid block bar. + + Args: + size (float): Value for the end of the bar. + begin (float): Begin point (between 0 and size, inclusive). + end (float): End point (between 0 and size, inclusive). + width (int, optional): Width of the bar, or ``None`` for maximum width. Defaults to None. + color (Union[Color, str], optional): Color of the bar. Defaults to "default". + bgcolor (Union[Color, str], optional): Color of bar background. Defaults to "default". + """ + + def __init__( + self, + size: float, + begin: float, + end: float, + *, + width: Optional[int] = None, + color: Union[Color, str] = "default", + bgcolor: Union[Color, str] = "default", + ): + self.size = size + self.begin = max(begin, 0) + self.end = min(end, size) + self.width = width + self.style = Style(color=color, bgcolor=bgcolor) + + def __repr__(self) -> str: + return f"Bar({self.size}, {self.begin}, {self.end})" + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = min( + self.width if self.width is not None else options.max_width, + options.max_width, + ) + + if self.begin >= self.end: + yield Segment(" " * width, self.style) + yield Segment.line() + return + + prefix_complete_eights = int(width * 8 * self.begin / self.size) + prefix_bar_count = prefix_complete_eights // 8 + prefix_eights_count = prefix_complete_eights % 8 + + body_complete_eights = int(width * 8 * self.end / self.size) + body_bar_count = body_complete_eights // 8 + body_eights_count = body_complete_eights % 8 + + # When start and end fall into the same cell, we ideally should render + # a symbol that's "center-aligned", but there is no good symbol in Unicode. + # In this case, we fall back to right-aligned block symbol for simplicity. + + prefix = " " * prefix_bar_count + if prefix_eights_count: + prefix += BEGIN_BLOCK_ELEMENTS[prefix_eights_count] + + body = FULL_BLOCK * body_bar_count + if body_eights_count: + body += END_BLOCK_ELEMENTS[body_eights_count] + + suffix = " " * (width - len(body)) + + yield Segment(prefix + body[len(prefix) :] + suffix, self.style) + yield Segment.line() + + def __rich_measure__( + self, console: Console, options: ConsoleOptions + ) -> Measurement: + return ( + Measurement(self.width, self.width) + if self.width is not None + else Measurement(4, options.max_width) + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/box.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/box.py new file mode 100644 index 0000000..0511a9e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/box.py @@ -0,0 +1,480 @@ +import sys +from typing import TYPE_CHECKING, Iterable, List + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + + +from ._loop import loop_last + +if TYPE_CHECKING: + from pip._vendor.rich.console import ConsoleOptions + + +class Box: + """Defines characters to render boxes. + + ┌─┬┐ top + │ ││ head + ├─┼┤ head_row + │ ││ mid + ├─┼┤ row + ├─┼┤ foot_row + │ ││ foot + └─┴┘ bottom + + Args: + box (str): Characters making up box. + ascii (bool, optional): True if this box uses ascii characters only. Default is False. + """ + + def __init__(self, box: str, *, ascii: bool = False) -> None: + self._box = box + self.ascii = ascii + line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines() + # top + self.top_left, self.top, self.top_divider, self.top_right = iter(line1) + # head + self.head_left, _, self.head_vertical, self.head_right = iter(line2) + # head_row + ( + self.head_row_left, + self.head_row_horizontal, + self.head_row_cross, + self.head_row_right, + ) = iter(line3) + + # mid + self.mid_left, _, self.mid_vertical, self.mid_right = iter(line4) + # row + self.row_left, self.row_horizontal, self.row_cross, self.row_right = iter(line5) + # foot_row + ( + self.foot_row_left, + self.foot_row_horizontal, + self.foot_row_cross, + self.foot_row_right, + ) = iter(line6) + # foot + self.foot_left, _, self.foot_vertical, self.foot_right = iter(line7) + # bottom + self.bottom_left, self.bottom, self.bottom_divider, self.bottom_right = iter( + line8 + ) + + def __repr__(self) -> str: + return "Box(...)" + + def __str__(self) -> str: + return self._box + + def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box": + """Substitute this box for another if it won't render due to platform issues. + + Args: + options (ConsoleOptions): Console options used in rendering. + safe (bool, optional): Substitute this for another Box if there are known problems + displaying on the platform (currently only relevant on Windows). Default is True. + + Returns: + Box: A different Box or the same Box. + """ + box = self + if options.legacy_windows and safe: + box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box) + if options.ascii_only and not box.ascii: + box = ASCII + return box + + def get_plain_headed_box(self) -> "Box": + """If this box uses special characters for the borders of the header, then + return the equivalent box that does not. + + Returns: + Box: The most similar Box that doesn't use header-specific box characters. + If the current Box already satisfies this criterion, then it's returned. + """ + return PLAIN_HEADED_SUBSTITUTIONS.get(self, self) + + def get_top(self, widths: Iterable[int]) -> str: + """Get the top of a simple box. + + Args: + widths (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + + parts: List[str] = [] + append = parts.append + append(self.top_left) + for last, width in loop_last(widths): + append(self.top * width) + if not last: + append(self.top_divider) + append(self.top_right) + return "".join(parts) + + def get_row( + self, + widths: Iterable[int], + level: Literal["head", "row", "foot", "mid"] = "row", + edge: bool = True, + ) -> str: + """Get the top of a simple box. + + Args: + width (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + if level == "head": + left = self.head_row_left + horizontal = self.head_row_horizontal + cross = self.head_row_cross + right = self.head_row_right + elif level == "row": + left = self.row_left + horizontal = self.row_horizontal + cross = self.row_cross + right = self.row_right + elif level == "mid": + left = self.mid_left + horizontal = " " + cross = self.mid_vertical + right = self.mid_right + elif level == "foot": + left = self.foot_row_left + horizontal = self.foot_row_horizontal + cross = self.foot_row_cross + right = self.foot_row_right + else: + raise ValueError("level must be 'head', 'row' or 'foot'") + + parts: List[str] = [] + append = parts.append + if edge: + append(left) + for last, width in loop_last(widths): + append(horizontal * width) + if not last: + append(cross) + if edge: + append(right) + return "".join(parts) + + def get_bottom(self, widths: Iterable[int]) -> str: + """Get the bottom of a simple box. + + Args: + widths (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + + parts: List[str] = [] + append = parts.append + append(self.bottom_left) + for last, width in loop_last(widths): + append(self.bottom * width) + if not last: + append(self.bottom_divider) + append(self.bottom_right) + return "".join(parts) + + +# fmt: off +ASCII: Box = Box( + "+--+\n" + "| ||\n" + "|-+|\n" + "| ||\n" + "|-+|\n" + "|-+|\n" + "| ||\n" + "+--+\n", + ascii=True, +) + +ASCII2: Box = Box( + "+-++\n" + "| ||\n" + "+-++\n" + "| ||\n" + "+-++\n" + "+-++\n" + "| ||\n" + "+-++\n", + ascii=True, +) + +ASCII_DOUBLE_HEAD: Box = Box( + "+-++\n" + "| ||\n" + "+=++\n" + "| ||\n" + "+-++\n" + "+-++\n" + "| ||\n" + "+-++\n", + ascii=True, +) + +SQUARE: Box = Box( + "┌─┬┐\n" + "│ ││\n" + "├─┼┤\n" + "│ ││\n" + "├─┼┤\n" + "├─┼┤\n" + "│ ││\n" + "└─┴┘\n" +) + +SQUARE_DOUBLE_HEAD: Box = Box( + "┌─┬┐\n" + "│ ││\n" + "╞═╪╡\n" + "│ ││\n" + "├─┼┤\n" + "├─┼┤\n" + "│ ││\n" + "└─┴┘\n" +) + +MINIMAL: Box = Box( + " ╷ \n" + " │ \n" + "╶─┼╴\n" + " │ \n" + "╶─┼╴\n" + "╶─┼╴\n" + " │ \n" + " ╵ \n" +) + + +MINIMAL_HEAVY_HEAD: Box = Box( + " ╷ \n" + " │ \n" + "╺━┿╸\n" + " │ \n" + "╶─┼╴\n" + "╶─┼╴\n" + " │ \n" + " ╵ \n" +) + +MINIMAL_DOUBLE_HEAD: Box = Box( + " ╷ \n" + " │ \n" + " ═╪ \n" + " │ \n" + " ─┼ \n" + " ─┼ \n" + " │ \n" + " ╵ \n" +) + + +SIMPLE: Box = Box( + " \n" + " \n" + " ── \n" + " \n" + " \n" + " ── \n" + " \n" + " \n" +) + +SIMPLE_HEAD: Box = Box( + " \n" + " \n" + " ── \n" + " \n" + " \n" + " \n" + " \n" + " \n" +) + + +SIMPLE_HEAVY: Box = Box( + " \n" + " \n" + " ━━ \n" + " \n" + " \n" + " ━━ \n" + " \n" + " \n" +) + + +HORIZONTALS: Box = Box( + " ── \n" + " \n" + " ── \n" + " \n" + " ── \n" + " ── \n" + " \n" + " ── \n" +) + +ROUNDED: Box = Box( + "╭─┬╮\n" + "│ ││\n" + "├─┼┤\n" + "│ ││\n" + "├─┼┤\n" + "├─┼┤\n" + "│ ││\n" + "╰─┴╯\n" +) + +HEAVY: Box = Box( + "┏━┳┓\n" + "┃ ┃┃\n" + "┣━╋┫\n" + "┃ ┃┃\n" + "┣━╋┫\n" + "┣━╋┫\n" + "┃ ┃┃\n" + "┗━┻┛\n" +) + +HEAVY_EDGE: Box = Box( + "┏━┯┓\n" + "┃ │┃\n" + "┠─┼┨\n" + "┃ │┃\n" + "┠─┼┨\n" + "┠─┼┨\n" + "┃ │┃\n" + "┗━┷┛\n" +) + +HEAVY_HEAD: Box = Box( + "┏━┳┓\n" + "┃ ┃┃\n" + "┡━╇┩\n" + "│ ││\n" + "├─┼┤\n" + "├─┼┤\n" + "│ ││\n" + "└─┴┘\n" +) + +DOUBLE: Box = Box( + "╔═╦╗\n" + "║ ║║\n" + "╠═╬╣\n" + "║ ║║\n" + "╠═╬╣\n" + "╠═╬╣\n" + "║ ║║\n" + "╚═╩╝\n" +) + +DOUBLE_EDGE: Box = Box( + "╔═╤╗\n" + "║ │║\n" + "╟─┼╢\n" + "║ │║\n" + "╟─┼╢\n" + "╟─┼╢\n" + "║ │║\n" + "╚═╧╝\n" +) + +MARKDOWN: Box = Box( + " \n" + "| ||\n" + "|-||\n" + "| ||\n" + "|-||\n" + "|-||\n" + "| ||\n" + " \n", + ascii=True, +) +# fmt: on + +# Map Boxes that don't render with raster fonts on to equivalent that do +LEGACY_WINDOWS_SUBSTITUTIONS = { + ROUNDED: SQUARE, + MINIMAL_HEAVY_HEAD: MINIMAL, + SIMPLE_HEAVY: SIMPLE, + HEAVY: SQUARE, + HEAVY_EDGE: SQUARE, + HEAVY_HEAD: SQUARE, +} + +# Map headed boxes to their headerless equivalents +PLAIN_HEADED_SUBSTITUTIONS = { + HEAVY_HEAD: SQUARE, + SQUARE_DOUBLE_HEAD: SQUARE, + MINIMAL_DOUBLE_HEAD: MINIMAL, + MINIMAL_HEAVY_HEAD: MINIMAL, + ASCII_DOUBLE_HEAD: ASCII2, +} + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.columns import Columns + from pip._vendor.rich.panel import Panel + + from . import box as box + from .console import Console + from .table import Table + from .text import Text + + console = Console(record=True) + + BOXES = [ + "ASCII", + "ASCII2", + "ASCII_DOUBLE_HEAD", + "SQUARE", + "SQUARE_DOUBLE_HEAD", + "MINIMAL", + "MINIMAL_HEAVY_HEAD", + "MINIMAL_DOUBLE_HEAD", + "SIMPLE", + "SIMPLE_HEAD", + "SIMPLE_HEAVY", + "HORIZONTALS", + "ROUNDED", + "HEAVY", + "HEAVY_EDGE", + "HEAVY_HEAD", + "DOUBLE", + "DOUBLE_EDGE", + "MARKDOWN", + ] + + console.print(Panel("[bold green]Box Constants", style="green"), justify="center") + console.print() + + columns = Columns(expand=True, padding=2) + for box_name in sorted(BOXES): + table = Table( + show_footer=True, style="dim", border_style="not dim", expand=True + ) + table.add_column("Header 1", "Footer 1") + table.add_column("Header 2", "Footer 2") + table.add_row("Cell", "Cell") + table.add_row("Cell", "Cell") + table.box = getattr(box, box_name) + table.title = Text(f"box.{box_name}", style="magenta") + columns.add_renderable(table) + console.print(columns) + + # console.save_svg("box.svg") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/cells.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/cells.py new file mode 100644 index 0000000..a854622 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/cells.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +from functools import lru_cache +from typing import Callable + +from ._cell_widths import CELL_WIDTHS + +# Ranges of unicode ordinals that produce a 1-cell wide character +# This is non-exhaustive, but covers most common Western characters +_SINGLE_CELL_UNICODE_RANGES: list[tuple[int, int]] = [ + (0x20, 0x7E), # Latin (excluding non-printable) + (0xA0, 0xAC), + (0xAE, 0x002FF), + (0x00370, 0x00482), # Greek / Cyrillic + (0x02500, 0x025FC), # Box drawing, box elements, geometric shapes + (0x02800, 0x028FF), # Braille +] + +# A set of characters that are a single cell wide +_SINGLE_CELLS = frozenset( + [ + character + for _start, _end in _SINGLE_CELL_UNICODE_RANGES + for character in map(chr, range(_start, _end + 1)) + ] +) + +# When called with a string this will return True if all +# characters are single-cell, otherwise False +_is_single_cell_widths: Callable[[str], bool] = _SINGLE_CELLS.issuperset + + +@lru_cache(4096) +def cached_cell_len(text: str) -> int: + """Get the number of cells required to display text. + + This method always caches, which may use up a lot of memory. It is recommended to use + `cell_len` over this method. + + Args: + text (str): Text to display. + + Returns: + int: Get the number of cells required to display text. + """ + if _is_single_cell_widths(text): + return len(text) + return sum(map(get_character_cell_size, text)) + + +def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> int: + """Get the number of cells required to display text. + + Args: + text (str): Text to display. + + Returns: + int: Get the number of cells required to display text. + """ + if len(text) < 512: + return _cell_len(text) + if _is_single_cell_widths(text): + return len(text) + return sum(map(get_character_cell_size, text)) + + +@lru_cache(maxsize=4096) +def get_character_cell_size(character: str) -> int: + """Get the cell size of a character. + + Args: + character (str): A single character. + + Returns: + int: Number of cells (0, 1 or 2) occupied by that character. + """ + codepoint = ord(character) + _table = CELL_WIDTHS + lower_bound = 0 + upper_bound = len(_table) - 1 + index = (lower_bound + upper_bound) // 2 + while True: + start, end, width = _table[index] + if codepoint < start: + upper_bound = index - 1 + elif codepoint > end: + lower_bound = index + 1 + else: + return 0 if width == -1 else width + if upper_bound < lower_bound: + break + index = (lower_bound + upper_bound) // 2 + return 1 + + +def set_cell_size(text: str, total: int) -> str: + """Set the length of a string to fit within given number of cells.""" + + if _is_single_cell_widths(text): + size = len(text) + if size < total: + return text + " " * (total - size) + return text[:total] + + if total <= 0: + return "" + cell_size = cell_len(text) + if cell_size == total: + return text + if cell_size < total: + return text + " " * (total - cell_size) + + start = 0 + end = len(text) + + # Binary search until we find the right size + while True: + pos = (start + end) // 2 + before = text[: pos + 1] + before_len = cell_len(before) + if before_len == total + 1 and cell_len(before[-1]) == 2: + return before[:-1] + " " + if before_len == total: + return before + if before_len > total: + end = pos + else: + start = pos + + +def chop_cells( + text: str, + width: int, +) -> list[str]: + """Split text into lines such that each line fits within the available (cell) width. + + Args: + text: The text to fold such that it fits in the given width. + width: The width available (number of cells). + + Returns: + A list of strings such that each string in the list has cell width + less than or equal to the available width. + """ + _get_character_cell_size = get_character_cell_size + lines: list[list[str]] = [[]] + + append_new_line = lines.append + append_to_last_line = lines[-1].append + + total_width = 0 + + for character in text: + cell_width = _get_character_cell_size(character) + char_doesnt_fit = total_width + cell_width > width + + if char_doesnt_fit: + append_new_line([character]) + append_to_last_line = lines[-1].append + total_width = cell_width + else: + append_to_last_line(character) + total_width += cell_width + + return ["".join(line) for line in lines] + + +if __name__ == "__main__": # pragma: no cover + print(get_character_cell_size("😽")) + for line in chop_cells("""这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑。""", 8): + print(line) + for n in range(80, 1, -1): + print(set_cell_size("""这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑。""", n) + "|") + print("x" * n) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/color.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/color.py new file mode 100644 index 0000000..e2c23a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/color.py @@ -0,0 +1,621 @@ +import re +import sys +from colorsys import rgb_to_hls +from enum import IntEnum +from functools import lru_cache +from typing import TYPE_CHECKING, NamedTuple, Optional, Tuple + +from ._palettes import EIGHT_BIT_PALETTE, STANDARD_PALETTE, WINDOWS_PALETTE +from .color_triplet import ColorTriplet +from .repr import Result, rich_repr +from .terminal_theme import DEFAULT_TERMINAL_THEME + +if TYPE_CHECKING: # pragma: no cover + from .terminal_theme import TerminalTheme + from .text import Text + + +WINDOWS = sys.platform == "win32" + + +class ColorSystem(IntEnum): + """One of the 3 color system supported by terminals.""" + + STANDARD = 1 + EIGHT_BIT = 2 + TRUECOLOR = 3 + WINDOWS = 4 + + def __repr__(self) -> str: + return f"ColorSystem.{self.name}" + + def __str__(self) -> str: + return repr(self) + + +class ColorType(IntEnum): + """Type of color stored in Color class.""" + + DEFAULT = 0 + STANDARD = 1 + EIGHT_BIT = 2 + TRUECOLOR = 3 + WINDOWS = 4 + + def __repr__(self) -> str: + return f"ColorType.{self.name}" + + +ANSI_COLOR_NAMES = { + "black": 0, + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "magenta": 5, + "cyan": 6, + "white": 7, + "bright_black": 8, + "bright_red": 9, + "bright_green": 10, + "bright_yellow": 11, + "bright_blue": 12, + "bright_magenta": 13, + "bright_cyan": 14, + "bright_white": 15, + "grey0": 16, + "gray0": 16, + "navy_blue": 17, + "dark_blue": 18, + "blue3": 20, + "blue1": 21, + "dark_green": 22, + "deep_sky_blue4": 25, + "dodger_blue3": 26, + "dodger_blue2": 27, + "green4": 28, + "spring_green4": 29, + "turquoise4": 30, + "deep_sky_blue3": 32, + "dodger_blue1": 33, + "green3": 40, + "spring_green3": 41, + "dark_cyan": 36, + "light_sea_green": 37, + "deep_sky_blue2": 38, + "deep_sky_blue1": 39, + "spring_green2": 47, + "cyan3": 43, + "dark_turquoise": 44, + "turquoise2": 45, + "green1": 46, + "spring_green1": 48, + "medium_spring_green": 49, + "cyan2": 50, + "cyan1": 51, + "dark_red": 88, + "deep_pink4": 125, + "purple4": 55, + "purple3": 56, + "blue_violet": 57, + "orange4": 94, + "grey37": 59, + "gray37": 59, + "medium_purple4": 60, + "slate_blue3": 62, + "royal_blue1": 63, + "chartreuse4": 64, + "dark_sea_green4": 71, + "pale_turquoise4": 66, + "steel_blue": 67, + "steel_blue3": 68, + "cornflower_blue": 69, + "chartreuse3": 76, + "cadet_blue": 73, + "sky_blue3": 74, + "steel_blue1": 81, + "pale_green3": 114, + "sea_green3": 78, + "aquamarine3": 79, + "medium_turquoise": 80, + "chartreuse2": 112, + "sea_green2": 83, + "sea_green1": 85, + "aquamarine1": 122, + "dark_slate_gray2": 87, + "dark_magenta": 91, + "dark_violet": 128, + "purple": 129, + "light_pink4": 95, + "plum4": 96, + "medium_purple3": 98, + "slate_blue1": 99, + "yellow4": 106, + "wheat4": 101, + "grey53": 102, + "gray53": 102, + "light_slate_grey": 103, + "light_slate_gray": 103, + "medium_purple": 104, + "light_slate_blue": 105, + "dark_olive_green3": 149, + "dark_sea_green": 108, + "light_sky_blue3": 110, + "sky_blue2": 111, + "dark_sea_green3": 150, + "dark_slate_gray3": 116, + "sky_blue1": 117, + "chartreuse1": 118, + "light_green": 120, + "pale_green1": 156, + "dark_slate_gray1": 123, + "red3": 160, + "medium_violet_red": 126, + "magenta3": 164, + "dark_orange3": 166, + "indian_red": 167, + "hot_pink3": 168, + "medium_orchid3": 133, + "medium_orchid": 134, + "medium_purple2": 140, + "dark_goldenrod": 136, + "light_salmon3": 173, + "rosy_brown": 138, + "grey63": 139, + "gray63": 139, + "medium_purple1": 141, + "gold3": 178, + "dark_khaki": 143, + "navajo_white3": 144, + "grey69": 145, + "gray69": 145, + "light_steel_blue3": 146, + "light_steel_blue": 147, + "yellow3": 184, + "dark_sea_green2": 157, + "light_cyan3": 152, + "light_sky_blue1": 153, + "green_yellow": 154, + "dark_olive_green2": 155, + "dark_sea_green1": 193, + "pale_turquoise1": 159, + "deep_pink3": 162, + "magenta2": 200, + "hot_pink2": 169, + "orchid": 170, + "medium_orchid1": 207, + "orange3": 172, + "light_pink3": 174, + "pink3": 175, + "plum3": 176, + "violet": 177, + "light_goldenrod3": 179, + "tan": 180, + "misty_rose3": 181, + "thistle3": 182, + "plum2": 183, + "khaki3": 185, + "light_goldenrod2": 222, + "light_yellow3": 187, + "grey84": 188, + "gray84": 188, + "light_steel_blue1": 189, + "yellow2": 190, + "dark_olive_green1": 192, + "honeydew2": 194, + "light_cyan1": 195, + "red1": 196, + "deep_pink2": 197, + "deep_pink1": 199, + "magenta1": 201, + "orange_red1": 202, + "indian_red1": 204, + "hot_pink": 206, + "dark_orange": 208, + "salmon1": 209, + "light_coral": 210, + "pale_violet_red1": 211, + "orchid2": 212, + "orchid1": 213, + "orange1": 214, + "sandy_brown": 215, + "light_salmon1": 216, + "light_pink1": 217, + "pink1": 218, + "plum1": 219, + "gold1": 220, + "navajo_white1": 223, + "misty_rose1": 224, + "thistle1": 225, + "yellow1": 226, + "light_goldenrod1": 227, + "khaki1": 228, + "wheat1": 229, + "cornsilk1": 230, + "grey100": 231, + "gray100": 231, + "grey3": 232, + "gray3": 232, + "grey7": 233, + "gray7": 233, + "grey11": 234, + "gray11": 234, + "grey15": 235, + "gray15": 235, + "grey19": 236, + "gray19": 236, + "grey23": 237, + "gray23": 237, + "grey27": 238, + "gray27": 238, + "grey30": 239, + "gray30": 239, + "grey35": 240, + "gray35": 240, + "grey39": 241, + "gray39": 241, + "grey42": 242, + "gray42": 242, + "grey46": 243, + "gray46": 243, + "grey50": 244, + "gray50": 244, + "grey54": 245, + "gray54": 245, + "grey58": 246, + "gray58": 246, + "grey62": 247, + "gray62": 247, + "grey66": 248, + "gray66": 248, + "grey70": 249, + "gray70": 249, + "grey74": 250, + "gray74": 250, + "grey78": 251, + "gray78": 251, + "grey82": 252, + "gray82": 252, + "grey85": 253, + "gray85": 253, + "grey89": 254, + "gray89": 254, + "grey93": 255, + "gray93": 255, +} + + +class ColorParseError(Exception): + """The color could not be parsed.""" + + +RE_COLOR = re.compile( + r"""^ +\#([0-9a-f]{6})$| +color\(([0-9]{1,3})\)$| +rgb\(([\d\s,]+)\)$ +""", + re.VERBOSE, +) + + +@rich_repr +class Color(NamedTuple): + """Terminal color definition.""" + + name: str + """The name of the color (typically the input to Color.parse).""" + type: ColorType + """The type of the color.""" + number: Optional[int] = None + """The color number, if a standard color, or None.""" + triplet: Optional[ColorTriplet] = None + """A triplet of color components, if an RGB color.""" + + def __rich__(self) -> "Text": + """Displays the actual color if Rich printed.""" + from .style import Style + from .text import Text + + return Text.assemble( + f"", + ) + + def __rich_repr__(self) -> Result: + yield self.name + yield self.type + yield "number", self.number, None + yield "triplet", self.triplet, None + + @property + def system(self) -> ColorSystem: + """Get the native color system for this color.""" + if self.type == ColorType.DEFAULT: + return ColorSystem.STANDARD + return ColorSystem(int(self.type)) + + @property + def is_system_defined(self) -> bool: + """Check if the color is ultimately defined by the system.""" + return self.system not in (ColorSystem.EIGHT_BIT, ColorSystem.TRUECOLOR) + + @property + def is_default(self) -> bool: + """Check if the color is a default color.""" + return self.type == ColorType.DEFAULT + + def get_truecolor( + self, theme: Optional["TerminalTheme"] = None, foreground: bool = True + ) -> ColorTriplet: + """Get an equivalent color triplet for this color. + + Args: + theme (TerminalTheme, optional): Optional terminal theme, or None to use default. Defaults to None. + foreground (bool, optional): True for a foreground color, or False for background. Defaults to True. + + Returns: + ColorTriplet: A color triplet containing RGB components. + """ + + if theme is None: + theme = DEFAULT_TERMINAL_THEME + if self.type == ColorType.TRUECOLOR: + assert self.triplet is not None + return self.triplet + elif self.type == ColorType.EIGHT_BIT: + assert self.number is not None + return EIGHT_BIT_PALETTE[self.number] + elif self.type == ColorType.STANDARD: + assert self.number is not None + return theme.ansi_colors[self.number] + elif self.type == ColorType.WINDOWS: + assert self.number is not None + return WINDOWS_PALETTE[self.number] + else: # self.type == ColorType.DEFAULT: + assert self.number is None + return theme.foreground_color if foreground else theme.background_color + + @classmethod + def from_ansi(cls, number: int) -> "Color": + """Create a Color number from it's 8-bit ansi number. + + Args: + number (int): A number between 0-255 inclusive. + + Returns: + Color: A new Color instance. + """ + return cls( + name=f"color({number})", + type=(ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT), + number=number, + ) + + @classmethod + def from_triplet(cls, triplet: "ColorTriplet") -> "Color": + """Create a truecolor RGB color from a triplet of values. + + Args: + triplet (ColorTriplet): A color triplet containing red, green and blue components. + + Returns: + Color: A new color object. + """ + return cls(name=triplet.hex, type=ColorType.TRUECOLOR, triplet=triplet) + + @classmethod + def from_rgb(cls, red: float, green: float, blue: float) -> "Color": + """Create a truecolor from three color components in the range(0->255). + + Args: + red (float): Red component in range 0-255. + green (float): Green component in range 0-255. + blue (float): Blue component in range 0-255. + + Returns: + Color: A new color object. + """ + return cls.from_triplet(ColorTriplet(int(red), int(green), int(blue))) + + @classmethod + def default(cls) -> "Color": + """Get a Color instance representing the default color. + + Returns: + Color: Default color. + """ + return cls(name="default", type=ColorType.DEFAULT) + + @classmethod + @lru_cache(maxsize=1024) + def parse(cls, color: str) -> "Color": + """Parse a color definition.""" + original_color = color + color = color.lower().strip() + + if color == "default": + return cls(color, type=ColorType.DEFAULT) + + color_number = ANSI_COLOR_NAMES.get(color) + if color_number is not None: + return cls( + color, + type=(ColorType.STANDARD if color_number < 16 else ColorType.EIGHT_BIT), + number=color_number, + ) + + color_match = RE_COLOR.match(color) + if color_match is None: + raise ColorParseError(f"{original_color!r} is not a valid color") + + color_24, color_8, color_rgb = color_match.groups() + if color_24: + triplet = ColorTriplet( + int(color_24[0:2], 16), int(color_24[2:4], 16), int(color_24[4:6], 16) + ) + return cls(color, ColorType.TRUECOLOR, triplet=triplet) + + elif color_8: + number = int(color_8) + if number > 255: + raise ColorParseError(f"color number must be <= 255 in {color!r}") + return cls( + color, + type=(ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT), + number=number, + ) + + else: # color_rgb: + components = color_rgb.split(",") + if len(components) != 3: + raise ColorParseError( + f"expected three components in {original_color!r}" + ) + red, green, blue = components + triplet = ColorTriplet(int(red), int(green), int(blue)) + if not all(component <= 255 for component in triplet): + raise ColorParseError( + f"color components must be <= 255 in {original_color!r}" + ) + return cls(color, ColorType.TRUECOLOR, triplet=triplet) + + @lru_cache(maxsize=1024) + def get_ansi_codes(self, foreground: bool = True) -> Tuple[str, ...]: + """Get the ANSI escape codes for this color.""" + _type = self.type + if _type == ColorType.DEFAULT: + return ("39" if foreground else "49",) + + elif _type == ColorType.WINDOWS: + number = self.number + assert number is not None + fore, back = (30, 40) if number < 8 else (82, 92) + return (str(fore + number if foreground else back + number),) + + elif _type == ColorType.STANDARD: + number = self.number + assert number is not None + fore, back = (30, 40) if number < 8 else (82, 92) + return (str(fore + number if foreground else back + number),) + + elif _type == ColorType.EIGHT_BIT: + assert self.number is not None + return ("38" if foreground else "48", "5", str(self.number)) + + else: # self.standard == ColorStandard.TRUECOLOR: + assert self.triplet is not None + red, green, blue = self.triplet + return ("38" if foreground else "48", "2", str(red), str(green), str(blue)) + + @lru_cache(maxsize=1024) + def downgrade(self, system: ColorSystem) -> "Color": + """Downgrade a color system to a system with fewer colors.""" + + if self.type in (ColorType.DEFAULT, system): + return self + # Convert to 8-bit color from truecolor color + if system == ColorSystem.EIGHT_BIT and self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + _h, l, s = rgb_to_hls(*self.triplet.normalized) + # If saturation is under 15% assume it is grayscale + if s < 0.15: + gray = round(l * 25.0) + if gray == 0: + color_number = 16 + elif gray == 25: + color_number = 231 + else: + color_number = 231 + gray + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + + red, green, blue = self.triplet + six_red = red / 95 if red < 95 else 1 + (red - 95) / 40 + six_green = green / 95 if green < 95 else 1 + (green - 95) / 40 + six_blue = blue / 95 if blue < 95 else 1 + (blue - 95) / 40 + + color_number = ( + 16 + 36 * round(six_red) + 6 * round(six_green) + round(six_blue) + ) + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + + # Convert to standard from truecolor or 8-bit + elif system == ColorSystem.STANDARD: + if self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + triplet = self.triplet + else: # self.system == ColorSystem.EIGHT_BIT + assert self.number is not None + triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number]) + + color_number = STANDARD_PALETTE.match(triplet) + return Color(self.name, ColorType.STANDARD, number=color_number) + + elif system == ColorSystem.WINDOWS: + if self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + triplet = self.triplet + else: # self.system == ColorSystem.EIGHT_BIT + assert self.number is not None + if self.number < 16: + return Color(self.name, ColorType.WINDOWS, number=self.number) + triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number]) + + color_number = WINDOWS_PALETTE.match(triplet) + return Color(self.name, ColorType.WINDOWS, number=color_number) + + return self + + +def parse_rgb_hex(hex_color: str) -> ColorTriplet: + """Parse six hex characters in to RGB triplet.""" + assert len(hex_color) == 6, "must be 6 characters" + color = ColorTriplet( + int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16) + ) + return color + + +def blend_rgb( + color1: ColorTriplet, color2: ColorTriplet, cross_fade: float = 0.5 +) -> ColorTriplet: + """Blend one RGB color in to another.""" + r1, g1, b1 = color1 + r2, g2, b2 = color2 + new_color = ColorTriplet( + int(r1 + (r2 - r1) * cross_fade), + int(g1 + (g2 - g1) * cross_fade), + int(b1 + (b2 - b1) * cross_fade), + ) + return new_color + + +if __name__ == "__main__": # pragma: no cover + from .console import Console + from .table import Table + from .text import Text + + console = Console() + + table = Table(show_footer=False, show_edge=True) + table.add_column("Color", width=10, overflow="ellipsis") + table.add_column("Number", justify="right", style="yellow") + table.add_column("Name", style="green") + table.add_column("Hex", style="blue") + table.add_column("RGB", style="magenta") + + colors = sorted((v, k) for k, v in ANSI_COLOR_NAMES.items()) + for color_number, name in colors: + if "grey" in name: + continue + color_cell = Text(" " * 10, style=f"on {name}") + if color_number < 16: + table.add_row(color_cell, f"{color_number}", Text(f'"{name}"')) + else: + color = EIGHT_BIT_PALETTE[color_number] # type: ignore[has-type] + table.add_row( + color_cell, str(color_number), Text(f'"{name}"'), color.hex, color.rgb + ) + + console.print(table) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py new file mode 100644 index 0000000..02cab32 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py @@ -0,0 +1,38 @@ +from typing import NamedTuple, Tuple + + +class ColorTriplet(NamedTuple): + """The red, green, and blue components of a color.""" + + red: int + """Red component in 0 to 255 range.""" + green: int + """Green component in 0 to 255 range.""" + blue: int + """Blue component in 0 to 255 range.""" + + @property + def hex(self) -> str: + """get the color triplet in CSS style.""" + red, green, blue = self + return f"#{red:02x}{green:02x}{blue:02x}" + + @property + def rgb(self) -> str: + """The color in RGB format. + + Returns: + str: An rgb color, e.g. ``"rgb(100,23,255)"``. + """ + red, green, blue = self + return f"rgb({red},{green},{blue})" + + @property + def normalized(self) -> Tuple[float, float, float]: + """Convert components into floats between 0 and 1. + + Returns: + Tuple[float, float, float]: A tuple of three normalized colour components. + """ + red, green, blue = self + return red / 255.0, green / 255.0, blue / 255.0 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/columns.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/columns.py new file mode 100644 index 0000000..669a3a7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/columns.py @@ -0,0 +1,187 @@ +from collections import defaultdict +from itertools import chain +from operator import itemgetter +from typing import Dict, Iterable, List, Optional, Tuple + +from .align import Align, AlignMethod +from .console import Console, ConsoleOptions, RenderableType, RenderResult +from .constrain import Constrain +from .measure import Measurement +from .padding import Padding, PaddingDimensions +from .table import Table +from .text import TextType +from .jupyter import JupyterMixin + + +class Columns(JupyterMixin): + """Display renderables in neat columns. + + Args: + renderables (Iterable[RenderableType]): Any number of Rich renderables (including str). + width (int, optional): The desired width of the columns, or None to auto detect. Defaults to None. + padding (PaddingDimensions, optional): Optional padding around cells. Defaults to (0, 1). + expand (bool, optional): Expand columns to full width. Defaults to False. + equal (bool, optional): Arrange in to equal sized columns. Defaults to False. + column_first (bool, optional): Align items from top to bottom (rather than left to right). Defaults to False. + right_to_left (bool, optional): Start column from right hand side. Defaults to False. + align (str, optional): Align value ("left", "right", or "center") or None for default. Defaults to None. + title (TextType, optional): Optional title for Columns. + """ + + def __init__( + self, + renderables: Optional[Iterable[RenderableType]] = None, + padding: PaddingDimensions = (0, 1), + *, + width: Optional[int] = None, + expand: bool = False, + equal: bool = False, + column_first: bool = False, + right_to_left: bool = False, + align: Optional[AlignMethod] = None, + title: Optional[TextType] = None, + ) -> None: + self.renderables = list(renderables or []) + self.width = width + self.padding = padding + self.expand = expand + self.equal = equal + self.column_first = column_first + self.right_to_left = right_to_left + self.align: Optional[AlignMethod] = align + self.title = title + + def add_renderable(self, renderable: RenderableType) -> None: + """Add a renderable to the columns. + + Args: + renderable (RenderableType): Any renderable object. + """ + self.renderables.append(renderable) + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + render_str = console.render_str + renderables = [ + render_str(renderable) if isinstance(renderable, str) else renderable + for renderable in self.renderables + ] + if not renderables: + return + _top, right, _bottom, left = Padding.unpack(self.padding) + width_padding = max(left, right) + max_width = options.max_width + widths: Dict[int, int] = defaultdict(int) + column_count = len(renderables) + + get_measurement = Measurement.get + renderable_widths = [ + get_measurement(console, options, renderable).maximum + for renderable in renderables + ] + if self.equal: + renderable_widths = [max(renderable_widths)] * len(renderable_widths) + + def iter_renderables( + column_count: int, + ) -> Iterable[Tuple[int, Optional[RenderableType]]]: + item_count = len(renderables) + if self.column_first: + width_renderables = list(zip(renderable_widths, renderables)) + + column_lengths: List[int] = [item_count // column_count] * column_count + for col_no in range(item_count % column_count): + column_lengths[col_no] += 1 + + row_count = (item_count + column_count - 1) // column_count + cells = [[-1] * column_count for _ in range(row_count)] + row = col = 0 + for index in range(item_count): + cells[row][col] = index + column_lengths[col] -= 1 + if column_lengths[col]: + row += 1 + else: + col += 1 + row = 0 + for index in chain.from_iterable(cells): + if index == -1: + break + yield width_renderables[index] + else: + yield from zip(renderable_widths, renderables) + # Pad odd elements with spaces + if item_count % column_count: + for _ in range(column_count - (item_count % column_count)): + yield 0, None + + table = Table.grid(padding=self.padding, collapse_padding=True, pad_edge=False) + table.expand = self.expand + table.title = self.title + + if self.width is not None: + column_count = (max_width) // (self.width + width_padding) + for _ in range(column_count): + table.add_column(width=self.width) + else: + while column_count > 1: + widths.clear() + column_no = 0 + for renderable_width, _ in iter_renderables(column_count): + widths[column_no] = max(widths[column_no], renderable_width) + total_width = sum(widths.values()) + width_padding * ( + len(widths) - 1 + ) + if total_width > max_width: + column_count = len(widths) - 1 + break + else: + column_no = (column_no + 1) % column_count + else: + break + + get_renderable = itemgetter(1) + _renderables = [ + get_renderable(_renderable) + for _renderable in iter_renderables(column_count) + ] + if self.equal: + _renderables = [ + None + if renderable is None + else Constrain(renderable, renderable_widths[0]) + for renderable in _renderables + ] + if self.align: + align = self.align + _Align = Align + _renderables = [ + None if renderable is None else _Align(renderable, align) + for renderable in _renderables + ] + + right_to_left = self.right_to_left + add_row = table.add_row + for start in range(0, len(_renderables), column_count): + row = _renderables[start : start + column_count] + if right_to_left: + row = row[::-1] + add_row(*row) + yield table + + +if __name__ == "__main__": # pragma: no cover + import os + + console = Console() + + files = [f"{i} {s}" for i, s in enumerate(sorted(os.listdir()))] + columns = Columns(files, padding=(0, 1), expand=False, equal=False) + console.print(columns) + console.rule() + columns.column_first = True + console.print(columns) + columns.right_to_left = True + console.rule() + console.print(columns) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/console.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/console.py new file mode 100644 index 0000000..5728845 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/console.py @@ -0,0 +1,2661 @@ +import inspect +import os +import sys +import threading +import zlib +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from datetime import datetime +from functools import wraps +from getpass import getpass +from html import escape +from inspect import isclass +from itertools import islice +from math import ceil +from time import monotonic +from types import FrameType, ModuleType, TracebackType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterable, + List, + Mapping, + NamedTuple, + Optional, + TextIO, + Tuple, + Type, + Union, + cast, +) + +from pip._vendor.rich._null_file import NULL_FILE + +if sys.version_info >= (3, 8): + from typing import Literal, Protocol, runtime_checkable +else: + from pip._vendor.typing_extensions import ( + Literal, + Protocol, + runtime_checkable, + ) # pragma: no cover + +from . import errors, themes +from ._emoji_replace import _emoji_replace +from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT +from ._fileno import get_fileno +from ._log_render import FormatTimeCallable, LogRender +from .align import Align, AlignMethod +from .color import ColorSystem, blend_rgb +from .control import Control +from .emoji import EmojiVariant +from .highlighter import NullHighlighter, ReprHighlighter +from .markup import render as render_markup +from .measure import Measurement, measure_renderables +from .pager import Pager, SystemPager +from .pretty import Pretty, is_expandable +from .protocol import rich_cast +from .region import Region +from .scope import render_scope +from .screen import Screen +from .segment import Segment +from .style import Style, StyleType +from .styled import Styled +from .terminal_theme import DEFAULT_TERMINAL_THEME, SVG_EXPORT_THEME, TerminalTheme +from .text import Text, TextType +from .theme import Theme, ThemeStack + +if TYPE_CHECKING: + from ._windows import WindowsConsoleFeatures + from .live import Live + from .status import Status + +JUPYTER_DEFAULT_COLUMNS = 115 +JUPYTER_DEFAULT_LINES = 100 +WINDOWS = sys.platform == "win32" + +HighlighterType = Callable[[Union[str, "Text"]], "Text"] +JustifyMethod = Literal["default", "left", "center", "right", "full"] +OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"] + + +class NoChange: + pass + + +NO_CHANGE = NoChange() + +try: + _STDIN_FILENO = sys.__stdin__.fileno() # type: ignore[union-attr] +except Exception: + _STDIN_FILENO = 0 +try: + _STDOUT_FILENO = sys.__stdout__.fileno() # type: ignore[union-attr] +except Exception: + _STDOUT_FILENO = 1 +try: + _STDERR_FILENO = sys.__stderr__.fileno() # type: ignore[union-attr] +except Exception: + _STDERR_FILENO = 2 + +_STD_STREAMS = (_STDIN_FILENO, _STDOUT_FILENO, _STDERR_FILENO) +_STD_STREAMS_OUTPUT = (_STDOUT_FILENO, _STDERR_FILENO) + + +_TERM_COLORS = { + "kitty": ColorSystem.EIGHT_BIT, + "256color": ColorSystem.EIGHT_BIT, + "16color": ColorSystem.STANDARD, +} + + +class ConsoleDimensions(NamedTuple): + """Size of the terminal.""" + + width: int + """The width of the console in 'cells'.""" + height: int + """The height of the console in lines.""" + + +@dataclass +class ConsoleOptions: + """Options for __rich_console__ method.""" + + size: ConsoleDimensions + """Size of console.""" + legacy_windows: bool + """legacy_windows: flag for legacy windows.""" + min_width: int + """Minimum width of renderable.""" + max_width: int + """Maximum width of renderable.""" + is_terminal: bool + """True if the target is a terminal, otherwise False.""" + encoding: str + """Encoding of terminal.""" + max_height: int + """Height of container (starts as terminal)""" + justify: Optional[JustifyMethod] = None + """Justify value override for renderable.""" + overflow: Optional[OverflowMethod] = None + """Overflow value override for renderable.""" + no_wrap: Optional[bool] = False + """Disable wrapping for text.""" + highlight: Optional[bool] = None + """Highlight override for render_str.""" + markup: Optional[bool] = None + """Enable markup when rendering strings.""" + height: Optional[int] = None + + @property + def ascii_only(self) -> bool: + """Check if renderables should use ascii only.""" + return not self.encoding.startswith("utf") + + def copy(self) -> "ConsoleOptions": + """Return a copy of the options. + + Returns: + ConsoleOptions: a copy of self. + """ + options: ConsoleOptions = ConsoleOptions.__new__(ConsoleOptions) + options.__dict__ = self.__dict__.copy() + return options + + def update( + self, + *, + width: Union[int, NoChange] = NO_CHANGE, + min_width: Union[int, NoChange] = NO_CHANGE, + max_width: Union[int, NoChange] = NO_CHANGE, + justify: Union[Optional[JustifyMethod], NoChange] = NO_CHANGE, + overflow: Union[Optional[OverflowMethod], NoChange] = NO_CHANGE, + no_wrap: Union[Optional[bool], NoChange] = NO_CHANGE, + highlight: Union[Optional[bool], NoChange] = NO_CHANGE, + markup: Union[Optional[bool], NoChange] = NO_CHANGE, + height: Union[Optional[int], NoChange] = NO_CHANGE, + ) -> "ConsoleOptions": + """Update values, return a copy.""" + options = self.copy() + if not isinstance(width, NoChange): + options.min_width = options.max_width = max(0, width) + if not isinstance(min_width, NoChange): + options.min_width = min_width + if not isinstance(max_width, NoChange): + options.max_width = max_width + if not isinstance(justify, NoChange): + options.justify = justify + if not isinstance(overflow, NoChange): + options.overflow = overflow + if not isinstance(no_wrap, NoChange): + options.no_wrap = no_wrap + if not isinstance(highlight, NoChange): + options.highlight = highlight + if not isinstance(markup, NoChange): + options.markup = markup + if not isinstance(height, NoChange): + if height is not None: + options.max_height = height + options.height = None if height is None else max(0, height) + return options + + def update_width(self, width: int) -> "ConsoleOptions": + """Update just the width, return a copy. + + Args: + width (int): New width (sets both min_width and max_width) + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.min_width = options.max_width = max(0, width) + return options + + def update_height(self, height: int) -> "ConsoleOptions": + """Update the height, and return a copy. + + Args: + height (int): New height + + Returns: + ~ConsoleOptions: New Console options instance. + """ + options = self.copy() + options.max_height = options.height = height + return options + + def reset_height(self) -> "ConsoleOptions": + """Return a copy of the options with height set to ``None``. + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.height = None + return options + + def update_dimensions(self, width: int, height: int) -> "ConsoleOptions": + """Update the width and height, and return a copy. + + Args: + width (int): New width (sets both min_width and max_width). + height (int): New height. + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.min_width = options.max_width = max(0, width) + options.height = options.max_height = height + return options + + +@runtime_checkable +class RichCast(Protocol): + """An object that may be 'cast' to a console renderable.""" + + def __rich__( + self, + ) -> Union["ConsoleRenderable", "RichCast", str]: # pragma: no cover + ... + + +@runtime_checkable +class ConsoleRenderable(Protocol): + """An object that supports the console protocol.""" + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": # pragma: no cover + ... + + +# A type that may be rendered by Console. +RenderableType = Union[ConsoleRenderable, RichCast, str] +"""A string or any object that may be rendered by Rich.""" + +# The result of calling a __rich_console__ method. +RenderResult = Iterable[Union[RenderableType, Segment]] + +_null_highlighter = NullHighlighter() + + +class CaptureError(Exception): + """An error in the Capture context manager.""" + + +class NewLine: + """A renderable to generate new line(s)""" + + def __init__(self, count: int = 1) -> None: + self.count = count + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> Iterable[Segment]: + yield Segment("\n" * self.count) + + +class ScreenUpdate: + """Render a list of lines at a given offset.""" + + def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None: + self._lines = lines + self.x = x + self.y = y + + def __rich_console__( + self, console: "Console", options: ConsoleOptions + ) -> RenderResult: + x = self.x + move_to = Control.move_to + for offset, line in enumerate(self._lines, self.y): + yield move_to(x, offset) + yield from line + + +class Capture: + """Context manager to capture the result of printing to the console. + See :meth:`~rich.console.Console.capture` for how to use. + + Args: + console (Console): A console instance to capture output. + """ + + def __init__(self, console: "Console") -> None: + self._console = console + self._result: Optional[str] = None + + def __enter__(self) -> "Capture": + self._console.begin_capture() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self._result = self._console.end_capture() + + def get(self) -> str: + """Get the result of the capture.""" + if self._result is None: + raise CaptureError( + "Capture result is not available until context manager exits." + ) + return self._result + + +class ThemeContext: + """A context manager to use a temporary theme. See :meth:`~rich.console.Console.use_theme` for usage.""" + + def __init__(self, console: "Console", theme: Theme, inherit: bool = True) -> None: + self.console = console + self.theme = theme + self.inherit = inherit + + def __enter__(self) -> "ThemeContext": + self.console.push_theme(self.theme) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.console.pop_theme() + + +class PagerContext: + """A context manager that 'pages' content. See :meth:`~rich.console.Console.pager` for usage.""" + + def __init__( + self, + console: "Console", + pager: Optional[Pager] = None, + styles: bool = False, + links: bool = False, + ) -> None: + self._console = console + self.pager = SystemPager() if pager is None else pager + self.styles = styles + self.links = links + + def __enter__(self) -> "PagerContext": + self._console._enter_buffer() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if exc_type is None: + with self._console._lock: + buffer: List[Segment] = self._console._buffer[:] + del self._console._buffer[:] + segments: Iterable[Segment] = buffer + if not self.styles: + segments = Segment.strip_styles(segments) + elif not self.links: + segments = Segment.strip_links(segments) + content = self._console._render_buffer(segments) + self.pager.show(content) + self._console._exit_buffer() + + +class ScreenContext: + """A context manager that enables an alternative screen. See :meth:`~rich.console.Console.screen` for usage.""" + + def __init__( + self, console: "Console", hide_cursor: bool, style: StyleType = "" + ) -> None: + self.console = console + self.hide_cursor = hide_cursor + self.screen = Screen(style=style) + self._changed = False + + def update( + self, *renderables: RenderableType, style: Optional[StyleType] = None + ) -> None: + """Update the screen. + + Args: + renderable (RenderableType, optional): Optional renderable to replace current renderable, + or None for no change. Defaults to None. + style: (Style, optional): Replacement style, or None for no change. Defaults to None. + """ + if renderables: + self.screen.renderable = ( + Group(*renderables) if len(renderables) > 1 else renderables[0] + ) + if style is not None: + self.screen.style = style + self.console.print(self.screen, end="") + + def __enter__(self) -> "ScreenContext": + self._changed = self.console.set_alt_screen(True) + if self._changed and self.hide_cursor: + self.console.show_cursor(False) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if self._changed: + self.console.set_alt_screen(False) + if self.hide_cursor: + self.console.show_cursor(True) + + +class Group: + """Takes a group of renderables and returns a renderable object that renders the group. + + Args: + renderables (Iterable[RenderableType]): An iterable of renderable objects. + fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True. + """ + + def __init__(self, *renderables: "RenderableType", fit: bool = True) -> None: + self._renderables = renderables + self.fit = fit + self._render: Optional[List[RenderableType]] = None + + @property + def renderables(self) -> List["RenderableType"]: + if self._render is None: + self._render = list(self._renderables) + return self._render + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + if self.fit: + return measure_renderables(console, options, self.renderables) + else: + return Measurement(options.max_width, options.max_width) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> RenderResult: + yield from self.renderables + + +def group(fit: bool = True) -> Callable[..., Callable[..., Group]]: + """A decorator that turns an iterable of renderables in to a group. + + Args: + fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True. + """ + + def decorator( + method: Callable[..., Iterable[RenderableType]] + ) -> Callable[..., Group]: + """Convert a method that returns an iterable of renderables in to a Group.""" + + @wraps(method) + def _replace(*args: Any, **kwargs: Any) -> Group: + renderables = method(*args, **kwargs) + return Group(*renderables, fit=fit) + + return _replace + + return decorator + + +def _is_jupyter() -> bool: # pragma: no cover + """Check if we're running in a Jupyter notebook.""" + try: + get_ipython # type: ignore[name-defined] + except NameError: + return False + ipython = get_ipython() # type: ignore[name-defined] + shell = ipython.__class__.__name__ + if ( + "google.colab" in str(ipython.__class__) + or os.getenv("DATABRICKS_RUNTIME_VERSION") + or shell == "ZMQInteractiveShell" + ): + return True # Jupyter notebook or qtconsole + elif shell == "TerminalInteractiveShell": + return False # Terminal running IPython + else: + return False # Other type (?) + + +COLOR_SYSTEMS = { + "standard": ColorSystem.STANDARD, + "256": ColorSystem.EIGHT_BIT, + "truecolor": ColorSystem.TRUECOLOR, + "windows": ColorSystem.WINDOWS, +} + +_COLOR_SYSTEMS_NAMES = {system: name for name, system in COLOR_SYSTEMS.items()} + + +@dataclass +class ConsoleThreadLocals(threading.local): + """Thread local values for Console context.""" + + theme_stack: ThemeStack + buffer: List[Segment] = field(default_factory=list) + buffer_index: int = 0 + + +class RenderHook(ABC): + """Provides hooks in to the render process.""" + + @abstractmethod + def process_renderables( + self, renderables: List[ConsoleRenderable] + ) -> List[ConsoleRenderable]: + """Called with a list of objects to render. + + This method can return a new list of renderables, or modify and return the same list. + + Args: + renderables (List[ConsoleRenderable]): A number of renderable objects. + + Returns: + List[ConsoleRenderable]: A replacement list of renderables. + """ + + +_windows_console_features: Optional["WindowsConsoleFeatures"] = None + + +def get_windows_console_features() -> "WindowsConsoleFeatures": # pragma: no cover + global _windows_console_features + if _windows_console_features is not None: + return _windows_console_features + from ._windows import get_windows_console_features + + _windows_console_features = get_windows_console_features() + return _windows_console_features + + +def detect_legacy_windows() -> bool: + """Detect legacy Windows.""" + return WINDOWS and not get_windows_console_features().vt + + +class Console: + """A high level console interface. + + Args: + color_system (str, optional): The color system supported by your terminal, + either ``"standard"``, ``"256"`` or ``"truecolor"``. Leave as ``"auto"`` to autodetect. + force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None. + force_jupyter (Optional[bool], optional): Enable/disable Jupyter rendering, or None to auto-detect Jupyter. Defaults to None. + force_interactive (Optional[bool], optional): Enable/disable interactive mode, or None to auto detect. Defaults to None. + soft_wrap (Optional[bool], optional): Set soft wrap default on print method. Defaults to False. + theme (Theme, optional): An optional style theme object, or ``None`` for default theme. + stderr (bool, optional): Use stderr rather than stdout if ``file`` is not specified. Defaults to False. + file (IO, optional): A file object where the console should write to. Defaults to stdout. + quiet (bool, Optional): Boolean to suppress all output. Defaults to False. + width (int, optional): The width of the terminal. Leave as default to auto-detect width. + height (int, optional): The height of the terminal. Leave as default to auto-detect height. + style (StyleType, optional): Style to apply to all output, or None for no style. Defaults to None. + no_color (Optional[bool], optional): Enabled no color mode, or None to auto detect. Defaults to None. + tab_size (int, optional): Number of spaces used to replace a tab character. Defaults to 8. + record (bool, optional): Boolean to enable recording of terminal output, + required to call :meth:`export_html`, :meth:`export_svg`, and :meth:`export_text`. Defaults to False. + markup (bool, optional): Boolean to enable :ref:`console_markup`. Defaults to True. + emoji (bool, optional): Enable emoji code. Defaults to True. + emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None. + highlight (bool, optional): Enable automatic highlighting. Defaults to True. + log_time (bool, optional): Boolean to enable logging of time by :meth:`log` methods. Defaults to True. + log_path (bool, optional): Boolean to enable the logging of the caller by :meth:`log`. Defaults to True. + log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%X] ". + highlighter (HighlighterType, optional): Default highlighter. + legacy_windows (bool, optional): Enable legacy Windows mode, or ``None`` to auto detect. Defaults to ``None``. + safe_box (bool, optional): Restrict box options that don't render on legacy Windows. + get_datetime (Callable[[], datetime], optional): Callable that gets the current time as a datetime.datetime object (used by Console.log), + or None for datetime.now. + get_time (Callable[[], time], optional): Callable that gets the current time in seconds, default uses time.monotonic. + """ + + _environ: Mapping[str, str] = os.environ + + def __init__( + self, + *, + color_system: Optional[ + Literal["auto", "standard", "256", "truecolor", "windows"] + ] = "auto", + force_terminal: Optional[bool] = None, + force_jupyter: Optional[bool] = None, + force_interactive: Optional[bool] = None, + soft_wrap: bool = False, + theme: Optional[Theme] = None, + stderr: bool = False, + file: Optional[IO[str]] = None, + quiet: bool = False, + width: Optional[int] = None, + height: Optional[int] = None, + style: Optional[StyleType] = None, + no_color: Optional[bool] = None, + tab_size: int = 8, + record: bool = False, + markup: bool = True, + emoji: bool = True, + emoji_variant: Optional[EmojiVariant] = None, + highlight: bool = True, + log_time: bool = True, + log_path: bool = True, + log_time_format: Union[str, FormatTimeCallable] = "[%X]", + highlighter: Optional["HighlighterType"] = ReprHighlighter(), + legacy_windows: Optional[bool] = None, + safe_box: bool = True, + get_datetime: Optional[Callable[[], datetime]] = None, + get_time: Optional[Callable[[], float]] = None, + _environ: Optional[Mapping[str, str]] = None, + ): + # Copy of os.environ allows us to replace it for testing + if _environ is not None: + self._environ = _environ + + self.is_jupyter = _is_jupyter() if force_jupyter is None else force_jupyter + if self.is_jupyter: + if width is None: + jupyter_columns = self._environ.get("JUPYTER_COLUMNS") + if jupyter_columns is not None and jupyter_columns.isdigit(): + width = int(jupyter_columns) + else: + width = JUPYTER_DEFAULT_COLUMNS + if height is None: + jupyter_lines = self._environ.get("JUPYTER_LINES") + if jupyter_lines is not None and jupyter_lines.isdigit(): + height = int(jupyter_lines) + else: + height = JUPYTER_DEFAULT_LINES + + self.tab_size = tab_size + self.record = record + self._markup = markup + self._emoji = emoji + self._emoji_variant: Optional[EmojiVariant] = emoji_variant + self._highlight = highlight + self.legacy_windows: bool = ( + (detect_legacy_windows() and not self.is_jupyter) + if legacy_windows is None + else legacy_windows + ) + + if width is None: + columns = self._environ.get("COLUMNS") + if columns is not None and columns.isdigit(): + width = int(columns) - self.legacy_windows + if height is None: + lines = self._environ.get("LINES") + if lines is not None and lines.isdigit(): + height = int(lines) + + self.soft_wrap = soft_wrap + self._width = width + self._height = height + + self._color_system: Optional[ColorSystem] + + self._force_terminal = None + if force_terminal is not None: + self._force_terminal = force_terminal + + self._file = file + self.quiet = quiet + self.stderr = stderr + + if color_system is None: + self._color_system = None + elif color_system == "auto": + self._color_system = self._detect_color_system() + else: + self._color_system = COLOR_SYSTEMS[color_system] + + self._lock = threading.RLock() + self._log_render = LogRender( + show_time=log_time, + show_path=log_path, + time_format=log_time_format, + ) + self.highlighter: HighlighterType = highlighter or _null_highlighter + self.safe_box = safe_box + self.get_datetime = get_datetime or datetime.now + self.get_time = get_time or monotonic + self.style = style + self.no_color = ( + no_color if no_color is not None else "NO_COLOR" in self._environ + ) + self.is_interactive = ( + (self.is_terminal and not self.is_dumb_terminal) + if force_interactive is None + else force_interactive + ) + + self._record_buffer_lock = threading.RLock() + self._thread_locals = ConsoleThreadLocals( + theme_stack=ThemeStack(themes.DEFAULT if theme is None else theme) + ) + self._record_buffer: List[Segment] = [] + self._render_hooks: List[RenderHook] = [] + self._live: Optional["Live"] = None + self._is_alt_screen = False + + def __repr__(self) -> str: + return f"" + + @property + def file(self) -> IO[str]: + """Get the file object to write to.""" + file = self._file or (sys.stderr if self.stderr else sys.stdout) + file = getattr(file, "rich_proxied_file", file) + if file is None: + file = NULL_FILE + return file + + @file.setter + def file(self, new_file: IO[str]) -> None: + """Set a new file object.""" + self._file = new_file + + @property + def _buffer(self) -> List[Segment]: + """Get a thread local buffer.""" + return self._thread_locals.buffer + + @property + def _buffer_index(self) -> int: + """Get a thread local buffer.""" + return self._thread_locals.buffer_index + + @_buffer_index.setter + def _buffer_index(self, value: int) -> None: + self._thread_locals.buffer_index = value + + @property + def _theme_stack(self) -> ThemeStack: + """Get the thread local theme stack.""" + return self._thread_locals.theme_stack + + def _detect_color_system(self) -> Optional[ColorSystem]: + """Detect color system from env vars.""" + if self.is_jupyter: + return ColorSystem.TRUECOLOR + if not self.is_terminal or self.is_dumb_terminal: + return None + if WINDOWS: # pragma: no cover + if self.legacy_windows: # pragma: no cover + return ColorSystem.WINDOWS + windows_console_features = get_windows_console_features() + return ( + ColorSystem.TRUECOLOR + if windows_console_features.truecolor + else ColorSystem.EIGHT_BIT + ) + else: + color_term = self._environ.get("COLORTERM", "").strip().lower() + if color_term in ("truecolor", "24bit"): + return ColorSystem.TRUECOLOR + term = self._environ.get("TERM", "").strip().lower() + _term_name, _hyphen, colors = term.rpartition("-") + color_system = _TERM_COLORS.get(colors, ColorSystem.STANDARD) + return color_system + + def _enter_buffer(self) -> None: + """Enter in to a buffer context, and buffer all output.""" + self._buffer_index += 1 + + def _exit_buffer(self) -> None: + """Leave buffer context, and render content if required.""" + self._buffer_index -= 1 + self._check_buffer() + + def set_live(self, live: "Live") -> None: + """Set Live instance. Used by Live context manager. + + Args: + live (Live): Live instance using this Console. + + Raises: + errors.LiveError: If this Console has a Live context currently active. + """ + with self._lock: + if self._live is not None: + raise errors.LiveError("Only one live display may be active at once") + self._live = live + + def clear_live(self) -> None: + """Clear the Live instance.""" + with self._lock: + self._live = None + + def push_render_hook(self, hook: RenderHook) -> None: + """Add a new render hook to the stack. + + Args: + hook (RenderHook): Render hook instance. + """ + with self._lock: + self._render_hooks.append(hook) + + def pop_render_hook(self) -> None: + """Pop the last renderhook from the stack.""" + with self._lock: + self._render_hooks.pop() + + def __enter__(self) -> "Console": + """Own context manager to enter buffer context.""" + self._enter_buffer() + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + """Exit buffer context.""" + self._exit_buffer() + + def begin_capture(self) -> None: + """Begin capturing console output. Call :meth:`end_capture` to exit capture mode and return output.""" + self._enter_buffer() + + def end_capture(self) -> str: + """End capture mode and return captured string. + + Returns: + str: Console output. + """ + render_result = self._render_buffer(self._buffer) + del self._buffer[:] + self._exit_buffer() + return render_result + + def push_theme(self, theme: Theme, *, inherit: bool = True) -> None: + """Push a new theme on to the top of the stack, replacing the styles from the previous theme. + Generally speaking, you should call :meth:`~rich.console.Console.use_theme` to get a context manager, rather + than calling this method directly. + + Args: + theme (Theme): A theme instance. + inherit (bool, optional): Inherit existing styles. Defaults to True. + """ + self._theme_stack.push_theme(theme, inherit=inherit) + + def pop_theme(self) -> None: + """Remove theme from top of stack, restoring previous theme.""" + self._theme_stack.pop_theme() + + def use_theme(self, theme: Theme, *, inherit: bool = True) -> ThemeContext: + """Use a different theme for the duration of the context manager. + + Args: + theme (Theme): Theme instance to user. + inherit (bool, optional): Inherit existing console styles. Defaults to True. + + Returns: + ThemeContext: [description] + """ + return ThemeContext(self, theme, inherit) + + @property + def color_system(self) -> Optional[str]: + """Get color system string. + + Returns: + Optional[str]: "standard", "256" or "truecolor". + """ + + if self._color_system is not None: + return _COLOR_SYSTEMS_NAMES[self._color_system] + else: + return None + + @property + def encoding(self) -> str: + """Get the encoding of the console file, e.g. ``"utf-8"``. + + Returns: + str: A standard encoding string. + """ + return (getattr(self.file, "encoding", "utf-8") or "utf-8").lower() + + @property + def is_terminal(self) -> bool: + """Check if the console is writing to a terminal. + + Returns: + bool: True if the console writing to a device capable of + understanding terminal codes, otherwise False. + """ + if self._force_terminal is not None: + return self._force_terminal + + if hasattr(sys.stdin, "__module__") and sys.stdin.__module__.startswith( + "idlelib" + ): + # Return False for Idle which claims to be a tty but can't handle ansi codes + return False + + if self.is_jupyter: + # return False for Jupyter, which may have FORCE_COLOR set + return False + + # If FORCE_COLOR env var has any value at all, we assume a terminal. + force_color = self._environ.get("FORCE_COLOR") + if force_color is not None: + self._force_terminal = True + return True + + isatty: Optional[Callable[[], bool]] = getattr(self.file, "isatty", None) + try: + return False if isatty is None else isatty() + except ValueError: + # in some situation (at the end of a pytest run for example) isatty() can raise + # ValueError: I/O operation on closed file + # return False because we aren't in a terminal anymore + return False + + @property + def is_dumb_terminal(self) -> bool: + """Detect dumb terminal. + + Returns: + bool: True if writing to a dumb terminal, otherwise False. + + """ + _term = self._environ.get("TERM", "") + is_dumb = _term.lower() in ("dumb", "unknown") + return self.is_terminal and is_dumb + + @property + def options(self) -> ConsoleOptions: + """Get default console options.""" + return ConsoleOptions( + max_height=self.size.height, + size=self.size, + legacy_windows=self.legacy_windows, + min_width=1, + max_width=self.width, + encoding=self.encoding, + is_terminal=self.is_terminal, + ) + + @property + def size(self) -> ConsoleDimensions: + """Get the size of the console. + + Returns: + ConsoleDimensions: A named tuple containing the dimensions. + """ + + if self._width is not None and self._height is not None: + return ConsoleDimensions(self._width - self.legacy_windows, self._height) + + if self.is_dumb_terminal: + return ConsoleDimensions(80, 25) + + width: Optional[int] = None + height: Optional[int] = None + + streams = _STD_STREAMS_OUTPUT if WINDOWS else _STD_STREAMS + for file_descriptor in streams: + try: + width, height = os.get_terminal_size(file_descriptor) + except (AttributeError, ValueError, OSError): # Probably not a terminal + pass + else: + break + + columns = self._environ.get("COLUMNS") + if columns is not None and columns.isdigit(): + width = int(columns) + lines = self._environ.get("LINES") + if lines is not None and lines.isdigit(): + height = int(lines) + + # get_terminal_size can report 0, 0 if run from pseudo-terminal + width = width or 80 + height = height or 25 + return ConsoleDimensions( + width - self.legacy_windows if self._width is None else self._width, + height if self._height is None else self._height, + ) + + @size.setter + def size(self, new_size: Tuple[int, int]) -> None: + """Set a new size for the terminal. + + Args: + new_size (Tuple[int, int]): New width and height. + """ + width, height = new_size + self._width = width + self._height = height + + @property + def width(self) -> int: + """Get the width of the console. + + Returns: + int: The width (in characters) of the console. + """ + return self.size.width + + @width.setter + def width(self, width: int) -> None: + """Set width. + + Args: + width (int): New width. + """ + self._width = width + + @property + def height(self) -> int: + """Get the height of the console. + + Returns: + int: The height (in lines) of the console. + """ + return self.size.height + + @height.setter + def height(self, height: int) -> None: + """Set height. + + Args: + height (int): new height. + """ + self._height = height + + def bell(self) -> None: + """Play a 'bell' sound (if supported by the terminal).""" + self.control(Control.bell()) + + def capture(self) -> Capture: + """A context manager to *capture* the result of print() or log() in a string, + rather than writing it to the console. + + Example: + >>> from rich.console import Console + >>> console = Console() + >>> with console.capture() as capture: + ... console.print("[bold magenta]Hello World[/]") + >>> print(capture.get()) + + Returns: + Capture: Context manager with disables writing to the terminal. + """ + capture = Capture(self) + return capture + + def pager( + self, pager: Optional[Pager] = None, styles: bool = False, links: bool = False + ) -> PagerContext: + """A context manager to display anything printed within a "pager". The pager application + is defined by the system and will typically support at least pressing a key to scroll. + + Args: + pager (Pager, optional): A pager object, or None to use :class:`~rich.pager.SystemPager`. Defaults to None. + styles (bool, optional): Show styles in pager. Defaults to False. + links (bool, optional): Show links in pager. Defaults to False. + + Example: + >>> from rich.console import Console + >>> from rich.__main__ import make_test_card + >>> console = Console() + >>> with console.pager(): + console.print(make_test_card()) + + Returns: + PagerContext: A context manager. + """ + return PagerContext(self, pager=pager, styles=styles, links=links) + + def line(self, count: int = 1) -> None: + """Write new line(s). + + Args: + count (int, optional): Number of new lines. Defaults to 1. + """ + + assert count >= 0, "count must be >= 0" + self.print(NewLine(count)) + + def clear(self, home: bool = True) -> None: + """Clear the screen. + + Args: + home (bool, optional): Also move the cursor to 'home' position. Defaults to True. + """ + if home: + self.control(Control.clear(), Control.home()) + else: + self.control(Control.clear()) + + def status( + self, + status: RenderableType, + *, + spinner: str = "dots", + spinner_style: StyleType = "status.spinner", + speed: float = 1.0, + refresh_per_second: float = 12.5, + ) -> "Status": + """Display a status and spinner. + + Args: + status (RenderableType): A status renderable (str or Text typically). + spinner (str, optional): Name of spinner animation (see python -m rich.spinner). Defaults to "dots". + spinner_style (StyleType, optional): Style of spinner. Defaults to "status.spinner". + speed (float, optional): Speed factor for spinner animation. Defaults to 1.0. + refresh_per_second (float, optional): Number of refreshes per second. Defaults to 12.5. + + Returns: + Status: A Status object that may be used as a context manager. + """ + from .status import Status + + status_renderable = Status( + status, + console=self, + spinner=spinner, + spinner_style=spinner_style, + speed=speed, + refresh_per_second=refresh_per_second, + ) + return status_renderable + + def show_cursor(self, show: bool = True) -> bool: + """Show or hide the cursor. + + Args: + show (bool, optional): Set visibility of the cursor. + """ + if self.is_terminal: + self.control(Control.show_cursor(show)) + return True + return False + + def set_alt_screen(self, enable: bool = True) -> bool: + """Enables alternative screen mode. + + Note, if you enable this mode, you should ensure that is disabled before + the application exits. See :meth:`~rich.Console.screen` for a context manager + that handles this for you. + + Args: + enable (bool, optional): Enable (True) or disable (False) alternate screen. Defaults to True. + + Returns: + bool: True if the control codes were written. + + """ + changed = False + if self.is_terminal and not self.legacy_windows: + self.control(Control.alt_screen(enable)) + changed = True + self._is_alt_screen = enable + return changed + + @property + def is_alt_screen(self) -> bool: + """Check if the alt screen was enabled. + + Returns: + bool: True if the alt screen was enabled, otherwise False. + """ + return self._is_alt_screen + + def set_window_title(self, title: str) -> bool: + """Set the title of the console terminal window. + + Warning: There is no means within Rich of "resetting" the window title to its + previous value, meaning the title you set will persist even after your application + exits. + + ``fish`` shell resets the window title before and after each command by default, + negating this issue. Windows Terminal and command prompt will also reset the title for you. + Most other shells and terminals, however, do not do this. + + Some terminals may require configuration changes before you can set the title. + Some terminals may not support setting the title at all. + + Other software (including the terminal itself, the shell, custom prompts, plugins, etc.) + may also set the terminal window title. This could result in whatever value you write + using this method being overwritten. + + Args: + title (str): The new title of the terminal window. + + Returns: + bool: True if the control code to change the terminal title was + written, otherwise False. Note that a return value of True + does not guarantee that the window title has actually changed, + since the feature may be unsupported/disabled in some terminals. + """ + if self.is_terminal: + self.control(Control.title(title)) + return True + return False + + def screen( + self, hide_cursor: bool = True, style: Optional[StyleType] = None + ) -> "ScreenContext": + """Context manager to enable and disable 'alternative screen' mode. + + Args: + hide_cursor (bool, optional): Also hide the cursor. Defaults to False. + style (Style, optional): Optional style for screen. Defaults to None. + + Returns: + ~ScreenContext: Context which enables alternate screen on enter, and disables it on exit. + """ + return ScreenContext(self, hide_cursor=hide_cursor, style=style or "") + + def measure( + self, renderable: RenderableType, *, options: Optional[ConsoleOptions] = None + ) -> Measurement: + """Measure a renderable. Returns a :class:`~rich.measure.Measurement` object which contains + information regarding the number of characters required to print the renderable. + + Args: + renderable (RenderableType): Any renderable or string. + options (Optional[ConsoleOptions], optional): Options to use when measuring, or None + to use default options. Defaults to None. + + Returns: + Measurement: A measurement of the renderable. + """ + measurement = Measurement.get(self, options or self.options, renderable) + return measurement + + def render( + self, renderable: RenderableType, options: Optional[ConsoleOptions] = None + ) -> Iterable[Segment]: + """Render an object in to an iterable of `Segment` instances. + + This method contains the logic for rendering objects with the console protocol. + You are unlikely to need to use it directly, unless you are extending the library. + + Args: + renderable (RenderableType): An object supporting the console protocol, or + an object that may be converted to a string. + options (ConsoleOptions, optional): An options object, or None to use self.options. Defaults to None. + + Returns: + Iterable[Segment]: An iterable of segments that may be rendered. + """ + + _options = options or self.options + if _options.max_width < 1: + # No space to render anything. This prevents potential recursion errors. + return + render_iterable: RenderResult + + renderable = rich_cast(renderable) + if hasattr(renderable, "__rich_console__") and not isclass(renderable): + render_iterable = renderable.__rich_console__(self, _options) + elif isinstance(renderable, str): + text_renderable = self.render_str( + renderable, highlight=_options.highlight, markup=_options.markup + ) + render_iterable = text_renderable.__rich_console__(self, _options) + else: + raise errors.NotRenderableError( + f"Unable to render {renderable!r}; " + "A str, Segment or object with __rich_console__ method is required" + ) + + try: + iter_render = iter(render_iterable) + except TypeError: + raise errors.NotRenderableError( + f"object {render_iterable!r} is not renderable" + ) + _Segment = Segment + _options = _options.reset_height() + for render_output in iter_render: + if isinstance(render_output, _Segment): + yield render_output + else: + yield from self.render(render_output, _options) + + def render_lines( + self, + renderable: RenderableType, + options: Optional[ConsoleOptions] = None, + *, + style: Optional[Style] = None, + pad: bool = True, + new_lines: bool = False, + ) -> List[List[Segment]]: + """Render objects in to a list of lines. + + The output of render_lines is useful when further formatting of rendered console text + is required, such as the Panel class which draws a border around any renderable object. + + Args: + renderable (RenderableType): Any object renderable in the console. + options (Optional[ConsoleOptions], optional): Console options, or None to use self.options. Default to ``None``. + style (Style, optional): Optional style to apply to renderables. Defaults to ``None``. + pad (bool, optional): Pad lines shorter than render width. Defaults to ``True``. + new_lines (bool, optional): Include "\n" characters at end of lines. + + Returns: + List[List[Segment]]: A list of lines, where a line is a list of Segment objects. + """ + with self._lock: + render_options = options or self.options + _rendered = self.render(renderable, render_options) + if style: + _rendered = Segment.apply_style(_rendered, style) + + render_height = render_options.height + if render_height is not None: + render_height = max(0, render_height) + + lines = list( + islice( + Segment.split_and_crop_lines( + _rendered, + render_options.max_width, + include_new_lines=new_lines, + pad=pad, + style=style, + ), + None, + render_height, + ) + ) + if render_options.height is not None: + extra_lines = render_options.height - len(lines) + if extra_lines > 0: + pad_line = [ + ( + [ + Segment(" " * render_options.max_width, style), + Segment("\n"), + ] + if new_lines + else [Segment(" " * render_options.max_width, style)] + ) + ] + lines.extend(pad_line * extra_lines) + + return lines + + def render_str( + self, + text: str, + *, + style: Union[str, Style] = "", + justify: Optional[JustifyMethod] = None, + overflow: Optional[OverflowMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + highlighter: Optional[HighlighterType] = None, + ) -> "Text": + """Convert a string to a Text instance. This is called automatically if + you print or log a string. + + Args: + text (str): Text to render. + style (Union[str, Style], optional): Style to apply to rendered text. + justify (str, optional): Justify method: "default", "left", "center", "full", or "right". Defaults to ``None``. + overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to ``None``. + emoji (Optional[bool], optional): Enable emoji, or ``None`` to use Console default. + markup (Optional[bool], optional): Enable markup, or ``None`` to use Console default. + highlight (Optional[bool], optional): Enable highlighting, or ``None`` to use Console default. + highlighter (HighlighterType, optional): Optional highlighter to apply. + Returns: + ConsoleRenderable: Renderable object. + + """ + emoji_enabled = emoji or (emoji is None and self._emoji) + markup_enabled = markup or (markup is None and self._markup) + highlight_enabled = highlight or (highlight is None and self._highlight) + + if markup_enabled: + rich_text = render_markup( + text, + style=style, + emoji=emoji_enabled, + emoji_variant=self._emoji_variant, + ) + rich_text.justify = justify + rich_text.overflow = overflow + else: + rich_text = Text( + ( + _emoji_replace(text, default_variant=self._emoji_variant) + if emoji_enabled + else text + ), + justify=justify, + overflow=overflow, + style=style, + ) + + _highlighter = (highlighter or self.highlighter) if highlight_enabled else None + if _highlighter is not None: + highlight_text = _highlighter(str(rich_text)) + highlight_text.copy_styles(rich_text) + return highlight_text + + return rich_text + + def get_style( + self, name: Union[str, Style], *, default: Optional[Union[Style, str]] = None + ) -> Style: + """Get a Style instance by its theme name or parse a definition. + + Args: + name (str): The name of a style or a style definition. + + Returns: + Style: A Style object. + + Raises: + MissingStyle: If no style could be parsed from name. + + """ + if isinstance(name, Style): + return name + + try: + style = self._theme_stack.get(name) + if style is None: + style = Style.parse(name) + return style.copy() if style.link else style + except errors.StyleSyntaxError as error: + if default is not None: + return self.get_style(default) + raise errors.MissingStyle( + f"Failed to get style {name!r}; {error}" + ) from None + + def _collect_renderables( + self, + objects: Iterable[Any], + sep: str, + end: str, + *, + justify: Optional[JustifyMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + ) -> List[ConsoleRenderable]: + """Combine a number of renderables and text into one renderable. + + Args: + objects (Iterable[Any]): Anything that Rich can render. + sep (str): String to write between print data. + end (str): String to write at end of print data. + justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. + + Returns: + List[ConsoleRenderable]: A list of things to render. + """ + renderables: List[ConsoleRenderable] = [] + _append = renderables.append + text: List[Text] = [] + append_text = text.append + + append = _append + if justify in ("left", "center", "right"): + + def align_append(renderable: RenderableType) -> None: + _append(Align(renderable, cast(AlignMethod, justify))) + + append = align_append + + _highlighter: HighlighterType = _null_highlighter + if highlight or (highlight is None and self._highlight): + _highlighter = self.highlighter + + def check_text() -> None: + if text: + sep_text = Text(sep, justify=justify, end=end) + append(sep_text.join(text)) + text.clear() + + for renderable in objects: + renderable = rich_cast(renderable) + if isinstance(renderable, str): + append_text( + self.render_str( + renderable, + emoji=emoji, + markup=markup, + highlight=highlight, + highlighter=_highlighter, + ) + ) + elif isinstance(renderable, Text): + append_text(renderable) + elif isinstance(renderable, ConsoleRenderable): + check_text() + append(renderable) + elif is_expandable(renderable): + check_text() + append(Pretty(renderable, highlighter=_highlighter)) + else: + append_text(_highlighter(str(renderable))) + + check_text() + + if self.style is not None: + style = self.get_style(self.style) + renderables = [Styled(renderable, style) for renderable in renderables] + + return renderables + + def rule( + self, + title: TextType = "", + *, + characters: str = "─", + style: Union[str, Style] = "rule.line", + align: AlignMethod = "center", + ) -> None: + """Draw a line with optional centered title. + + Args: + title (str, optional): Text to render over the rule. Defaults to "". + characters (str, optional): Character(s) to form the line. Defaults to "─". + style (str, optional): Style of line. Defaults to "rule.line". + align (str, optional): How to align the title, one of "left", "center", or "right". Defaults to "center". + """ + from .rule import Rule + + rule = Rule(title=title, characters=characters, style=style, align=align) + self.print(rule) + + def control(self, *control: Control) -> None: + """Insert non-printing control codes. + + Args: + control_codes (str): Control codes, such as those that may move the cursor. + """ + if not self.is_dumb_terminal: + with self: + self._buffer.extend(_control.segment for _control in control) + + def out( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + highlight: Optional[bool] = None, + ) -> None: + """Output to the terminal. This is a low-level way of writing to the terminal which unlike + :meth:`~rich.console.Console.print` won't pretty print, wrap text, or apply markup, but will + optionally apply highlighting and a basic style. + + Args: + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use + console default. Defaults to ``None``. + """ + raw_output: str = sep.join(str(_object) for _object in objects) + self.print( + raw_output, + style=style, + highlight=highlight, + emoji=False, + markup=False, + no_wrap=True, + overflow="ignore", + crop=False, + end=end, + ) + + def print( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + justify: Optional[JustifyMethod] = None, + overflow: Optional[OverflowMethod] = None, + no_wrap: Optional[bool] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + width: Optional[int] = None, + height: Optional[int] = None, + crop: bool = True, + soft_wrap: Optional[bool] = None, + new_line_start: bool = False, + ) -> None: + """Print to the console. + + Args: + objects (positional args): Objects to log to the terminal. + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + justify (str, optional): Justify method: "default", "left", "right", "center", or "full". Defaults to ``None``. + overflow (str, optional): Overflow method: "ignore", "crop", "fold", or "ellipsis". Defaults to None. + no_wrap (Optional[bool], optional): Disable word wrapping. Defaults to None. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to ``None``. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to ``None``. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to ``None``. + width (Optional[int], optional): Width of output, or ``None`` to auto-detect. Defaults to ``None``. + crop (Optional[bool], optional): Crop output to width of terminal. Defaults to True. + soft_wrap (bool, optional): Enable soft wrap mode which disables word wrapping and cropping of text or ``None`` for + Console default. Defaults to ``None``. + new_line_start (bool, False): Insert a new line at the start if the output contains more than one line. Defaults to ``False``. + """ + if not objects: + objects = (NewLine(),) + + if soft_wrap is None: + soft_wrap = self.soft_wrap + if soft_wrap: + if no_wrap is None: + no_wrap = True + if overflow is None: + overflow = "ignore" + crop = False + render_hooks = self._render_hooks[:] + with self: + renderables = self._collect_renderables( + objects, + sep, + end, + justify=justify, + emoji=emoji, + markup=markup, + highlight=highlight, + ) + for hook in render_hooks: + renderables = hook.process_renderables(renderables) + render_options = self.options.update( + justify=justify, + overflow=overflow, + width=min(width, self.width) if width is not None else NO_CHANGE, + height=height, + no_wrap=no_wrap, + markup=markup, + highlight=highlight, + ) + + new_segments: List[Segment] = [] + extend = new_segments.extend + render = self.render + if style is None: + for renderable in renderables: + extend(render(renderable, render_options)) + else: + for renderable in renderables: + extend( + Segment.apply_style( + render(renderable, render_options), self.get_style(style) + ) + ) + if new_line_start: + if ( + len("".join(segment.text for segment in new_segments).splitlines()) + > 1 + ): + new_segments.insert(0, Segment.line()) + if crop: + buffer_extend = self._buffer.extend + for line in Segment.split_and_crop_lines( + new_segments, self.width, pad=False + ): + buffer_extend(line) + else: + self._buffer.extend(new_segments) + + def print_json( + self, + json: Optional[str] = None, + *, + data: Any = None, + indent: Union[None, int, str] = 2, + highlight: bool = True, + skip_keys: bool = False, + ensure_ascii: bool = False, + check_circular: bool = True, + allow_nan: bool = True, + default: Optional[Callable[[Any], Any]] = None, + sort_keys: bool = False, + ) -> None: + """Pretty prints JSON. Output will be valid JSON. + + Args: + json (Optional[str]): A string containing JSON. + data (Any): If json is not supplied, then encode this data. + indent (Union[None, int, str], optional): Number of spaces to indent. Defaults to 2. + highlight (bool, optional): Enable highlighting of output: Defaults to True. + skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False. + ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False. + check_circular (bool, optional): Check for circular references. Defaults to True. + allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True. + default (Callable, optional): A callable that converts values that can not be encoded + in to something that can be JSON encoded. Defaults to None. + sort_keys (bool, optional): Sort dictionary keys. Defaults to False. + """ + from pip._vendor.rich.json import JSON + + if json is None: + json_renderable = JSON.from_data( + data, + indent=indent, + highlight=highlight, + skip_keys=skip_keys, + ensure_ascii=ensure_ascii, + check_circular=check_circular, + allow_nan=allow_nan, + default=default, + sort_keys=sort_keys, + ) + else: + if not isinstance(json, str): + raise TypeError( + f"json must be str. Did you mean print_json(data={json!r}) ?" + ) + json_renderable = JSON( + json, + indent=indent, + highlight=highlight, + skip_keys=skip_keys, + ensure_ascii=ensure_ascii, + check_circular=check_circular, + allow_nan=allow_nan, + default=default, + sort_keys=sort_keys, + ) + self.print(json_renderable, soft_wrap=True) + + def update_screen( + self, + renderable: RenderableType, + *, + region: Optional[Region] = None, + options: Optional[ConsoleOptions] = None, + ) -> None: + """Update the screen at a given offset. + + Args: + renderable (RenderableType): A Rich renderable. + region (Region, optional): Region of screen to update, or None for entire screen. Defaults to None. + x (int, optional): x offset. Defaults to 0. + y (int, optional): y offset. Defaults to 0. + + Raises: + errors.NoAltScreen: If the Console isn't in alt screen mode. + + """ + if not self.is_alt_screen: + raise errors.NoAltScreen("Alt screen must be enabled to call update_screen") + render_options = options or self.options + if region is None: + x = y = 0 + render_options = render_options.update_dimensions( + render_options.max_width, render_options.height or self.height + ) + else: + x, y, width, height = region + render_options = render_options.update_dimensions(width, height) + + lines = self.render_lines(renderable, options=render_options) + self.update_screen_lines(lines, x, y) + + def update_screen_lines( + self, lines: List[List[Segment]], x: int = 0, y: int = 0 + ) -> None: + """Update lines of the screen at a given offset. + + Args: + lines (List[List[Segment]]): Rendered lines (as produced by :meth:`~rich.Console.render_lines`). + x (int, optional): x offset (column no). Defaults to 0. + y (int, optional): y offset (column no). Defaults to 0. + + Raises: + errors.NoAltScreen: If the Console isn't in alt screen mode. + """ + if not self.is_alt_screen: + raise errors.NoAltScreen("Alt screen must be enabled to call update_screen") + screen_update = ScreenUpdate(lines, x, y) + segments = self.render(screen_update) + self._buffer.extend(segments) + self._check_buffer() + + def print_exception( + self, + *, + width: Optional[int] = 100, + extra_lines: int = 3, + theme: Optional[str] = None, + word_wrap: bool = False, + show_locals: bool = False, + suppress: Iterable[Union[str, ModuleType]] = (), + max_frames: int = 100, + ) -> None: + """Prints a rich render of the last exception and traceback. + + Args: + width (Optional[int], optional): Number of characters used to render code. Defaults to 100. + extra_lines (int, optional): Additional lines of code to render. Defaults to 3. + theme (str, optional): Override pygments theme used in traceback + word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. + """ + from .traceback import Traceback + + traceback = Traceback( + width=width, + extra_lines=extra_lines, + theme=theme, + word_wrap=word_wrap, + show_locals=show_locals, + suppress=suppress, + max_frames=max_frames, + ) + self.print(traceback) + + @staticmethod + def _caller_frame_info( + offset: int, + currentframe: Callable[[], Optional[FrameType]] = inspect.currentframe, + ) -> Tuple[str, int, Dict[str, Any]]: + """Get caller frame information. + + Args: + offset (int): the caller offset within the current frame stack. + currentframe (Callable[[], Optional[FrameType]], optional): the callable to use to + retrieve the current frame. Defaults to ``inspect.currentframe``. + + Returns: + Tuple[str, int, Dict[str, Any]]: A tuple containing the filename, the line number and + the dictionary of local variables associated with the caller frame. + + Raises: + RuntimeError: If the stack offset is invalid. + """ + # Ignore the frame of this local helper + offset += 1 + + frame = currentframe() + if frame is not None: + # Use the faster currentframe where implemented + while offset and frame is not None: + frame = frame.f_back + offset -= 1 + assert frame is not None + return frame.f_code.co_filename, frame.f_lineno, frame.f_locals + else: + # Fallback to the slower stack + frame_info = inspect.stack()[offset] + return frame_info.filename, frame_info.lineno, frame_info.frame.f_locals + + def log( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + justify: Optional[JustifyMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + log_locals: bool = False, + _stack_offset: int = 1, + ) -> None: + """Log rich content to the terminal. + + Args: + objects (positional args): Objects to log to the terminal. + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to None. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to None. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to None. + log_locals (bool, optional): Boolean to enable logging of locals where ``log()`` + was called. Defaults to False. + _stack_offset (int, optional): Offset of caller from end of call stack. Defaults to 1. + """ + if not objects: + objects = (NewLine(),) + + render_hooks = self._render_hooks[:] + + with self: + renderables = self._collect_renderables( + objects, + sep, + end, + justify=justify, + emoji=emoji, + markup=markup, + highlight=highlight, + ) + if style is not None: + renderables = [Styled(renderable, style) for renderable in renderables] + + filename, line_no, locals = self._caller_frame_info(_stack_offset) + link_path = None if filename.startswith("<") else os.path.abspath(filename) + path = filename.rpartition(os.sep)[-1] + if log_locals: + locals_map = { + key: value + for key, value in locals.items() + if not key.startswith("__") + } + renderables.append(render_scope(locals_map, title="[i]locals")) + + renderables = [ + self._log_render( + self, + renderables, + log_time=self.get_datetime(), + path=path, + line_no=line_no, + link_path=link_path, + ) + ] + for hook in render_hooks: + renderables = hook.process_renderables(renderables) + new_segments: List[Segment] = [] + extend = new_segments.extend + render = self.render + render_options = self.options + for renderable in renderables: + extend(render(renderable, render_options)) + buffer_extend = self._buffer.extend + for line in Segment.split_and_crop_lines( + new_segments, self.width, pad=False + ): + buffer_extend(line) + + def on_broken_pipe(self) -> None: + """This function is called when a `BrokenPipeError` is raised. + + This can occur when piping Textual output in Linux and macOS. + The default implementation is to exit the app, but you could implement + this method in a subclass to change the behavior. + + See https://docs.python.org/3/library/signal.html#note-on-sigpipe for details. + """ + self.quiet = True + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + raise SystemExit(1) + + def _check_buffer(self) -> None: + """Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False) + Rendering is supported on Windows, Unix and Jupyter environments. For + legacy Windows consoles, the win32 API is called directly. + This method will also record what it renders if recording is enabled via Console.record. + """ + if self.quiet: + del self._buffer[:] + return + + try: + self._write_buffer() + except BrokenPipeError: + self.on_broken_pipe() + + def _write_buffer(self) -> None: + """Write the buffer to the output file.""" + + with self._lock: + if self.record and not self._buffer_index: + with self._record_buffer_lock: + self._record_buffer.extend(self._buffer[:]) + + if self._buffer_index == 0: + if self.is_jupyter: # pragma: no cover + from .jupyter import display + + display(self._buffer, self._render_buffer(self._buffer[:])) + del self._buffer[:] + else: + if WINDOWS: + use_legacy_windows_render = False + if self.legacy_windows: + fileno = get_fileno(self.file) + if fileno is not None: + use_legacy_windows_render = ( + fileno in _STD_STREAMS_OUTPUT + ) + + if use_legacy_windows_render: + from pip._vendor.rich._win32_console import LegacyWindowsTerm + from pip._vendor.rich._windows_renderer import legacy_windows_render + + buffer = self._buffer[:] + if self.no_color and self._color_system: + buffer = list(Segment.remove_color(buffer)) + + legacy_windows_render(buffer, LegacyWindowsTerm(self.file)) + else: + # Either a non-std stream on legacy Windows, or modern Windows. + text = self._render_buffer(self._buffer[:]) + # https://bugs.python.org/issue37871 + # https://github.com/python/cpython/issues/82052 + # We need to avoid writing more than 32Kb in a single write, due to the above bug + write = self.file.write + # Worse case scenario, every character is 4 bytes of utf-8 + MAX_WRITE = 32 * 1024 // 4 + try: + if len(text) <= MAX_WRITE: + write(text) + else: + batch: List[str] = [] + batch_append = batch.append + size = 0 + for line in text.splitlines(True): + if size + len(line) > MAX_WRITE and batch: + write("".join(batch)) + batch.clear() + size = 0 + batch_append(line) + size += len(line) + if batch: + write("".join(batch)) + batch.clear() + except UnicodeEncodeError as error: + error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***" + raise + else: + text = self._render_buffer(self._buffer[:]) + try: + self.file.write(text) + except UnicodeEncodeError as error: + error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***" + raise + + self.file.flush() + del self._buffer[:] + + def _render_buffer(self, buffer: Iterable[Segment]) -> str: + """Render buffered output, and clear buffer.""" + output: List[str] = [] + append = output.append + color_system = self._color_system + legacy_windows = self.legacy_windows + not_terminal = not self.is_terminal + if self.no_color and color_system: + buffer = Segment.remove_color(buffer) + for text, style, control in buffer: + if style: + append( + style.render( + text, + color_system=color_system, + legacy_windows=legacy_windows, + ) + ) + elif not (not_terminal and control): + append(text) + + rendered = "".join(output) + return rendered + + def input( + self, + prompt: TextType = "", + *, + markup: bool = True, + emoji: bool = True, + password: bool = False, + stream: Optional[TextIO] = None, + ) -> str: + """Displays a prompt and waits for input from the user. The prompt may contain color / style. + + It works in the same way as Python's builtin :func:`input` function and provides elaborate line editing and history features if Python's builtin :mod:`readline` module is previously loaded. + + Args: + prompt (Union[str, Text]): Text to render in the prompt. + markup (bool, optional): Enable console markup (requires a str prompt). Defaults to True. + emoji (bool, optional): Enable emoji (requires a str prompt). Defaults to True. + password: (bool, optional): Hide typed text. Defaults to False. + stream: (TextIO, optional): Optional file to read input from (rather than stdin). Defaults to None. + + Returns: + str: Text read from stdin. + """ + if prompt: + self.print(prompt, markup=markup, emoji=emoji, end="") + if password: + result = getpass("", stream=stream) + else: + if stream: + result = stream.readline() + else: + result = input() + return result + + def export_text(self, *, clear: bool = True, styles: bool = False) -> str: + """Generate text from console contents (requires record=True argument in constructor). + + Args: + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + styles (bool, optional): If ``True``, ansi escape codes will be included. ``False`` for plain text. + Defaults to ``False``. + + Returns: + str: String containing console contents. + + """ + assert ( + self.record + ), "To export console contents set record=True in the constructor or instance" + + with self._record_buffer_lock: + if styles: + text = "".join( + (style.render(text) if style else text) + for text, style, _ in self._record_buffer + ) + else: + text = "".join( + segment.text + for segment in self._record_buffer + if not segment.control + ) + if clear: + del self._record_buffer[:] + return text + + def save_text(self, path: str, *, clear: bool = True, styles: bool = False) -> None: + """Generate text from console and save to a given location (requires record=True argument in constructor). + + Args: + path (str): Path to write text files. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + styles (bool, optional): If ``True``, ansi style codes will be included. ``False`` for plain text. + Defaults to ``False``. + + """ + text = self.export_text(clear=clear, styles=styles) + with open(path, "w", encoding="utf-8") as write_file: + write_file.write(text) + + def export_html( + self, + *, + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: Optional[str] = None, + inline_styles: bool = False, + ) -> str: + """Generate HTML from console contents (requires record=True argument in constructor). + + Args: + theme (TerminalTheme, optional): TerminalTheme object containing console colors. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + code_format (str, optional): Format string to render HTML. In addition to '{foreground}', + '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``. + inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files + larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag. + Defaults to False. + + Returns: + str: String containing console contents as HTML. + """ + assert ( + self.record + ), "To export console contents set record=True in the constructor or instance" + fragments: List[str] = [] + append = fragments.append + _theme = theme or DEFAULT_TERMINAL_THEME + stylesheet = "" + + render_code_format = CONSOLE_HTML_FORMAT if code_format is None else code_format + + with self._record_buffer_lock: + if inline_styles: + for text, style, _ in Segment.filter_control( + Segment.simplify(self._record_buffer) + ): + text = escape(text) + if style: + rule = style.get_html_style(_theme) + if style.link: + text = f'
        {text}' + text = f'{text}' if rule else text + append(text) + else: + styles: Dict[str, int] = {} + for text, style, _ in Segment.filter_control( + Segment.simplify(self._record_buffer) + ): + text = escape(text) + if style: + rule = style.get_html_style(_theme) + style_number = styles.setdefault(rule, len(styles) + 1) + if style.link: + text = f'{text}' + else: + text = f'{text}' + append(text) + stylesheet_rules: List[str] = [] + stylesheet_append = stylesheet_rules.append + for style_rule, style_number in styles.items(): + if style_rule: + stylesheet_append(f".r{style_number} {{{style_rule}}}") + stylesheet = "\n".join(stylesheet_rules) + + rendered_code = render_code_format.format( + code="".join(fragments), + stylesheet=stylesheet, + foreground=_theme.foreground_color.hex, + background=_theme.background_color.hex, + ) + if clear: + del self._record_buffer[:] + return rendered_code + + def save_html( + self, + path: str, + *, + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_HTML_FORMAT, + inline_styles: bool = False, + ) -> None: + """Generate HTML from console contents and write to a file (requires record=True argument in constructor). + + Args: + path (str): Path to write html file. + theme (TerminalTheme, optional): TerminalTheme object containing console colors. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + code_format (str, optional): Format string to render HTML. In addition to '{foreground}', + '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``. + inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files + larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag. + Defaults to False. + + """ + html = self.export_html( + theme=theme, + clear=clear, + code_format=code_format, + inline_styles=inline_styles, + ) + with open(path, "w", encoding="utf-8") as write_file: + write_file.write(html) + + def export_svg( + self, + *, + title: str = "Rich", + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_SVG_FORMAT, + font_aspect_ratio: float = 0.61, + unique_id: Optional[str] = None, + ) -> str: + """ + Generate an SVG from the console contents (requires record=True in Console constructor). + + Args: + title (str, optional): The title of the tab in the output image + theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` + code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables + into the string in order to form the final SVG output. The default template used and the variables + injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. + font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format`` + string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font). + If you aren't specifying a different font inside ``code_format``, you probably don't need this. + unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node + ids). If not set, this defaults to a computed value based on the recorded content. + """ + + from pip._vendor.rich.cells import cell_len + + style_cache: Dict[Style, str] = {} + + def get_svg_style(style: Style) -> str: + """Convert a Style to CSS rules for SVG.""" + if style in style_cache: + return style_cache[style] + css_rules = [] + color = ( + _theme.foreground_color + if (style.color is None or style.color.is_default) + else style.color.get_truecolor(_theme) + ) + bgcolor = ( + _theme.background_color + if (style.bgcolor is None or style.bgcolor.is_default) + else style.bgcolor.get_truecolor(_theme) + ) + if style.reverse: + color, bgcolor = bgcolor, color + if style.dim: + color = blend_rgb(color, bgcolor, 0.4) + css_rules.append(f"fill: {color.hex}") + if style.bold: + css_rules.append("font-weight: bold") + if style.italic: + css_rules.append("font-style: italic;") + if style.underline: + css_rules.append("text-decoration: underline;") + if style.strike: + css_rules.append("text-decoration: line-through;") + + css = ";".join(css_rules) + style_cache[style] = css + return css + + _theme = theme or SVG_EXPORT_THEME + + width = self.width + char_height = 20 + char_width = char_height * font_aspect_ratio + line_height = char_height * 1.22 + + margin_top = 1 + margin_right = 1 + margin_bottom = 1 + margin_left = 1 + + padding_top = 40 + padding_right = 8 + padding_bottom = 8 + padding_left = 8 + + padding_width = padding_left + padding_right + padding_height = padding_top + padding_bottom + margin_width = margin_left + margin_right + margin_height = margin_top + margin_bottom + + text_backgrounds: List[str] = [] + text_group: List[str] = [] + classes: Dict[str, int] = {} + style_no = 1 + + def escape_text(text: str) -> str: + """HTML escape text and replace spaces with nbsp.""" + return escape(text).replace(" ", " ") + + def make_tag( + name: str, content: Optional[str] = None, **attribs: object + ) -> str: + """Make a tag from name, content, and attributes.""" + + def stringify(value: object) -> str: + if isinstance(value, (float)): + return format(value, "g") + return str(value) + + tag_attribs = " ".join( + f'{k.lstrip("_").replace("_", "-")}="{stringify(v)}"' + for k, v in attribs.items() + ) + return ( + f"<{name} {tag_attribs}>{content}" + if content + else f"<{name} {tag_attribs}/>" + ) + + with self._record_buffer_lock: + segments = list(Segment.filter_control(self._record_buffer)) + if clear: + self._record_buffer.clear() + + if unique_id is None: + unique_id = "terminal-" + str( + zlib.adler32( + ("".join(repr(segment) for segment in segments)).encode( + "utf-8", + "ignore", + ) + + title.encode("utf-8", "ignore") + ) + ) + y = 0 + for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)): + x = 0 + for text, style, _control in line: + style = style or Style() + rules = get_svg_style(style) + if rules not in classes: + classes[rules] = style_no + style_no += 1 + class_name = f"r{classes[rules]}" + + if style.reverse: + has_background = True + background = ( + _theme.foreground_color.hex + if style.color is None + else style.color.get_truecolor(_theme).hex + ) + else: + bgcolor = style.bgcolor + has_background = bgcolor is not None and not bgcolor.is_default + background = ( + _theme.background_color.hex + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme).hex + ) + + text_length = cell_len(text) + if has_background: + text_backgrounds.append( + make_tag( + "rect", + fill=background, + x=x * char_width, + y=y * line_height + 1.5, + width=char_width * text_length, + height=line_height + 0.25, + shape_rendering="crispEdges", + ) + ) + + if text != " " * len(text): + text_group.append( + make_tag( + "text", + escape_text(text), + _class=f"{unique_id}-{class_name}", + x=x * char_width, + y=y * line_height + char_height, + textLength=char_width * len(text), + clip_path=f"url(#{unique_id}-line-{y})", + ) + ) + x += cell_len(text) + + line_offsets = [line_no * line_height + 1.5 for line_no in range(y)] + lines = "\n".join( + f""" + {make_tag("rect", x=0, y=offset, width=char_width * width, height=line_height + 0.25)} + """ + for line_no, offset in enumerate(line_offsets) + ) + + styles = "\n".join( + f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items() + ) + backgrounds = "".join(text_backgrounds) + matrix = "".join(text_group) + + terminal_width = ceil(width * char_width + padding_width) + terminal_height = (y + 1) * line_height + padding_height + chrome = make_tag( + "rect", + fill=_theme.background_color.hex, + stroke="rgba(255,255,255,0.35)", + stroke_width="1", + x=margin_left, + y=margin_top, + width=terminal_width, + height=terminal_height, + rx=8, + ) + + title_color = _theme.foreground_color.hex + if title: + chrome += make_tag( + "text", + escape_text(title), + _class=f"{unique_id}-title", + fill=title_color, + text_anchor="middle", + x=terminal_width // 2, + y=margin_top + char_height + 6, + ) + chrome += f""" + + + + + + """ + + svg = code_format.format( + unique_id=unique_id, + char_width=char_width, + char_height=char_height, + line_height=line_height, + terminal_width=char_width * width - 1, + terminal_height=(y + 1) * line_height - 1, + width=terminal_width + margin_width, + height=terminal_height + margin_height, + terminal_x=margin_left + padding_left, + terminal_y=margin_top + padding_top, + styles=styles, + chrome=chrome, + backgrounds=backgrounds, + matrix=matrix, + lines=lines, + ) + return svg + + def save_svg( + self, + path: str, + *, + title: str = "Rich", + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_SVG_FORMAT, + font_aspect_ratio: float = 0.61, + unique_id: Optional[str] = None, + ) -> None: + """Generate an SVG file from the console contents (requires record=True in Console constructor). + + Args: + path (str): The path to write the SVG to. + title (str, optional): The title of the tab in the output image + theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` + code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables + into the string in order to form the final SVG output. The default template used and the variables + injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. + font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format`` + string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font). + If you aren't specifying a different font inside ``code_format``, you probably don't need this. + unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node + ids). If not set, this defaults to a computed value based on the recorded content. + """ + svg = self.export_svg( + title=title, + theme=theme, + clear=clear, + code_format=code_format, + font_aspect_ratio=font_aspect_ratio, + unique_id=unique_id, + ) + with open(path, "w", encoding="utf-8") as write_file: + write_file.write(svg) + + +def _svg_hash(svg_main_code: str) -> str: + """Returns a unique hash for the given SVG main code. + + Args: + svg_main_code (str): The content we're going to inject in the SVG envelope. + + Returns: + str: a hash of the given content + """ + return str(zlib.adler32(svg_main_code.encode())) + + +if __name__ == "__main__": # pragma: no cover + console = Console(record=True) + + console.log( + "JSONRPC [i]request[/i]", + 5, + 1.3, + True, + False, + None, + { + "jsonrpc": "2.0", + "method": "subtract", + "params": {"minuend": 42, "subtrahend": 23}, + "id": 3, + }, + ) + + console.log("Hello, World!", "{'a': 1}", repr(console)) + + console.print( + { + "name": None, + "empty": [], + "quiz": { + "sport": { + "answered": True, + "q1": { + "question": "Which one is correct team name in NBA?", + "options": [ + "New York Bulls", + "Los Angeles Kings", + "Golden State Warriors", + "Huston Rocket", + ], + "answer": "Huston Rocket", + }, + }, + "maths": { + "answered": False, + "q1": { + "question": "5 + 7 = ?", + "options": [10, 11, 12, 13], + "answer": 12, + }, + "q2": { + "question": "12 - 8 = ?", + "options": [1, 2, 3, 4], + "answer": 4, + }, + }, + }, + } + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/constrain.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/constrain.py new file mode 100644 index 0000000..65fdf56 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/constrain.py @@ -0,0 +1,37 @@ +from typing import Optional, TYPE_CHECKING + +from .jupyter import JupyterMixin +from .measure import Measurement + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType, RenderResult + + +class Constrain(JupyterMixin): + """Constrain the width of a renderable to a given number of characters. + + Args: + renderable (RenderableType): A renderable object. + width (int, optional): The maximum width (in characters) to render. Defaults to 80. + """ + + def __init__(self, renderable: "RenderableType", width: Optional[int] = 80) -> None: + self.renderable = renderable + self.width = width + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.width is None: + yield self.renderable + else: + child_options = options.update_width(min(self.width, options.max_width)) + yield from console.render(self.renderable, child_options) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + if self.width is not None: + options = options.update_width(self.width) + measurement = Measurement.get(console, options, self.renderable) + return measurement diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/containers.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/containers.py new file mode 100644 index 0000000..901ff8b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/containers.py @@ -0,0 +1,167 @@ +from itertools import zip_longest +from typing import ( + TYPE_CHECKING, + Iterable, + Iterator, + List, + Optional, + TypeVar, + Union, + overload, +) + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + JustifyMethod, + OverflowMethod, + RenderResult, + RenderableType, + ) + from .text import Text + +from .cells import cell_len +from .measure import Measurement + +T = TypeVar("T") + + +class Renderables: + """A list subclass which renders its contents to the console.""" + + def __init__( + self, renderables: Optional[Iterable["RenderableType"]] = None + ) -> None: + self._renderables: List["RenderableType"] = ( + list(renderables) if renderables is not None else [] + ) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + """Console render method to insert line-breaks.""" + yield from self._renderables + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + dimensions = [ + Measurement.get(console, options, renderable) + for renderable in self._renderables + ] + if not dimensions: + return Measurement(1, 1) + _min = max(dimension.minimum for dimension in dimensions) + _max = max(dimension.maximum for dimension in dimensions) + return Measurement(_min, _max) + + def append(self, renderable: "RenderableType") -> None: + self._renderables.append(renderable) + + def __iter__(self) -> Iterable["RenderableType"]: + return iter(self._renderables) + + +class Lines: + """A list subclass which can render to the console.""" + + def __init__(self, lines: Iterable["Text"] = ()) -> None: + self._lines: List["Text"] = list(lines) + + def __repr__(self) -> str: + return f"Lines({self._lines!r})" + + def __iter__(self) -> Iterator["Text"]: + return iter(self._lines) + + @overload + def __getitem__(self, index: int) -> "Text": + ... + + @overload + def __getitem__(self, index: slice) -> List["Text"]: + ... + + def __getitem__(self, index: Union[slice, int]) -> Union["Text", List["Text"]]: + return self._lines[index] + + def __setitem__(self, index: int, value: "Text") -> "Lines": + self._lines[index] = value + return self + + def __len__(self) -> int: + return self._lines.__len__() + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + """Console render method to insert line-breaks.""" + yield from self._lines + + def append(self, line: "Text") -> None: + self._lines.append(line) + + def extend(self, lines: Iterable["Text"]) -> None: + self._lines.extend(lines) + + def pop(self, index: int = -1) -> "Text": + return self._lines.pop(index) + + def justify( + self, + console: "Console", + width: int, + justify: "JustifyMethod" = "left", + overflow: "OverflowMethod" = "fold", + ) -> None: + """Justify and overflow text to a given width. + + Args: + console (Console): Console instance. + width (int): Number of cells available per line. + justify (str, optional): Default justify method for text: "left", "center", "full" or "right". Defaults to "left". + overflow (str, optional): Default overflow for text: "crop", "fold", or "ellipsis". Defaults to "fold". + + """ + from .text import Text + + if justify == "left": + for line in self._lines: + line.truncate(width, overflow=overflow, pad=True) + elif justify == "center": + for line in self._lines: + line.rstrip() + line.truncate(width, overflow=overflow) + line.pad_left((width - cell_len(line.plain)) // 2) + line.pad_right(width - cell_len(line.plain)) + elif justify == "right": + for line in self._lines: + line.rstrip() + line.truncate(width, overflow=overflow) + line.pad_left(width - cell_len(line.plain)) + elif justify == "full": + for line_index, line in enumerate(self._lines): + if line_index == len(self._lines) - 1: + break + words = line.split(" ") + words_size = sum(cell_len(word.plain) for word in words) + num_spaces = len(words) - 1 + spaces = [1 for _ in range(num_spaces)] + index = 0 + if spaces: + while words_size + num_spaces < width: + spaces[len(spaces) - index - 1] += 1 + num_spaces += 1 + index = (index + 1) % len(spaces) + tokens: List[Text] = [] + for index, (word, next_word) in enumerate( + zip_longest(words, words[1:]) + ): + tokens.append(word) + if index < len(spaces): + style = word.get_style_at_offset(console, -1) + next_style = next_word.get_style_at_offset(console, 0) + space_style = style if style == next_style else line.style + tokens.append(Text(" " * spaces[index], style=space_style)) + self[line_index] = Text("").join(tokens) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/control.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/control.py new file mode 100644 index 0000000..88fcb92 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/control.py @@ -0,0 +1,225 @@ +import sys +import time +from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union + +if sys.version_info >= (3, 8): + from typing import Final +else: + from pip._vendor.typing_extensions import Final # pragma: no cover + +from .segment import ControlCode, ControlType, Segment + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult + +STRIP_CONTROL_CODES: Final = [ + 7, # Bell + 8, # Backspace + 11, # Vertical tab + 12, # Form feed + 13, # Carriage return +] +_CONTROL_STRIP_TRANSLATE: Final = { + _codepoint: None for _codepoint in STRIP_CONTROL_CODES +} + +CONTROL_ESCAPE: Final = { + 7: "\\a", + 8: "\\b", + 11: "\\v", + 12: "\\f", + 13: "\\r", +} + +CONTROL_CODES_FORMAT: Dict[int, Callable[..., str]] = { + ControlType.BELL: lambda: "\x07", + ControlType.CARRIAGE_RETURN: lambda: "\r", + ControlType.HOME: lambda: "\x1b[H", + ControlType.CLEAR: lambda: "\x1b[2J", + ControlType.ENABLE_ALT_SCREEN: lambda: "\x1b[?1049h", + ControlType.DISABLE_ALT_SCREEN: lambda: "\x1b[?1049l", + ControlType.SHOW_CURSOR: lambda: "\x1b[?25h", + ControlType.HIDE_CURSOR: lambda: "\x1b[?25l", + ControlType.CURSOR_UP: lambda param: f"\x1b[{param}A", + ControlType.CURSOR_DOWN: lambda param: f"\x1b[{param}B", + ControlType.CURSOR_FORWARD: lambda param: f"\x1b[{param}C", + ControlType.CURSOR_BACKWARD: lambda param: f"\x1b[{param}D", + ControlType.CURSOR_MOVE_TO_COLUMN: lambda param: f"\x1b[{param+1}G", + ControlType.ERASE_IN_LINE: lambda param: f"\x1b[{param}K", + ControlType.CURSOR_MOVE_TO: lambda x, y: f"\x1b[{y+1};{x+1}H", + ControlType.SET_WINDOW_TITLE: lambda title: f"\x1b]0;{title}\x07", +} + + +class Control: + """A renderable that inserts a control code (non printable but may move cursor). + + Args: + *codes (str): Positional arguments are either a :class:`~rich.segment.ControlType` enum or a + tuple of ControlType and an integer parameter + """ + + __slots__ = ["segment"] + + def __init__(self, *codes: Union[ControlType, ControlCode]) -> None: + control_codes: List[ControlCode] = [ + (code,) if isinstance(code, ControlType) else code for code in codes + ] + _format_map = CONTROL_CODES_FORMAT + rendered_codes = "".join( + _format_map[code](*parameters) for code, *parameters in control_codes + ) + self.segment = Segment(rendered_codes, None, control_codes) + + @classmethod + def bell(cls) -> "Control": + """Ring the 'bell'.""" + return cls(ControlType.BELL) + + @classmethod + def home(cls) -> "Control": + """Move cursor to 'home' position.""" + return cls(ControlType.HOME) + + @classmethod + def move(cls, x: int = 0, y: int = 0) -> "Control": + """Move cursor relative to current position. + + Args: + x (int): X offset. + y (int): Y offset. + + Returns: + ~Control: Control object. + + """ + + def get_codes() -> Iterable[ControlCode]: + control = ControlType + if x: + yield ( + control.CURSOR_FORWARD if x > 0 else control.CURSOR_BACKWARD, + abs(x), + ) + if y: + yield ( + control.CURSOR_DOWN if y > 0 else control.CURSOR_UP, + abs(y), + ) + + control = cls(*get_codes()) + return control + + @classmethod + def move_to_column(cls, x: int, y: int = 0) -> "Control": + """Move to the given column, optionally add offset to row. + + Returns: + x (int): absolute x (column) + y (int): optional y offset (row) + + Returns: + ~Control: Control object. + """ + + return ( + cls( + (ControlType.CURSOR_MOVE_TO_COLUMN, x), + ( + ControlType.CURSOR_DOWN if y > 0 else ControlType.CURSOR_UP, + abs(y), + ), + ) + if y + else cls((ControlType.CURSOR_MOVE_TO_COLUMN, x)) + ) + + @classmethod + def move_to(cls, x: int, y: int) -> "Control": + """Move cursor to absolute position. + + Args: + x (int): x offset (column) + y (int): y offset (row) + + Returns: + ~Control: Control object. + """ + return cls((ControlType.CURSOR_MOVE_TO, x, y)) + + @classmethod + def clear(cls) -> "Control": + """Clear the screen.""" + return cls(ControlType.CLEAR) + + @classmethod + def show_cursor(cls, show: bool) -> "Control": + """Show or hide the cursor.""" + return cls(ControlType.SHOW_CURSOR if show else ControlType.HIDE_CURSOR) + + @classmethod + def alt_screen(cls, enable: bool) -> "Control": + """Enable or disable alt screen.""" + if enable: + return cls(ControlType.ENABLE_ALT_SCREEN, ControlType.HOME) + else: + return cls(ControlType.DISABLE_ALT_SCREEN) + + @classmethod + def title(cls, title: str) -> "Control": + """Set the terminal window title + + Args: + title (str): The new terminal window title + """ + return cls((ControlType.SET_WINDOW_TITLE, title)) + + def __str__(self) -> str: + return self.segment.text + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.segment.text: + yield self.segment + + +def strip_control_codes( + text: str, _translate_table: Dict[int, None] = _CONTROL_STRIP_TRANSLATE +) -> str: + """Remove control codes from text. + + Args: + text (str): A string possibly contain control codes. + + Returns: + str: String with control codes removed. + """ + return text.translate(_translate_table) + + +def escape_control_codes( + text: str, + _translate_table: Dict[int, str] = CONTROL_ESCAPE, +) -> str: + """Replace control codes with their "escaped" equivalent in the given text. + (e.g. "\b" becomes "\\b") + + Args: + text (str): A string possibly containing control codes. + + Returns: + str: String with control codes replaced with their escaped version. + """ + return text.translate(_translate_table) + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + + console = Console() + console.print("Look at the title of your terminal window ^") + # console.print(Control((ControlType.SET_WINDOW_TITLE, "Hello, world!"))) + for i in range(10): + console.set_window_title("🚀 Loading" + "." * i) + time.sleep(0.5) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/default_styles.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/default_styles.py new file mode 100644 index 0000000..6c0d732 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/default_styles.py @@ -0,0 +1,191 @@ +from typing import Dict + +from .style import Style + +DEFAULT_STYLES: Dict[str, Style] = { + "none": Style.null(), + "reset": Style( + color="default", + bgcolor="default", + dim=False, + bold=False, + italic=False, + underline=False, + blink=False, + blink2=False, + reverse=False, + conceal=False, + strike=False, + ), + "dim": Style(dim=True), + "bright": Style(dim=False), + "bold": Style(bold=True), + "strong": Style(bold=True), + "code": Style(reverse=True, bold=True), + "italic": Style(italic=True), + "emphasize": Style(italic=True), + "underline": Style(underline=True), + "blink": Style(blink=True), + "blink2": Style(blink2=True), + "reverse": Style(reverse=True), + "strike": Style(strike=True), + "black": Style(color="black"), + "red": Style(color="red"), + "green": Style(color="green"), + "yellow": Style(color="yellow"), + "magenta": Style(color="magenta"), + "cyan": Style(color="cyan"), + "white": Style(color="white"), + "inspect.attr": Style(color="yellow", italic=True), + "inspect.attr.dunder": Style(color="yellow", italic=True, dim=True), + "inspect.callable": Style(bold=True, color="red"), + "inspect.async_def": Style(italic=True, color="bright_cyan"), + "inspect.def": Style(italic=True, color="bright_cyan"), + "inspect.class": Style(italic=True, color="bright_cyan"), + "inspect.error": Style(bold=True, color="red"), + "inspect.equals": Style(), + "inspect.help": Style(color="cyan"), + "inspect.doc": Style(dim=True), + "inspect.value.border": Style(color="green"), + "live.ellipsis": Style(bold=True, color="red"), + "layout.tree.row": Style(dim=False, color="red"), + "layout.tree.column": Style(dim=False, color="blue"), + "logging.keyword": Style(bold=True, color="yellow"), + "logging.level.notset": Style(dim=True), + "logging.level.debug": Style(color="green"), + "logging.level.info": Style(color="blue"), + "logging.level.warning": Style(color="yellow"), + "logging.level.error": Style(color="red", bold=True), + "logging.level.critical": Style(color="red", bold=True, reverse=True), + "log.level": Style.null(), + "log.time": Style(color="cyan", dim=True), + "log.message": Style.null(), + "log.path": Style(dim=True), + "repr.ellipsis": Style(color="yellow"), + "repr.indent": Style(color="green", dim=True), + "repr.error": Style(color="red", bold=True), + "repr.str": Style(color="green", italic=False, bold=False), + "repr.brace": Style(bold=True), + "repr.comma": Style(bold=True), + "repr.ipv4": Style(bold=True, color="bright_green"), + "repr.ipv6": Style(bold=True, color="bright_green"), + "repr.eui48": Style(bold=True, color="bright_green"), + "repr.eui64": Style(bold=True, color="bright_green"), + "repr.tag_start": Style(bold=True), + "repr.tag_name": Style(color="bright_magenta", bold=True), + "repr.tag_contents": Style(color="default"), + "repr.tag_end": Style(bold=True), + "repr.attrib_name": Style(color="yellow", italic=False), + "repr.attrib_equal": Style(bold=True), + "repr.attrib_value": Style(color="magenta", italic=False), + "repr.number": Style(color="cyan", bold=True, italic=False), + "repr.number_complex": Style(color="cyan", bold=True, italic=False), # same + "repr.bool_true": Style(color="bright_green", italic=True), + "repr.bool_false": Style(color="bright_red", italic=True), + "repr.none": Style(color="magenta", italic=True), + "repr.url": Style(underline=True, color="bright_blue", italic=False, bold=False), + "repr.uuid": Style(color="bright_yellow", bold=False), + "repr.call": Style(color="magenta", bold=True), + "repr.path": Style(color="magenta"), + "repr.filename": Style(color="bright_magenta"), + "rule.line": Style(color="bright_green"), + "rule.text": Style.null(), + "json.brace": Style(bold=True), + "json.bool_true": Style(color="bright_green", italic=True), + "json.bool_false": Style(color="bright_red", italic=True), + "json.null": Style(color="magenta", italic=True), + "json.number": Style(color="cyan", bold=True, italic=False), + "json.str": Style(color="green", italic=False, bold=False), + "json.key": Style(color="blue", bold=True), + "prompt": Style.null(), + "prompt.choices": Style(color="magenta", bold=True), + "prompt.default": Style(color="cyan", bold=True), + "prompt.invalid": Style(color="red"), + "prompt.invalid.choice": Style(color="red"), + "pretty": Style.null(), + "scope.border": Style(color="blue"), + "scope.key": Style(color="yellow", italic=True), + "scope.key.special": Style(color="yellow", italic=True, dim=True), + "scope.equals": Style(color="red"), + "table.header": Style(bold=True), + "table.footer": Style(bold=True), + "table.cell": Style.null(), + "table.title": Style(italic=True), + "table.caption": Style(italic=True, dim=True), + "traceback.error": Style(color="red", italic=True), + "traceback.border.syntax_error": Style(color="bright_red"), + "traceback.border": Style(color="red"), + "traceback.text": Style.null(), + "traceback.title": Style(color="red", bold=True), + "traceback.exc_type": Style(color="bright_red", bold=True), + "traceback.exc_value": Style.null(), + "traceback.offset": Style(color="bright_red", bold=True), + "traceback.error_range": Style(underline=True, bold=True, dim=False), + "bar.back": Style(color="grey23"), + "bar.complete": Style(color="rgb(249,38,114)"), + "bar.finished": Style(color="rgb(114,156,31)"), + "bar.pulse": Style(color="rgb(249,38,114)"), + "progress.description": Style.null(), + "progress.filesize": Style(color="green"), + "progress.filesize.total": Style(color="green"), + "progress.download": Style(color="green"), + "progress.elapsed": Style(color="yellow"), + "progress.percentage": Style(color="magenta"), + "progress.remaining": Style(color="cyan"), + "progress.data.speed": Style(color="red"), + "progress.spinner": Style(color="green"), + "status.spinner": Style(color="green"), + "tree": Style(), + "tree.line": Style(), + "markdown.paragraph": Style(), + "markdown.text": Style(), + "markdown.em": Style(italic=True), + "markdown.emph": Style(italic=True), # For commonmark backwards compatibility + "markdown.strong": Style(bold=True), + "markdown.code": Style(bold=True, color="cyan", bgcolor="black"), + "markdown.code_block": Style(color="cyan", bgcolor="black"), + "markdown.block_quote": Style(color="magenta"), + "markdown.list": Style(color="cyan"), + "markdown.item": Style(), + "markdown.item.bullet": Style(color="yellow", bold=True), + "markdown.item.number": Style(color="yellow", bold=True), + "markdown.hr": Style(color="yellow"), + "markdown.h1.border": Style(), + "markdown.h1": Style(bold=True), + "markdown.h2": Style(bold=True, underline=True), + "markdown.h3": Style(bold=True), + "markdown.h4": Style(bold=True, dim=True), + "markdown.h5": Style(underline=True), + "markdown.h6": Style(italic=True), + "markdown.h7": Style(italic=True, dim=True), + "markdown.link": Style(color="bright_blue"), + "markdown.link_url": Style(color="blue", underline=True), + "markdown.s": Style(strike=True), + "iso8601.date": Style(color="blue"), + "iso8601.time": Style(color="magenta"), + "iso8601.timezone": Style(color="yellow"), +} + + +if __name__ == "__main__": # pragma: no cover + import argparse + import io + + from pip._vendor.rich.console import Console + from pip._vendor.rich.table import Table + from pip._vendor.rich.text import Text + + parser = argparse.ArgumentParser() + parser.add_argument("--html", action="store_true", help="Export as HTML table") + args = parser.parse_args() + html: bool = args.html + console = Console(record=True, width=70, file=io.StringIO()) if html else Console() + + table = Table("Name", "Styling") + + for style_name, style in DEFAULT_STYLES.items(): + table.add_row(Text(style_name, style=style), str(style)) + + console.print(table) + if html: + print(console.export_html(inline_styles=True)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/diagnose.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/diagnose.py new file mode 100644 index 0000000..ad36183 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/diagnose.py @@ -0,0 +1,37 @@ +import os +import platform + +from pip._vendor.rich import inspect +from pip._vendor.rich.console import Console, get_windows_console_features +from pip._vendor.rich.panel import Panel +from pip._vendor.rich.pretty import Pretty + + +def report() -> None: # pragma: no cover + """Print a report to the terminal with debugging information""" + console = Console() + inspect(console) + features = get_windows_console_features() + inspect(features) + + env_names = ( + "TERM", + "COLORTERM", + "CLICOLOR", + "NO_COLOR", + "TERM_PROGRAM", + "COLUMNS", + "LINES", + "JUPYTER_COLUMNS", + "JUPYTER_LINES", + "JPY_PARENT_PID", + "VSCODE_VERBOSE_LOGGING", + ) + env = {name: os.getenv(name) for name in env_names} + console.print(Panel.fit((Pretty(env)), title="[b]Environment Variables")) + + console.print(f'platform="{platform.system()}"') + + +if __name__ == "__main__": # pragma: no cover + report() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/emoji.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/emoji.py new file mode 100644 index 0000000..791f046 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/emoji.py @@ -0,0 +1,96 @@ +import sys +from typing import TYPE_CHECKING, Optional, Union + +from .jupyter import JupyterMixin +from .segment import Segment +from .style import Style +from ._emoji_codes import EMOJI +from ._emoji_replace import _emoji_replace + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult + + +EmojiVariant = Literal["emoji", "text"] + + +class NoEmoji(Exception): + """No emoji by that name.""" + + +class Emoji(JupyterMixin): + __slots__ = ["name", "style", "_char", "variant"] + + VARIANTS = {"text": "\uFE0E", "emoji": "\uFE0F"} + + def __init__( + self, + name: str, + style: Union[str, Style] = "none", + variant: Optional[EmojiVariant] = None, + ) -> None: + """A single emoji character. + + Args: + name (str): Name of emoji. + style (Union[str, Style], optional): Optional style. Defaults to None. + + Raises: + NoEmoji: If the emoji doesn't exist. + """ + self.name = name + self.style = style + self.variant = variant + try: + self._char = EMOJI[name] + except KeyError: + raise NoEmoji(f"No emoji called {name!r}") + if variant is not None: + self._char += self.VARIANTS.get(variant, "") + + @classmethod + def replace(cls, text: str) -> str: + """Replace emoji markup with corresponding unicode characters. + + Args: + text (str): A string with emojis codes, e.g. "Hello :smiley:!" + + Returns: + str: A string with emoji codes replaces with actual emoji. + """ + return _emoji_replace(text) + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return self._char + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + yield Segment(self._char, console.get_style(self.style)) + + +if __name__ == "__main__": # pragma: no cover + import sys + + from pip._vendor.rich.columns import Columns + from pip._vendor.rich.console import Console + + console = Console(record=True) + + columns = Columns( + (f":{name}: {name}" for name in sorted(EMOJI.keys()) if "\u200D" not in name), + column_first=True, + ) + + console.print(columns) + if len(sys.argv) > 1: + console.save_html(sys.argv[1]) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/errors.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/errors.py new file mode 100644 index 0000000..0bcbe53 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/errors.py @@ -0,0 +1,34 @@ +class ConsoleError(Exception): + """An error in console operation.""" + + +class StyleError(Exception): + """An error in styles.""" + + +class StyleSyntaxError(ConsoleError): + """Style was badly formatted.""" + + +class MissingStyle(StyleError): + """No such style.""" + + +class StyleStackError(ConsoleError): + """Style stack is invalid.""" + + +class NotRenderableError(ConsoleError): + """Object is not renderable.""" + + +class MarkupError(ConsoleError): + """Markup was badly formatted.""" + + +class LiveError(ConsoleError): + """Error related to Live display.""" + + +class NoAltScreen(ConsoleError): + """Alt screen mode was required.""" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py new file mode 100644 index 0000000..4b0b0da --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py @@ -0,0 +1,57 @@ +import io +from typing import IO, TYPE_CHECKING, Any, List + +from .ansi import AnsiDecoder +from .text import Text + +if TYPE_CHECKING: + from .console import Console + + +class FileProxy(io.TextIOBase): + """Wraps a file (e.g. sys.stdout) and redirects writes to a console.""" + + def __init__(self, console: "Console", file: IO[str]) -> None: + self.__console = console + self.__file = file + self.__buffer: List[str] = [] + self.__ansi_decoder = AnsiDecoder() + + @property + def rich_proxied_file(self) -> IO[str]: + """Get proxied file.""" + return self.__file + + def __getattr__(self, name: str) -> Any: + return getattr(self.__file, name) + + def write(self, text: str) -> int: + if not isinstance(text, str): + raise TypeError(f"write() argument must be str, not {type(text).__name__}") + buffer = self.__buffer + lines: List[str] = [] + while text: + line, new_line, text = text.partition("\n") + if new_line: + lines.append("".join(buffer) + line) + buffer.clear() + else: + buffer.append(line) + break + if lines: + console = self.__console + with console: + output = Text("\n").join( + self.__ansi_decoder.decode_line(line) for line in lines + ) + console.print(output) + return len(text) + + def flush(self) -> None: + output = "".join(self.__buffer) + if output: + self.__console.print(output) + del self.__buffer[:] + + def fileno(self) -> int: + return self.__file.fileno() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/filesize.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/filesize.py new file mode 100644 index 0000000..83bc911 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/filesize.py @@ -0,0 +1,88 @@ +"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2 + +The functions declared in this module should cover the different +use cases needed to generate a string representation of a file size +using several different units. Since there are many standards regarding +file size units, three different functions have been implemented. + +See Also: + * `Wikipedia: Binary prefix `_ + +""" + +__all__ = ["decimal"] + +from typing import Iterable, List, Optional, Tuple + + +def _to_str( + size: int, + suffixes: Iterable[str], + base: int, + *, + precision: Optional[int] = 1, + separator: Optional[str] = " ", +) -> str: + if size == 1: + return "1 byte" + elif size < base: + return f"{size:,} bytes" + + for i, suffix in enumerate(suffixes, 2): # noqa: B007 + unit = base**i + if size < unit: + break + return "{:,.{precision}f}{separator}{}".format( + (base * size / unit), + suffix, + precision=precision, + separator=separator, + ) + + +def pick_unit_and_suffix(size: int, suffixes: List[str], base: int) -> Tuple[int, str]: + """Pick a suffix and base for the given size.""" + for i, suffix in enumerate(suffixes): + unit = base**i + if size < unit * base: + break + return unit, suffix + + +def decimal( + size: int, + *, + precision: Optional[int] = 1, + separator: Optional[str] = " ", +) -> str: + """Convert a filesize in to a string (powers of 1000, SI prefixes). + + In this convention, ``1000 B = 1 kB``. + + This is typically the format used to advertise the storage + capacity of USB flash drives and the like (*256 MB* meaning + actually a storage capacity of more than *256 000 000 B*), + or used by **Mac OS X** since v10.6 to report file sizes. + + Arguments: + int (size): A file size. + int (precision): The number of decimal places to include (default = 1). + str (separator): The string to separate the value from the units (default = " "). + + Returns: + `str`: A string containing a abbreviated file size and units. + + Example: + >>> filesize.decimal(30000) + '30.0 kB' + >>> filesize.decimal(30000, precision=2, separator="") + '30.00kB' + + """ + return _to_str( + size, + ("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"), + 1000, + precision=precision, + separator=separator, + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/highlighter.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/highlighter.py new file mode 100644 index 0000000..e4c462e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/highlighter.py @@ -0,0 +1,232 @@ +import re +from abc import ABC, abstractmethod +from typing import List, Union + +from .text import Span, Text + + +def _combine_regex(*regexes: str) -> str: + """Combine a number of regexes in to a single regex. + + Returns: + str: New regex with all regexes ORed together. + """ + return "|".join(regexes) + + +class Highlighter(ABC): + """Abstract base class for highlighters.""" + + def __call__(self, text: Union[str, Text]) -> Text: + """Highlight a str or Text instance. + + Args: + text (Union[str, ~Text]): Text to highlight. + + Raises: + TypeError: If not called with text or str. + + Returns: + Text: A test instance with highlighting applied. + """ + if isinstance(text, str): + highlight_text = Text(text) + elif isinstance(text, Text): + highlight_text = text.copy() + else: + raise TypeError(f"str or Text instance required, not {text!r}") + self.highlight(highlight_text) + return highlight_text + + @abstractmethod + def highlight(self, text: Text) -> None: + """Apply highlighting in place to text. + + Args: + text (~Text): A text object highlight. + """ + + +class NullHighlighter(Highlighter): + """A highlighter object that doesn't highlight. + + May be used to disable highlighting entirely. + + """ + + def highlight(self, text: Text) -> None: + """Nothing to do""" + + +class RegexHighlighter(Highlighter): + """Applies highlighting from a list of regular expressions.""" + + highlights: List[str] = [] + base_style: str = "" + + def highlight(self, text: Text) -> None: + """Highlight :class:`rich.text.Text` using regular expressions. + + Args: + text (~Text): Text to highlighted. + + """ + + highlight_regex = text.highlight_regex + for re_highlight in self.highlights: + highlight_regex(re_highlight, style_prefix=self.base_style) + + +class ReprHighlighter(RegexHighlighter): + """Highlights the text typically produced from ``__repr__`` methods.""" + + base_style = "repr." + highlights = [ + r"(?P<)(?P[-\w.:|]*)(?P[\w\W]*)(?P>)", + r'(?P[\w_]{1,50})=(?P"?[\w_]+"?)?', + r"(?P[][{}()])", + _combine_regex( + r"(?P[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})", + r"(?P([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})", + r"(?P[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})", + r"(?P[\w.]*?)\(", + r"\b(?PTrue)\b|\b(?PFalse)\b|\b(?PNone)\b", + r"(?P\.\.\.)", + r"(?P(?(?\B(/[-\w._+]+)*\/)(?P[-\w._+]*)?", + r"(?b?'''.*?(?(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)", + ), + ] + + +class JSONHighlighter(RegexHighlighter): + """Highlights JSON""" + + # Captures the start and end of JSON strings, handling escaped quotes + JSON_STR = r"(?b?\".*?(?[\{\[\(\)\]\}])", + r"\b(?Ptrue)\b|\b(?Pfalse)\b|\b(?Pnull)\b", + r"(?P(? None: + super().highlight(text) + + # Additional work to handle highlighting JSON keys + plain = text.plain + append = text.spans.append + whitespace = self.JSON_WHITESPACE + for match in re.finditer(self.JSON_STR, plain): + start, end = match.span() + cursor = end + while cursor < len(plain): + char = plain[cursor] + cursor += 1 + if char == ":": + append(Span(start, end, "json.key")) + elif char in whitespace: + continue + break + + +class ISO8601Highlighter(RegexHighlighter): + """Highlights the ISO8601 date time strings. + Regex reference: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html + """ + + base_style = "iso8601." + highlights = [ + # + # Dates + # + # Calendar month (e.g. 2008-08). The hyphen is required + r"^(?P[0-9]{4})-(?P1[0-2]|0[1-9])$", + # Calendar date w/o hyphens (e.g. 20080830) + r"^(?P(?P[0-9]{4})(?P1[0-2]|0[1-9])(?P3[01]|0[1-9]|[12][0-9]))$", + # Ordinal date (e.g. 2008-243). The hyphen is optional + r"^(?P(?P[0-9]{4})-?(?P36[0-6]|3[0-5][0-9]|[12][0-9]{2}|0[1-9][0-9]|00[1-9]))$", + # + # Weeks + # + # Week of the year (e.g., 2008-W35). The hyphen is optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9]))$", + # Week date (e.g., 2008-W35-6). The hyphens are optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9])-?(?P[1-7]))$", + # + # Times + # + # Hours and minutes (e.g., 17:21). The colon is optional + r"^(?P
        {text}' + append_fragment(text) + + code = "".join(fragments) + html = JUPYTER_HTML_FORMAT.format(code=code) + + return html + + +def display(segments: Iterable[Segment], text: str) -> None: + """Render segments to Jupyter.""" + html = _render_segments(segments) + jupyter_renderable = JupyterRenderable(html, text) + try: + from IPython.display import display as ipython_display + + ipython_display(jupyter_renderable) + except ModuleNotFoundError: + # Handle the case where the Console has force_jupyter=True, + # but IPython is not installed. + pass + + +def print(*args: Any, **kwargs: Any) -> None: + """Proxy for Console print.""" + console = get_console() + return console.print(*args, **kwargs) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/layout.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/layout.py new file mode 100644 index 0000000..a6f1a31 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/layout.py @@ -0,0 +1,442 @@ +from abc import ABC, abstractmethod +from itertools import islice +from operator import itemgetter +from threading import RLock +from typing import ( + TYPE_CHECKING, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Sequence, + Tuple, + Union, +) + +from ._ratio import ratio_resolve +from .align import Align +from .console import Console, ConsoleOptions, RenderableType, RenderResult +from .highlighter import ReprHighlighter +from .panel import Panel +from .pretty import Pretty +from .region import Region +from .repr import Result, rich_repr +from .segment import Segment +from .style import StyleType + +if TYPE_CHECKING: + from pip._vendor.rich.tree import Tree + + +class LayoutRender(NamedTuple): + """An individual layout render.""" + + region: Region + render: List[List[Segment]] + + +RegionMap = Dict["Layout", Region] +RenderMap = Dict["Layout", LayoutRender] + + +class LayoutError(Exception): + """Layout related error.""" + + +class NoSplitter(LayoutError): + """Requested splitter does not exist.""" + + +class _Placeholder: + """An internal renderable used as a Layout placeholder.""" + + highlighter = ReprHighlighter() + + def __init__(self, layout: "Layout", style: StyleType = "") -> None: + self.layout = layout + self.style = style + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = options.max_width + height = options.height or options.size.height + layout = self.layout + title = ( + f"{layout.name!r} ({width} x {height})" + if layout.name + else f"({width} x {height})" + ) + yield Panel( + Align.center(Pretty(layout), vertical="middle"), + style=self.style, + title=self.highlighter(title), + border_style="blue", + height=height, + ) + + +class Splitter(ABC): + """Base class for a splitter.""" + + name: str = "" + + @abstractmethod + def get_tree_icon(self) -> str: + """Get the icon (emoji) used in layout.tree""" + + @abstractmethod + def divide( + self, children: Sequence["Layout"], region: Region + ) -> Iterable[Tuple["Layout", Region]]: + """Divide a region amongst several child layouts. + + Args: + children (Sequence(Layout)): A number of child layouts. + region (Region): A rectangular region to divide. + """ + + +class RowSplitter(Splitter): + """Split a layout region in to rows.""" + + name = "row" + + def get_tree_icon(self) -> str: + return "[layout.tree.row]⬌" + + def divide( + self, children: Sequence["Layout"], region: Region + ) -> Iterable[Tuple["Layout", Region]]: + x, y, width, height = region + render_widths = ratio_resolve(width, children) + offset = 0 + _Region = Region + for child, child_width in zip(children, render_widths): + yield child, _Region(x + offset, y, child_width, height) + offset += child_width + + +class ColumnSplitter(Splitter): + """Split a layout region in to columns.""" + + name = "column" + + def get_tree_icon(self) -> str: + return "[layout.tree.column]⬍" + + def divide( + self, children: Sequence["Layout"], region: Region + ) -> Iterable[Tuple["Layout", Region]]: + x, y, width, height = region + render_heights = ratio_resolve(height, children) + offset = 0 + _Region = Region + for child, child_height in zip(children, render_heights): + yield child, _Region(x, y + offset, width, child_height) + offset += child_height + + +@rich_repr +class Layout: + """A renderable to divide a fixed height in to rows or columns. + + Args: + renderable (RenderableType, optional): Renderable content, or None for placeholder. Defaults to None. + name (str, optional): Optional identifier for Layout. Defaults to None. + size (int, optional): Optional fixed size of layout. Defaults to None. + minimum_size (int, optional): Minimum size of layout. Defaults to 1. + ratio (int, optional): Optional ratio for flexible layout. Defaults to 1. + visible (bool, optional): Visibility of layout. Defaults to True. + """ + + splitters = {"row": RowSplitter, "column": ColumnSplitter} + + def __init__( + self, + renderable: Optional[RenderableType] = None, + *, + name: Optional[str] = None, + size: Optional[int] = None, + minimum_size: int = 1, + ratio: int = 1, + visible: bool = True, + ) -> None: + self._renderable = renderable or _Placeholder(self) + self.size = size + self.minimum_size = minimum_size + self.ratio = ratio + self.name = name + self.visible = visible + self.splitter: Splitter = self.splitters["column"]() + self._children: List[Layout] = [] + self._render_map: RenderMap = {} + self._lock = RLock() + + def __rich_repr__(self) -> Result: + yield "name", self.name, None + yield "size", self.size, None + yield "minimum_size", self.minimum_size, 1 + yield "ratio", self.ratio, 1 + + @property + def renderable(self) -> RenderableType: + """Layout renderable.""" + return self if self._children else self._renderable + + @property + def children(self) -> List["Layout"]: + """Gets (visible) layout children.""" + return [child for child in self._children if child.visible] + + @property + def map(self) -> RenderMap: + """Get a map of the last render.""" + return self._render_map + + def get(self, name: str) -> Optional["Layout"]: + """Get a named layout, or None if it doesn't exist. + + Args: + name (str): Name of layout. + + Returns: + Optional[Layout]: Layout instance or None if no layout was found. + """ + if self.name == name: + return self + else: + for child in self._children: + named_layout = child.get(name) + if named_layout is not None: + return named_layout + return None + + def __getitem__(self, name: str) -> "Layout": + layout = self.get(name) + if layout is None: + raise KeyError(f"No layout with name {name!r}") + return layout + + @property + def tree(self) -> "Tree": + """Get a tree renderable to show layout structure.""" + from pip._vendor.rich.styled import Styled + from pip._vendor.rich.table import Table + from pip._vendor.rich.tree import Tree + + def summary(layout: "Layout") -> Table: + icon = layout.splitter.get_tree_icon() + + table = Table.grid(padding=(0, 1, 0, 0)) + + text: RenderableType = ( + Pretty(layout) if layout.visible else Styled(Pretty(layout), "dim") + ) + table.add_row(icon, text) + _summary = table + return _summary + + layout = self + tree = Tree( + summary(layout), + guide_style=f"layout.tree.{layout.splitter.name}", + highlight=True, + ) + + def recurse(tree: "Tree", layout: "Layout") -> None: + for child in layout._children: + recurse( + tree.add( + summary(child), + guide_style=f"layout.tree.{child.splitter.name}", + ), + child, + ) + + recurse(tree, self) + return tree + + def split( + self, + *layouts: Union["Layout", RenderableType], + splitter: Union[Splitter, str] = "column", + ) -> None: + """Split the layout in to multiple sub-layouts. + + Args: + *layouts (Layout): Positional arguments should be (sub) Layout instances. + splitter (Union[Splitter, str]): Splitter instance or name of splitter. + """ + _layouts = [ + layout if isinstance(layout, Layout) else Layout(layout) + for layout in layouts + ] + try: + self.splitter = ( + splitter + if isinstance(splitter, Splitter) + else self.splitters[splitter]() + ) + except KeyError: + raise NoSplitter(f"No splitter called {splitter!r}") + self._children[:] = _layouts + + def add_split(self, *layouts: Union["Layout", RenderableType]) -> None: + """Add a new layout(s) to existing split. + + Args: + *layouts (Union[Layout, RenderableType]): Positional arguments should be renderables or (sub) Layout instances. + + """ + _layouts = ( + layout if isinstance(layout, Layout) else Layout(layout) + for layout in layouts + ) + self._children.extend(_layouts) + + def split_row(self, *layouts: Union["Layout", RenderableType]) -> None: + """Split the layout in to a row (layouts side by side). + + Args: + *layouts (Layout): Positional arguments should be (sub) Layout instances. + """ + self.split(*layouts, splitter="row") + + def split_column(self, *layouts: Union["Layout", RenderableType]) -> None: + """Split the layout in to a column (layouts stacked on top of each other). + + Args: + *layouts (Layout): Positional arguments should be (sub) Layout instances. + """ + self.split(*layouts, splitter="column") + + def unsplit(self) -> None: + """Reset splits to initial state.""" + del self._children[:] + + def update(self, renderable: RenderableType) -> None: + """Update renderable. + + Args: + renderable (RenderableType): New renderable object. + """ + with self._lock: + self._renderable = renderable + + def refresh_screen(self, console: "Console", layout_name: str) -> None: + """Refresh a sub-layout. + + Args: + console (Console): Console instance where Layout is to be rendered. + layout_name (str): Name of layout. + """ + with self._lock: + layout = self[layout_name] + region, _lines = self._render_map[layout] + (x, y, width, height) = region + lines = console.render_lines( + layout, console.options.update_dimensions(width, height) + ) + self._render_map[layout] = LayoutRender(region, lines) + console.update_screen_lines(lines, x, y) + + def _make_region_map(self, width: int, height: int) -> RegionMap: + """Create a dict that maps layout on to Region.""" + stack: List[Tuple[Layout, Region]] = [(self, Region(0, 0, width, height))] + push = stack.append + pop = stack.pop + layout_regions: List[Tuple[Layout, Region]] = [] + append_layout_region = layout_regions.append + while stack: + append_layout_region(pop()) + layout, region = layout_regions[-1] + children = layout.children + if children: + for child_and_region in layout.splitter.divide(children, region): + push(child_and_region) + + region_map = { + layout: region + for layout, region in sorted(layout_regions, key=itemgetter(1)) + } + return region_map + + def render(self, console: Console, options: ConsoleOptions) -> RenderMap: + """Render the sub_layouts. + + Args: + console (Console): Console instance. + options (ConsoleOptions): Console options. + + Returns: + RenderMap: A dict that maps Layout on to a tuple of Region, lines + """ + render_width = options.max_width + render_height = options.height or console.height + region_map = self._make_region_map(render_width, render_height) + layout_regions = [ + (layout, region) + for layout, region in region_map.items() + if not layout.children + ] + render_map: Dict["Layout", "LayoutRender"] = {} + render_lines = console.render_lines + update_dimensions = options.update_dimensions + + for layout, region in layout_regions: + lines = render_lines( + layout.renderable, update_dimensions(region.width, region.height) + ) + render_map[layout] = LayoutRender(region, lines) + return render_map + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + with self._lock: + width = options.max_width or console.width + height = options.height or console.height + render_map = self.render(console, options.update_dimensions(width, height)) + self._render_map = render_map + layout_lines: List[List[Segment]] = [[] for _ in range(height)] + _islice = islice + for region, lines in render_map.values(): + _x, y, _layout_width, layout_height = region + for row, line in zip( + _islice(layout_lines, y, y + layout_height), lines + ): + row.extend(line) + + new_line = Segment.line() + for layout_row in layout_lines: + yield from layout_row + yield new_line + + +if __name__ == "__main__": + from pip._vendor.rich.console import Console + + console = Console() + layout = Layout() + + layout.split_column( + Layout(name="header", size=3), + Layout(ratio=1, name="main"), + Layout(size=10, name="footer"), + ) + + layout["main"].split_row(Layout(name="side"), Layout(name="body", ratio=2)) + + layout["body"].split_row(Layout(name="content", ratio=2), Layout(name="s2")) + + layout["s2"].split_column( + Layout(name="top"), Layout(name="middle"), Layout(name="bottom") + ) + + layout["side"].split_column(Layout(layout.tree, name="left1"), Layout(name="left2")) + + layout["content"].update("foo") + + console.print(layout) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/live.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/live.py new file mode 100644 index 0000000..8738cf0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/live.py @@ -0,0 +1,375 @@ +import sys +from threading import Event, RLock, Thread +from types import TracebackType +from typing import IO, Any, Callable, List, Optional, TextIO, Type, cast + +from . import get_console +from .console import Console, ConsoleRenderable, RenderableType, RenderHook +from .control import Control +from .file_proxy import FileProxy +from .jupyter import JupyterMixin +from .live_render import LiveRender, VerticalOverflowMethod +from .screen import Screen +from .text import Text + + +class _RefreshThread(Thread): + """A thread that calls refresh() at regular intervals.""" + + def __init__(self, live: "Live", refresh_per_second: float) -> None: + self.live = live + self.refresh_per_second = refresh_per_second + self.done = Event() + super().__init__(daemon=True) + + def stop(self) -> None: + self.done.set() + + def run(self) -> None: + while not self.done.wait(1 / self.refresh_per_second): + with self.live._lock: + if not self.done.is_set(): + self.live.refresh() + + +class Live(JupyterMixin, RenderHook): + """Renders an auto-updating live display of any given renderable. + + Args: + renderable (RenderableType, optional): The renderable to live display. Defaults to displaying nothing. + console (Console, optional): Optional Console instance. Defaults to an internal Console instance writing to stdout. + screen (bool, optional): Enable alternate screen mode. Defaults to False. + auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()` or `update()` with refresh flag. Defaults to True + refresh_per_second (float, optional): Number of times per second to refresh the live display. Defaults to 4. + transient (bool, optional): Clear the renderable on exit (has no effect when screen=True). Defaults to False. + redirect_stdout (bool, optional): Enable redirection of stdout, so ``print`` may be used. Defaults to True. + redirect_stderr (bool, optional): Enable redirection of stderr. Defaults to True. + vertical_overflow (VerticalOverflowMethod, optional): How to handle renderable when it is too tall for the console. Defaults to "ellipsis". + get_renderable (Callable[[], RenderableType], optional): Optional callable to get renderable. Defaults to None. + """ + + def __init__( + self, + renderable: Optional[RenderableType] = None, + *, + console: Optional[Console] = None, + screen: bool = False, + auto_refresh: bool = True, + refresh_per_second: float = 4, + transient: bool = False, + redirect_stdout: bool = True, + redirect_stderr: bool = True, + vertical_overflow: VerticalOverflowMethod = "ellipsis", + get_renderable: Optional[Callable[[], RenderableType]] = None, + ) -> None: + assert refresh_per_second > 0, "refresh_per_second must be > 0" + self._renderable = renderable + self.console = console if console is not None else get_console() + self._screen = screen + self._alt_screen = False + + self._redirect_stdout = redirect_stdout + self._redirect_stderr = redirect_stderr + self._restore_stdout: Optional[IO[str]] = None + self._restore_stderr: Optional[IO[str]] = None + + self._lock = RLock() + self.ipy_widget: Optional[Any] = None + self.auto_refresh = auto_refresh + self._started: bool = False + self.transient = True if screen else transient + + self._refresh_thread: Optional[_RefreshThread] = None + self.refresh_per_second = refresh_per_second + + self.vertical_overflow = vertical_overflow + self._get_renderable = get_renderable + self._live_render = LiveRender( + self.get_renderable(), vertical_overflow=vertical_overflow + ) + + @property + def is_started(self) -> bool: + """Check if live display has been started.""" + return self._started + + def get_renderable(self) -> RenderableType: + renderable = ( + self._get_renderable() + if self._get_renderable is not None + else self._renderable + ) + return renderable or "" + + def start(self, refresh: bool = False) -> None: + """Start live rendering display. + + Args: + refresh (bool, optional): Also refresh. Defaults to False. + """ + with self._lock: + if self._started: + return + self.console.set_live(self) + self._started = True + if self._screen: + self._alt_screen = self.console.set_alt_screen(True) + self.console.show_cursor(False) + self._enable_redirect_io() + self.console.push_render_hook(self) + if refresh: + try: + self.refresh() + except Exception: + # If refresh fails, we want to stop the redirection of sys.stderr, + # so the error stacktrace is properly displayed in the terminal. + # (or, if the code that calls Rich captures the exception and wants to display something, + # let this be displayed in the terminal). + self.stop() + raise + if self.auto_refresh: + self._refresh_thread = _RefreshThread(self, self.refresh_per_second) + self._refresh_thread.start() + + def stop(self) -> None: + """Stop live rendering display.""" + with self._lock: + if not self._started: + return + self.console.clear_live() + self._started = False + + if self.auto_refresh and self._refresh_thread is not None: + self._refresh_thread.stop() + self._refresh_thread = None + # allow it to fully render on the last even if overflow + self.vertical_overflow = "visible" + with self.console: + try: + if not self._alt_screen and not self.console.is_jupyter: + self.refresh() + finally: + self._disable_redirect_io() + self.console.pop_render_hook() + if not self._alt_screen and self.console.is_terminal: + self.console.line() + self.console.show_cursor(True) + if self._alt_screen: + self.console.set_alt_screen(False) + + if self.transient and not self._alt_screen: + self.console.control(self._live_render.restore_cursor()) + if self.ipy_widget is not None and self.transient: + self.ipy_widget.close() # pragma: no cover + + def __enter__(self) -> "Live": + self.start(refresh=self._renderable is not None) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.stop() + + def _enable_redirect_io(self) -> None: + """Enable redirecting of stdout / stderr.""" + if self.console.is_terminal or self.console.is_jupyter: + if self._redirect_stdout and not isinstance(sys.stdout, FileProxy): + self._restore_stdout = sys.stdout + sys.stdout = cast("TextIO", FileProxy(self.console, sys.stdout)) + if self._redirect_stderr and not isinstance(sys.stderr, FileProxy): + self._restore_stderr = sys.stderr + sys.stderr = cast("TextIO", FileProxy(self.console, sys.stderr)) + + def _disable_redirect_io(self) -> None: + """Disable redirecting of stdout / stderr.""" + if self._restore_stdout: + sys.stdout = cast("TextIO", self._restore_stdout) + self._restore_stdout = None + if self._restore_stderr: + sys.stderr = cast("TextIO", self._restore_stderr) + self._restore_stderr = None + + @property + def renderable(self) -> RenderableType: + """Get the renderable that is being displayed + + Returns: + RenderableType: Displayed renderable. + """ + renderable = self.get_renderable() + return Screen(renderable) if self._alt_screen else renderable + + def update(self, renderable: RenderableType, *, refresh: bool = False) -> None: + """Update the renderable that is being displayed + + Args: + renderable (RenderableType): New renderable to use. + refresh (bool, optional): Refresh the display. Defaults to False. + """ + if isinstance(renderable, str): + renderable = self.console.render_str(renderable) + with self._lock: + self._renderable = renderable + if refresh: + self.refresh() + + def refresh(self) -> None: + """Update the display of the Live Render.""" + with self._lock: + self._live_render.set_renderable(self.renderable) + if self.console.is_jupyter: # pragma: no cover + try: + from IPython.display import display + from ipywidgets import Output + except ImportError: + import warnings + + warnings.warn('install "ipywidgets" for Jupyter support') + else: + if self.ipy_widget is None: + self.ipy_widget = Output() + display(self.ipy_widget) + + with self.ipy_widget: + self.ipy_widget.clear_output(wait=True) + self.console.print(self._live_render.renderable) + elif self.console.is_terminal and not self.console.is_dumb_terminal: + with self.console: + self.console.print(Control()) + elif ( + not self._started and not self.transient + ): # if it is finished allow files or dumb-terminals to see final result + with self.console: + self.console.print(Control()) + + def process_renderables( + self, renderables: List[ConsoleRenderable] + ) -> List[ConsoleRenderable]: + """Process renderables to restore cursor and display progress.""" + self._live_render.vertical_overflow = self.vertical_overflow + if self.console.is_interactive: + # lock needs acquiring as user can modify live_render renderable at any time unlike in Progress. + with self._lock: + reset = ( + Control.home() + if self._alt_screen + else self._live_render.position_cursor() + ) + renderables = [reset, *renderables, self._live_render] + elif ( + not self._started and not self.transient + ): # if it is finished render the final output for files or dumb_terminals + renderables = [*renderables, self._live_render] + + return renderables + + +if __name__ == "__main__": # pragma: no cover + import random + import time + from itertools import cycle + from typing import Dict, List, Tuple + + from .align import Align + from .console import Console + from .live import Live as Live + from .panel import Panel + from .rule import Rule + from .syntax import Syntax + from .table import Table + + console = Console() + + syntax = Syntax( + '''def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value''', + "python", + line_numbers=True, + ) + + table = Table("foo", "bar", "baz") + table.add_row("1", "2", "3") + + progress_renderables = [ + "You can make the terminal shorter and taller to see the live table hide" + "Text may be printed while the progress bars are rendering.", + Panel("In fact, [i]any[/i] renderable will work"), + "Such as [magenta]tables[/]...", + table, + "Pretty printed structures...", + {"type": "example", "text": "Pretty printed"}, + "Syntax...", + syntax, + Rule("Give it a try!"), + ] + + examples = cycle(progress_renderables) + + exchanges = [ + "SGD", + "MYR", + "EUR", + "USD", + "AUD", + "JPY", + "CNH", + "HKD", + "CAD", + "INR", + "DKK", + "GBP", + "RUB", + "NZD", + "MXN", + "IDR", + "TWD", + "THB", + "VND", + ] + with Live(console=console) as live_table: + exchange_rate_dict: Dict[Tuple[str, str], float] = {} + + for index in range(100): + select_exchange = exchanges[index % len(exchanges)] + + for exchange in exchanges: + if exchange == select_exchange: + continue + time.sleep(0.4) + if random.randint(0, 10) < 1: + console.log(next(examples)) + exchange_rate_dict[(select_exchange, exchange)] = 200 / ( + (random.random() * 320) + 1 + ) + if len(exchange_rate_dict) > len(exchanges) - 1: + exchange_rate_dict.pop(list(exchange_rate_dict.keys())[0]) + table = Table(title="Exchange Rates") + + table.add_column("Source Currency") + table.add_column("Destination Currency") + table.add_column("Exchange Rate") + + for (source, dest), exchange_rate in exchange_rate_dict.items(): + table.add_row( + source, + dest, + Text( + f"{exchange_rate:.4f}", + style="red" if exchange_rate < 1.0 else "green", + ), + ) + + live_table.update(Align.center(table)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/live_render.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/live_render.py new file mode 100644 index 0000000..e20745d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/live_render.py @@ -0,0 +1,112 @@ +import sys +from typing import Optional, Tuple + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + + +from ._loop import loop_last +from .console import Console, ConsoleOptions, RenderableType, RenderResult +from .control import Control +from .segment import ControlType, Segment +from .style import StyleType +from .text import Text + +VerticalOverflowMethod = Literal["crop", "ellipsis", "visible"] + + +class LiveRender: + """Creates a renderable that may be updated. + + Args: + renderable (RenderableType): Any renderable object. + style (StyleType, optional): An optional style to apply to the renderable. Defaults to "". + """ + + def __init__( + self, + renderable: RenderableType, + style: StyleType = "", + vertical_overflow: VerticalOverflowMethod = "ellipsis", + ) -> None: + self.renderable = renderable + self.style = style + self.vertical_overflow = vertical_overflow + self._shape: Optional[Tuple[int, int]] = None + + def set_renderable(self, renderable: RenderableType) -> None: + """Set a new renderable. + + Args: + renderable (RenderableType): Any renderable object, including str. + """ + self.renderable = renderable + + def position_cursor(self) -> Control: + """Get control codes to move cursor to beginning of live render. + + Returns: + Control: A control instance that may be printed. + """ + if self._shape is not None: + _, height = self._shape + return Control( + ControlType.CARRIAGE_RETURN, + (ControlType.ERASE_IN_LINE, 2), + *( + ( + (ControlType.CURSOR_UP, 1), + (ControlType.ERASE_IN_LINE, 2), + ) + * (height - 1) + ) + ) + return Control() + + def restore_cursor(self) -> Control: + """Get control codes to clear the render and restore the cursor to its previous position. + + Returns: + Control: A Control instance that may be printed. + """ + if self._shape is not None: + _, height = self._shape + return Control( + ControlType.CARRIAGE_RETURN, + *((ControlType.CURSOR_UP, 1), (ControlType.ERASE_IN_LINE, 2)) * height + ) + return Control() + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + renderable = self.renderable + style = console.get_style(self.style) + lines = console.render_lines(renderable, options, style=style, pad=False) + shape = Segment.get_shape(lines) + + _, height = shape + if height > options.size.height: + if self.vertical_overflow == "crop": + lines = lines[: options.size.height] + shape = Segment.get_shape(lines) + elif self.vertical_overflow == "ellipsis": + lines = lines[: (options.size.height - 1)] + overflow_text = Text( + "...", + overflow="crop", + justify="center", + end="", + style="live.ellipsis", + ) + lines.append(list(console.render(overflow_text))) + shape = Segment.get_shape(lines) + self._shape = shape + + new_line = Segment.line() + for last, line in loop_last(lines): + yield from line + if not last: + yield new_line diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/logging.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/logging.py new file mode 100644 index 0000000..ff8d5d9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/logging.py @@ -0,0 +1,297 @@ +import logging +from datetime import datetime +from logging import Handler, LogRecord +from pathlib import Path +from types import ModuleType +from typing import ClassVar, Iterable, List, Optional, Type, Union + +from pip._vendor.rich._null_file import NullFile + +from . import get_console +from ._log_render import FormatTimeCallable, LogRender +from .console import Console, ConsoleRenderable +from .highlighter import Highlighter, ReprHighlighter +from .text import Text +from .traceback import Traceback + + +class RichHandler(Handler): + """A logging handler that renders output with Rich. The time / level / message and file are displayed in columns. + The level is color coded, and the message is syntax highlighted. + + Note: + Be careful when enabling console markup in log messages if you have configured logging for libraries not + under your control. If a dependency writes messages containing square brackets, it may not produce the intended output. + + Args: + level (Union[int, str], optional): Log level. Defaults to logging.NOTSET. + console (:class:`~rich.console.Console`, optional): Optional console instance to write logs. + Default will use a global console instance writing to stdout. + show_time (bool, optional): Show a column for the time. Defaults to True. + omit_repeated_times (bool, optional): Omit repetition of the same time. Defaults to True. + show_level (bool, optional): Show a column for the level. Defaults to True. + show_path (bool, optional): Show the path to the original log call. Defaults to True. + enable_link_path (bool, optional): Enable terminal link of path column to file. Defaults to True. + highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None. + markup (bool, optional): Enable console markup in log messages. Defaults to False. + rich_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False. + tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks, or None for full width. Defaults to None. + tracebacks_code_width (int, optional): Number of code characters used to render tracebacks, or None for full width. Defaults to 88. + tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks, or None for full width. Defaults to None. + tracebacks_theme (str, optional): Override pygments theme used in traceback. + tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to True. + tracebacks_show_locals (bool, optional): Enable display of locals in tracebacks. Defaults to False. + tracebacks_suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + tracebacks_max_frames (int, optional): Optional maximum number of frames returned by traceback. + locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to 10. + locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. + log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%x %X] ". + keywords (List[str], optional): List of words to highlight instead of ``RichHandler.KEYWORDS``. + """ + + KEYWORDS: ClassVar[Optional[List[str]]] = [ + "GET", + "POST", + "HEAD", + "PUT", + "DELETE", + "OPTIONS", + "TRACE", + "PATCH", + ] + HIGHLIGHTER_CLASS: ClassVar[Type[Highlighter]] = ReprHighlighter + + def __init__( + self, + level: Union[int, str] = logging.NOTSET, + console: Optional[Console] = None, + *, + show_time: bool = True, + omit_repeated_times: bool = True, + show_level: bool = True, + show_path: bool = True, + enable_link_path: bool = True, + highlighter: Optional[Highlighter] = None, + markup: bool = False, + rich_tracebacks: bool = False, + tracebacks_width: Optional[int] = None, + tracebacks_code_width: int = 88, + tracebacks_extra_lines: int = 3, + tracebacks_theme: Optional[str] = None, + tracebacks_word_wrap: bool = True, + tracebacks_show_locals: bool = False, + tracebacks_suppress: Iterable[Union[str, ModuleType]] = (), + tracebacks_max_frames: int = 100, + locals_max_length: int = 10, + locals_max_string: int = 80, + log_time_format: Union[str, FormatTimeCallable] = "[%x %X]", + keywords: Optional[List[str]] = None, + ) -> None: + super().__init__(level=level) + self.console = console or get_console() + self.highlighter = highlighter or self.HIGHLIGHTER_CLASS() + self._log_render = LogRender( + show_time=show_time, + show_level=show_level, + show_path=show_path, + time_format=log_time_format, + omit_repeated_times=omit_repeated_times, + level_width=None, + ) + self.enable_link_path = enable_link_path + self.markup = markup + self.rich_tracebacks = rich_tracebacks + self.tracebacks_width = tracebacks_width + self.tracebacks_extra_lines = tracebacks_extra_lines + self.tracebacks_theme = tracebacks_theme + self.tracebacks_word_wrap = tracebacks_word_wrap + self.tracebacks_show_locals = tracebacks_show_locals + self.tracebacks_suppress = tracebacks_suppress + self.tracebacks_max_frames = tracebacks_max_frames + self.tracebacks_code_width = tracebacks_code_width + self.locals_max_length = locals_max_length + self.locals_max_string = locals_max_string + self.keywords = keywords + + def get_level_text(self, record: LogRecord) -> Text: + """Get the level name from the record. + + Args: + record (LogRecord): LogRecord instance. + + Returns: + Text: A tuple of the style and level name. + """ + level_name = record.levelname + level_text = Text.styled( + level_name.ljust(8), f"logging.level.{level_name.lower()}" + ) + return level_text + + def emit(self, record: LogRecord) -> None: + """Invoked by logging.""" + message = self.format(record) + traceback = None + if ( + self.rich_tracebacks + and record.exc_info + and record.exc_info != (None, None, None) + ): + exc_type, exc_value, exc_traceback = record.exc_info + assert exc_type is not None + assert exc_value is not None + traceback = Traceback.from_exception( + exc_type, + exc_value, + exc_traceback, + width=self.tracebacks_width, + code_width=self.tracebacks_code_width, + extra_lines=self.tracebacks_extra_lines, + theme=self.tracebacks_theme, + word_wrap=self.tracebacks_word_wrap, + show_locals=self.tracebacks_show_locals, + locals_max_length=self.locals_max_length, + locals_max_string=self.locals_max_string, + suppress=self.tracebacks_suppress, + max_frames=self.tracebacks_max_frames, + ) + message = record.getMessage() + if self.formatter: + record.message = record.getMessage() + formatter = self.formatter + if hasattr(formatter, "usesTime") and formatter.usesTime(): + record.asctime = formatter.formatTime(record, formatter.datefmt) + message = formatter.formatMessage(record) + + message_renderable = self.render_message(record, message) + log_renderable = self.render( + record=record, traceback=traceback, message_renderable=message_renderable + ) + if isinstance(self.console.file, NullFile): + # Handles pythonw, where stdout/stderr are null, and we return NullFile + # instance from Console.file. In this case, we still want to make a log record + # even though we won't be writing anything to a file. + self.handleError(record) + else: + try: + self.console.print(log_renderable) + except Exception: + self.handleError(record) + + def render_message(self, record: LogRecord, message: str) -> "ConsoleRenderable": + """Render message text in to Text. + + Args: + record (LogRecord): logging Record. + message (str): String containing log message. + + Returns: + ConsoleRenderable: Renderable to display log message. + """ + use_markup = getattr(record, "markup", self.markup) + message_text = Text.from_markup(message) if use_markup else Text(message) + + highlighter = getattr(record, "highlighter", self.highlighter) + if highlighter: + message_text = highlighter(message_text) + + if self.keywords is None: + self.keywords = self.KEYWORDS + + if self.keywords: + message_text.highlight_words(self.keywords, "logging.keyword") + + return message_text + + def render( + self, + *, + record: LogRecord, + traceback: Optional[Traceback], + message_renderable: "ConsoleRenderable", + ) -> "ConsoleRenderable": + """Render log for display. + + Args: + record (LogRecord): logging Record. + traceback (Optional[Traceback]): Traceback instance or None for no Traceback. + message_renderable (ConsoleRenderable): Renderable (typically Text) containing log message contents. + + Returns: + ConsoleRenderable: Renderable to display log. + """ + path = Path(record.pathname).name + level = self.get_level_text(record) + time_format = None if self.formatter is None else self.formatter.datefmt + log_time = datetime.fromtimestamp(record.created) + + log_renderable = self._log_render( + self.console, + [message_renderable] if not traceback else [message_renderable, traceback], + log_time=log_time, + time_format=time_format, + level=level, + path=path, + line_no=record.lineno, + link_path=record.pathname if self.enable_link_path else None, + ) + return log_renderable + + +if __name__ == "__main__": # pragma: no cover + from time import sleep + + FORMAT = "%(message)s" + # FORMAT = "%(asctime)-15s - %(levelname)s - %(message)s" + logging.basicConfig( + level="NOTSET", + format=FORMAT, + datefmt="[%X]", + handlers=[RichHandler(rich_tracebacks=True, tracebacks_show_locals=True)], + ) + log = logging.getLogger("rich") + + log.info("Server starting...") + log.info("Listening on http://127.0.0.1:8080") + sleep(1) + + log.info("GET /index.html 200 1298") + log.info("GET /imgs/backgrounds/back1.jpg 200 54386") + log.info("GET /css/styles.css 200 54386") + log.warning("GET /favicon.ico 404 242") + sleep(1) + + log.debug( + "JSONRPC request\n--> %r\n<-- %r", + { + "version": "1.1", + "method": "confirmFruitPurchase", + "params": [["apple", "orange", "mangoes", "pomelo"], 1.123], + "id": "194521489", + }, + {"version": "1.1", "result": True, "error": None, "id": "194521489"}, + ) + log.debug( + "Loading configuration file /adasd/asdasd/qeqwe/qwrqwrqwr/sdgsdgsdg/werwerwer/dfgerert/ertertert/ertetert/werwerwer" + ) + log.error("Unable to find 'pomelo' in database!") + log.info("POST /jsonrpc/ 200 65532") + log.info("POST /admin/ 401 42234") + log.warning("password was rejected for admin site.") + + def divide() -> None: + number = 1 + divisor = 0 + foos = ["foo"] * 100 + log.debug("in divide") + try: + number / divisor + except: + log.exception("An error of some kind occurred!") + + divide() + sleep(1) + log.critical("Out of memory!") + log.info("Server exited with code=-1") + log.info("[bold]EXITING...[/bold]", extra=dict(markup=True)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/markup.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/markup.py new file mode 100644 index 0000000..f617187 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/markup.py @@ -0,0 +1,251 @@ +import re +from ast import literal_eval +from operator import attrgetter +from typing import Callable, Iterable, List, Match, NamedTuple, Optional, Tuple, Union + +from ._emoji_replace import _emoji_replace +from .emoji import EmojiVariant +from .errors import MarkupError +from .style import Style +from .text import Span, Text + +RE_TAGS = re.compile( + r"""((\\*)\[([a-z#/@][^[]*?)])""", + re.VERBOSE, +) + +RE_HANDLER = re.compile(r"^([\w.]*?)(\(.*?\))?$") + + +class Tag(NamedTuple): + """A tag in console markup.""" + + name: str + """The tag name. e.g. 'bold'.""" + parameters: Optional[str] + """Any additional parameters after the name.""" + + def __str__(self) -> str: + return ( + self.name if self.parameters is None else f"{self.name} {self.parameters}" + ) + + @property + def markup(self) -> str: + """Get the string representation of this tag.""" + return ( + f"[{self.name}]" + if self.parameters is None + else f"[{self.name}={self.parameters}]" + ) + + +_ReStringMatch = Match[str] # regex match object +_ReSubCallable = Callable[[_ReStringMatch], str] # Callable invoked by re.sub +_EscapeSubMethod = Callable[[_ReSubCallable, str], str] # Sub method of a compiled re + + +def escape( + markup: str, + _escape: _EscapeSubMethod = re.compile(r"(\\*)(\[[a-z#/@][^[]*?])").sub, +) -> str: + """Escapes text so that it won't be interpreted as markup. + + Args: + markup (str): Content to be inserted in to markup. + + Returns: + str: Markup with square brackets escaped. + """ + + def escape_backslashes(match: Match[str]) -> str: + """Called by re.sub replace matches.""" + backslashes, text = match.groups() + return f"{backslashes}{backslashes}\\{text}" + + markup = _escape(escape_backslashes, markup) + if markup.endswith("\\") and not markup.endswith("\\\\"): + return markup + "\\" + + return markup + + +def _parse(markup: str) -> Iterable[Tuple[int, Optional[str], Optional[Tag]]]: + """Parse markup in to an iterable of tuples of (position, text, tag). + + Args: + markup (str): A string containing console markup + + """ + position = 0 + _divmod = divmod + _Tag = Tag + for match in RE_TAGS.finditer(markup): + full_text, escapes, tag_text = match.groups() + start, end = match.span() + if start > position: + yield start, markup[position:start], None + if escapes: + backslashes, escaped = _divmod(len(escapes), 2) + if backslashes: + # Literal backslashes + yield start, "\\" * backslashes, None + start += backslashes * 2 + if escaped: + # Escape of tag + yield start, full_text[len(escapes) :], None + position = end + continue + text, equals, parameters = tag_text.partition("=") + yield start, None, _Tag(text, parameters if equals else None) + position = end + if position < len(markup): + yield position, markup[position:], None + + +def render( + markup: str, + style: Union[str, Style] = "", + emoji: bool = True, + emoji_variant: Optional[EmojiVariant] = None, +) -> Text: + """Render console markup in to a Text instance. + + Args: + markup (str): A string containing console markup. + style: (Union[str, Style]): The style to use. + emoji (bool, optional): Also render emoji code. Defaults to True. + emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None. + + + Raises: + MarkupError: If there is a syntax error in the markup. + + Returns: + Text: A test instance. + """ + emoji_replace = _emoji_replace + if "[" not in markup: + return Text( + emoji_replace(markup, default_variant=emoji_variant) if emoji else markup, + style=style, + ) + text = Text(style=style) + append = text.append + normalize = Style.normalize + + style_stack: List[Tuple[int, Tag]] = [] + pop = style_stack.pop + + spans: List[Span] = [] + append_span = spans.append + + _Span = Span + _Tag = Tag + + def pop_style(style_name: str) -> Tuple[int, Tag]: + """Pop tag matching given style name.""" + for index, (_, tag) in enumerate(reversed(style_stack), 1): + if tag.name == style_name: + return pop(-index) + raise KeyError(style_name) + + for position, plain_text, tag in _parse(markup): + if plain_text is not None: + # Handle open brace escapes, where the brace is not part of a tag. + plain_text = plain_text.replace("\\[", "[") + append(emoji_replace(plain_text) if emoji else plain_text) + elif tag is not None: + if tag.name.startswith("/"): # Closing tag + style_name = tag.name[1:].strip() + + if style_name: # explicit close + style_name = normalize(style_name) + try: + start, open_tag = pop_style(style_name) + except KeyError: + raise MarkupError( + f"closing tag '{tag.markup}' at position {position} doesn't match any open tag" + ) from None + else: # implicit close + try: + start, open_tag = pop() + except IndexError: + raise MarkupError( + f"closing tag '[/]' at position {position} has nothing to close" + ) from None + + if open_tag.name.startswith("@"): + if open_tag.parameters: + handler_name = "" + parameters = open_tag.parameters.strip() + handler_match = RE_HANDLER.match(parameters) + if handler_match is not None: + handler_name, match_parameters = handler_match.groups() + parameters = ( + "()" if match_parameters is None else match_parameters + ) + + try: + meta_params = literal_eval(parameters) + except SyntaxError as error: + raise MarkupError( + f"error parsing {parameters!r} in {open_tag.parameters!r}; {error.msg}" + ) + except Exception as error: + raise MarkupError( + f"error parsing {open_tag.parameters!r}; {error}" + ) from None + + if handler_name: + meta_params = ( + handler_name, + meta_params + if isinstance(meta_params, tuple) + else (meta_params,), + ) + + else: + meta_params = () + + append_span( + _Span( + start, len(text), Style(meta={open_tag.name: meta_params}) + ) + ) + else: + append_span(_Span(start, len(text), str(open_tag))) + + else: # Opening tag + normalized_tag = _Tag(normalize(tag.name), tag.parameters) + style_stack.append((len(text), normalized_tag)) + + text_length = len(text) + while style_stack: + start, tag = style_stack.pop() + style = str(tag) + if style: + append_span(_Span(start, text_length, style)) + + text.spans = sorted(spans[::-1], key=attrgetter("start")) + return text + + +if __name__ == "__main__": # pragma: no cover + MARKUP = [ + "[red]Hello World[/red]", + "[magenta]Hello [b]World[/b]", + "[bold]Bold[italic] bold and italic [/bold]italic[/italic]", + "Click [link=https://www.willmcgugan.com]here[/link] to visit my Blog", + ":warning-emoji: [bold red blink] DANGER![/]", + ] + + from pip._vendor.rich import print + from pip._vendor.rich.table import Table + + grid = Table("Markup", "Result", padding=(0, 1)) + + for markup in MARKUP: + grid.add_row(Text(markup), markup) + + print(grid) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/measure.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/measure.py new file mode 100644 index 0000000..a508ffa --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/measure.py @@ -0,0 +1,151 @@ +from operator import itemgetter +from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, Sequence + +from . import errors +from .protocol import is_renderable, rich_cast + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType + + +class Measurement(NamedTuple): + """Stores the minimum and maximum widths (in characters) required to render an object.""" + + minimum: int + """Minimum number of cells required to render.""" + maximum: int + """Maximum number of cells required to render.""" + + @property + def span(self) -> int: + """Get difference between maximum and minimum.""" + return self.maximum - self.minimum + + def normalize(self) -> "Measurement": + """Get measurement that ensures that minimum <= maximum and minimum >= 0 + + Returns: + Measurement: A normalized measurement. + """ + minimum, maximum = self + minimum = min(max(0, minimum), maximum) + return Measurement(max(0, minimum), max(0, max(minimum, maximum))) + + def with_maximum(self, width: int) -> "Measurement": + """Get a RenderableWith where the widths are <= width. + + Args: + width (int): Maximum desired width. + + Returns: + Measurement: New Measurement object. + """ + minimum, maximum = self + return Measurement(min(minimum, width), min(maximum, width)) + + def with_minimum(self, width: int) -> "Measurement": + """Get a RenderableWith where the widths are >= width. + + Args: + width (int): Minimum desired width. + + Returns: + Measurement: New Measurement object. + """ + minimum, maximum = self + width = max(0, width) + return Measurement(max(minimum, width), max(maximum, width)) + + def clamp( + self, min_width: Optional[int] = None, max_width: Optional[int] = None + ) -> "Measurement": + """Clamp a measurement within the specified range. + + Args: + min_width (int): Minimum desired width, or ``None`` for no minimum. Defaults to None. + max_width (int): Maximum desired width, or ``None`` for no maximum. Defaults to None. + + Returns: + Measurement: New Measurement object. + """ + measurement = self + if min_width is not None: + measurement = measurement.with_minimum(min_width) + if max_width is not None: + measurement = measurement.with_maximum(max_width) + return measurement + + @classmethod + def get( + cls, console: "Console", options: "ConsoleOptions", renderable: "RenderableType" + ) -> "Measurement": + """Get a measurement for a renderable. + + Args: + console (~rich.console.Console): Console instance. + options (~rich.console.ConsoleOptions): Console options. + renderable (RenderableType): An object that may be rendered with Rich. + + Raises: + errors.NotRenderableError: If the object is not renderable. + + Returns: + Measurement: Measurement object containing range of character widths required to render the object. + """ + _max_width = options.max_width + if _max_width < 1: + return Measurement(0, 0) + if isinstance(renderable, str): + renderable = console.render_str( + renderable, markup=options.markup, highlight=False + ) + renderable = rich_cast(renderable) + if is_renderable(renderable): + get_console_width: Optional[ + Callable[["Console", "ConsoleOptions"], "Measurement"] + ] = getattr(renderable, "__rich_measure__", None) + if get_console_width is not None: + render_width = ( + get_console_width(console, options) + .normalize() + .with_maximum(_max_width) + ) + if render_width.maximum < 1: + return Measurement(0, 0) + return render_width.normalize() + else: + return Measurement(0, _max_width) + else: + raise errors.NotRenderableError( + f"Unable to get render width for {renderable!r}; " + "a str, Segment, or object with __rich_console__ method is required" + ) + + +def measure_renderables( + console: "Console", + options: "ConsoleOptions", + renderables: Sequence["RenderableType"], +) -> "Measurement": + """Get a measurement that would fit a number of renderables. + + Args: + console (~rich.console.Console): Console instance. + options (~rich.console.ConsoleOptions): Console options. + renderables (Iterable[RenderableType]): One or more renderable objects. + + Returns: + Measurement: Measurement object containing range of character widths required to + contain all given renderables. + """ + if not renderables: + return Measurement(0, 0) + get_measurement = Measurement.get + measurements = [ + get_measurement(console, options, renderable) for renderable in renderables + ] + measured_width = Measurement( + max(measurements, key=itemgetter(0)).minimum, + max(measurements, key=itemgetter(1)).maximum, + ) + return measured_width diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/padding.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/padding.py new file mode 100644 index 0000000..0161cd1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/padding.py @@ -0,0 +1,141 @@ +from typing import TYPE_CHECKING, List, Optional, Tuple, Union + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + RenderableType, + RenderResult, + ) + +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style + +PaddingDimensions = Union[int, Tuple[int], Tuple[int, int], Tuple[int, int, int, int]] + + +class Padding(JupyterMixin): + """Draw space around content. + + Example: + >>> print(Padding("Hello", (2, 4), style="on blue")) + + Args: + renderable (RenderableType): String or other renderable. + pad (Union[int, Tuple[int]]): Padding for top, right, bottom, and left borders. + May be specified with 1, 2, or 4 integers (CSS style). + style (Union[str, Style], optional): Style for padding characters. Defaults to "none". + expand (bool, optional): Expand padding to fit available width. Defaults to True. + """ + + def __init__( + self, + renderable: "RenderableType", + pad: "PaddingDimensions" = (0, 0, 0, 0), + *, + style: Union[str, Style] = "none", + expand: bool = True, + ): + self.renderable = renderable + self.top, self.right, self.bottom, self.left = self.unpack(pad) + self.style = style + self.expand = expand + + @classmethod + def indent(cls, renderable: "RenderableType", level: int) -> "Padding": + """Make padding instance to render an indent. + + Args: + renderable (RenderableType): String or other renderable. + level (int): Number of characters to indent. + + Returns: + Padding: A Padding instance. + """ + + return Padding(renderable, pad=(0, 0, 0, level), expand=False) + + @staticmethod + def unpack(pad: "PaddingDimensions") -> Tuple[int, int, int, int]: + """Unpack padding specified in CSS style.""" + if isinstance(pad, int): + return (pad, pad, pad, pad) + if len(pad) == 1: + _pad = pad[0] + return (_pad, _pad, _pad, _pad) + if len(pad) == 2: + pad_top, pad_right = pad + return (pad_top, pad_right, pad_top, pad_right) + if len(pad) == 4: + top, right, bottom, left = pad + return (top, right, bottom, left) + raise ValueError(f"1, 2 or 4 integers required for padding; {len(pad)} given") + + def __repr__(self) -> str: + return f"Padding({self.renderable!r}, ({self.top},{self.right},{self.bottom},{self.left}))" + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + style = console.get_style(self.style) + if self.expand: + width = options.max_width + else: + width = min( + Measurement.get(console, options, self.renderable).maximum + + self.left + + self.right, + options.max_width, + ) + render_options = options.update_width(width - self.left - self.right) + if render_options.height is not None: + render_options = render_options.update_height( + height=render_options.height - self.top - self.bottom + ) + lines = console.render_lines( + self.renderable, render_options, style=style, pad=True + ) + _Segment = Segment + + left = _Segment(" " * self.left, style) if self.left else None + right = ( + [_Segment(f'{" " * self.right}', style), _Segment.line()] + if self.right + else [_Segment.line()] + ) + blank_line: Optional[List[Segment]] = None + if self.top: + blank_line = [_Segment(f'{" " * width}\n', style)] + yield from blank_line * self.top + if left: + for line in lines: + yield left + yield from line + yield from right + else: + for line in lines: + yield from line + yield from right + if self.bottom: + blank_line = blank_line or [_Segment(f'{" " * width}\n', style)] + yield from blank_line * self.bottom + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + max_width = options.max_width + extra_width = self.left + self.right + if max_width - extra_width < 1: + return Measurement(max_width, max_width) + measure_min, measure_max = Measurement.get(console, options, self.renderable) + measurement = Measurement(measure_min + extra_width, measure_max + extra_width) + measurement = measurement.with_maximum(max_width) + return measurement + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich import print + + print(Padding("Hello, World", (2, 4), style="on blue")) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/pager.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/pager.py new file mode 100644 index 0000000..a3f7aa6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/pager.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod +from typing import Any + + +class Pager(ABC): + """Base class for a pager.""" + + @abstractmethod + def show(self, content: str) -> None: + """Show content in pager. + + Args: + content (str): Content to be displayed. + """ + + +class SystemPager(Pager): + """Uses the pager installed on the system.""" + + def _pager(self, content: str) -> Any: #  pragma: no cover + return __import__("pydoc").pager(content) + + def show(self, content: str) -> None: + """Use the same pager used by pydoc.""" + self._pager(content) + + +if __name__ == "__main__": # pragma: no cover + from .__main__ import make_test_card + from .console import Console + + console = Console() + with console.pager(styles=True): + console.print(make_test_card()) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/palette.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/palette.py new file mode 100644 index 0000000..fa0c4dd --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/palette.py @@ -0,0 +1,100 @@ +from math import sqrt +from functools import lru_cache +from typing import Sequence, Tuple, TYPE_CHECKING + +from .color_triplet import ColorTriplet + +if TYPE_CHECKING: + from pip._vendor.rich.table import Table + + +class Palette: + """A palette of available colors.""" + + def __init__(self, colors: Sequence[Tuple[int, int, int]]): + self._colors = colors + + def __getitem__(self, number: int) -> ColorTriplet: + return ColorTriplet(*self._colors[number]) + + def __rich__(self) -> "Table": + from pip._vendor.rich.color import Color + from pip._vendor.rich.style import Style + from pip._vendor.rich.text import Text + from pip._vendor.rich.table import Table + + table = Table( + "index", + "RGB", + "Color", + title="Palette", + caption=f"{len(self._colors)} colors", + highlight=True, + caption_justify="right", + ) + for index, color in enumerate(self._colors): + table.add_row( + str(index), + repr(color), + Text(" " * 16, style=Style(bgcolor=Color.from_rgb(*color))), + ) + return table + + # This is somewhat inefficient and needs caching + @lru_cache(maxsize=1024) + def match(self, color: Tuple[int, int, int]) -> int: + """Find a color from a palette that most closely matches a given color. + + Args: + color (Tuple[int, int, int]): RGB components in range 0 > 255. + + Returns: + int: Index of closes matching color. + """ + red1, green1, blue1 = color + _sqrt = sqrt + get_color = self._colors.__getitem__ + + def get_color_distance(index: int) -> float: + """Get the distance to a color.""" + red2, green2, blue2 = get_color(index) + red_mean = (red1 + red2) // 2 + red = red1 - red2 + green = green1 - green2 + blue = blue1 - blue2 + return _sqrt( + (((512 + red_mean) * red * red) >> 8) + + 4 * green * green + + (((767 - red_mean) * blue * blue) >> 8) + ) + + min_index = min(range(len(self._colors)), key=get_color_distance) + return min_index + + +if __name__ == "__main__": # pragma: no cover + import colorsys + from typing import Iterable + from pip._vendor.rich.color import Color + from pip._vendor.rich.console import Console, ConsoleOptions + from pip._vendor.rich.segment import Segment + from pip._vendor.rich.style import Style + + class ColorBox: + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> Iterable[Segment]: + height = console.size.height - 3 + for y in range(0, height): + for x in range(options.max_width): + h = x / options.max_width + l = y / (height + 1) + r1, g1, b1 = colorsys.hls_to_rgb(h, l, 1.0) + r2, g2, b2 = colorsys.hls_to_rgb(h, l + (1 / height / 2), 1.0) + bgcolor = Color.from_rgb(r1 * 255, g1 * 255, b1 * 255) + color = Color.from_rgb(r2 * 255, g2 * 255, b2 * 255) + yield Segment("▄", Style(color=color, bgcolor=bgcolor)) + yield Segment.line() + + console = Console() + console.print(ColorBox()) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/panel.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/panel.py new file mode 100644 index 0000000..8cfa6f4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/panel.py @@ -0,0 +1,318 @@ +from typing import TYPE_CHECKING, Optional + +from .align import AlignMethod +from .box import ROUNDED, Box +from .cells import cell_len +from .jupyter import JupyterMixin +from .measure import Measurement, measure_renderables +from .padding import Padding, PaddingDimensions +from .segment import Segment +from .style import Style, StyleType +from .text import Text, TextType + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType, RenderResult + + +class Panel(JupyterMixin): + """A console renderable that draws a border around its contents. + + Example: + >>> console.print(Panel("Hello, World!")) + + Args: + renderable (RenderableType): A console renderable object. + box (Box, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`. Defaults to box.ROUNDED. + title (Optional[TextType], optional): Optional title displayed in panel header. Defaults to None. + title_align (AlignMethod, optional): Alignment of title. Defaults to "center". + subtitle (Optional[TextType], optional): Optional subtitle displayed in panel footer. Defaults to None. + subtitle_align (AlignMethod, optional): Alignment of subtitle. Defaults to "center". + safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True. + expand (bool, optional): If True the panel will stretch to fill the console width, otherwise it will be sized to fit the contents. Defaults to True. + style (str, optional): The style of the panel (border and contents). Defaults to "none". + border_style (str, optional): The style of the border. Defaults to "none". + width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect. + height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect. + padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0. + highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False. + """ + + def __init__( + self, + renderable: "RenderableType", + box: Box = ROUNDED, + *, + title: Optional[TextType] = None, + title_align: AlignMethod = "center", + subtitle: Optional[TextType] = None, + subtitle_align: AlignMethod = "center", + safe_box: Optional[bool] = None, + expand: bool = True, + style: StyleType = "none", + border_style: StyleType = "none", + width: Optional[int] = None, + height: Optional[int] = None, + padding: PaddingDimensions = (0, 1), + highlight: bool = False, + ) -> None: + self.renderable = renderable + self.box = box + self.title = title + self.title_align: AlignMethod = title_align + self.subtitle = subtitle + self.subtitle_align = subtitle_align + self.safe_box = safe_box + self.expand = expand + self.style = style + self.border_style = border_style + self.width = width + self.height = height + self.padding = padding + self.highlight = highlight + + @classmethod + def fit( + cls, + renderable: "RenderableType", + box: Box = ROUNDED, + *, + title: Optional[TextType] = None, + title_align: AlignMethod = "center", + subtitle: Optional[TextType] = None, + subtitle_align: AlignMethod = "center", + safe_box: Optional[bool] = None, + style: StyleType = "none", + border_style: StyleType = "none", + width: Optional[int] = None, + height: Optional[int] = None, + padding: PaddingDimensions = (0, 1), + highlight: bool = False, + ) -> "Panel": + """An alternative constructor that sets expand=False.""" + return cls( + renderable, + box, + title=title, + title_align=title_align, + subtitle=subtitle, + subtitle_align=subtitle_align, + safe_box=safe_box, + style=style, + border_style=border_style, + width=width, + height=height, + padding=padding, + highlight=highlight, + expand=False, + ) + + @property + def _title(self) -> Optional[Text]: + if self.title: + title_text = ( + Text.from_markup(self.title) + if isinstance(self.title, str) + else self.title.copy() + ) + title_text.end = "" + title_text.plain = title_text.plain.replace("\n", " ") + title_text.no_wrap = True + title_text.expand_tabs() + title_text.pad(1) + return title_text + return None + + @property + def _subtitle(self) -> Optional[Text]: + if self.subtitle: + subtitle_text = ( + Text.from_markup(self.subtitle) + if isinstance(self.subtitle, str) + else self.subtitle.copy() + ) + subtitle_text.end = "" + subtitle_text.plain = subtitle_text.plain.replace("\n", " ") + subtitle_text.no_wrap = True + subtitle_text.expand_tabs() + subtitle_text.pad(1) + return subtitle_text + return None + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + _padding = Padding.unpack(self.padding) + renderable = ( + Padding(self.renderable, _padding) if any(_padding) else self.renderable + ) + style = console.get_style(self.style) + partial_border_style = console.get_style(self.border_style) + border_style = style + partial_border_style + width = ( + options.max_width + if self.width is None + else min(options.max_width, self.width) + ) + + safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box + box = self.box.substitute(options, safe=safe_box) + + def align_text( + text: Text, width: int, align: str, character: str, style: Style + ) -> Text: + """Gets new aligned text. + + Args: + text (Text): Title or subtitle text. + width (int): Desired width. + align (str): Alignment. + character (str): Character for alignment. + style (Style): Border style + + Returns: + Text: New text instance + """ + text = text.copy() + text.truncate(width) + excess_space = width - cell_len(text.plain) + if text.style: + text.stylize(console.get_style(text.style)) + + if excess_space: + if align == "left": + return Text.assemble( + text, + (character * excess_space, style), + no_wrap=True, + end="", + ) + elif align == "center": + left = excess_space // 2 + return Text.assemble( + (character * left, style), + text, + (character * (excess_space - left), style), + no_wrap=True, + end="", + ) + else: + return Text.assemble( + (character * excess_space, style), + text, + no_wrap=True, + end="", + ) + return text + + title_text = self._title + if title_text is not None: + title_text.stylize_before(partial_border_style) + + child_width = ( + width - 2 + if self.expand + else console.measure( + renderable, options=options.update_width(width - 2) + ).maximum + ) + child_height = self.height or options.height or None + if child_height: + child_height -= 2 + if title_text is not None: + child_width = min( + options.max_width - 2, max(child_width, title_text.cell_len + 2) + ) + + width = child_width + 2 + child_options = options.update( + width=child_width, height=child_height, highlight=self.highlight + ) + lines = console.render_lines(renderable, child_options, style=style) + + line_start = Segment(box.mid_left, border_style) + line_end = Segment(f"{box.mid_right}", border_style) + new_line = Segment.line() + if title_text is None or width <= 4: + yield Segment(box.get_top([width - 2]), border_style) + else: + title_text = align_text( + title_text, + width - 4, + self.title_align, + box.top, + border_style, + ) + yield Segment(box.top_left + box.top, border_style) + yield from console.render(title_text, child_options.update_width(width - 4)) + yield Segment(box.top + box.top_right, border_style) + + yield new_line + for line in lines: + yield line_start + yield from line + yield line_end + yield new_line + + subtitle_text = self._subtitle + if subtitle_text is not None: + subtitle_text.stylize_before(partial_border_style) + + if subtitle_text is None or width <= 4: + yield Segment(box.get_bottom([width - 2]), border_style) + else: + subtitle_text = align_text( + subtitle_text, + width - 4, + self.subtitle_align, + box.bottom, + border_style, + ) + yield Segment(box.bottom_left + box.bottom, border_style) + yield from console.render( + subtitle_text, child_options.update_width(width - 4) + ) + yield Segment(box.bottom + box.bottom_right, border_style) + + yield new_line + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + _title = self._title + _, right, _, left = Padding.unpack(self.padding) + padding = left + right + renderables = [self.renderable, _title] if _title else [self.renderable] + + if self.width is None: + width = ( + measure_renderables( + console, + options.update_width(options.max_width - padding - 2), + renderables, + ).maximum + + padding + + 2 + ) + else: + width = self.width + return Measurement(width, width) + + +if __name__ == "__main__": # pragma: no cover + from .console import Console + + c = Console() + + from .box import DOUBLE, ROUNDED + from .padding import Padding + + p = Panel( + "Hello, World!", + title="rich.Panel", + style="white on blue", + box=DOUBLE, + padding=1, + ) + + c.print() + c.print(p) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/pretty.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/pretty.py new file mode 100644 index 0000000..c4a274f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/pretty.py @@ -0,0 +1,1016 @@ +import builtins +import collections +import dataclasses +import inspect +import os +import reprlib +import sys +from array import array +from collections import Counter, UserDict, UserList, defaultdict, deque +from dataclasses import dataclass, fields, is_dataclass +from inspect import isclass +from itertools import islice +from types import MappingProxyType +from typing import ( + TYPE_CHECKING, + Any, + Callable, + DefaultDict, + Deque, + Dict, + Iterable, + List, + Optional, + Sequence, + Set, + Tuple, + Union, +) + +from pip._vendor.rich.repr import RichReprResult + +try: + import attr as _attr_module + + _has_attrs = hasattr(_attr_module, "ib") +except ImportError: # pragma: no cover + _has_attrs = False + +from . import get_console +from ._loop import loop_last +from ._pick import pick_bool +from .abc import RichRenderable +from .cells import cell_len +from .highlighter import ReprHighlighter +from .jupyter import JupyterMixin, JupyterRenderable +from .measure import Measurement +from .text import Text + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + HighlighterType, + JustifyMethod, + OverflowMethod, + RenderResult, + ) + + +def _is_attr_object(obj: Any) -> bool: + """Check if an object was created with attrs module.""" + return _has_attrs and _attr_module.has(type(obj)) + + +def _get_attr_fields(obj: Any) -> Sequence["_attr_module.Attribute[Any]"]: + """Get fields for an attrs object.""" + return _attr_module.fields(type(obj)) if _has_attrs else [] + + +def _is_dataclass_repr(obj: object) -> bool: + """Check if an instance of a dataclass contains the default repr. + + Args: + obj (object): A dataclass instance. + + Returns: + bool: True if the default repr is used, False if there is a custom repr. + """ + # Digging in to a lot of internals here + # Catching all exceptions in case something is missing on a non CPython implementation + try: + return obj.__repr__.__code__.co_filename in ( + dataclasses.__file__, + reprlib.__file__, + ) + except Exception: # pragma: no coverage + return False + + +_dummy_namedtuple = collections.namedtuple("_dummy_namedtuple", []) + + +def _has_default_namedtuple_repr(obj: object) -> bool: + """Check if an instance of namedtuple contains the default repr + + Args: + obj (object): A namedtuple + + Returns: + bool: True if the default repr is used, False if there's a custom repr. + """ + obj_file = None + try: + obj_file = inspect.getfile(obj.__repr__) + except (OSError, TypeError): + # OSError handles case where object is defined in __main__ scope, e.g. REPL - no filename available. + # TypeError trapped defensively, in case of object without filename slips through. + pass + default_repr_file = inspect.getfile(_dummy_namedtuple.__repr__) + return obj_file == default_repr_file + + +def _ipy_display_hook( + value: Any, + console: Optional["Console"] = None, + overflow: "OverflowMethod" = "ignore", + crop: bool = False, + indent_guides: bool = False, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, + expand_all: bool = False, +) -> Union[str, None]: + # needed here to prevent circular import: + from .console import ConsoleRenderable + + # always skip rich generated jupyter renderables or None values + if _safe_isinstance(value, JupyterRenderable) or value is None: + return None + + console = console or get_console() + + with console.capture() as capture: + # certain renderables should start on a new line + if _safe_isinstance(value, ConsoleRenderable): + console.line() + console.print( + ( + value + if _safe_isinstance(value, RichRenderable) + else Pretty( + value, + overflow=overflow, + indent_guides=indent_guides, + max_length=max_length, + max_string=max_string, + max_depth=max_depth, + expand_all=expand_all, + margin=12, + ) + ), + crop=crop, + new_line_start=True, + end="", + ) + # strip trailing newline, not usually part of a text repr + # I'm not sure if this should be prevented at a lower level + return capture.get().rstrip("\n") + + +def _safe_isinstance( + obj: object, class_or_tuple: Union[type, Tuple[type, ...]] +) -> bool: + """isinstance can fail in rare cases, for example types with no __class__""" + try: + return isinstance(obj, class_or_tuple) + except Exception: + return False + + +def install( + console: Optional["Console"] = None, + overflow: "OverflowMethod" = "ignore", + crop: bool = False, + indent_guides: bool = False, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, + expand_all: bool = False, +) -> None: + """Install automatic pretty printing in the Python REPL. + + Args: + console (Console, optional): Console instance or ``None`` to use global console. Defaults to None. + overflow (Optional[OverflowMethod], optional): Overflow method. Defaults to "ignore". + crop (Optional[bool], optional): Enable cropping of long lines. Defaults to False. + indent_guides (bool, optional): Enable indentation guides. Defaults to False. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to None. + max_depth (int, optional): Maximum depth of nested data structures, or None for no maximum. Defaults to None. + expand_all (bool, optional): Expand all containers. Defaults to False. + max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. + """ + from pip._vendor.rich import get_console + + console = console or get_console() + assert console is not None + + def display_hook(value: Any) -> None: + """Replacement sys.displayhook which prettifies objects with Rich.""" + if value is not None: + assert console is not None + builtins._ = None # type: ignore[attr-defined] + console.print( + ( + value + if _safe_isinstance(value, RichRenderable) + else Pretty( + value, + overflow=overflow, + indent_guides=indent_guides, + max_length=max_length, + max_string=max_string, + max_depth=max_depth, + expand_all=expand_all, + ) + ), + crop=crop, + ) + builtins._ = value # type: ignore[attr-defined] + + try: + ip = get_ipython() # type: ignore[name-defined] + except NameError: + sys.displayhook = display_hook + else: + from IPython.core.formatters import BaseFormatter + + class RichFormatter(BaseFormatter): # type: ignore[misc] + pprint: bool = True + + def __call__(self, value: Any) -> Any: + if self.pprint: + return _ipy_display_hook( + value, + console=get_console(), + overflow=overflow, + indent_guides=indent_guides, + max_length=max_length, + max_string=max_string, + max_depth=max_depth, + expand_all=expand_all, + ) + else: + return repr(value) + + # replace plain text formatter with rich formatter + rich_formatter = RichFormatter() + ip.display_formatter.formatters["text/plain"] = rich_formatter + + +class Pretty(JupyterMixin): + """A rich renderable that pretty prints an object. + + Args: + _object (Any): An object to pretty print. + highlighter (HighlighterType, optional): Highlighter object to apply to result, or None for ReprHighlighter. Defaults to None. + indent_size (int, optional): Number of spaces in indent. Defaults to 4. + justify (JustifyMethod, optional): Justify method, or None for default. Defaults to None. + overflow (OverflowMethod, optional): Overflow method, or None for default. Defaults to None. + no_wrap (Optional[bool], optional): Disable word wrapping. Defaults to False. + indent_guides (bool, optional): Enable indentation guides. Defaults to False. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to None. + max_depth (int, optional): Maximum depth of nested data structures, or None for no maximum. Defaults to None. + expand_all (bool, optional): Expand all containers. Defaults to False. + margin (int, optional): Subtrace a margin from width to force containers to expand earlier. Defaults to 0. + insert_line (bool, optional): Insert a new line if the output has multiple new lines. Defaults to False. + """ + + def __init__( + self, + _object: Any, + highlighter: Optional["HighlighterType"] = None, + *, + indent_size: int = 4, + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + no_wrap: Optional[bool] = False, + indent_guides: bool = False, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, + expand_all: bool = False, + margin: int = 0, + insert_line: bool = False, + ) -> None: + self._object = _object + self.highlighter = highlighter or ReprHighlighter() + self.indent_size = indent_size + self.justify: Optional["JustifyMethod"] = justify + self.overflow: Optional["OverflowMethod"] = overflow + self.no_wrap = no_wrap + self.indent_guides = indent_guides + self.max_length = max_length + self.max_string = max_string + self.max_depth = max_depth + self.expand_all = expand_all + self.margin = margin + self.insert_line = insert_line + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + pretty_str = pretty_repr( + self._object, + max_width=options.max_width - self.margin, + indent_size=self.indent_size, + max_length=self.max_length, + max_string=self.max_string, + max_depth=self.max_depth, + expand_all=self.expand_all, + ) + pretty_text = Text.from_ansi( + pretty_str, + justify=self.justify or options.justify, + overflow=self.overflow or options.overflow, + no_wrap=pick_bool(self.no_wrap, options.no_wrap), + style="pretty", + ) + pretty_text = ( + self.highlighter(pretty_text) + if pretty_text + else Text( + f"{type(self._object)}.__repr__ returned empty string", + style="dim italic", + ) + ) + if self.indent_guides and not options.ascii_only: + pretty_text = pretty_text.with_indent_guides( + self.indent_size, style="repr.indent" + ) + if self.insert_line and "\n" in pretty_text: + yield "" + yield pretty_text + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + pretty_str = pretty_repr( + self._object, + max_width=options.max_width, + indent_size=self.indent_size, + max_length=self.max_length, + max_string=self.max_string, + max_depth=self.max_depth, + expand_all=self.expand_all, + ) + text_width = ( + max(cell_len(line) for line in pretty_str.splitlines()) if pretty_str else 0 + ) + return Measurement(text_width, text_width) + + +def _get_braces_for_defaultdict(_object: DefaultDict[Any, Any]) -> Tuple[str, str, str]: + return ( + f"defaultdict({_object.default_factory!r}, {{", + "})", + f"defaultdict({_object.default_factory!r}, {{}})", + ) + + +def _get_braces_for_deque(_object: Deque[Any]) -> Tuple[str, str, str]: + if _object.maxlen is None: + return ("deque([", "])", "deque()") + return ( + "deque([", + f"], maxlen={_object.maxlen})", + f"deque(maxlen={_object.maxlen})", + ) + + +def _get_braces_for_array(_object: "array[Any]") -> Tuple[str, str, str]: + return (f"array({_object.typecode!r}, [", "])", f"array({_object.typecode!r})") + + +_BRACES: Dict[type, Callable[[Any], Tuple[str, str, str]]] = { + os._Environ: lambda _object: ("environ({", "})", "environ({})"), + array: _get_braces_for_array, + defaultdict: _get_braces_for_defaultdict, + Counter: lambda _object: ("Counter({", "})", "Counter()"), + deque: _get_braces_for_deque, + dict: lambda _object: ("{", "}", "{}"), + UserDict: lambda _object: ("{", "}", "{}"), + frozenset: lambda _object: ("frozenset({", "})", "frozenset()"), + list: lambda _object: ("[", "]", "[]"), + UserList: lambda _object: ("[", "]", "[]"), + set: lambda _object: ("{", "}", "set()"), + tuple: lambda _object: ("(", ")", "()"), + MappingProxyType: lambda _object: ("mappingproxy({", "})", "mappingproxy({})"), +} +_CONTAINERS = tuple(_BRACES.keys()) +_MAPPING_CONTAINERS = (dict, os._Environ, MappingProxyType, UserDict) + + +def is_expandable(obj: Any) -> bool: + """Check if an object may be expanded by pretty print.""" + return ( + _safe_isinstance(obj, _CONTAINERS) + or (is_dataclass(obj)) + or (hasattr(obj, "__rich_repr__")) + or _is_attr_object(obj) + ) and not isclass(obj) + + +@dataclass +class Node: + """A node in a repr tree. May be atomic or a container.""" + + key_repr: str = "" + value_repr: str = "" + open_brace: str = "" + close_brace: str = "" + empty: str = "" + last: bool = False + is_tuple: bool = False + is_namedtuple: bool = False + children: Optional[List["Node"]] = None + key_separator: str = ": " + separator: str = ", " + + def iter_tokens(self) -> Iterable[str]: + """Generate tokens for this node.""" + if self.key_repr: + yield self.key_repr + yield self.key_separator + if self.value_repr: + yield self.value_repr + elif self.children is not None: + if self.children: + yield self.open_brace + if self.is_tuple and not self.is_namedtuple and len(self.children) == 1: + yield from self.children[0].iter_tokens() + yield "," + else: + for child in self.children: + yield from child.iter_tokens() + if not child.last: + yield self.separator + yield self.close_brace + else: + yield self.empty + + def check_length(self, start_length: int, max_length: int) -> bool: + """Check the length fits within a limit. + + Args: + start_length (int): Starting length of the line (indent, prefix, suffix). + max_length (int): Maximum length. + + Returns: + bool: True if the node can be rendered within max length, otherwise False. + """ + total_length = start_length + for token in self.iter_tokens(): + total_length += cell_len(token) + if total_length > max_length: + return False + return True + + def __str__(self) -> str: + repr_text = "".join(self.iter_tokens()) + return repr_text + + def render( + self, max_width: int = 80, indent_size: int = 4, expand_all: bool = False + ) -> str: + """Render the node to a pretty repr. + + Args: + max_width (int, optional): Maximum width of the repr. Defaults to 80. + indent_size (int, optional): Size of indents. Defaults to 4. + expand_all (bool, optional): Expand all levels. Defaults to False. + + Returns: + str: A repr string of the original object. + """ + lines = [_Line(node=self, is_root=True)] + line_no = 0 + while line_no < len(lines): + line = lines[line_no] + if line.expandable and not line.expanded: + if expand_all or not line.check_length(max_width): + lines[line_no : line_no + 1] = line.expand(indent_size) + line_no += 1 + + repr_str = "\n".join(str(line) for line in lines) + return repr_str + + +@dataclass +class _Line: + """A line in repr output.""" + + parent: Optional["_Line"] = None + is_root: bool = False + node: Optional[Node] = None + text: str = "" + suffix: str = "" + whitespace: str = "" + expanded: bool = False + last: bool = False + + @property + def expandable(self) -> bool: + """Check if the line may be expanded.""" + return bool(self.node is not None and self.node.children) + + def check_length(self, max_length: int) -> bool: + """Check this line fits within a given number of cells.""" + start_length = ( + len(self.whitespace) + cell_len(self.text) + cell_len(self.suffix) + ) + assert self.node is not None + return self.node.check_length(start_length, max_length) + + def expand(self, indent_size: int) -> Iterable["_Line"]: + """Expand this line by adding children on their own line.""" + node = self.node + assert node is not None + whitespace = self.whitespace + assert node.children + if node.key_repr: + new_line = yield _Line( + text=f"{node.key_repr}{node.key_separator}{node.open_brace}", + whitespace=whitespace, + ) + else: + new_line = yield _Line(text=node.open_brace, whitespace=whitespace) + child_whitespace = self.whitespace + " " * indent_size + tuple_of_one = node.is_tuple and len(node.children) == 1 + for last, child in loop_last(node.children): + separator = "," if tuple_of_one else node.separator + line = _Line( + parent=new_line, + node=child, + whitespace=child_whitespace, + suffix=separator, + last=last and not tuple_of_one, + ) + yield line + + yield _Line( + text=node.close_brace, + whitespace=whitespace, + suffix=self.suffix, + last=self.last, + ) + + def __str__(self) -> str: + if self.last: + return f"{self.whitespace}{self.text}{self.node or ''}" + else: + return ( + f"{self.whitespace}{self.text}{self.node or ''}{self.suffix.rstrip()}" + ) + + +def _is_namedtuple(obj: Any) -> bool: + """Checks if an object is most likely a namedtuple. It is possible + to craft an object that passes this check and isn't a namedtuple, but + there is only a minuscule chance of this happening unintentionally. + + Args: + obj (Any): The object to test + + Returns: + bool: True if the object is a namedtuple. False otherwise. + """ + try: + fields = getattr(obj, "_fields", None) + except Exception: + # Being very defensive - if we cannot get the attr then its not a namedtuple + return False + return isinstance(obj, tuple) and isinstance(fields, tuple) + + +def traverse( + _object: Any, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, +) -> Node: + """Traverse object and generate a tree. + + Args: + _object (Any): Object to be traversed. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of string before truncating, or None to disable truncating. + Defaults to None. + max_depth (int, optional): Maximum depth of data structures, or None for no maximum. + Defaults to None. + + Returns: + Node: The root of a tree structure which can be used to render a pretty repr. + """ + + def to_repr(obj: Any) -> str: + """Get repr string for an object, but catch errors.""" + if ( + max_string is not None + and _safe_isinstance(obj, (bytes, str)) + and len(obj) > max_string + ): + truncated = len(obj) - max_string + obj_repr = f"{obj[:max_string]!r}+{truncated}" + else: + try: + obj_repr = repr(obj) + except Exception as error: + obj_repr = f"" + return obj_repr + + visited_ids: Set[int] = set() + push_visited = visited_ids.add + pop_visited = visited_ids.remove + + def _traverse(obj: Any, root: bool = False, depth: int = 0) -> Node: + """Walk the object depth first.""" + + obj_id = id(obj) + if obj_id in visited_ids: + # Recursion detected + return Node(value_repr="...") + + obj_type = type(obj) + children: List[Node] + reached_max_depth = max_depth is not None and depth >= max_depth + + def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]: + for arg in rich_args: + if _safe_isinstance(arg, tuple): + if len(arg) == 3: + key, child, default = arg + if default == child: + continue + yield key, child + elif len(arg) == 2: + key, child = arg + yield key, child + elif len(arg) == 1: + yield arg[0] + else: + yield arg + + try: + fake_attributes = hasattr( + obj, "awehoi234_wdfjwljet234_234wdfoijsdfmmnxpi492" + ) + except Exception: + fake_attributes = False + + rich_repr_result: Optional[RichReprResult] = None + if not fake_attributes: + try: + if hasattr(obj, "__rich_repr__") and not isclass(obj): + rich_repr_result = obj.__rich_repr__() + except Exception: + pass + + if rich_repr_result is not None: + push_visited(obj_id) + angular = getattr(obj.__rich_repr__, "angular", False) + args = list(iter_rich_args(rich_repr_result)) + class_name = obj.__class__.__name__ + + if args: + children = [] + append = children.append + + if reached_max_depth: + if angular: + node = Node(value_repr=f"<{class_name}...>") + else: + node = Node(value_repr=f"{class_name}(...)") + else: + if angular: + node = Node( + open_brace=f"<{class_name} ", + close_brace=">", + children=children, + last=root, + separator=" ", + ) + else: + node = Node( + open_brace=f"{class_name}(", + close_brace=")", + children=children, + last=root, + ) + for last, arg in loop_last(args): + if _safe_isinstance(arg, tuple): + key, child = arg + child_node = _traverse(child, depth=depth + 1) + child_node.last = last + child_node.key_repr = key + child_node.key_separator = "=" + append(child_node) + else: + child_node = _traverse(arg, depth=depth + 1) + child_node.last = last + append(child_node) + else: + node = Node( + value_repr=f"<{class_name}>" if angular else f"{class_name}()", + children=[], + last=root, + ) + pop_visited(obj_id) + elif _is_attr_object(obj) and not fake_attributes: + push_visited(obj_id) + children = [] + append = children.append + + attr_fields = _get_attr_fields(obj) + if attr_fields: + if reached_max_depth: + node = Node(value_repr=f"{obj.__class__.__name__}(...)") + else: + node = Node( + open_brace=f"{obj.__class__.__name__}(", + close_brace=")", + children=children, + last=root, + ) + + def iter_attrs() -> ( + Iterable[Tuple[str, Any, Optional[Callable[[Any], str]]]] + ): + """Iterate over attr fields and values.""" + for attr in attr_fields: + if attr.repr: + try: + value = getattr(obj, attr.name) + except Exception as error: + # Can happen, albeit rarely + yield (attr.name, error, None) + else: + yield ( + attr.name, + value, + attr.repr if callable(attr.repr) else None, + ) + + for last, (name, value, repr_callable) in loop_last(iter_attrs()): + if repr_callable: + child_node = Node(value_repr=str(repr_callable(value))) + else: + child_node = _traverse(value, depth=depth + 1) + child_node.last = last + child_node.key_repr = name + child_node.key_separator = "=" + append(child_node) + else: + node = Node( + value_repr=f"{obj.__class__.__name__}()", children=[], last=root + ) + pop_visited(obj_id) + elif ( + is_dataclass(obj) + and not _safe_isinstance(obj, type) + and not fake_attributes + and _is_dataclass_repr(obj) + ): + push_visited(obj_id) + children = [] + append = children.append + if reached_max_depth: + node = Node(value_repr=f"{obj.__class__.__name__}(...)") + else: + node = Node( + open_brace=f"{obj.__class__.__name__}(", + close_brace=")", + children=children, + last=root, + empty=f"{obj.__class__.__name__}()", + ) + + for last, field in loop_last( + field + for field in fields(obj) + if field.repr and hasattr(obj, field.name) + ): + child_node = _traverse(getattr(obj, field.name), depth=depth + 1) + child_node.key_repr = field.name + child_node.last = last + child_node.key_separator = "=" + append(child_node) + + pop_visited(obj_id) + elif _is_namedtuple(obj) and _has_default_namedtuple_repr(obj): + push_visited(obj_id) + class_name = obj.__class__.__name__ + if reached_max_depth: + # If we've reached the max depth, we still show the class name, but not its contents + node = Node( + value_repr=f"{class_name}(...)", + ) + else: + children = [] + append = children.append + node = Node( + open_brace=f"{class_name}(", + close_brace=")", + children=children, + empty=f"{class_name}()", + ) + for last, (key, value) in loop_last(obj._asdict().items()): + child_node = _traverse(value, depth=depth + 1) + child_node.key_repr = key + child_node.last = last + child_node.key_separator = "=" + append(child_node) + pop_visited(obj_id) + elif _safe_isinstance(obj, _CONTAINERS): + for container_type in _CONTAINERS: + if _safe_isinstance(obj, container_type): + obj_type = container_type + break + + push_visited(obj_id) + + open_brace, close_brace, empty = _BRACES[obj_type](obj) + + if reached_max_depth: + node = Node(value_repr=f"{open_brace}...{close_brace}") + elif obj_type.__repr__ != type(obj).__repr__: + node = Node(value_repr=to_repr(obj), last=root) + elif obj: + children = [] + node = Node( + open_brace=open_brace, + close_brace=close_brace, + children=children, + last=root, + ) + append = children.append + num_items = len(obj) + last_item_index = num_items - 1 + + if _safe_isinstance(obj, _MAPPING_CONTAINERS): + iter_items = iter(obj.items()) + if max_length is not None: + iter_items = islice(iter_items, max_length) + for index, (key, child) in enumerate(iter_items): + child_node = _traverse(child, depth=depth + 1) + child_node.key_repr = to_repr(key) + child_node.last = index == last_item_index + append(child_node) + else: + iter_values = iter(obj) + if max_length is not None: + iter_values = islice(iter_values, max_length) + for index, child in enumerate(iter_values): + child_node = _traverse(child, depth=depth + 1) + child_node.last = index == last_item_index + append(child_node) + if max_length is not None and num_items > max_length: + append(Node(value_repr=f"... +{num_items - max_length}", last=True)) + else: + node = Node(empty=empty, children=[], last=root) + + pop_visited(obj_id) + else: + node = Node(value_repr=to_repr(obj), last=root) + node.is_tuple = type(obj) == tuple + node.is_namedtuple = _is_namedtuple(obj) + return node + + node = _traverse(_object, root=True) + return node + + +def pretty_repr( + _object: Any, + *, + max_width: int = 80, + indent_size: int = 4, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, + expand_all: bool = False, +) -> str: + """Prettify repr string by expanding on to new lines to fit within a given width. + + Args: + _object (Any): Object to repr. + max_width (int, optional): Desired maximum width of repr string. Defaults to 80. + indent_size (int, optional): Number of spaces to indent. Defaults to 4. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of string before truncating, or None to disable truncating. + Defaults to None. + max_depth (int, optional): Maximum depth of nested data structure, or None for no depth. + Defaults to None. + expand_all (bool, optional): Expand all containers regardless of available width. Defaults to False. + + Returns: + str: A possibly multi-line representation of the object. + """ + + if _safe_isinstance(_object, Node): + node = _object + else: + node = traverse( + _object, max_length=max_length, max_string=max_string, max_depth=max_depth + ) + repr_str: str = node.render( + max_width=max_width, indent_size=indent_size, expand_all=expand_all + ) + return repr_str + + +def pprint( + _object: Any, + *, + console: Optional["Console"] = None, + indent_guides: bool = True, + max_length: Optional[int] = None, + max_string: Optional[int] = None, + max_depth: Optional[int] = None, + expand_all: bool = False, +) -> None: + """A convenience function for pretty printing. + + Args: + _object (Any): Object to pretty print. + console (Console, optional): Console instance, or None to use default. Defaults to None. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of strings before truncating, or None to disable. Defaults to None. + max_depth (int, optional): Maximum depth for nested data structures, or None for unlimited depth. Defaults to None. + indent_guides (bool, optional): Enable indentation guides. Defaults to True. + expand_all (bool, optional): Expand all containers. Defaults to False. + """ + _console = get_console() if console is None else console + _console.print( + Pretty( + _object, + max_length=max_length, + max_string=max_string, + max_depth=max_depth, + indent_guides=indent_guides, + expand_all=expand_all, + overflow="ignore", + ), + soft_wrap=True, + ) + + +if __name__ == "__main__": # pragma: no cover + + class BrokenRepr: + def __repr__(self) -> str: + 1 / 0 + return "this will fail" + + from typing import NamedTuple + + class StockKeepingUnit(NamedTuple): + name: str + description: str + price: float + category: str + reviews: List[str] + + d = defaultdict(int) + d["foo"] = 5 + data = { + "foo": [ + 1, + "Hello World!", + 100.123, + 323.232, + 432324.0, + {5, 6, 7, (1, 2, 3, 4), 8}, + ], + "bar": frozenset({1, 2, 3}), + "defaultdict": defaultdict( + list, {"crumble": ["apple", "rhubarb", "butter", "sugar", "flour"]} + ), + "counter": Counter( + [ + "apple", + "orange", + "pear", + "kumquat", + "kumquat", + "durian" * 100, + ] + ), + "atomic": (False, True, None), + "namedtuple": StockKeepingUnit( + "Sparkling British Spring Water", + "Carbonated spring water", + 0.9, + "water", + ["its amazing!", "its terrible!"], + ), + "Broken": BrokenRepr(), + } + data["foo"].append(data) # type: ignore[attr-defined] + + from pip._vendor.rich import print + + print(Pretty(data, indent_guides=True, max_string=20)) + + class Thing: + def __repr__(self) -> str: + return "Hello\x1b[38;5;239m World!" + + print(Pretty(Thing())) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/progress.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/progress.py new file mode 100644 index 0000000..ec086d9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/progress.py @@ -0,0 +1,1715 @@ +import io +import sys +import typing +import warnings +from abc import ABC, abstractmethod +from collections import deque +from dataclasses import dataclass, field +from datetime import timedelta +from io import RawIOBase, UnsupportedOperation +from math import ceil +from mmap import mmap +from operator import length_hint +from os import PathLike, stat +from threading import Event, RLock, Thread +from types import TracebackType +from typing import ( + Any, + BinaryIO, + Callable, + ContextManager, + Deque, + Dict, + Generic, + Iterable, + List, + NamedTuple, + NewType, + Optional, + Sequence, + TextIO, + Tuple, + Type, + TypeVar, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + +if sys.version_info >= (3, 11): + from typing import Self +else: + from pip._vendor.typing_extensions import Self # pragma: no cover + +from . import filesize, get_console +from .console import Console, Group, JustifyMethod, RenderableType +from .highlighter import Highlighter +from .jupyter import JupyterMixin +from .live import Live +from .progress_bar import ProgressBar +from .spinner import Spinner +from .style import StyleType +from .table import Column, Table +from .text import Text, TextType + +TaskID = NewType("TaskID", int) + +ProgressType = TypeVar("ProgressType") + +GetTimeCallable = Callable[[], float] + + +_I = typing.TypeVar("_I", TextIO, BinaryIO) + + +class _TrackThread(Thread): + """A thread to periodically update progress.""" + + def __init__(self, progress: "Progress", task_id: "TaskID", update_period: float): + self.progress = progress + self.task_id = task_id + self.update_period = update_period + self.done = Event() + + self.completed = 0 + super().__init__(daemon=True) + + def run(self) -> None: + task_id = self.task_id + advance = self.progress.advance + update_period = self.update_period + last_completed = 0 + wait = self.done.wait + while not wait(update_period) and self.progress.live.is_started: + completed = self.completed + if last_completed != completed: + advance(task_id, completed - last_completed) + last_completed = completed + + self.progress.update(self.task_id, completed=self.completed, refresh=True) + + def __enter__(self) -> "_TrackThread": + self.start() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.done.set() + self.join() + + +def track( + sequence: Union[Sequence[ProgressType], Iterable[ProgressType]], + description: str = "Working...", + total: Optional[float] = None, + completed: int = 0, + auto_refresh: bool = True, + console: Optional[Console] = None, + transient: bool = False, + get_time: Optional[Callable[[], float]] = None, + refresh_per_second: float = 10, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + update_period: float = 0.1, + disable: bool = False, + show_speed: bool = True, +) -> Iterable[ProgressType]: + """Track progress by iterating over a sequence. + + Args: + sequence (Iterable[ProgressType]): A sequence (must support "len") you wish to iterate over. + description (str, optional): Description of task show next to progress bar. Defaults to "Working". + total: (float, optional): Total number of steps. Default is len(sequence). + completed (int, optional): Number of steps completed so far. Defaults to 0. + auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True. + transient: (bool, optional): Clear the progress on exit. Defaults to False. + console (Console, optional): Console to write to. Default creates internal Console instance. + refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10. + style (StyleType, optional): Style for the bar background. Defaults to "bar.back". + complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete". + finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished". + pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse". + update_period (float, optional): Minimum time (in seconds) between calls to update(). Defaults to 0.1. + disable (bool, optional): Disable display of progress. + show_speed (bool, optional): Show speed if total isn't known. Defaults to True. + Returns: + Iterable[ProgressType]: An iterable of the values in the sequence. + + """ + + columns: List["ProgressColumn"] = ( + [TextColumn("[progress.description]{task.description}")] if description else [] + ) + columns.extend( + ( + BarColumn( + style=style, + complete_style=complete_style, + finished_style=finished_style, + pulse_style=pulse_style, + ), + TaskProgressColumn(show_speed=show_speed), + TimeRemainingColumn(elapsed_when_finished=True), + ) + ) + progress = Progress( + *columns, + auto_refresh=auto_refresh, + console=console, + transient=transient, + get_time=get_time, + refresh_per_second=refresh_per_second or 10, + disable=disable, + ) + + with progress: + yield from progress.track( + sequence, + total=total, + completed=completed, + description=description, + update_period=update_period, + ) + + +class _Reader(RawIOBase, BinaryIO): + """A reader that tracks progress while it's being read from.""" + + def __init__( + self, + handle: BinaryIO, + progress: "Progress", + task: TaskID, + close_handle: bool = True, + ) -> None: + self.handle = handle + self.progress = progress + self.task = task + self.close_handle = close_handle + self._closed = False + + def __enter__(self) -> "_Reader": + self.handle.__enter__() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.close() + + def __iter__(self) -> BinaryIO: + return self + + def __next__(self) -> bytes: + line = next(self.handle) + self.progress.advance(self.task, advance=len(line)) + return line + + @property + def closed(self) -> bool: + return self._closed + + def fileno(self) -> int: + return self.handle.fileno() + + def isatty(self) -> bool: + return self.handle.isatty() + + @property + def mode(self) -> str: + return self.handle.mode + + @property + def name(self) -> str: + return self.handle.name + + def readable(self) -> bool: + return self.handle.readable() + + def seekable(self) -> bool: + return self.handle.seekable() + + def writable(self) -> bool: + return False + + def read(self, size: int = -1) -> bytes: + block = self.handle.read(size) + self.progress.advance(self.task, advance=len(block)) + return block + + def readinto(self, b: Union[bytearray, memoryview, mmap]): # type: ignore[no-untyped-def, override] + n = self.handle.readinto(b) # type: ignore[attr-defined] + self.progress.advance(self.task, advance=n) + return n + + def readline(self, size: int = -1) -> bytes: # type: ignore[override] + line = self.handle.readline(size) + self.progress.advance(self.task, advance=len(line)) + return line + + def readlines(self, hint: int = -1) -> List[bytes]: + lines = self.handle.readlines(hint) + self.progress.advance(self.task, advance=sum(map(len, lines))) + return lines + + def close(self) -> None: + if self.close_handle: + self.handle.close() + self._closed = True + + def seek(self, offset: int, whence: int = 0) -> int: + pos = self.handle.seek(offset, whence) + self.progress.update(self.task, completed=pos) + return pos + + def tell(self) -> int: + return self.handle.tell() + + def write(self, s: Any) -> int: + raise UnsupportedOperation("write") + + def writelines(self, lines: Iterable[Any]) -> None: + raise UnsupportedOperation("writelines") + + +class _ReadContext(ContextManager[_I], Generic[_I]): + """A utility class to handle a context for both a reader and a progress.""" + + def __init__(self, progress: "Progress", reader: _I) -> None: + self.progress = progress + self.reader: _I = reader + + def __enter__(self) -> _I: + self.progress.start() + return self.reader.__enter__() + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.progress.stop() + self.reader.__exit__(exc_type, exc_val, exc_tb) + + +def wrap_file( + file: BinaryIO, + total: int, + *, + description: str = "Reading...", + auto_refresh: bool = True, + console: Optional[Console] = None, + transient: bool = False, + get_time: Optional[Callable[[], float]] = None, + refresh_per_second: float = 10, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + disable: bool = False, +) -> ContextManager[BinaryIO]: + """Read bytes from a file while tracking progress. + + Args: + file (Union[str, PathLike[str], BinaryIO]): The path to the file to read, or a file-like object in binary mode. + total (int): Total number of bytes to read. + description (str, optional): Description of task show next to progress bar. Defaults to "Reading". + auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True. + transient: (bool, optional): Clear the progress on exit. Defaults to False. + console (Console, optional): Console to write to. Default creates internal Console instance. + refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10. + style (StyleType, optional): Style for the bar background. Defaults to "bar.back". + complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete". + finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished". + pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse". + disable (bool, optional): Disable display of progress. + Returns: + ContextManager[BinaryIO]: A context manager yielding a progress reader. + + """ + + columns: List["ProgressColumn"] = ( + [TextColumn("[progress.description]{task.description}")] if description else [] + ) + columns.extend( + ( + BarColumn( + style=style, + complete_style=complete_style, + finished_style=finished_style, + pulse_style=pulse_style, + ), + DownloadColumn(), + TimeRemainingColumn(), + ) + ) + progress = Progress( + *columns, + auto_refresh=auto_refresh, + console=console, + transient=transient, + get_time=get_time, + refresh_per_second=refresh_per_second or 10, + disable=disable, + ) + + reader = progress.wrap_file(file, total=total, description=description) + return _ReadContext(progress, reader) + + +@typing.overload +def open( + file: Union[str, "PathLike[str]", bytes], + mode: Union[Literal["rt"], Literal["r"]], + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + description: str = "Reading...", + auto_refresh: bool = True, + console: Optional[Console] = None, + transient: bool = False, + get_time: Optional[Callable[[], float]] = None, + refresh_per_second: float = 10, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + disable: bool = False, +) -> ContextManager[TextIO]: + pass + + +@typing.overload +def open( + file: Union[str, "PathLike[str]", bytes], + mode: Literal["rb"], + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + description: str = "Reading...", + auto_refresh: bool = True, + console: Optional[Console] = None, + transient: bool = False, + get_time: Optional[Callable[[], float]] = None, + refresh_per_second: float = 10, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + disable: bool = False, +) -> ContextManager[BinaryIO]: + pass + + +def open( + file: Union[str, "PathLike[str]", bytes], + mode: Union[Literal["rb"], Literal["rt"], Literal["r"]] = "r", + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + description: str = "Reading...", + auto_refresh: bool = True, + console: Optional[Console] = None, + transient: bool = False, + get_time: Optional[Callable[[], float]] = None, + refresh_per_second: float = 10, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + disable: bool = False, +) -> Union[ContextManager[BinaryIO], ContextManager[TextIO]]: + """Read bytes from a file while tracking progress. + + Args: + path (Union[str, PathLike[str], BinaryIO]): The path to the file to read, or a file-like object in binary mode. + mode (str): The mode to use to open the file. Only supports "r", "rb" or "rt". + buffering (int): The buffering strategy to use, see :func:`io.open`. + encoding (str, optional): The encoding to use when reading in text mode, see :func:`io.open`. + errors (str, optional): The error handling strategy for decoding errors, see :func:`io.open`. + newline (str, optional): The strategy for handling newlines in text mode, see :func:`io.open` + total: (int, optional): Total number of bytes to read. Must be provided if reading from a file handle. Default for a path is os.stat(file).st_size. + description (str, optional): Description of task show next to progress bar. Defaults to "Reading". + auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True. + transient: (bool, optional): Clear the progress on exit. Defaults to False. + console (Console, optional): Console to write to. Default creates internal Console instance. + refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10. + style (StyleType, optional): Style for the bar background. Defaults to "bar.back". + complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete". + finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished". + pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse". + disable (bool, optional): Disable display of progress. + encoding (str, optional): The encoding to use when reading in text mode. + + Returns: + ContextManager[BinaryIO]: A context manager yielding a progress reader. + + """ + + columns: List["ProgressColumn"] = ( + [TextColumn("[progress.description]{task.description}")] if description else [] + ) + columns.extend( + ( + BarColumn( + style=style, + complete_style=complete_style, + finished_style=finished_style, + pulse_style=pulse_style, + ), + DownloadColumn(), + TimeRemainingColumn(), + ) + ) + progress = Progress( + *columns, + auto_refresh=auto_refresh, + console=console, + transient=transient, + get_time=get_time, + refresh_per_second=refresh_per_second or 10, + disable=disable, + ) + + reader = progress.open( + file, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline, + total=total, + description=description, + ) + return _ReadContext(progress, reader) # type: ignore[return-value, type-var] + + +class ProgressColumn(ABC): + """Base class for a widget to use in progress display.""" + + max_refresh: Optional[float] = None + + def __init__(self, table_column: Optional[Column] = None) -> None: + self._table_column = table_column + self._renderable_cache: Dict[TaskID, Tuple[float, RenderableType]] = {} + self._update_time: Optional[float] = None + + def get_table_column(self) -> Column: + """Get a table column, used to build tasks table.""" + return self._table_column or Column() + + def __call__(self, task: "Task") -> RenderableType: + """Called by the Progress object to return a renderable for the given task. + + Args: + task (Task): An object containing information regarding the task. + + Returns: + RenderableType: Anything renderable (including str). + """ + current_time = task.get_time() + if self.max_refresh is not None and not task.completed: + try: + timestamp, renderable = self._renderable_cache[task.id] + except KeyError: + pass + else: + if timestamp + self.max_refresh > current_time: + return renderable + + renderable = self.render(task) + self._renderable_cache[task.id] = (current_time, renderable) + return renderable + + @abstractmethod + def render(self, task: "Task") -> RenderableType: + """Should return a renderable object.""" + + +class RenderableColumn(ProgressColumn): + """A column to insert an arbitrary column. + + Args: + renderable (RenderableType, optional): Any renderable. Defaults to empty string. + """ + + def __init__( + self, renderable: RenderableType = "", *, table_column: Optional[Column] = None + ): + self.renderable = renderable + super().__init__(table_column=table_column) + + def render(self, task: "Task") -> RenderableType: + return self.renderable + + +class SpinnerColumn(ProgressColumn): + """A column with a 'spinner' animation. + + Args: + spinner_name (str, optional): Name of spinner animation. Defaults to "dots". + style (StyleType, optional): Style of spinner. Defaults to "progress.spinner". + speed (float, optional): Speed factor of spinner. Defaults to 1.0. + finished_text (TextType, optional): Text used when task is finished. Defaults to " ". + """ + + def __init__( + self, + spinner_name: str = "dots", + style: Optional[StyleType] = "progress.spinner", + speed: float = 1.0, + finished_text: TextType = " ", + table_column: Optional[Column] = None, + ): + self.spinner = Spinner(spinner_name, style=style, speed=speed) + self.finished_text = ( + Text.from_markup(finished_text) + if isinstance(finished_text, str) + else finished_text + ) + super().__init__(table_column=table_column) + + def set_spinner( + self, + spinner_name: str, + spinner_style: Optional[StyleType] = "progress.spinner", + speed: float = 1.0, + ) -> None: + """Set a new spinner. + + Args: + spinner_name (str): Spinner name, see python -m rich.spinner. + spinner_style (Optional[StyleType], optional): Spinner style. Defaults to "progress.spinner". + speed (float, optional): Speed factor of spinner. Defaults to 1.0. + """ + self.spinner = Spinner(spinner_name, style=spinner_style, speed=speed) + + def render(self, task: "Task") -> RenderableType: + text = ( + self.finished_text + if task.finished + else self.spinner.render(task.get_time()) + ) + return text + + +class TextColumn(ProgressColumn): + """A column containing text.""" + + def __init__( + self, + text_format: str, + style: StyleType = "none", + justify: JustifyMethod = "left", + markup: bool = True, + highlighter: Optional[Highlighter] = None, + table_column: Optional[Column] = None, + ) -> None: + self.text_format = text_format + self.justify: JustifyMethod = justify + self.style = style + self.markup = markup + self.highlighter = highlighter + super().__init__(table_column=table_column or Column(no_wrap=True)) + + def render(self, task: "Task") -> Text: + _text = self.text_format.format(task=task) + if self.markup: + text = Text.from_markup(_text, style=self.style, justify=self.justify) + else: + text = Text(_text, style=self.style, justify=self.justify) + if self.highlighter: + self.highlighter.highlight(text) + return text + + +class BarColumn(ProgressColumn): + """Renders a visual progress bar. + + Args: + bar_width (Optional[int], optional): Width of bar or None for full width. Defaults to 40. + style (StyleType, optional): Style for the bar background. Defaults to "bar.back". + complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete". + finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished". + pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse". + """ + + def __init__( + self, + bar_width: Optional[int] = 40, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + table_column: Optional[Column] = None, + ) -> None: + self.bar_width = bar_width + self.style = style + self.complete_style = complete_style + self.finished_style = finished_style + self.pulse_style = pulse_style + super().__init__(table_column=table_column) + + def render(self, task: "Task") -> ProgressBar: + """Gets a progress bar widget for a task.""" + return ProgressBar( + total=max(0, task.total) if task.total is not None else None, + completed=max(0, task.completed), + width=None if self.bar_width is None else max(1, self.bar_width), + pulse=not task.started, + animation_time=task.get_time(), + style=self.style, + complete_style=self.complete_style, + finished_style=self.finished_style, + pulse_style=self.pulse_style, + ) + + +class TimeElapsedColumn(ProgressColumn): + """Renders time elapsed.""" + + def render(self, task: "Task") -> Text: + """Show time elapsed.""" + elapsed = task.finished_time if task.finished else task.elapsed + if elapsed is None: + return Text("-:--:--", style="progress.elapsed") + delta = timedelta(seconds=max(0, int(elapsed))) + return Text(str(delta), style="progress.elapsed") + + +class TaskProgressColumn(TextColumn): + """Show task progress as a percentage. + + Args: + text_format (str, optional): Format for percentage display. Defaults to "[progress.percentage]{task.percentage:>3.0f}%". + text_format_no_percentage (str, optional): Format if percentage is unknown. Defaults to "". + style (StyleType, optional): Style of output. Defaults to "none". + justify (JustifyMethod, optional): Text justification. Defaults to "left". + markup (bool, optional): Enable markup. Defaults to True. + highlighter (Optional[Highlighter], optional): Highlighter to apply to output. Defaults to None. + table_column (Optional[Column], optional): Table Column to use. Defaults to None. + show_speed (bool, optional): Show speed if total is unknown. Defaults to False. + """ + + def __init__( + self, + text_format: str = "[progress.percentage]{task.percentage:>3.0f}%", + text_format_no_percentage: str = "", + style: StyleType = "none", + justify: JustifyMethod = "left", + markup: bool = True, + highlighter: Optional[Highlighter] = None, + table_column: Optional[Column] = None, + show_speed: bool = False, + ) -> None: + self.text_format_no_percentage = text_format_no_percentage + self.show_speed = show_speed + super().__init__( + text_format=text_format, + style=style, + justify=justify, + markup=markup, + highlighter=highlighter, + table_column=table_column, + ) + + @classmethod + def render_speed(cls, speed: Optional[float]) -> Text: + """Render the speed in iterations per second. + + Args: + task (Task): A Task object. + + Returns: + Text: Text object containing the task speed. + """ + if speed is None: + return Text("", style="progress.percentage") + unit, suffix = filesize.pick_unit_and_suffix( + int(speed), + ["", "×10³", "×10⁶", "×10⁹", "×10¹²"], + 1000, + ) + data_speed = speed / unit + return Text(f"{data_speed:.1f}{suffix} it/s", style="progress.percentage") + + def render(self, task: "Task") -> Text: + if task.total is None and self.show_speed: + return self.render_speed(task.finished_speed or task.speed) + text_format = ( + self.text_format_no_percentage if task.total is None else self.text_format + ) + _text = text_format.format(task=task) + if self.markup: + text = Text.from_markup(_text, style=self.style, justify=self.justify) + else: + text = Text(_text, style=self.style, justify=self.justify) + if self.highlighter: + self.highlighter.highlight(text) + return text + + +class TimeRemainingColumn(ProgressColumn): + """Renders estimated time remaining. + + Args: + compact (bool, optional): Render MM:SS when time remaining is less than an hour. Defaults to False. + elapsed_when_finished (bool, optional): Render time elapsed when the task is finished. Defaults to False. + """ + + # Only refresh twice a second to prevent jitter + max_refresh = 0.5 + + def __init__( + self, + compact: bool = False, + elapsed_when_finished: bool = False, + table_column: Optional[Column] = None, + ): + self.compact = compact + self.elapsed_when_finished = elapsed_when_finished + super().__init__(table_column=table_column) + + def render(self, task: "Task") -> Text: + """Show time remaining.""" + if self.elapsed_when_finished and task.finished: + task_time = task.finished_time + style = "progress.elapsed" + else: + task_time = task.time_remaining + style = "progress.remaining" + + if task.total is None: + return Text("", style=style) + + if task_time is None: + return Text("--:--" if self.compact else "-:--:--", style=style) + + # Based on https://github.com/tqdm/tqdm/blob/master/tqdm/std.py + minutes, seconds = divmod(int(task_time), 60) + hours, minutes = divmod(minutes, 60) + + if self.compact and not hours: + formatted = f"{minutes:02d}:{seconds:02d}" + else: + formatted = f"{hours:d}:{minutes:02d}:{seconds:02d}" + + return Text(formatted, style=style) + + +class FileSizeColumn(ProgressColumn): + """Renders completed filesize.""" + + def render(self, task: "Task") -> Text: + """Show data completed.""" + data_size = filesize.decimal(int(task.completed)) + return Text(data_size, style="progress.filesize") + + +class TotalFileSizeColumn(ProgressColumn): + """Renders total filesize.""" + + def render(self, task: "Task") -> Text: + """Show data completed.""" + data_size = filesize.decimal(int(task.total)) if task.total is not None else "" + return Text(data_size, style="progress.filesize.total") + + +class MofNCompleteColumn(ProgressColumn): + """Renders completed count/total, e.g. ' 10/1000'. + + Best for bounded tasks with int quantities. + + Space pads the completed count so that progress length does not change as task progresses + past powers of 10. + + Args: + separator (str, optional): Text to separate completed and total values. Defaults to "/". + """ + + def __init__(self, separator: str = "/", table_column: Optional[Column] = None): + self.separator = separator + super().__init__(table_column=table_column) + + def render(self, task: "Task") -> Text: + """Show completed/total.""" + completed = int(task.completed) + total = int(task.total) if task.total is not None else "?" + total_width = len(str(total)) + return Text( + f"{completed:{total_width}d}{self.separator}{total}", + style="progress.download", + ) + + +class DownloadColumn(ProgressColumn): + """Renders file size downloaded and total, e.g. '0.5/2.3 GB'. + + Args: + binary_units (bool, optional): Use binary units, KiB, MiB etc. Defaults to False. + """ + + def __init__( + self, binary_units: bool = False, table_column: Optional[Column] = None + ) -> None: + self.binary_units = binary_units + super().__init__(table_column=table_column) + + def render(self, task: "Task") -> Text: + """Calculate common unit for completed and total.""" + completed = int(task.completed) + + unit_and_suffix_calculation_base = ( + int(task.total) if task.total is not None else completed + ) + if self.binary_units: + unit, suffix = filesize.pick_unit_and_suffix( + unit_and_suffix_calculation_base, + ["bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], + 1024, + ) + else: + unit, suffix = filesize.pick_unit_and_suffix( + unit_and_suffix_calculation_base, + ["bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], + 1000, + ) + precision = 0 if unit == 1 else 1 + + completed_ratio = completed / unit + completed_str = f"{completed_ratio:,.{precision}f}" + + if task.total is not None: + total = int(task.total) + total_ratio = total / unit + total_str = f"{total_ratio:,.{precision}f}" + else: + total_str = "?" + + download_status = f"{completed_str}/{total_str} {suffix}" + download_text = Text(download_status, style="progress.download") + return download_text + + +class TransferSpeedColumn(ProgressColumn): + """Renders human readable transfer speed.""" + + def render(self, task: "Task") -> Text: + """Show data transfer speed.""" + speed = task.finished_speed or task.speed + if speed is None: + return Text("?", style="progress.data.speed") + data_speed = filesize.decimal(int(speed)) + return Text(f"{data_speed}/s", style="progress.data.speed") + + +class ProgressSample(NamedTuple): + """Sample of progress for a given time.""" + + timestamp: float + """Timestamp of sample.""" + completed: float + """Number of steps completed.""" + + +@dataclass +class Task: + """Information regarding a progress task. + + This object should be considered read-only outside of the :class:`~Progress` class. + + """ + + id: TaskID + """Task ID associated with this task (used in Progress methods).""" + + description: str + """str: Description of the task.""" + + total: Optional[float] + """Optional[float]: Total number of steps in this task.""" + + completed: float + """float: Number of steps completed""" + + _get_time: GetTimeCallable + """Callable to get the current time.""" + + finished_time: Optional[float] = None + """float: Time task was finished.""" + + visible: bool = True + """bool: Indicates if this task is visible in the progress display.""" + + fields: Dict[str, Any] = field(default_factory=dict) + """dict: Arbitrary fields passed in via Progress.update.""" + + start_time: Optional[float] = field(default=None, init=False, repr=False) + """Optional[float]: Time this task was started, or None if not started.""" + + stop_time: Optional[float] = field(default=None, init=False, repr=False) + """Optional[float]: Time this task was stopped, or None if not stopped.""" + + finished_speed: Optional[float] = None + """Optional[float]: The last speed for a finished task.""" + + _progress: Deque[ProgressSample] = field( + default_factory=lambda: deque(maxlen=1000), init=False, repr=False + ) + + _lock: RLock = field(repr=False, default_factory=RLock) + """Thread lock.""" + + def get_time(self) -> float: + """float: Get the current time, in seconds.""" + return self._get_time() + + @property + def started(self) -> bool: + """bool: Check if the task as started.""" + return self.start_time is not None + + @property + def remaining(self) -> Optional[float]: + """Optional[float]: Get the number of steps remaining, if a non-None total was set.""" + if self.total is None: + return None + return self.total - self.completed + + @property + def elapsed(self) -> Optional[float]: + """Optional[float]: Time elapsed since task was started, or ``None`` if the task hasn't started.""" + if self.start_time is None: + return None + if self.stop_time is not None: + return self.stop_time - self.start_time + return self.get_time() - self.start_time + + @property + def finished(self) -> bool: + """Check if the task has finished.""" + return self.finished_time is not None + + @property + def percentage(self) -> float: + """float: Get progress of task as a percentage. If a None total was set, returns 0""" + if not self.total: + return 0.0 + completed = (self.completed / self.total) * 100.0 + completed = min(100.0, max(0.0, completed)) + return completed + + @property + def speed(self) -> Optional[float]: + """Optional[float]: Get the estimated speed in steps per second.""" + if self.start_time is None: + return None + with self._lock: + progress = self._progress + if not progress: + return None + total_time = progress[-1].timestamp - progress[0].timestamp + if total_time == 0: + return None + iter_progress = iter(progress) + next(iter_progress) + total_completed = sum(sample.completed for sample in iter_progress) + speed = total_completed / total_time + return speed + + @property + def time_remaining(self) -> Optional[float]: + """Optional[float]: Get estimated time to completion, or ``None`` if no data.""" + if self.finished: + return 0.0 + speed = self.speed + if not speed: + return None + remaining = self.remaining + if remaining is None: + return None + estimate = ceil(remaining / speed) + return estimate + + def _reset(self) -> None: + """Reset progress.""" + self._progress.clear() + self.finished_time = None + self.finished_speed = None + + +class Progress(JupyterMixin): + """Renders an auto-updating progress bar(s). + + Args: + console (Console, optional): Optional Console instance. Defaults to an internal Console instance writing to stdout. + auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()`. + refresh_per_second (Optional[float], optional): Number of times per second to refresh the progress information or None to use default (10). Defaults to None. + speed_estimate_period: (float, optional): Period (in seconds) used to calculate the speed estimate. Defaults to 30. + transient: (bool, optional): Clear the progress on exit. Defaults to False. + redirect_stdout: (bool, optional): Enable redirection of stdout, so ``print`` may be used. Defaults to True. + redirect_stderr: (bool, optional): Enable redirection of stderr. Defaults to True. + get_time: (Callable, optional): A callable that gets the current time, or None to use Console.get_time. Defaults to None. + disable (bool, optional): Disable progress display. Defaults to False + expand (bool, optional): Expand tasks table to fit width. Defaults to False. + """ + + def __init__( + self, + *columns: Union[str, ProgressColumn], + console: Optional[Console] = None, + auto_refresh: bool = True, + refresh_per_second: float = 10, + speed_estimate_period: float = 30.0, + transient: bool = False, + redirect_stdout: bool = True, + redirect_stderr: bool = True, + get_time: Optional[GetTimeCallable] = None, + disable: bool = False, + expand: bool = False, + ) -> None: + assert refresh_per_second > 0, "refresh_per_second must be > 0" + self._lock = RLock() + self.columns = columns or self.get_default_columns() + self.speed_estimate_period = speed_estimate_period + + self.disable = disable + self.expand = expand + self._tasks: Dict[TaskID, Task] = {} + self._task_index: TaskID = TaskID(0) + self.live = Live( + console=console or get_console(), + auto_refresh=auto_refresh, + refresh_per_second=refresh_per_second, + transient=transient, + redirect_stdout=redirect_stdout, + redirect_stderr=redirect_stderr, + get_renderable=self.get_renderable, + ) + self.get_time = get_time or self.console.get_time + self.print = self.console.print + self.log = self.console.log + + @classmethod + def get_default_columns(cls) -> Tuple[ProgressColumn, ...]: + """Get the default columns used for a new Progress instance: + - a text column for the description (TextColumn) + - the bar itself (BarColumn) + - a text column showing completion percentage (TextColumn) + - an estimated-time-remaining column (TimeRemainingColumn) + If the Progress instance is created without passing a columns argument, + the default columns defined here will be used. + + You can also create a Progress instance using custom columns before + and/or after the defaults, as in this example: + + progress = Progress( + SpinnerColumn(), + *Progress.get_default_columns(), + "Elapsed:", + TimeElapsedColumn(), + ) + + This code shows the creation of a Progress display, containing + a spinner to the left, the default columns, and a labeled elapsed + time column. + """ + return ( + TextColumn("[progress.description]{task.description}"), + BarColumn(), + TaskProgressColumn(), + TimeRemainingColumn(), + ) + + @property + def console(self) -> Console: + return self.live.console + + @property + def tasks(self) -> List[Task]: + """Get a list of Task instances.""" + with self._lock: + return list(self._tasks.values()) + + @property + def task_ids(self) -> List[TaskID]: + """A list of task IDs.""" + with self._lock: + return list(self._tasks.keys()) + + @property + def finished(self) -> bool: + """Check if all tasks have been completed.""" + with self._lock: + if not self._tasks: + return True + return all(task.finished for task in self._tasks.values()) + + def start(self) -> None: + """Start the progress display.""" + if not self.disable: + self.live.start(refresh=True) + + def stop(self) -> None: + """Stop the progress display.""" + self.live.stop() + if not self.console.is_interactive and not self.console.is_jupyter: + self.console.print() + + def __enter__(self) -> Self: + self.start() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.stop() + + def track( + self, + sequence: Union[Iterable[ProgressType], Sequence[ProgressType]], + total: Optional[float] = None, + completed: int = 0, + task_id: Optional[TaskID] = None, + description: str = "Working...", + update_period: float = 0.1, + ) -> Iterable[ProgressType]: + """Track progress by iterating over a sequence. + + Args: + sequence (Sequence[ProgressType]): A sequence of values you want to iterate over and track progress. + total: (float, optional): Total number of steps. Default is len(sequence). + completed (int, optional): Number of steps completed so far. Defaults to 0. + task_id: (TaskID): Task to track. Default is new task. + description: (str, optional): Description of task, if new task is created. + update_period (float, optional): Minimum time (in seconds) between calls to update(). Defaults to 0.1. + + Returns: + Iterable[ProgressType]: An iterable of values taken from the provided sequence. + """ + if total is None: + total = float(length_hint(sequence)) or None + + if task_id is None: + task_id = self.add_task(description, total=total, completed=completed) + else: + self.update(task_id, total=total, completed=completed) + + if self.live.auto_refresh: + with _TrackThread(self, task_id, update_period) as track_thread: + for value in sequence: + yield value + track_thread.completed += 1 + else: + advance = self.advance + refresh = self.refresh + for value in sequence: + yield value + advance(task_id, 1) + refresh() + + def wrap_file( + self, + file: BinaryIO, + total: Optional[int] = None, + *, + task_id: Optional[TaskID] = None, + description: str = "Reading...", + ) -> BinaryIO: + """Track progress file reading from a binary file. + + Args: + file (BinaryIO): A file-like object opened in binary mode. + total (int, optional): Total number of bytes to read. This must be provided unless a task with a total is also given. + task_id (TaskID): Task to track. Default is new task. + description (str, optional): Description of task, if new task is created. + + Returns: + BinaryIO: A readable file-like object in binary mode. + + Raises: + ValueError: When no total value can be extracted from the arguments or the task. + """ + # attempt to recover the total from the task + total_bytes: Optional[float] = None + if total is not None: + total_bytes = total + elif task_id is not None: + with self._lock: + total_bytes = self._tasks[task_id].total + if total_bytes is None: + raise ValueError( + f"unable to get the total number of bytes, please specify 'total'" + ) + + # update total of task or create new task + if task_id is None: + task_id = self.add_task(description, total=total_bytes) + else: + self.update(task_id, total=total_bytes) + + return _Reader(file, self, task_id, close_handle=False) + + @typing.overload + def open( + self, + file: Union[str, "PathLike[str]", bytes], + mode: Literal["rb"], + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + task_id: Optional[TaskID] = None, + description: str = "Reading...", + ) -> BinaryIO: + pass + + @typing.overload + def open( + self, + file: Union[str, "PathLike[str]", bytes], + mode: Union[Literal["r"], Literal["rt"]], + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + task_id: Optional[TaskID] = None, + description: str = "Reading...", + ) -> TextIO: + pass + + def open( + self, + file: Union[str, "PathLike[str]", bytes], + mode: Union[Literal["rb"], Literal["rt"], Literal["r"]] = "r", + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + *, + total: Optional[int] = None, + task_id: Optional[TaskID] = None, + description: str = "Reading...", + ) -> Union[BinaryIO, TextIO]: + """Track progress while reading from a binary file. + + Args: + path (Union[str, PathLike[str]]): The path to the file to read. + mode (str): The mode to use to open the file. Only supports "r", "rb" or "rt". + buffering (int): The buffering strategy to use, see :func:`io.open`. + encoding (str, optional): The encoding to use when reading in text mode, see :func:`io.open`. + errors (str, optional): The error handling strategy for decoding errors, see :func:`io.open`. + newline (str, optional): The strategy for handling newlines in text mode, see :func:`io.open`. + total (int, optional): Total number of bytes to read. If none given, os.stat(path).st_size is used. + task_id (TaskID): Task to track. Default is new task. + description (str, optional): Description of task, if new task is created. + + Returns: + BinaryIO: A readable file-like object in binary mode. + + Raises: + ValueError: When an invalid mode is given. + """ + # normalize the mode (always rb, rt) + _mode = "".join(sorted(mode, reverse=False)) + if _mode not in ("br", "rt", "r"): + raise ValueError(f"invalid mode {mode!r}") + + # patch buffering to provide the same behaviour as the builtin `open` + line_buffering = buffering == 1 + if _mode == "br" and buffering == 1: + warnings.warn( + "line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used", + RuntimeWarning, + ) + buffering = -1 + elif _mode in ("rt", "r"): + if buffering == 0: + raise ValueError("can't have unbuffered text I/O") + elif buffering == 1: + buffering = -1 + + # attempt to get the total with `os.stat` + if total is None: + total = stat(file).st_size + + # update total of task or create new task + if task_id is None: + task_id = self.add_task(description, total=total) + else: + self.update(task_id, total=total) + + # open the file in binary mode, + handle = io.open(file, "rb", buffering=buffering) + reader = _Reader(handle, self, task_id, close_handle=True) + + # wrap the reader in a `TextIOWrapper` if text mode + if mode in ("r", "rt"): + return io.TextIOWrapper( + reader, + encoding=encoding, + errors=errors, + newline=newline, + line_buffering=line_buffering, + ) + + return reader + + def start_task(self, task_id: TaskID) -> None: + """Start a task. + + Starts a task (used when calculating elapsed time). You may need to call this manually, + if you called ``add_task`` with ``start=False``. + + Args: + task_id (TaskID): ID of task. + """ + with self._lock: + task = self._tasks[task_id] + if task.start_time is None: + task.start_time = self.get_time() + + def stop_task(self, task_id: TaskID) -> None: + """Stop a task. + + This will freeze the elapsed time on the task. + + Args: + task_id (TaskID): ID of task. + """ + with self._lock: + task = self._tasks[task_id] + current_time = self.get_time() + if task.start_time is None: + task.start_time = current_time + task.stop_time = current_time + + def update( + self, + task_id: TaskID, + *, + total: Optional[float] = None, + completed: Optional[float] = None, + advance: Optional[float] = None, + description: Optional[str] = None, + visible: Optional[bool] = None, + refresh: bool = False, + **fields: Any, + ) -> None: + """Update information associated with a task. + + Args: + task_id (TaskID): Task id (returned by add_task). + total (float, optional): Updates task.total if not None. + completed (float, optional): Updates task.completed if not None. + advance (float, optional): Add a value to task.completed if not None. + description (str, optional): Change task description if not None. + visible (bool, optional): Set visible flag if not None. + refresh (bool): Force a refresh of progress information. Default is False. + **fields (Any): Additional data fields required for rendering. + """ + with self._lock: + task = self._tasks[task_id] + completed_start = task.completed + + if total is not None and total != task.total: + task.total = total + task._reset() + if advance is not None: + task.completed += advance + if completed is not None: + task.completed = completed + if description is not None: + task.description = description + if visible is not None: + task.visible = visible + task.fields.update(fields) + update_completed = task.completed - completed_start + + current_time = self.get_time() + old_sample_time = current_time - self.speed_estimate_period + _progress = task._progress + + popleft = _progress.popleft + while _progress and _progress[0].timestamp < old_sample_time: + popleft() + if update_completed > 0: + _progress.append(ProgressSample(current_time, update_completed)) + if ( + task.total is not None + and task.completed >= task.total + and task.finished_time is None + ): + task.finished_time = task.elapsed + + if refresh: + self.refresh() + + def reset( + self, + task_id: TaskID, + *, + start: bool = True, + total: Optional[float] = None, + completed: int = 0, + visible: Optional[bool] = None, + description: Optional[str] = None, + **fields: Any, + ) -> None: + """Reset a task so completed is 0 and the clock is reset. + + Args: + task_id (TaskID): ID of task. + start (bool, optional): Start the task after reset. Defaults to True. + total (float, optional): New total steps in task, or None to use current total. Defaults to None. + completed (int, optional): Number of steps completed. Defaults to 0. + visible (bool, optional): Enable display of the task. Defaults to True. + description (str, optional): Change task description if not None. Defaults to None. + **fields (str): Additional data fields required for rendering. + """ + current_time = self.get_time() + with self._lock: + task = self._tasks[task_id] + task._reset() + task.start_time = current_time if start else None + if total is not None: + task.total = total + task.completed = completed + if visible is not None: + task.visible = visible + if fields: + task.fields = fields + if description is not None: + task.description = description + task.finished_time = None + self.refresh() + + def advance(self, task_id: TaskID, advance: float = 1) -> None: + """Advance task by a number of steps. + + Args: + task_id (TaskID): ID of task. + advance (float): Number of steps to advance. Default is 1. + """ + current_time = self.get_time() + with self._lock: + task = self._tasks[task_id] + completed_start = task.completed + task.completed += advance + update_completed = task.completed - completed_start + old_sample_time = current_time - self.speed_estimate_period + _progress = task._progress + + popleft = _progress.popleft + while _progress and _progress[0].timestamp < old_sample_time: + popleft() + while len(_progress) > 1000: + popleft() + _progress.append(ProgressSample(current_time, update_completed)) + if ( + task.total is not None + and task.completed >= task.total + and task.finished_time is None + ): + task.finished_time = task.elapsed + task.finished_speed = task.speed + + def refresh(self) -> None: + """Refresh (render) the progress information.""" + if not self.disable and self.live.is_started: + self.live.refresh() + + def get_renderable(self) -> RenderableType: + """Get a renderable for the progress display.""" + renderable = Group(*self.get_renderables()) + return renderable + + def get_renderables(self) -> Iterable[RenderableType]: + """Get a number of renderables for the progress display.""" + table = self.make_tasks_table(self.tasks) + yield table + + def make_tasks_table(self, tasks: Iterable[Task]) -> Table: + """Get a table to render the Progress display. + + Args: + tasks (Iterable[Task]): An iterable of Task instances, one per row of the table. + + Returns: + Table: A table instance. + """ + table_columns = ( + ( + Column(no_wrap=True) + if isinstance(_column, str) + else _column.get_table_column().copy() + ) + for _column in self.columns + ) + table = Table.grid(*table_columns, padding=(0, 1), expand=self.expand) + + for task in tasks: + if task.visible: + table.add_row( + *( + ( + column.format(task=task) + if isinstance(column, str) + else column(task) + ) + for column in self.columns + ) + ) + return table + + def __rich__(self) -> RenderableType: + """Makes the Progress class itself renderable.""" + with self._lock: + return self.get_renderable() + + def add_task( + self, + description: str, + start: bool = True, + total: Optional[float] = 100.0, + completed: int = 0, + visible: bool = True, + **fields: Any, + ) -> TaskID: + """Add a new 'task' to the Progress display. + + Args: + description (str): A description of the task. + start (bool, optional): Start the task immediately (to calculate elapsed time). If set to False, + you will need to call `start` manually. Defaults to True. + total (float, optional): Number of total steps in the progress if known. + Set to None to render a pulsing animation. Defaults to 100. + completed (int, optional): Number of steps completed so far. Defaults to 0. + visible (bool, optional): Enable display of the task. Defaults to True. + **fields (str): Additional data fields required for rendering. + + Returns: + TaskID: An ID you can use when calling `update`. + """ + with self._lock: + task = Task( + self._task_index, + description, + total, + completed, + visible=visible, + fields=fields, + _get_time=self.get_time, + _lock=self._lock, + ) + self._tasks[self._task_index] = task + if start: + self.start_task(self._task_index) + new_task_index = self._task_index + self._task_index = TaskID(int(self._task_index) + 1) + self.refresh() + return new_task_index + + def remove_task(self, task_id: TaskID) -> None: + """Delete a task if it exists. + + Args: + task_id (TaskID): A task ID. + + """ + with self._lock: + del self._tasks[task_id] + + +if __name__ == "__main__": # pragma: no coverage + import random + import time + + from .panel import Panel + from .rule import Rule + from .syntax import Syntax + from .table import Table + + syntax = Syntax( + '''def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value''', + "python", + line_numbers=True, + ) + + table = Table("foo", "bar", "baz") + table.add_row("1", "2", "3") + + progress_renderables = [ + "Text may be printed while the progress bars are rendering.", + Panel("In fact, [i]any[/i] renderable will work"), + "Such as [magenta]tables[/]...", + table, + "Pretty printed structures...", + {"type": "example", "text": "Pretty printed"}, + "Syntax...", + syntax, + Rule("Give it a try!"), + ] + + from itertools import cycle + + examples = cycle(progress_renderables) + + console = Console(record=True) + + with Progress( + SpinnerColumn(), + *Progress.get_default_columns(), + TimeElapsedColumn(), + console=console, + transient=False, + ) as progress: + task1 = progress.add_task("[red]Downloading", total=1000) + task2 = progress.add_task("[green]Processing", total=1000) + task3 = progress.add_task("[yellow]Thinking", total=None) + + while not progress.finished: + progress.update(task1, advance=0.5) + progress.update(task2, advance=0.3) + time.sleep(0.01) + if random.randint(0, 100) < 1: + progress.log(next(examples)) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py new file mode 100644 index 0000000..41794f7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py @@ -0,0 +1,223 @@ +import math +from functools import lru_cache +from time import monotonic +from typing import Iterable, List, Optional + +from .color import Color, blend_rgb +from .color_triplet import ColorTriplet +from .console import Console, ConsoleOptions, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style, StyleType + +# Number of characters before 'pulse' animation repeats +PULSE_SIZE = 20 + + +class ProgressBar(JupyterMixin): + """Renders a (progress) bar. Used by rich.progress. + + Args: + total (float, optional): Number of steps in the bar. Defaults to 100. Set to None to render a pulsing animation. + completed (float, optional): Number of steps completed. Defaults to 0. + width (int, optional): Width of the bar, or ``None`` for maximum width. Defaults to None. + pulse (bool, optional): Enable pulse effect. Defaults to False. Will pulse if a None total was passed. + style (StyleType, optional): Style for the bar background. Defaults to "bar.back". + complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete". + finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished". + pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse". + animation_time (Optional[float], optional): Time in seconds to use for animation, or None to use system time. + """ + + def __init__( + self, + total: Optional[float] = 100.0, + completed: float = 0, + width: Optional[int] = None, + pulse: bool = False, + style: StyleType = "bar.back", + complete_style: StyleType = "bar.complete", + finished_style: StyleType = "bar.finished", + pulse_style: StyleType = "bar.pulse", + animation_time: Optional[float] = None, + ): + self.total = total + self.completed = completed + self.width = width + self.pulse = pulse + self.style = style + self.complete_style = complete_style + self.finished_style = finished_style + self.pulse_style = pulse_style + self.animation_time = animation_time + + self._pulse_segments: Optional[List[Segment]] = None + + def __repr__(self) -> str: + return f"" + + @property + def percentage_completed(self) -> Optional[float]: + """Calculate percentage complete.""" + if self.total is None: + return None + completed = (self.completed / self.total) * 100.0 + completed = min(100, max(0.0, completed)) + return completed + + @lru_cache(maxsize=16) + def _get_pulse_segments( + self, + fore_style: Style, + back_style: Style, + color_system: str, + no_color: bool, + ascii: bool = False, + ) -> List[Segment]: + """Get a list of segments to render a pulse animation. + + Returns: + List[Segment]: A list of segments, one segment per character. + """ + bar = "-" if ascii else "━" + segments: List[Segment] = [] + if color_system not in ("standard", "eight_bit", "truecolor") or no_color: + segments += [Segment(bar, fore_style)] * (PULSE_SIZE // 2) + segments += [Segment(" " if no_color else bar, back_style)] * ( + PULSE_SIZE - (PULSE_SIZE // 2) + ) + return segments + + append = segments.append + fore_color = ( + fore_style.color.get_truecolor() + if fore_style.color + else ColorTriplet(255, 0, 255) + ) + back_color = ( + back_style.color.get_truecolor() + if back_style.color + else ColorTriplet(0, 0, 0) + ) + cos = math.cos + pi = math.pi + _Segment = Segment + _Style = Style + from_triplet = Color.from_triplet + + for index in range(PULSE_SIZE): + position = index / PULSE_SIZE + fade = 0.5 + cos(position * pi * 2) / 2.0 + color = blend_rgb(fore_color, back_color, cross_fade=fade) + append(_Segment(bar, _Style(color=from_triplet(color)))) + return segments + + def update(self, completed: float, total: Optional[float] = None) -> None: + """Update progress with new values. + + Args: + completed (float): Number of steps completed. + total (float, optional): Total number of steps, or ``None`` to not change. Defaults to None. + """ + self.completed = completed + self.total = total if total is not None else self.total + + def _render_pulse( + self, console: Console, width: int, ascii: bool = False + ) -> Iterable[Segment]: + """Renders the pulse animation. + + Args: + console (Console): Console instance. + width (int): Width in characters of pulse animation. + + Returns: + RenderResult: [description] + + Yields: + Iterator[Segment]: Segments to render pulse + """ + fore_style = console.get_style(self.pulse_style, default="white") + back_style = console.get_style(self.style, default="black") + + pulse_segments = self._get_pulse_segments( + fore_style, back_style, console.color_system, console.no_color, ascii=ascii + ) + segment_count = len(pulse_segments) + current_time = ( + monotonic() if self.animation_time is None else self.animation_time + ) + segments = pulse_segments * (int(width / segment_count) + 2) + offset = int(-current_time * 15) % segment_count + segments = segments[offset : offset + width] + yield from segments + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = min(self.width or options.max_width, options.max_width) + ascii = options.legacy_windows or options.ascii_only + should_pulse = self.pulse or self.total is None + if should_pulse: + yield from self._render_pulse(console, width, ascii=ascii) + return + + completed: Optional[float] = ( + min(self.total, max(0, self.completed)) if self.total is not None else None + ) + + bar = "-" if ascii else "━" + half_bar_right = " " if ascii else "╸" + half_bar_left = " " if ascii else "╺" + complete_halves = ( + int(width * 2 * completed / self.total) + if self.total and completed is not None + else width * 2 + ) + bar_count = complete_halves // 2 + half_bar_count = complete_halves % 2 + style = console.get_style(self.style) + is_finished = self.total is None or self.completed >= self.total + complete_style = console.get_style( + self.finished_style if is_finished else self.complete_style + ) + _Segment = Segment + if bar_count: + yield _Segment(bar * bar_count, complete_style) + if half_bar_count: + yield _Segment(half_bar_right * half_bar_count, complete_style) + + if not console.no_color: + remaining_bars = width - bar_count - half_bar_count + if remaining_bars and console.color_system is not None: + if not half_bar_count and bar_count: + yield _Segment(half_bar_left, style) + remaining_bars -= 1 + if remaining_bars: + yield _Segment(bar * remaining_bars, style) + + def __rich_measure__( + self, console: Console, options: ConsoleOptions + ) -> Measurement: + return ( + Measurement(self.width, self.width) + if self.width is not None + else Measurement(4, options.max_width) + ) + + +if __name__ == "__main__": # pragma: no cover + console = Console() + bar = ProgressBar(width=50, total=100) + + import time + + console.show_cursor(False) + for n in range(0, 101, 1): + bar.update(n) + console.print(bar) + console.file.write("\r") + time.sleep(0.05) + console.show_cursor(True) + console.print() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/prompt.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/prompt.py new file mode 100644 index 0000000..fccb70d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/prompt.py @@ -0,0 +1,400 @@ +from typing import Any, Generic, List, Optional, TextIO, TypeVar, Union, overload + +from . import get_console +from .console import Console +from .text import Text, TextType + +PromptType = TypeVar("PromptType") +DefaultType = TypeVar("DefaultType") + + +class PromptError(Exception): + """Exception base class for prompt related errors.""" + + +class InvalidResponse(PromptError): + """Exception to indicate a response was invalid. Raise this within process_response() to indicate an error + and provide an error message. + + Args: + message (Union[str, Text]): Error message. + """ + + def __init__(self, message: TextType) -> None: + self.message = message + + def __rich__(self) -> TextType: + return self.message + + +class PromptBase(Generic[PromptType]): + """Ask the user for input until a valid response is received. This is the base class, see one of + the concrete classes for examples. + + Args: + prompt (TextType, optional): Prompt text. Defaults to "". + console (Console, optional): A Console instance or None to use global console. Defaults to None. + password (bool, optional): Enable password input. Defaults to False. + choices (List[str], optional): A list of valid choices. Defaults to None. + case_sensitive (bool, optional): Matching of choices should be case-sensitive. Defaults to True. + show_default (bool, optional): Show default in prompt. Defaults to True. + show_choices (bool, optional): Show choices in prompt. Defaults to True. + """ + + response_type: type = str + + validate_error_message = "[prompt.invalid]Please enter a valid value" + illegal_choice_message = ( + "[prompt.invalid.choice]Please select one of the available options" + ) + prompt_suffix = ": " + + choices: Optional[List[str]] = None + + def __init__( + self, + prompt: TextType = "", + *, + console: Optional[Console] = None, + password: bool = False, + choices: Optional[List[str]] = None, + case_sensitive: bool = True, + show_default: bool = True, + show_choices: bool = True, + ) -> None: + self.console = console or get_console() + self.prompt = ( + Text.from_markup(prompt, style="prompt") + if isinstance(prompt, str) + else prompt + ) + self.password = password + if choices is not None: + self.choices = choices + self.case_sensitive = case_sensitive + self.show_default = show_default + self.show_choices = show_choices + + @classmethod + @overload + def ask( + cls, + prompt: TextType = "", + *, + console: Optional[Console] = None, + password: bool = False, + choices: Optional[List[str]] = None, + case_sensitive: bool = True, + show_default: bool = True, + show_choices: bool = True, + default: DefaultType, + stream: Optional[TextIO] = None, + ) -> Union[DefaultType, PromptType]: + ... + + @classmethod + @overload + def ask( + cls, + prompt: TextType = "", + *, + console: Optional[Console] = None, + password: bool = False, + choices: Optional[List[str]] = None, + case_sensitive: bool = True, + show_default: bool = True, + show_choices: bool = True, + stream: Optional[TextIO] = None, + ) -> PromptType: + ... + + @classmethod + def ask( + cls, + prompt: TextType = "", + *, + console: Optional[Console] = None, + password: bool = False, + choices: Optional[List[str]] = None, + case_sensitive: bool = True, + show_default: bool = True, + show_choices: bool = True, + default: Any = ..., + stream: Optional[TextIO] = None, + ) -> Any: + """Shortcut to construct and run a prompt loop and return the result. + + Example: + >>> filename = Prompt.ask("Enter a filename") + + Args: + prompt (TextType, optional): Prompt text. Defaults to "". + console (Console, optional): A Console instance or None to use global console. Defaults to None. + password (bool, optional): Enable password input. Defaults to False. + choices (List[str], optional): A list of valid choices. Defaults to None. + case_sensitive (bool, optional): Matching of choices should be case-sensitive. Defaults to True. + show_default (bool, optional): Show default in prompt. Defaults to True. + show_choices (bool, optional): Show choices in prompt. Defaults to True. + stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None. + """ + _prompt = cls( + prompt, + console=console, + password=password, + choices=choices, + case_sensitive=case_sensitive, + show_default=show_default, + show_choices=show_choices, + ) + return _prompt(default=default, stream=stream) + + def render_default(self, default: DefaultType) -> Text: + """Turn the supplied default in to a Text instance. + + Args: + default (DefaultType): Default value. + + Returns: + Text: Text containing rendering of default value. + """ + return Text(f"({default})", "prompt.default") + + def make_prompt(self, default: DefaultType) -> Text: + """Make prompt text. + + Args: + default (DefaultType): Default value. + + Returns: + Text: Text to display in prompt. + """ + prompt = self.prompt.copy() + prompt.end = "" + + if self.show_choices and self.choices: + _choices = "/".join(self.choices) + choices = f"[{_choices}]" + prompt.append(" ") + prompt.append(choices, "prompt.choices") + + if ( + default != ... + and self.show_default + and isinstance(default, (str, self.response_type)) + ): + prompt.append(" ") + _default = self.render_default(default) + prompt.append(_default) + + prompt.append(self.prompt_suffix) + + return prompt + + @classmethod + def get_input( + cls, + console: Console, + prompt: TextType, + password: bool, + stream: Optional[TextIO] = None, + ) -> str: + """Get input from user. + + Args: + console (Console): Console instance. + prompt (TextType): Prompt text. + password (bool): Enable password entry. + + Returns: + str: String from user. + """ + return console.input(prompt, password=password, stream=stream) + + def check_choice(self, value: str) -> bool: + """Check value is in the list of valid choices. + + Args: + value (str): Value entered by user. + + Returns: + bool: True if choice was valid, otherwise False. + """ + assert self.choices is not None + if self.case_sensitive: + return value.strip() in self.choices + return value.strip().lower() in [choice.lower() for choice in self.choices] + + def process_response(self, value: str) -> PromptType: + """Process response from user, convert to prompt type. + + Args: + value (str): String typed by user. + + Raises: + InvalidResponse: If ``value`` is invalid. + + Returns: + PromptType: The value to be returned from ask method. + """ + value = value.strip() + try: + return_value: PromptType = self.response_type(value) + except ValueError: + raise InvalidResponse(self.validate_error_message) + + if self.choices is not None: + if not self.check_choice(value): + raise InvalidResponse(self.illegal_choice_message) + + if not self.case_sensitive: + # return the original choice, not the lower case version + return_value = self.response_type( + self.choices[ + [choice.lower() for choice in self.choices].index(value.lower()) + ] + ) + return return_value + + def on_validate_error(self, value: str, error: InvalidResponse) -> None: + """Called to handle validation error. + + Args: + value (str): String entered by user. + error (InvalidResponse): Exception instance the initiated the error. + """ + self.console.print(error) + + def pre_prompt(self) -> None: + """Hook to display something before the prompt.""" + + @overload + def __call__(self, *, stream: Optional[TextIO] = None) -> PromptType: + ... + + @overload + def __call__( + self, *, default: DefaultType, stream: Optional[TextIO] = None + ) -> Union[PromptType, DefaultType]: + ... + + def __call__(self, *, default: Any = ..., stream: Optional[TextIO] = None) -> Any: + """Run the prompt loop. + + Args: + default (Any, optional): Optional default value. + + Returns: + PromptType: Processed value. + """ + while True: + self.pre_prompt() + prompt = self.make_prompt(default) + value = self.get_input(self.console, prompt, self.password, stream=stream) + if value == "" and default != ...: + return default + try: + return_value = self.process_response(value) + except InvalidResponse as error: + self.on_validate_error(value, error) + continue + else: + return return_value + + +class Prompt(PromptBase[str]): + """A prompt that returns a str. + + Example: + >>> name = Prompt.ask("Enter your name") + + + """ + + response_type = str + + +class IntPrompt(PromptBase[int]): + """A prompt that returns an integer. + + Example: + >>> burrito_count = IntPrompt.ask("How many burritos do you want to order") + + """ + + response_type = int + validate_error_message = "[prompt.invalid]Please enter a valid integer number" + + +class FloatPrompt(PromptBase[float]): + """A prompt that returns a float. + + Example: + >>> temperature = FloatPrompt.ask("Enter desired temperature") + + """ + + response_type = float + validate_error_message = "[prompt.invalid]Please enter a number" + + +class Confirm(PromptBase[bool]): + """A yes / no confirmation prompt. + + Example: + >>> if Confirm.ask("Continue"): + run_job() + + """ + + response_type = bool + validate_error_message = "[prompt.invalid]Please enter Y or N" + choices: List[str] = ["y", "n"] + + def render_default(self, default: DefaultType) -> Text: + """Render the default as (y) or (n) rather than True/False.""" + yes, no = self.choices + return Text(f"({yes})" if default else f"({no})", style="prompt.default") + + def process_response(self, value: str) -> bool: + """Convert choices to a bool.""" + value = value.strip().lower() + if value not in self.choices: + raise InvalidResponse(self.validate_error_message) + return value == self.choices[0] + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich import print + + if Confirm.ask("Run [i]prompt[/i] tests?", default=True): + while True: + result = IntPrompt.ask( + ":rocket: Enter a number between [b]1[/b] and [b]10[/b]", default=5 + ) + if result >= 1 and result <= 10: + break + print(":pile_of_poo: [prompt.invalid]Number must be between 1 and 10") + print(f"number={result}") + + while True: + password = Prompt.ask( + "Please enter a password [cyan](must be at least 5 characters)", + password=True, + ) + if len(password) >= 5: + break + print("[prompt.invalid]password too short") + print(f"password={password!r}") + + fruit = Prompt.ask("Enter a fruit", choices=["apple", "orange", "pear"]) + print(f"fruit={fruit!r}") + + doggie = Prompt.ask( + "What's the best Dog? (Case INSENSITIVE)", + choices=["Border Terrier", "Collie", "Labradoodle"], + case_sensitive=False, + ) + print(f"doggie={doggie!r}") + + else: + print("[b]OK :loudly_crying_face:") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/protocol.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/protocol.py new file mode 100644 index 0000000..12ab237 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/protocol.py @@ -0,0 +1,42 @@ +from typing import Any, cast, Set, TYPE_CHECKING +from inspect import isclass + +if TYPE_CHECKING: + from pip._vendor.rich.console import RenderableType + +_GIBBERISH = """aihwerij235234ljsdnp34ksodfipwoe234234jlskjdf""" + + +def is_renderable(check_object: Any) -> bool: + """Check if an object may be rendered by Rich.""" + return ( + isinstance(check_object, str) + or hasattr(check_object, "__rich__") + or hasattr(check_object, "__rich_console__") + ) + + +def rich_cast(renderable: object) -> "RenderableType": + """Cast an object to a renderable by calling __rich__ if present. + + Args: + renderable (object): A potentially renderable object + + Returns: + object: The result of recursively calling __rich__. + """ + from pip._vendor.rich.console import RenderableType + + rich_visited_set: Set[type] = set() # Prevent potential infinite loop + while hasattr(renderable, "__rich__") and not isclass(renderable): + # Detect object which claim to have all the attributes + if hasattr(renderable, _GIBBERISH): + return repr(renderable) + cast_method = getattr(renderable, "__rich__") + renderable = cast_method() + renderable_type = type(renderable) + if renderable_type in rich_visited_set: + break + rich_visited_set.add(renderable_type) + + return cast(RenderableType, renderable) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/rich/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/region.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/region.py new file mode 100644 index 0000000..75b3631 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/region.py @@ -0,0 +1,10 @@ +from typing import NamedTuple + + +class Region(NamedTuple): + """Defines a rectangular region of the screen.""" + + x: int + y: int + width: int + height: int diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/repr.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/repr.py new file mode 100644 index 0000000..10efc42 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/repr.py @@ -0,0 +1,149 @@ +import inspect +from functools import partial +from typing import ( + Any, + Callable, + Iterable, + List, + Optional, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +T = TypeVar("T") + + +Result = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]] +RichReprResult = Result + + +class ReprError(Exception): + """An error occurred when attempting to build a repr.""" + + +@overload +def auto(cls: Optional[Type[T]]) -> Type[T]: + ... + + +@overload +def auto(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]: + ... + + +def auto( + cls: Optional[Type[T]] = None, *, angular: Optional[bool] = None +) -> Union[Type[T], Callable[[Type[T]], Type[T]]]: + """Class decorator to create __repr__ from __rich_repr__""" + + def do_replace(cls: Type[T], angular: Optional[bool] = None) -> Type[T]: + def auto_repr(self: T) -> str: + """Create repr string from __rich_repr__""" + repr_str: List[str] = [] + append = repr_str.append + + angular: bool = getattr(self.__rich_repr__, "angular", False) # type: ignore[attr-defined] + for arg in self.__rich_repr__(): # type: ignore[attr-defined] + if isinstance(arg, tuple): + if len(arg) == 1: + append(repr(arg[0])) + else: + key, value, *default = arg + if key is None: + append(repr(value)) + else: + if default and default[0] == value: + continue + append(f"{key}={value!r}") + else: + append(repr(arg)) + if angular: + return f"<{self.__class__.__name__} {' '.join(repr_str)}>" + else: + return f"{self.__class__.__name__}({', '.join(repr_str)})" + + def auto_rich_repr(self: Type[T]) -> Result: + """Auto generate __rich_rep__ from signature of __init__""" + try: + signature = inspect.signature(self.__init__) + for name, param in signature.parameters.items(): + if param.kind == param.POSITIONAL_ONLY: + yield getattr(self, name) + elif param.kind in ( + param.POSITIONAL_OR_KEYWORD, + param.KEYWORD_ONLY, + ): + if param.default is param.empty: + yield getattr(self, param.name) + else: + yield param.name, getattr(self, param.name), param.default + except Exception as error: + raise ReprError( + f"Failed to auto generate __rich_repr__; {error}" + ) from None + + if not hasattr(cls, "__rich_repr__"): + auto_rich_repr.__doc__ = "Build a rich repr" + cls.__rich_repr__ = auto_rich_repr # type: ignore[attr-defined] + + auto_repr.__doc__ = "Return repr(self)" + cls.__repr__ = auto_repr # type: ignore[assignment] + if angular is not None: + cls.__rich_repr__.angular = angular # type: ignore[attr-defined] + return cls + + if cls is None: + return partial(do_replace, angular=angular) + else: + return do_replace(cls, angular=angular) + + +@overload +def rich_repr(cls: Optional[Type[T]]) -> Type[T]: + ... + + +@overload +def rich_repr(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]: + ... + + +def rich_repr( + cls: Optional[Type[T]] = None, *, angular: bool = False +) -> Union[Type[T], Callable[[Type[T]], Type[T]]]: + if cls is None: + return auto(angular=angular) + else: + return auto(cls) + + +if __name__ == "__main__": + + @auto + class Foo: + def __rich_repr__(self) -> Result: + yield "foo" + yield "bar", {"shopping": ["eggs", "ham", "pineapple"]} + yield "buy", "hand sanitizer" + + foo = Foo() + from pip._vendor.rich.console import Console + + console = Console() + + console.rule("Standard repr") + console.print(foo) + + console.print(foo, width=60) + console.print(foo, width=30) + + console.rule("Angular repr") + Foo.__rich_repr__.angular = True # type: ignore[attr-defined] + + console.print(foo) + + console.print(foo, width=60) + console.print(foo, width=30) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/rule.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/rule.py new file mode 100644 index 0000000..fd00ce6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/rule.py @@ -0,0 +1,130 @@ +from typing import Union + +from .align import AlignMethod +from .cells import cell_len, set_cell_size +from .console import Console, ConsoleOptions, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .style import Style +from .text import Text + + +class Rule(JupyterMixin): + """A console renderable to draw a horizontal rule (line). + + Args: + title (Union[str, Text], optional): Text to render in the rule. Defaults to "". + characters (str, optional): Character(s) used to draw the line. Defaults to "─". + style (StyleType, optional): Style of Rule. Defaults to "rule.line". + end (str, optional): Character at end of Rule. defaults to "\\\\n" + align (str, optional): How to align the title, one of "left", "center", or "right". Defaults to "center". + """ + + def __init__( + self, + title: Union[str, Text] = "", + *, + characters: str = "─", + style: Union[str, Style] = "rule.line", + end: str = "\n", + align: AlignMethod = "center", + ) -> None: + if cell_len(characters) < 1: + raise ValueError( + "'characters' argument must have a cell width of at least 1" + ) + if align not in ("left", "center", "right"): + raise ValueError( + f'invalid value for align, expected "left", "center", "right" (not {align!r})' + ) + self.title = title + self.characters = characters + self.style = style + self.end = end + self.align = align + + def __repr__(self) -> str: + return f"Rule({self.title!r}, {self.characters!r})" + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + width = options.max_width + + characters = ( + "-" + if (options.ascii_only and not self.characters.isascii()) + else self.characters + ) + + chars_len = cell_len(characters) + if not self.title: + yield self._rule_line(chars_len, width) + return + + if isinstance(self.title, Text): + title_text = self.title + else: + title_text = console.render_str(self.title, style="rule.text") + + title_text.plain = title_text.plain.replace("\n", " ") + title_text.expand_tabs() + + required_space = 4 if self.align == "center" else 2 + truncate_width = max(0, width - required_space) + if not truncate_width: + yield self._rule_line(chars_len, width) + return + + rule_text = Text(end=self.end) + if self.align == "center": + title_text.truncate(truncate_width, overflow="ellipsis") + side_width = (width - cell_len(title_text.plain)) // 2 + left = Text(characters * (side_width // chars_len + 1)) + left.truncate(side_width - 1) + right_length = width - cell_len(left.plain) - cell_len(title_text.plain) + right = Text(characters * (side_width // chars_len + 1)) + right.truncate(right_length) + rule_text.append(left.plain + " ", self.style) + rule_text.append(title_text) + rule_text.append(" " + right.plain, self.style) + elif self.align == "left": + title_text.truncate(truncate_width, overflow="ellipsis") + rule_text.append(title_text) + rule_text.append(" ") + rule_text.append(characters * (width - rule_text.cell_len), self.style) + elif self.align == "right": + title_text.truncate(truncate_width, overflow="ellipsis") + rule_text.append(characters * (width - title_text.cell_len - 1), self.style) + rule_text.append(" ") + rule_text.append(title_text) + + rule_text.plain = set_cell_size(rule_text.plain, width) + yield rule_text + + def _rule_line(self, chars_len: int, width: int) -> Text: + rule_text = Text(self.characters * ((width // chars_len) + 1), self.style) + rule_text.truncate(width) + rule_text.plain = set_cell_size(rule_text.plain, width) + return rule_text + + def __rich_measure__( + self, console: Console, options: ConsoleOptions + ) -> Measurement: + return Measurement(1, 1) + + +if __name__ == "__main__": # pragma: no cover + import sys + + from pip._vendor.rich.console import Console + + try: + text = sys.argv[1] + except IndexError: + text = "Hello, World" + console = Console() + console.print(Rule(title=text)) + + console = Console() + console.print(Rule("foo"), width=4) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/scope.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/scope.py new file mode 100644 index 0000000..c9d134c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/scope.py @@ -0,0 +1,86 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Optional, Tuple + +from .highlighter import ReprHighlighter +from .panel import Panel +from .pretty import Pretty +from .table import Table +from .text import Text, TextType + +if TYPE_CHECKING: + from .console import ConsoleRenderable + + +def render_scope( + scope: "Mapping[str, Any]", + *, + title: Optional[TextType] = None, + sort_keys: bool = True, + indent_guides: bool = False, + max_length: Optional[int] = None, + max_string: Optional[int] = None, +) -> "ConsoleRenderable": + """Render python variables in a given scope. + + Args: + scope (Mapping): A mapping containing variable names and values. + title (str, optional): Optional title. Defaults to None. + sort_keys (bool, optional): Enable sorting of items. Defaults to True. + indent_guides (bool, optional): Enable indentation guides. Defaults to False. + max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to None. + max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to None. + + Returns: + ConsoleRenderable: A renderable object. + """ + highlighter = ReprHighlighter() + items_table = Table.grid(padding=(0, 1), expand=False) + items_table.add_column(justify="right") + + def sort_items(item: Tuple[str, Any]) -> Tuple[bool, str]: + """Sort special variables first, then alphabetically.""" + key, _ = item + return (not key.startswith("__"), key.lower()) + + items = sorted(scope.items(), key=sort_items) if sort_keys else scope.items() + for key, value in items: + key_text = Text.assemble( + (key, "scope.key.special" if key.startswith("__") else "scope.key"), + (" =", "scope.equals"), + ) + items_table.add_row( + key_text, + Pretty( + value, + highlighter=highlighter, + indent_guides=indent_guides, + max_length=max_length, + max_string=max_string, + ), + ) + return Panel.fit( + items_table, + title=title, + border_style="scope.border", + padding=(0, 1), + ) + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich import print + + print() + + def test(foo: float, bar: float) -> None: + list_of_things = [1, 2, 3, None, 4, True, False, "Hello World"] + dict_of_things = { + "version": "1.1", + "method": "confirmFruitPurchase", + "params": [["apple", "orange", "mangoes", "pomelo"], 1.123], + "id": "194521489", + } + print(render_scope(locals(), title="[i]locals", sort_keys=False)) + + test(20.3423, 3.1427) + print() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/screen.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/screen.py new file mode 100644 index 0000000..7f416e1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/screen.py @@ -0,0 +1,54 @@ +from typing import Optional, TYPE_CHECKING + +from .segment import Segment +from .style import StyleType +from ._loop import loop_last + + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + RenderResult, + RenderableType, + Group, + ) + + +class Screen: + """A renderable that fills the terminal screen and crops excess. + + Args: + renderable (RenderableType): Child renderable. + style (StyleType, optional): Optional background style. Defaults to None. + """ + + renderable: "RenderableType" + + def __init__( + self, + *renderables: "RenderableType", + style: Optional[StyleType] = None, + application_mode: bool = False, + ) -> None: + from pip._vendor.rich.console import Group + + self.renderable = Group(*renderables) + self.style = style + self.application_mode = application_mode + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + width, height = options.size + style = console.get_style(self.style) if self.style else None + render_options = options.update(width=width, height=height) + lines = console.render_lines( + self.renderable or "", render_options, style=style, pad=True + ) + lines = Segment.set_shape(lines, width, height, style=style) + new_line = Segment("\n\r") if self.application_mode else Segment.line() + for last, line in loop_last(lines): + yield from line + if not last: + yield new_line diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/segment.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/segment.py new file mode 100644 index 0000000..4b5f997 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/segment.py @@ -0,0 +1,752 @@ +from enum import IntEnum +from functools import lru_cache +from itertools import filterfalse +from logging import getLogger +from operator import attrgetter +from typing import ( + TYPE_CHECKING, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +from .cells import ( + _is_single_cell_widths, + cached_cell_len, + cell_len, + get_character_cell_size, + set_cell_size, +) +from .repr import Result, rich_repr +from .style import Style + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult + +log = getLogger("rich") + + +class ControlType(IntEnum): + """Non-printable control codes which typically translate to ANSI codes.""" + + BELL = 1 + CARRIAGE_RETURN = 2 + HOME = 3 + CLEAR = 4 + SHOW_CURSOR = 5 + HIDE_CURSOR = 6 + ENABLE_ALT_SCREEN = 7 + DISABLE_ALT_SCREEN = 8 + CURSOR_UP = 9 + CURSOR_DOWN = 10 + CURSOR_FORWARD = 11 + CURSOR_BACKWARD = 12 + CURSOR_MOVE_TO_COLUMN = 13 + CURSOR_MOVE_TO = 14 + ERASE_IN_LINE = 15 + SET_WINDOW_TITLE = 16 + + +ControlCode = Union[ + Tuple[ControlType], + Tuple[ControlType, Union[int, str]], + Tuple[ControlType, int, int], +] + + +@rich_repr() +class Segment(NamedTuple): + """A piece of text with associated style. Segments are produced by the Console render process and + are ultimately converted in to strings to be written to the terminal. + + Args: + text (str): A piece of text. + style (:class:`~rich.style.Style`, optional): An optional style to apply to the text. + control (Tuple[ControlCode], optional): Optional sequence of control codes. + + Attributes: + cell_length (int): The cell length of this Segment. + """ + + text: str + style: Optional[Style] = None + control: Optional[Sequence[ControlCode]] = None + + @property + def cell_length(self) -> int: + """The number of terminal cells required to display self.text. + + Returns: + int: A number of cells. + """ + text, _style, control = self + return 0 if control else cell_len(text) + + def __rich_repr__(self) -> Result: + yield self.text + if self.control is None: + if self.style is not None: + yield self.style + else: + yield self.style + yield self.control + + def __bool__(self) -> bool: + """Check if the segment contains text.""" + return bool(self.text) + + @property + def is_control(self) -> bool: + """Check if the segment contains control codes.""" + return self.control is not None + + @classmethod + @lru_cache(1024 * 16) + def _split_cells(cls, segment: "Segment", cut: int) -> Tuple["Segment", "Segment"]: + """Split a segment in to two at a given cell position. + + Note that splitting a double-width character, may result in that character turning + into two spaces. + + Args: + segment (Segment): A segment to split. + cut (int): A cell position to cut on. + + Returns: + A tuple of two segments. + """ + text, style, control = segment + _Segment = Segment + cell_length = segment.cell_length + if cut >= cell_length: + return segment, _Segment("", style, control) + + cell_size = get_character_cell_size + + pos = int((cut / cell_length) * len(text)) + + while True: + before = text[:pos] + cell_pos = cell_len(before) + out_by = cell_pos - cut + if not out_by: + return ( + _Segment(before, style, control), + _Segment(text[pos:], style, control), + ) + if out_by == -1 and cell_size(text[pos]) == 2: + return ( + _Segment(text[:pos] + " ", style, control), + _Segment(" " + text[pos + 1 :], style, control), + ) + if out_by == +1 and cell_size(text[pos - 1]) == 2: + return ( + _Segment(text[: pos - 1] + " ", style, control), + _Segment(" " + text[pos:], style, control), + ) + if cell_pos < cut: + pos += 1 + else: + pos -= 1 + + def split_cells(self, cut: int) -> Tuple["Segment", "Segment"]: + """Split segment in to two segments at the specified column. + + If the cut point falls in the middle of a 2-cell wide character then it is replaced + by two spaces, to preserve the display width of the parent segment. + + Args: + cut (int): Offset within the segment to cut. + + Returns: + Tuple[Segment, Segment]: Two segments. + """ + text, style, control = self + assert cut >= 0 + + if _is_single_cell_widths(text): + # Fast path with all 1 cell characters + if cut >= len(text): + return self, Segment("", style, control) + return ( + Segment(text[:cut], style, control), + Segment(text[cut:], style, control), + ) + + return self._split_cells(self, cut) + + @classmethod + def line(cls) -> "Segment": + """Make a new line segment.""" + return cls("\n") + + @classmethod + def apply_style( + cls, + segments: Iterable["Segment"], + style: Optional[Style] = None, + post_style: Optional[Style] = None, + ) -> Iterable["Segment"]: + """Apply style(s) to an iterable of segments. + + Returns an iterable of segments where the style is replaced by ``style + segment.style + post_style``. + + Args: + segments (Iterable[Segment]): Segments to process. + style (Style, optional): Base style. Defaults to None. + post_style (Style, optional): Style to apply on top of segment style. Defaults to None. + + Returns: + Iterable[Segments]: A new iterable of segments (possibly the same iterable). + """ + result_segments = segments + if style: + apply = style.__add__ + result_segments = ( + cls(text, None if control else apply(_style), control) + for text, _style, control in result_segments + ) + if post_style: + result_segments = ( + cls( + text, + ( + None + if control + else (_style + post_style if _style else post_style) + ), + control, + ) + for text, _style, control in result_segments + ) + return result_segments + + @classmethod + def filter_control( + cls, segments: Iterable["Segment"], is_control: bool = False + ) -> Iterable["Segment"]: + """Filter segments by ``is_control`` attribute. + + Args: + segments (Iterable[Segment]): An iterable of Segment instances. + is_control (bool, optional): is_control flag to match in search. + + Returns: + Iterable[Segment]: And iterable of Segment instances. + + """ + if is_control: + return filter(attrgetter("control"), segments) + else: + return filterfalse(attrgetter("control"), segments) + + @classmethod + def split_lines(cls, segments: Iterable["Segment"]) -> Iterable[List["Segment"]]: + """Split a sequence of segments in to a list of lines. + + Args: + segments (Iterable[Segment]): Segments potentially containing line feeds. + + Yields: + Iterable[List[Segment]]: Iterable of segment lists, one per line. + """ + line: List[Segment] = [] + append = line.append + + for segment in segments: + if "\n" in segment.text and not segment.control: + text, style, _ = segment + while text: + _text, new_line, text = text.partition("\n") + if _text: + append(cls(_text, style)) + if new_line: + yield line + line = [] + append = line.append + else: + append(segment) + if line: + yield line + + @classmethod + def split_and_crop_lines( + cls, + segments: Iterable["Segment"], + length: int, + style: Optional[Style] = None, + pad: bool = True, + include_new_lines: bool = True, + ) -> Iterable[List["Segment"]]: + """Split segments in to lines, and crop lines greater than a given length. + + Args: + segments (Iterable[Segment]): An iterable of segments, probably + generated from console.render. + length (int): Desired line length. + style (Style, optional): Style to use for any padding. + pad (bool): Enable padding of lines that are less than `length`. + + Returns: + Iterable[List[Segment]]: An iterable of lines of segments. + """ + line: List[Segment] = [] + append = line.append + + adjust_line_length = cls.adjust_line_length + new_line_segment = cls("\n") + + for segment in segments: + if "\n" in segment.text and not segment.control: + text, segment_style, _ = segment + while text: + _text, new_line, text = text.partition("\n") + if _text: + append(cls(_text, segment_style)) + if new_line: + cropped_line = adjust_line_length( + line, length, style=style, pad=pad + ) + if include_new_lines: + cropped_line.append(new_line_segment) + yield cropped_line + line.clear() + else: + append(segment) + if line: + yield adjust_line_length(line, length, style=style, pad=pad) + + @classmethod + def adjust_line_length( + cls, + line: List["Segment"], + length: int, + style: Optional[Style] = None, + pad: bool = True, + ) -> List["Segment"]: + """Adjust a line to a given width (cropping or padding as required). + + Args: + segments (Iterable[Segment]): A list of segments in a single line. + length (int): The desired width of the line. + style (Style, optional): The style of padding if used (space on the end). Defaults to None. + pad (bool, optional): Pad lines with spaces if they are shorter than `length`. Defaults to True. + + Returns: + List[Segment]: A line of segments with the desired length. + """ + line_length = sum(segment.cell_length for segment in line) + new_line: List[Segment] + + if line_length < length: + if pad: + new_line = line + [cls(" " * (length - line_length), style)] + else: + new_line = line[:] + elif line_length > length: + new_line = [] + append = new_line.append + line_length = 0 + for segment in line: + segment_length = segment.cell_length + if line_length + segment_length < length or segment.control: + append(segment) + line_length += segment_length + else: + text, segment_style, _ = segment + text = set_cell_size(text, length - line_length) + append(cls(text, segment_style)) + break + else: + new_line = line[:] + return new_line + + @classmethod + def get_line_length(cls, line: List["Segment"]) -> int: + """Get the length of list of segments. + + Args: + line (List[Segment]): A line encoded as a list of Segments (assumes no '\\\\n' characters), + + Returns: + int: The length of the line. + """ + _cell_len = cell_len + return sum(_cell_len(text) for text, style, control in line if not control) + + @classmethod + def get_shape(cls, lines: List[List["Segment"]]) -> Tuple[int, int]: + """Get the shape (enclosing rectangle) of a list of lines. + + Args: + lines (List[List[Segment]]): A list of lines (no '\\\\n' characters). + + Returns: + Tuple[int, int]: Width and height in characters. + """ + get_line_length = cls.get_line_length + max_width = max(get_line_length(line) for line in lines) if lines else 0 + return (max_width, len(lines)) + + @classmethod + def set_shape( + cls, + lines: List[List["Segment"]], + width: int, + height: Optional[int] = None, + style: Optional[Style] = None, + new_lines: bool = False, + ) -> List[List["Segment"]]: + """Set the shape of a list of lines (enclosing rectangle). + + Args: + lines (List[List[Segment]]): A list of lines. + width (int): Desired width. + height (int, optional): Desired height or None for no change. + style (Style, optional): Style of any padding added. + new_lines (bool, optional): Padded lines should include "\n". Defaults to False. + + Returns: + List[List[Segment]]: New list of lines. + """ + _height = height or len(lines) + + blank = ( + [cls(" " * width + "\n", style)] if new_lines else [cls(" " * width, style)] + ) + + adjust_line_length = cls.adjust_line_length + shaped_lines = lines[:_height] + shaped_lines[:] = [ + adjust_line_length(line, width, style=style) for line in lines + ] + if len(shaped_lines) < _height: + shaped_lines.extend([blank] * (_height - len(shaped_lines))) + return shaped_lines + + @classmethod + def align_top( + cls: Type["Segment"], + lines: List[List["Segment"]], + width: int, + height: int, + style: Style, + new_lines: bool = False, + ) -> List[List["Segment"]]: + """Aligns lines to top (adds extra lines to bottom as required). + + Args: + lines (List[List[Segment]]): A list of lines. + width (int): Desired width. + height (int, optional): Desired height or None for no change. + style (Style): Style of any padding added. + new_lines (bool, optional): Padded lines should include "\n". Defaults to False. + + Returns: + List[List[Segment]]: New list of lines. + """ + extra_lines = height - len(lines) + if not extra_lines: + return lines[:] + lines = lines[:height] + blank = cls(" " * width + "\n", style) if new_lines else cls(" " * width, style) + lines = lines + [[blank]] * extra_lines + return lines + + @classmethod + def align_bottom( + cls: Type["Segment"], + lines: List[List["Segment"]], + width: int, + height: int, + style: Style, + new_lines: bool = False, + ) -> List[List["Segment"]]: + """Aligns render to bottom (adds extra lines above as required). + + Args: + lines (List[List[Segment]]): A list of lines. + width (int): Desired width. + height (int, optional): Desired height or None for no change. + style (Style): Style of any padding added. Defaults to None. + new_lines (bool, optional): Padded lines should include "\n". Defaults to False. + + Returns: + List[List[Segment]]: New list of lines. + """ + extra_lines = height - len(lines) + if not extra_lines: + return lines[:] + lines = lines[:height] + blank = cls(" " * width + "\n", style) if new_lines else cls(" " * width, style) + lines = [[blank]] * extra_lines + lines + return lines + + @classmethod + def align_middle( + cls: Type["Segment"], + lines: List[List["Segment"]], + width: int, + height: int, + style: Style, + new_lines: bool = False, + ) -> List[List["Segment"]]: + """Aligns lines to middle (adds extra lines to above and below as required). + + Args: + lines (List[List[Segment]]): A list of lines. + width (int): Desired width. + height (int, optional): Desired height or None for no change. + style (Style): Style of any padding added. + new_lines (bool, optional): Padded lines should include "\n". Defaults to False. + + Returns: + List[List[Segment]]: New list of lines. + """ + extra_lines = height - len(lines) + if not extra_lines: + return lines[:] + lines = lines[:height] + blank = cls(" " * width + "\n", style) if new_lines else cls(" " * width, style) + top_lines = extra_lines // 2 + bottom_lines = extra_lines - top_lines + lines = [[blank]] * top_lines + lines + [[blank]] * bottom_lines + return lines + + @classmethod + def simplify(cls, segments: Iterable["Segment"]) -> Iterable["Segment"]: + """Simplify an iterable of segments by combining contiguous segments with the same style. + + Args: + segments (Iterable[Segment]): An iterable of segments. + + Returns: + Iterable[Segment]: A possibly smaller iterable of segments that will render the same way. + """ + iter_segments = iter(segments) + try: + last_segment = next(iter_segments) + except StopIteration: + return + + _Segment = Segment + for segment in iter_segments: + if last_segment.style == segment.style and not segment.control: + last_segment = _Segment( + last_segment.text + segment.text, last_segment.style + ) + else: + yield last_segment + last_segment = segment + yield last_segment + + @classmethod + def strip_links(cls, segments: Iterable["Segment"]) -> Iterable["Segment"]: + """Remove all links from an iterable of styles. + + Args: + segments (Iterable[Segment]): An iterable segments. + + Yields: + Segment: Segments with link removed. + """ + for segment in segments: + if segment.control or segment.style is None: + yield segment + else: + text, style, _control = segment + yield cls(text, style.update_link(None) if style else None) + + @classmethod + def strip_styles(cls, segments: Iterable["Segment"]) -> Iterable["Segment"]: + """Remove all styles from an iterable of segments. + + Args: + segments (Iterable[Segment]): An iterable segments. + + Yields: + Segment: Segments with styles replace with None + """ + for text, _style, control in segments: + yield cls(text, None, control) + + @classmethod + def remove_color(cls, segments: Iterable["Segment"]) -> Iterable["Segment"]: + """Remove all color from an iterable of segments. + + Args: + segments (Iterable[Segment]): An iterable segments. + + Yields: + Segment: Segments with colorless style. + """ + + cache: Dict[Style, Style] = {} + for text, style, control in segments: + if style: + colorless_style = cache.get(style) + if colorless_style is None: + colorless_style = style.without_color + cache[style] = colorless_style + yield cls(text, colorless_style, control) + else: + yield cls(text, None, control) + + @classmethod + def divide( + cls, segments: Iterable["Segment"], cuts: Iterable[int] + ) -> Iterable[List["Segment"]]: + """Divides an iterable of segments in to portions. + + Args: + cuts (Iterable[int]): Cell positions where to divide. + + Yields: + [Iterable[List[Segment]]]: An iterable of Segments in List. + """ + split_segments: List["Segment"] = [] + add_segment = split_segments.append + + iter_cuts = iter(cuts) + + while True: + cut = next(iter_cuts, -1) + if cut == -1: + return + if cut != 0: + break + yield [] + pos = 0 + + segments_clear = split_segments.clear + segments_copy = split_segments.copy + + _cell_len = cached_cell_len + for segment in segments: + text, _style, control = segment + while text: + end_pos = pos if control else pos + _cell_len(text) + if end_pos < cut: + add_segment(segment) + pos = end_pos + break + + if end_pos == cut: + add_segment(segment) + yield segments_copy() + segments_clear() + pos = end_pos + + cut = next(iter_cuts, -1) + if cut == -1: + if split_segments: + yield segments_copy() + return + + break + + else: + before, segment = segment.split_cells(cut - pos) + text, _style, control = segment + add_segment(before) + yield segments_copy() + segments_clear() + pos = cut + + cut = next(iter_cuts, -1) + if cut == -1: + if split_segments: + yield segments_copy() + return + + yield segments_copy() + + +class Segments: + """A simple renderable to render an iterable of segments. This class may be useful if + you want to print segments outside of a __rich_console__ method. + + Args: + segments (Iterable[Segment]): An iterable of segments. + new_lines (bool, optional): Add new lines between segments. Defaults to False. + """ + + def __init__(self, segments: Iterable[Segment], new_lines: bool = False) -> None: + self.segments = list(segments) + self.new_lines = new_lines + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.new_lines: + line = Segment.line() + for segment in self.segments: + yield segment + yield line + else: + yield from self.segments + + +class SegmentLines: + def __init__(self, lines: Iterable[List[Segment]], new_lines: bool = False) -> None: + """A simple renderable containing a number of lines of segments. May be used as an intermediate + in rendering process. + + Args: + lines (Iterable[List[Segment]]): Lists of segments forming lines. + new_lines (bool, optional): Insert new lines after each line. Defaults to False. + """ + self.lines = list(lines) + self.new_lines = new_lines + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.new_lines: + new_line = Segment.line() + for line in self.lines: + yield from line + yield new_line + else: + for line in self.lines: + yield from line + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + from pip._vendor.rich.syntax import Syntax + from pip._vendor.rich.text import Text + + code = """from rich.console import Console +console = Console() +text = Text.from_markup("Hello, [bold magenta]World[/]!") +console.print(text)""" + + text = Text.from_markup("Hello, [bold magenta]World[/]!") + + console = Console() + + console.rule("rich.Segment") + console.print( + "A Segment is the last step in the Rich render process before generating text with ANSI codes." + ) + console.print("\nConsider the following code:\n") + console.print(Syntax(code, "python", line_numbers=True)) + console.print() + console.print( + "When you call [b]print()[/b], Rich [i]renders[/i] the object in to the following:\n" + ) + fragments = list(console.render(text)) + console.print(fragments) + console.print() + console.print("The Segments are then processed to produce the following output:\n") + console.print(text) + console.print( + "\nYou will only need to know this if you are implementing your own Rich renderables." + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/spinner.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/spinner.py new file mode 100644 index 0000000..70570b6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/spinner.py @@ -0,0 +1,138 @@ +from typing import cast, List, Optional, TYPE_CHECKING, Union + +from ._spinners import SPINNERS +from .measure import Measurement +from .table import Table +from .text import Text + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult, RenderableType + from .style import StyleType + + +class Spinner: + """A spinner animation. + + Args: + name (str): Name of spinner (run python -m rich.spinner). + text (RenderableType, optional): A renderable to display at the right of the spinner (str or Text typically). Defaults to "". + style (StyleType, optional): Style for spinner animation. Defaults to None. + speed (float, optional): Speed factor for animation. Defaults to 1.0. + + Raises: + KeyError: If name isn't one of the supported spinner animations. + """ + + def __init__( + self, + name: str, + text: "RenderableType" = "", + *, + style: Optional["StyleType"] = None, + speed: float = 1.0, + ) -> None: + try: + spinner = SPINNERS[name] + except KeyError: + raise KeyError(f"no spinner called {name!r}") + self.text: "Union[RenderableType, Text]" = ( + Text.from_markup(text) if isinstance(text, str) else text + ) + self.name = name + self.frames = cast(List[str], spinner["frames"])[:] + self.interval = cast(float, spinner["interval"]) + self.start_time: Optional[float] = None + self.style = style + self.speed = speed + self.frame_no_offset: float = 0.0 + self._update_speed = 0.0 + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + yield self.render(console.get_time()) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + text = self.render(0) + return Measurement.get(console, options, text) + + def render(self, time: float) -> "RenderableType": + """Render the spinner for a given time. + + Args: + time (float): Time in seconds. + + Returns: + RenderableType: A renderable containing animation frame. + """ + if self.start_time is None: + self.start_time = time + + frame_no = ((time - self.start_time) * self.speed) / ( + self.interval / 1000.0 + ) + self.frame_no_offset + frame = Text( + self.frames[int(frame_no) % len(self.frames)], style=self.style or "" + ) + + if self._update_speed: + self.frame_no_offset = frame_no + self.start_time = time + self.speed = self._update_speed + self._update_speed = 0.0 + + if not self.text: + return frame + elif isinstance(self.text, (str, Text)): + return Text.assemble(frame, " ", self.text) + else: + table = Table.grid(padding=1) + table.add_row(frame, self.text) + return table + + def update( + self, + *, + text: "RenderableType" = "", + style: Optional["StyleType"] = None, + speed: Optional[float] = None, + ) -> None: + """Updates attributes of a spinner after it has been started. + + Args: + text (RenderableType, optional): A renderable to display at the right of the spinner (str or Text typically). Defaults to "". + style (StyleType, optional): Style for spinner animation. Defaults to None. + speed (float, optional): Speed factor for animation. Defaults to None. + """ + if text: + self.text = Text.from_markup(text) if isinstance(text, str) else text + if style: + self.style = style + if speed: + self._update_speed = speed + + +if __name__ == "__main__": # pragma: no cover + from time import sleep + + from .columns import Columns + from .panel import Panel + from .live import Live + + all_spinners = Columns( + [ + Spinner(spinner_name, text=Text(repr(spinner_name), style="green")) + for spinner_name in sorted(SPINNERS.keys()) + ], + column_first=True, + expand=True, + ) + + with Live( + Panel(all_spinners, title="Spinners", border_style="blue"), + refresh_per_second=20, + ) as live: + while True: + sleep(0.1) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/status.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/status.py new file mode 100644 index 0000000..6574483 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/status.py @@ -0,0 +1,131 @@ +from types import TracebackType +from typing import Optional, Type + +from .console import Console, RenderableType +from .jupyter import JupyterMixin +from .live import Live +from .spinner import Spinner +from .style import StyleType + + +class Status(JupyterMixin): + """Displays a status indicator with a 'spinner' animation. + + Args: + status (RenderableType): A status renderable (str or Text typically). + console (Console, optional): Console instance to use, or None for global console. Defaults to None. + spinner (str, optional): Name of spinner animation (see python -m rich.spinner). Defaults to "dots". + spinner_style (StyleType, optional): Style of spinner. Defaults to "status.spinner". + speed (float, optional): Speed factor for spinner animation. Defaults to 1.0. + refresh_per_second (float, optional): Number of refreshes per second. Defaults to 12.5. + """ + + def __init__( + self, + status: RenderableType, + *, + console: Optional[Console] = None, + spinner: str = "dots", + spinner_style: StyleType = "status.spinner", + speed: float = 1.0, + refresh_per_second: float = 12.5, + ): + self.status = status + self.spinner_style = spinner_style + self.speed = speed + self._spinner = Spinner(spinner, text=status, style=spinner_style, speed=speed) + self._live = Live( + self.renderable, + console=console, + refresh_per_second=refresh_per_second, + transient=True, + ) + + @property + def renderable(self) -> Spinner: + return self._spinner + + @property + def console(self) -> "Console": + """Get the Console used by the Status objects.""" + return self._live.console + + def update( + self, + status: Optional[RenderableType] = None, + *, + spinner: Optional[str] = None, + spinner_style: Optional[StyleType] = None, + speed: Optional[float] = None, + ) -> None: + """Update status. + + Args: + status (Optional[RenderableType], optional): New status renderable or None for no change. Defaults to None. + spinner (Optional[str], optional): New spinner or None for no change. Defaults to None. + spinner_style (Optional[StyleType], optional): New spinner style or None for no change. Defaults to None. + speed (Optional[float], optional): Speed factor for spinner animation or None for no change. Defaults to None. + """ + if status is not None: + self.status = status + if spinner_style is not None: + self.spinner_style = spinner_style + if speed is not None: + self.speed = speed + if spinner is not None: + self._spinner = Spinner( + spinner, text=self.status, style=self.spinner_style, speed=self.speed + ) + self._live.update(self.renderable, refresh=True) + else: + self._spinner.update( + text=self.status, style=self.spinner_style, speed=self.speed + ) + + def start(self) -> None: + """Start the status animation.""" + self._live.start() + + def stop(self) -> None: + """Stop the spinner animation.""" + self._live.stop() + + def __rich__(self) -> RenderableType: + return self.renderable + + def __enter__(self) -> "Status": + self.start() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.stop() + + +if __name__ == "__main__": # pragma: no cover + from time import sleep + + from .console import Console + + console = Console() + with console.status("[magenta]Covid detector booting up") as status: + sleep(3) + console.log("Importing advanced AI") + sleep(3) + console.log("Advanced Covid AI Ready") + sleep(3) + status.update(status="[bold blue] Scanning for Covid", spinner="earth") + sleep(3) + console.log("Found 10,000,000,000 copies of Covid32.exe") + sleep(3) + status.update( + status="[bold red]Moving Covid32.exe to Trash", + spinner="bouncingBall", + spinner_style="yellow", + ) + sleep(5) + console.print("[bold green]Covid deleted successfully") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/style.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/style.py new file mode 100644 index 0000000..262fd6e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/style.py @@ -0,0 +1,796 @@ +import sys +from functools import lru_cache +from marshal import dumps, loads +from random import randint +from typing import Any, Dict, Iterable, List, Optional, Type, Union, cast + +from . import errors +from .color import Color, ColorParseError, ColorSystem, blend_rgb +from .repr import Result, rich_repr +from .terminal_theme import DEFAULT_TERMINAL_THEME, TerminalTheme + +# Style instances and style definitions are often interchangeable +StyleType = Union[str, "Style"] + + +class _Bit: + """A descriptor to get/set a style attribute bit.""" + + __slots__ = ["bit"] + + def __init__(self, bit_no: int) -> None: + self.bit = 1 << bit_no + + def __get__(self, obj: "Style", objtype: Type["Style"]) -> Optional[bool]: + if obj._set_attributes & self.bit: + return obj._attributes & self.bit != 0 + return None + + +@rich_repr +class Style: + """A terminal style. + + A terminal style consists of a color (`color`), a background color (`bgcolor`), and a number of attributes, such + as bold, italic etc. The attributes have 3 states: they can either be on + (``True``), off (``False``), or not set (``None``). + + Args: + color (Union[Color, str], optional): Color of terminal text. Defaults to None. + bgcolor (Union[Color, str], optional): Color of terminal background. Defaults to None. + bold (bool, optional): Enable bold text. Defaults to None. + dim (bool, optional): Enable dim text. Defaults to None. + italic (bool, optional): Enable italic text. Defaults to None. + underline (bool, optional): Enable underlined text. Defaults to None. + blink (bool, optional): Enabled blinking text. Defaults to None. + blink2 (bool, optional): Enable fast blinking text. Defaults to None. + reverse (bool, optional): Enabled reverse text. Defaults to None. + conceal (bool, optional): Enable concealed text. Defaults to None. + strike (bool, optional): Enable strikethrough text. Defaults to None. + underline2 (bool, optional): Enable doubly underlined text. Defaults to None. + frame (bool, optional): Enable framed text. Defaults to None. + encircle (bool, optional): Enable encircled text. Defaults to None. + overline (bool, optional): Enable overlined text. Defaults to None. + link (str, link): Link URL. Defaults to None. + + """ + + _color: Optional[Color] + _bgcolor: Optional[Color] + _attributes: int + _set_attributes: int + _hash: Optional[int] + _null: bool + _meta: Optional[bytes] + + __slots__ = [ + "_color", + "_bgcolor", + "_attributes", + "_set_attributes", + "_link", + "_link_id", + "_ansi", + "_style_definition", + "_hash", + "_null", + "_meta", + ] + + # maps bits on to SGR parameter + _style_map = { + 0: "1", + 1: "2", + 2: "3", + 3: "4", + 4: "5", + 5: "6", + 6: "7", + 7: "8", + 8: "9", + 9: "21", + 10: "51", + 11: "52", + 12: "53", + } + + STYLE_ATTRIBUTES = { + "dim": "dim", + "d": "dim", + "bold": "bold", + "b": "bold", + "italic": "italic", + "i": "italic", + "underline": "underline", + "u": "underline", + "blink": "blink", + "blink2": "blink2", + "reverse": "reverse", + "r": "reverse", + "conceal": "conceal", + "c": "conceal", + "strike": "strike", + "s": "strike", + "underline2": "underline2", + "uu": "underline2", + "frame": "frame", + "encircle": "encircle", + "overline": "overline", + "o": "overline", + } + + def __init__( + self, + *, + color: Optional[Union[Color, str]] = None, + bgcolor: Optional[Union[Color, str]] = None, + bold: Optional[bool] = None, + dim: Optional[bool] = None, + italic: Optional[bool] = None, + underline: Optional[bool] = None, + blink: Optional[bool] = None, + blink2: Optional[bool] = None, + reverse: Optional[bool] = None, + conceal: Optional[bool] = None, + strike: Optional[bool] = None, + underline2: Optional[bool] = None, + frame: Optional[bool] = None, + encircle: Optional[bool] = None, + overline: Optional[bool] = None, + link: Optional[str] = None, + meta: Optional[Dict[str, Any]] = None, + ): + self._ansi: Optional[str] = None + self._style_definition: Optional[str] = None + + def _make_color(color: Union[Color, str]) -> Color: + return color if isinstance(color, Color) else Color.parse(color) + + self._color = None if color is None else _make_color(color) + self._bgcolor = None if bgcolor is None else _make_color(bgcolor) + self._set_attributes = sum( + ( + bold is not None, + dim is not None and 2, + italic is not None and 4, + underline is not None and 8, + blink is not None and 16, + blink2 is not None and 32, + reverse is not None and 64, + conceal is not None and 128, + strike is not None and 256, + underline2 is not None and 512, + frame is not None and 1024, + encircle is not None and 2048, + overline is not None and 4096, + ) + ) + self._attributes = ( + sum( + ( + bold and 1 or 0, + dim and 2 or 0, + italic and 4 or 0, + underline and 8 or 0, + blink and 16 or 0, + blink2 and 32 or 0, + reverse and 64 or 0, + conceal and 128 or 0, + strike and 256 or 0, + underline2 and 512 or 0, + frame and 1024 or 0, + encircle and 2048 or 0, + overline and 4096 or 0, + ) + ) + if self._set_attributes + else 0 + ) + + self._link = link + self._meta = None if meta is None else dumps(meta) + self._link_id = ( + f"{randint(0, 999999)}{hash(self._meta)}" if (link or meta) else "" + ) + self._hash: Optional[int] = None + self._null = not (self._set_attributes or color or bgcolor or link or meta) + + @classmethod + def null(cls) -> "Style": + """Create an 'null' style, equivalent to Style(), but more performant.""" + return NULL_STYLE + + @classmethod + def from_color( + cls, color: Optional[Color] = None, bgcolor: Optional[Color] = None + ) -> "Style": + """Create a new style with colors and no attributes. + + Returns: + color (Optional[Color]): A (foreground) color, or None for no color. Defaults to None. + bgcolor (Optional[Color]): A (background) color, or None for no color. Defaults to None. + """ + style: Style = cls.__new__(Style) + style._ansi = None + style._style_definition = None + style._color = color + style._bgcolor = bgcolor + style._set_attributes = 0 + style._attributes = 0 + style._link = None + style._link_id = "" + style._meta = None + style._null = not (color or bgcolor) + style._hash = None + return style + + @classmethod + def from_meta(cls, meta: Optional[Dict[str, Any]]) -> "Style": + """Create a new style with meta data. + + Returns: + meta (Optional[Dict[str, Any]]): A dictionary of meta data. Defaults to None. + """ + style: Style = cls.__new__(Style) + style._ansi = None + style._style_definition = None + style._color = None + style._bgcolor = None + style._set_attributes = 0 + style._attributes = 0 + style._link = None + style._meta = dumps(meta) + style._link_id = f"{randint(0, 999999)}{hash(style._meta)}" + style._hash = None + style._null = not (meta) + return style + + @classmethod + def on(cls, meta: Optional[Dict[str, Any]] = None, **handlers: Any) -> "Style": + """Create a blank style with meta information. + + Example: + style = Style.on(click=self.on_click) + + Args: + meta (Optional[Dict[str, Any]], optional): An optional dict of meta information. + **handlers (Any): Keyword arguments are translated in to handlers. + + Returns: + Style: A Style with meta information attached. + """ + meta = {} if meta is None else meta + meta.update({f"@{key}": value for key, value in handlers.items()}) + return cls.from_meta(meta) + + bold = _Bit(0) + dim = _Bit(1) + italic = _Bit(2) + underline = _Bit(3) + blink = _Bit(4) + blink2 = _Bit(5) + reverse = _Bit(6) + conceal = _Bit(7) + strike = _Bit(8) + underline2 = _Bit(9) + frame = _Bit(10) + encircle = _Bit(11) + overline = _Bit(12) + + @property + def link_id(self) -> str: + """Get a link id, used in ansi code for links.""" + return self._link_id + + def __str__(self) -> str: + """Re-generate style definition from attributes.""" + if self._style_definition is None: + attributes: List[str] = [] + append = attributes.append + bits = self._set_attributes + if bits & 0b0000000001111: + if bits & 1: + append("bold" if self.bold else "not bold") + if bits & (1 << 1): + append("dim" if self.dim else "not dim") + if bits & (1 << 2): + append("italic" if self.italic else "not italic") + if bits & (1 << 3): + append("underline" if self.underline else "not underline") + if bits & 0b0000111110000: + if bits & (1 << 4): + append("blink" if self.blink else "not blink") + if bits & (1 << 5): + append("blink2" if self.blink2 else "not blink2") + if bits & (1 << 6): + append("reverse" if self.reverse else "not reverse") + if bits & (1 << 7): + append("conceal" if self.conceal else "not conceal") + if bits & (1 << 8): + append("strike" if self.strike else "not strike") + if bits & 0b1111000000000: + if bits & (1 << 9): + append("underline2" if self.underline2 else "not underline2") + if bits & (1 << 10): + append("frame" if self.frame else "not frame") + if bits & (1 << 11): + append("encircle" if self.encircle else "not encircle") + if bits & (1 << 12): + append("overline" if self.overline else "not overline") + if self._color is not None: + append(self._color.name) + if self._bgcolor is not None: + append("on") + append(self._bgcolor.name) + if self._link: + append("link") + append(self._link) + self._style_definition = " ".join(attributes) or "none" + return self._style_definition + + def __bool__(self) -> bool: + """A Style is false if it has no attributes, colors, or links.""" + return not self._null + + def _make_ansi_codes(self, color_system: ColorSystem) -> str: + """Generate ANSI codes for this style. + + Args: + color_system (ColorSystem): Color system. + + Returns: + str: String containing codes. + """ + + if self._ansi is None: + sgr: List[str] = [] + append = sgr.append + _style_map = self._style_map + attributes = self._attributes & self._set_attributes + if attributes: + if attributes & 1: + append(_style_map[0]) + if attributes & 2: + append(_style_map[1]) + if attributes & 4: + append(_style_map[2]) + if attributes & 8: + append(_style_map[3]) + if attributes & 0b0000111110000: + for bit in range(4, 9): + if attributes & (1 << bit): + append(_style_map[bit]) + if attributes & 0b1111000000000: + for bit in range(9, 13): + if attributes & (1 << bit): + append(_style_map[bit]) + if self._color is not None: + sgr.extend(self._color.downgrade(color_system).get_ansi_codes()) + if self._bgcolor is not None: + sgr.extend( + self._bgcolor.downgrade(color_system).get_ansi_codes( + foreground=False + ) + ) + self._ansi = ";".join(sgr) + return self._ansi + + @classmethod + @lru_cache(maxsize=1024) + def normalize(cls, style: str) -> str: + """Normalize a style definition so that styles with the same effect have the same string + representation. + + Args: + style (str): A style definition. + + Returns: + str: Normal form of style definition. + """ + try: + return str(cls.parse(style)) + except errors.StyleSyntaxError: + return style.strip().lower() + + @classmethod + def pick_first(cls, *values: Optional[StyleType]) -> StyleType: + """Pick first non-None style.""" + for value in values: + if value is not None: + return value + raise ValueError("expected at least one non-None style") + + def __rich_repr__(self) -> Result: + yield "color", self.color, None + yield "bgcolor", self.bgcolor, None + yield "bold", self.bold, None, + yield "dim", self.dim, None, + yield "italic", self.italic, None + yield "underline", self.underline, None, + yield "blink", self.blink, None + yield "blink2", self.blink2, None + yield "reverse", self.reverse, None + yield "conceal", self.conceal, None + yield "strike", self.strike, None + yield "underline2", self.underline2, None + yield "frame", self.frame, None + yield "encircle", self.encircle, None + yield "link", self.link, None + if self._meta: + yield "meta", self.meta + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Style): + return NotImplemented + return self.__hash__() == other.__hash__() + + def __ne__(self, other: Any) -> bool: + if not isinstance(other, Style): + return NotImplemented + return self.__hash__() != other.__hash__() + + def __hash__(self) -> int: + if self._hash is not None: + return self._hash + self._hash = hash( + ( + self._color, + self._bgcolor, + self._attributes, + self._set_attributes, + self._link, + self._meta, + ) + ) + return self._hash + + @property + def color(self) -> Optional[Color]: + """The foreground color or None if it is not set.""" + return self._color + + @property + def bgcolor(self) -> Optional[Color]: + """The background color or None if it is not set.""" + return self._bgcolor + + @property + def link(self) -> Optional[str]: + """Link text, if set.""" + return self._link + + @property + def transparent_background(self) -> bool: + """Check if the style specified a transparent background.""" + return self.bgcolor is None or self.bgcolor.is_default + + @property + def background_style(self) -> "Style": + """A Style with background only.""" + return Style(bgcolor=self.bgcolor) + + @property + def meta(self) -> Dict[str, Any]: + """Get meta information (can not be changed after construction).""" + return {} if self._meta is None else cast(Dict[str, Any], loads(self._meta)) + + @property + def without_color(self) -> "Style": + """Get a copy of the style with color removed.""" + if self._null: + return NULL_STYLE + style: Style = self.__new__(Style) + style._ansi = None + style._style_definition = None + style._color = None + style._bgcolor = None + style._attributes = self._attributes + style._set_attributes = self._set_attributes + style._link = self._link + style._link_id = f"{randint(0, 999999)}" if self._link else "" + style._null = False + style._meta = None + style._hash = None + return style + + @classmethod + @lru_cache(maxsize=4096) + def parse(cls, style_definition: str) -> "Style": + """Parse a style definition. + + Args: + style_definition (str): A string containing a style. + + Raises: + errors.StyleSyntaxError: If the style definition syntax is invalid. + + Returns: + `Style`: A Style instance. + """ + if style_definition.strip() == "none" or not style_definition: + return cls.null() + + STYLE_ATTRIBUTES = cls.STYLE_ATTRIBUTES + color: Optional[str] = None + bgcolor: Optional[str] = None + attributes: Dict[str, Optional[Any]] = {} + link: Optional[str] = None + + words = iter(style_definition.split()) + for original_word in words: + word = original_word.lower() + if word == "on": + word = next(words, "") + if not word: + raise errors.StyleSyntaxError("color expected after 'on'") + try: + Color.parse(word) is None + except ColorParseError as error: + raise errors.StyleSyntaxError( + f"unable to parse {word!r} as background color; {error}" + ) from None + bgcolor = word + + elif word == "not": + word = next(words, "") + attribute = STYLE_ATTRIBUTES.get(word) + if attribute is None: + raise errors.StyleSyntaxError( + f"expected style attribute after 'not', found {word!r}" + ) + attributes[attribute] = False + + elif word == "link": + word = next(words, "") + if not word: + raise errors.StyleSyntaxError("URL expected after 'link'") + link = word + + elif word in STYLE_ATTRIBUTES: + attributes[STYLE_ATTRIBUTES[word]] = True + + else: + try: + Color.parse(word) + except ColorParseError as error: + raise errors.StyleSyntaxError( + f"unable to parse {word!r} as color; {error}" + ) from None + color = word + style = Style(color=color, bgcolor=bgcolor, link=link, **attributes) + return style + + @lru_cache(maxsize=1024) + def get_html_style(self, theme: Optional[TerminalTheme] = None) -> str: + """Get a CSS style rule.""" + theme = theme or DEFAULT_TERMINAL_THEME + css: List[str] = [] + append = css.append + + color = self.color + bgcolor = self.bgcolor + if self.reverse: + color, bgcolor = bgcolor, color + if self.dim: + foreground_color = ( + theme.foreground_color if color is None else color.get_truecolor(theme) + ) + color = Color.from_triplet( + blend_rgb(foreground_color, theme.background_color, 0.5) + ) + if color is not None: + theme_color = color.get_truecolor(theme) + append(f"color: {theme_color.hex}") + append(f"text-decoration-color: {theme_color.hex}") + if bgcolor is not None: + theme_color = bgcolor.get_truecolor(theme, foreground=False) + append(f"background-color: {theme_color.hex}") + if self.bold: + append("font-weight: bold") + if self.italic: + append("font-style: italic") + if self.underline: + append("text-decoration: underline") + if self.strike: + append("text-decoration: line-through") + if self.overline: + append("text-decoration: overline") + return "; ".join(css) + + @classmethod + def combine(cls, styles: Iterable["Style"]) -> "Style": + """Combine styles and get result. + + Args: + styles (Iterable[Style]): Styles to combine. + + Returns: + Style: A new style instance. + """ + iter_styles = iter(styles) + return sum(iter_styles, next(iter_styles)) + + @classmethod + def chain(cls, *styles: "Style") -> "Style": + """Combine styles from positional argument in to a single style. + + Args: + *styles (Iterable[Style]): Styles to combine. + + Returns: + Style: A new style instance. + """ + iter_styles = iter(styles) + return sum(iter_styles, next(iter_styles)) + + def copy(self) -> "Style": + """Get a copy of this style. + + Returns: + Style: A new Style instance with identical attributes. + """ + if self._null: + return NULL_STYLE + style: Style = self.__new__(Style) + style._ansi = self._ansi + style._style_definition = self._style_definition + style._color = self._color + style._bgcolor = self._bgcolor + style._attributes = self._attributes + style._set_attributes = self._set_attributes + style._link = self._link + style._link_id = f"{randint(0, 999999)}" if self._link else "" + style._hash = self._hash + style._null = False + style._meta = self._meta + return style + + @lru_cache(maxsize=128) + def clear_meta_and_links(self) -> "Style": + """Get a copy of this style with link and meta information removed. + + Returns: + Style: New style object. + """ + if self._null: + return NULL_STYLE + style: Style = self.__new__(Style) + style._ansi = self._ansi + style._style_definition = self._style_definition + style._color = self._color + style._bgcolor = self._bgcolor + style._attributes = self._attributes + style._set_attributes = self._set_attributes + style._link = None + style._link_id = "" + style._hash = None + style._null = False + style._meta = None + return style + + def update_link(self, link: Optional[str] = None) -> "Style": + """Get a copy with a different value for link. + + Args: + link (str, optional): New value for link. Defaults to None. + + Returns: + Style: A new Style instance. + """ + style: Style = self.__new__(Style) + style._ansi = self._ansi + style._style_definition = self._style_definition + style._color = self._color + style._bgcolor = self._bgcolor + style._attributes = self._attributes + style._set_attributes = self._set_attributes + style._link = link + style._link_id = f"{randint(0, 999999)}" if link else "" + style._hash = None + style._null = False + style._meta = self._meta + return style + + def render( + self, + text: str = "", + *, + color_system: Optional[ColorSystem] = ColorSystem.TRUECOLOR, + legacy_windows: bool = False, + ) -> str: + """Render the ANSI codes for the style. + + Args: + text (str, optional): A string to style. Defaults to "". + color_system (Optional[ColorSystem], optional): Color system to render to. Defaults to ColorSystem.TRUECOLOR. + + Returns: + str: A string containing ANSI style codes. + """ + if not text or color_system is None: + return text + attrs = self._ansi or self._make_ansi_codes(color_system) + rendered = f"\x1b[{attrs}m{text}\x1b[0m" if attrs else text + if self._link and not legacy_windows: + rendered = ( + f"\x1b]8;id={self._link_id};{self._link}\x1b\\{rendered}\x1b]8;;\x1b\\" + ) + return rendered + + def test(self, text: Optional[str] = None) -> None: + """Write text with style directly to terminal. + + This method is for testing purposes only. + + Args: + text (Optional[str], optional): Text to style or None for style name. + + """ + text = text or str(self) + sys.stdout.write(f"{self.render(text)}\n") + + @lru_cache(maxsize=1024) + def _add(self, style: Optional["Style"]) -> "Style": + if style is None or style._null: + return self + if self._null: + return style + new_style: Style = self.__new__(Style) + new_style._ansi = None + new_style._style_definition = None + new_style._color = style._color or self._color + new_style._bgcolor = style._bgcolor or self._bgcolor + new_style._attributes = (self._attributes & ~style._set_attributes) | ( + style._attributes & style._set_attributes + ) + new_style._set_attributes = self._set_attributes | style._set_attributes + new_style._link = style._link or self._link + new_style._link_id = style._link_id or self._link_id + new_style._null = style._null + if self._meta and style._meta: + new_style._meta = dumps({**self.meta, **style.meta}) + else: + new_style._meta = self._meta or style._meta + new_style._hash = None + return new_style + + def __add__(self, style: Optional["Style"]) -> "Style": + combined_style = self._add(style) + return combined_style.copy() if combined_style.link else combined_style + + +NULL_STYLE = Style() + + +class StyleStack: + """A stack of styles.""" + + __slots__ = ["_stack"] + + def __init__(self, default_style: "Style") -> None: + self._stack: List[Style] = [default_style] + + def __repr__(self) -> str: + return f"" + + @property + def current(self) -> Style: + """Get the Style at the top of the stack.""" + return self._stack[-1] + + def push(self, style: Style) -> None: + """Push a new style on to the stack. + + Args: + style (Style): New style to combine with current style. + """ + self._stack.append(self._stack[-1] + style) + + def pop(self) -> Style: + """Pop last style and discard. + + Returns: + Style: New current style (also available as stack.current) + """ + self._stack.pop() + return self._stack[-1] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/styled.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/styled.py new file mode 100644 index 0000000..91cd0db --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/styled.py @@ -0,0 +1,42 @@ +from typing import TYPE_CHECKING + +from .measure import Measurement +from .segment import Segment +from .style import StyleType + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult, RenderableType + + +class Styled: + """Apply a style to a renderable. + + Args: + renderable (RenderableType): Any renderable. + style (StyleType): A style to apply across the entire renderable. + """ + + def __init__(self, renderable: "RenderableType", style: "StyleType") -> None: + self.renderable = renderable + self.style = style + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + style = console.get_style(self.style) + rendered_segments = console.render(self.renderable, options) + segments = Segment.apply_style(rendered_segments, style) + return segments + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + return Measurement.get(console, options, self.renderable) + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich import print + from pip._vendor.rich.panel import Panel + + panel = Styled(Panel("hello"), "on blue") + print(panel) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/syntax.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/syntax.py new file mode 100644 index 0000000..f3d483c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/syntax.py @@ -0,0 +1,966 @@ +import os.path +import re +import sys +import textwrap +from abc import ABC, abstractmethod +from pathlib import Path +from typing import ( + Any, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Sequence, + Set, + Tuple, + Type, + Union, +) + +from pip._vendor.pygments.lexer import Lexer +from pip._vendor.pygments.lexers import get_lexer_by_name, guess_lexer_for_filename +from pip._vendor.pygments.style import Style as PygmentsStyle +from pip._vendor.pygments.styles import get_style_by_name +from pip._vendor.pygments.token import ( + Comment, + Error, + Generic, + Keyword, + Name, + Number, + Operator, + String, + Token, + Whitespace, +) +from pip._vendor.pygments.util import ClassNotFound + +from pip._vendor.rich.containers import Lines +from pip._vendor.rich.padding import Padding, PaddingDimensions + +from ._loop import loop_first +from .cells import cell_len +from .color import Color, blend_rgb +from .console import Console, ConsoleOptions, JustifyMethod, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment, Segments +from .style import Style, StyleType +from .text import Text + +TokenType = Tuple[str, ...] + +WINDOWS = sys.platform == "win32" +DEFAULT_THEME = "monokai" + +# The following styles are based on https://github.com/pygments/pygments/blob/master/pygments/formatters/terminal.py +# A few modifications were made + +ANSI_LIGHT: Dict[TokenType, Style] = { + Token: Style(), + Whitespace: Style(color="white"), + Comment: Style(dim=True), + Comment.Preproc: Style(color="cyan"), + Keyword: Style(color="blue"), + Keyword.Type: Style(color="cyan"), + Operator.Word: Style(color="magenta"), + Name.Builtin: Style(color="cyan"), + Name.Function: Style(color="green"), + Name.Namespace: Style(color="cyan", underline=True), + Name.Class: Style(color="green", underline=True), + Name.Exception: Style(color="cyan"), + Name.Decorator: Style(color="magenta", bold=True), + Name.Variable: Style(color="red"), + Name.Constant: Style(color="red"), + Name.Attribute: Style(color="cyan"), + Name.Tag: Style(color="bright_blue"), + String: Style(color="yellow"), + Number: Style(color="blue"), + Generic.Deleted: Style(color="bright_red"), + Generic.Inserted: Style(color="green"), + Generic.Heading: Style(bold=True), + Generic.Subheading: Style(color="magenta", bold=True), + Generic.Prompt: Style(bold=True), + Generic.Error: Style(color="bright_red"), + Error: Style(color="red", underline=True), +} + +ANSI_DARK: Dict[TokenType, Style] = { + Token: Style(), + Whitespace: Style(color="bright_black"), + Comment: Style(dim=True), + Comment.Preproc: Style(color="bright_cyan"), + Keyword: Style(color="bright_blue"), + Keyword.Type: Style(color="bright_cyan"), + Operator.Word: Style(color="bright_magenta"), + Name.Builtin: Style(color="bright_cyan"), + Name.Function: Style(color="bright_green"), + Name.Namespace: Style(color="bright_cyan", underline=True), + Name.Class: Style(color="bright_green", underline=True), + Name.Exception: Style(color="bright_cyan"), + Name.Decorator: Style(color="bright_magenta", bold=True), + Name.Variable: Style(color="bright_red"), + Name.Constant: Style(color="bright_red"), + Name.Attribute: Style(color="bright_cyan"), + Name.Tag: Style(color="bright_blue"), + String: Style(color="yellow"), + Number: Style(color="bright_blue"), + Generic.Deleted: Style(color="bright_red"), + Generic.Inserted: Style(color="bright_green"), + Generic.Heading: Style(bold=True), + Generic.Subheading: Style(color="bright_magenta", bold=True), + Generic.Prompt: Style(bold=True), + Generic.Error: Style(color="bright_red"), + Error: Style(color="red", underline=True), +} + +RICH_SYNTAX_THEMES = {"ansi_light": ANSI_LIGHT, "ansi_dark": ANSI_DARK} +NUMBERS_COLUMN_DEFAULT_PADDING = 2 + + +class SyntaxTheme(ABC): + """Base class for a syntax theme.""" + + @abstractmethod + def get_style_for_token(self, token_type: TokenType) -> Style: + """Get a style for a given Pygments token.""" + raise NotImplementedError # pragma: no cover + + @abstractmethod + def get_background_style(self) -> Style: + """Get the background color.""" + raise NotImplementedError # pragma: no cover + + +class PygmentsSyntaxTheme(SyntaxTheme): + """Syntax theme that delegates to Pygments theme.""" + + def __init__(self, theme: Union[str, Type[PygmentsStyle]]) -> None: + self._style_cache: Dict[TokenType, Style] = {} + if isinstance(theme, str): + try: + self._pygments_style_class = get_style_by_name(theme) + except ClassNotFound: + self._pygments_style_class = get_style_by_name("default") + else: + self._pygments_style_class = theme + + self._background_color = self._pygments_style_class.background_color + self._background_style = Style(bgcolor=self._background_color) + + def get_style_for_token(self, token_type: TokenType) -> Style: + """Get a style from a Pygments class.""" + try: + return self._style_cache[token_type] + except KeyError: + try: + pygments_style = self._pygments_style_class.style_for_token(token_type) + except KeyError: + style = Style.null() + else: + color = pygments_style["color"] + bgcolor = pygments_style["bgcolor"] + style = Style( + color="#" + color if color else "#000000", + bgcolor="#" + bgcolor if bgcolor else self._background_color, + bold=pygments_style["bold"], + italic=pygments_style["italic"], + underline=pygments_style["underline"], + ) + self._style_cache[token_type] = style + return style + + def get_background_style(self) -> Style: + return self._background_style + + +class ANSISyntaxTheme(SyntaxTheme): + """Syntax theme to use standard colors.""" + + def __init__(self, style_map: Dict[TokenType, Style]) -> None: + self.style_map = style_map + self._missing_style = Style.null() + self._background_style = Style.null() + self._style_cache: Dict[TokenType, Style] = {} + + def get_style_for_token(self, token_type: TokenType) -> Style: + """Look up style in the style map.""" + try: + return self._style_cache[token_type] + except KeyError: + # Styles form a hierarchy + # We need to go from most to least specific + # e.g. ("foo", "bar", "baz") to ("foo", "bar") to ("foo",) + get_style = self.style_map.get + token = tuple(token_type) + style = self._missing_style + while token: + _style = get_style(token) + if _style is not None: + style = _style + break + token = token[:-1] + self._style_cache[token_type] = style + return style + + def get_background_style(self) -> Style: + return self._background_style + + +SyntaxPosition = Tuple[int, int] + + +class _SyntaxHighlightRange(NamedTuple): + """ + A range to highlight in a Syntax object. + `start` and `end` are 2-integers tuples, where the first integer is the line number + (starting from 1) and the second integer is the column index (starting from 0). + """ + + style: StyleType + start: SyntaxPosition + end: SyntaxPosition + style_before: bool = False + + +class Syntax(JupyterMixin): + """Construct a Syntax object to render syntax highlighted code. + + Args: + code (str): Code to highlight. + lexer (Lexer | str): Lexer to use (see https://pygments.org/docs/lexers/) + theme (str, optional): Color theme, aka Pygments style (see https://pygments.org/docs/styles/#getting-a-list-of-available-styles). Defaults to "monokai". + dedent (bool, optional): Enable stripping of initial whitespace. Defaults to False. + line_numbers (bool, optional): Enable rendering of line numbers. Defaults to False. + start_line (int, optional): Starting number for line numbers. Defaults to 1. + line_range (Tuple[int | None, int | None], optional): If given should be a tuple of the start and end line to render. + A value of None in the tuple indicates the range is open in that direction. + highlight_lines (Set[int]): A set of line numbers to highlight. + code_width: Width of code to render (not including line numbers), or ``None`` to use all available width. + tab_size (int, optional): Size of tabs. Defaults to 4. + word_wrap (bool, optional): Enable word wrapping. + background_color (str, optional): Optional background color, or None to use theme color. Defaults to None. + indent_guides (bool, optional): Show indent guides. Defaults to False. + padding (PaddingDimensions): Padding to apply around the syntax. Defaults to 0 (no padding). + """ + + _pygments_style_class: Type[PygmentsStyle] + _theme: SyntaxTheme + + @classmethod + def get_theme(cls, name: Union[str, SyntaxTheme]) -> SyntaxTheme: + """Get a syntax theme instance.""" + if isinstance(name, SyntaxTheme): + return name + theme: SyntaxTheme + if name in RICH_SYNTAX_THEMES: + theme = ANSISyntaxTheme(RICH_SYNTAX_THEMES[name]) + else: + theme = PygmentsSyntaxTheme(name) + return theme + + def __init__( + self, + code: str, + lexer: Union[Lexer, str], + *, + theme: Union[str, SyntaxTheme] = DEFAULT_THEME, + dedent: bool = False, + line_numbers: bool = False, + start_line: int = 1, + line_range: Optional[Tuple[Optional[int], Optional[int]]] = None, + highlight_lines: Optional[Set[int]] = None, + code_width: Optional[int] = None, + tab_size: int = 4, + word_wrap: bool = False, + background_color: Optional[str] = None, + indent_guides: bool = False, + padding: PaddingDimensions = 0, + ) -> None: + self.code = code + self._lexer = lexer + self.dedent = dedent + self.line_numbers = line_numbers + self.start_line = start_line + self.line_range = line_range + self.highlight_lines = highlight_lines or set() + self.code_width = code_width + self.tab_size = tab_size + self.word_wrap = word_wrap + self.background_color = background_color + self.background_style = ( + Style(bgcolor=background_color) if background_color else Style() + ) + self.indent_guides = indent_guides + self.padding = padding + + self._theme = self.get_theme(theme) + self._stylized_ranges: List[_SyntaxHighlightRange] = [] + + @classmethod + def from_path( + cls, + path: str, + encoding: str = "utf-8", + lexer: Optional[Union[Lexer, str]] = None, + theme: Union[str, SyntaxTheme] = DEFAULT_THEME, + dedent: bool = False, + line_numbers: bool = False, + line_range: Optional[Tuple[int, int]] = None, + start_line: int = 1, + highlight_lines: Optional[Set[int]] = None, + code_width: Optional[int] = None, + tab_size: int = 4, + word_wrap: bool = False, + background_color: Optional[str] = None, + indent_guides: bool = False, + padding: PaddingDimensions = 0, + ) -> "Syntax": + """Construct a Syntax object from a file. + + Args: + path (str): Path to file to highlight. + encoding (str): Encoding of file. + lexer (str | Lexer, optional): Lexer to use. If None, lexer will be auto-detected from path/file content. + theme (str, optional): Color theme, aka Pygments style (see https://pygments.org/docs/styles/#getting-a-list-of-available-styles). Defaults to "emacs". + dedent (bool, optional): Enable stripping of initial whitespace. Defaults to True. + line_numbers (bool, optional): Enable rendering of line numbers. Defaults to False. + start_line (int, optional): Starting number for line numbers. Defaults to 1. + line_range (Tuple[int, int], optional): If given should be a tuple of the start and end line to render. + highlight_lines (Set[int]): A set of line numbers to highlight. + code_width: Width of code to render (not including line numbers), or ``None`` to use all available width. + tab_size (int, optional): Size of tabs. Defaults to 4. + word_wrap (bool, optional): Enable word wrapping of code. + background_color (str, optional): Optional background color, or None to use theme color. Defaults to None. + indent_guides (bool, optional): Show indent guides. Defaults to False. + padding (PaddingDimensions): Padding to apply around the syntax. Defaults to 0 (no padding). + + Returns: + [Syntax]: A Syntax object that may be printed to the console + """ + code = Path(path).read_text(encoding=encoding) + + if not lexer: + lexer = cls.guess_lexer(path, code=code) + + return cls( + code, + lexer, + theme=theme, + dedent=dedent, + line_numbers=line_numbers, + line_range=line_range, + start_line=start_line, + highlight_lines=highlight_lines, + code_width=code_width, + tab_size=tab_size, + word_wrap=word_wrap, + background_color=background_color, + indent_guides=indent_guides, + padding=padding, + ) + + @classmethod + def guess_lexer(cls, path: str, code: Optional[str] = None) -> str: + """Guess the alias of the Pygments lexer to use based on a path and an optional string of code. + If code is supplied, it will use a combination of the code and the filename to determine the + best lexer to use. For example, if the file is ``index.html`` and the file contains Django + templating syntax, then "html+django" will be returned. If the file is ``index.html``, and no + templating language is used, the "html" lexer will be used. If no string of code + is supplied, the lexer will be chosen based on the file extension.. + + Args: + path (AnyStr): The path to the file containing the code you wish to know the lexer for. + code (str, optional): Optional string of code that will be used as a fallback if no lexer + is found for the supplied path. + + Returns: + str: The name of the Pygments lexer that best matches the supplied path/code. + """ + lexer: Optional[Lexer] = None + lexer_name = "default" + if code: + try: + lexer = guess_lexer_for_filename(path, code) + except ClassNotFound: + pass + + if not lexer: + try: + _, ext = os.path.splitext(path) + if ext: + extension = ext.lstrip(".").lower() + lexer = get_lexer_by_name(extension) + except ClassNotFound: + pass + + if lexer: + if lexer.aliases: + lexer_name = lexer.aliases[0] + else: + lexer_name = lexer.name + + return lexer_name + + def _get_base_style(self) -> Style: + """Get the base style.""" + default_style = self._theme.get_background_style() + self.background_style + return default_style + + def _get_token_color(self, token_type: TokenType) -> Optional[Color]: + """Get a color (if any) for the given token. + + Args: + token_type (TokenType): A token type tuple from Pygments. + + Returns: + Optional[Color]: Color from theme, or None for no color. + """ + style = self._theme.get_style_for_token(token_type) + return style.color + + @property + def lexer(self) -> Optional[Lexer]: + """The lexer for this syntax, or None if no lexer was found. + + Tries to find the lexer by name if a string was passed to the constructor. + """ + + if isinstance(self._lexer, Lexer): + return self._lexer + try: + return get_lexer_by_name( + self._lexer, + stripnl=False, + ensurenl=True, + tabsize=self.tab_size, + ) + except ClassNotFound: + return None + + @property + def default_lexer(self) -> Lexer: + """A Pygments Lexer to use if one is not specified or invalid.""" + return get_lexer_by_name( + "text", + stripnl=False, + ensurenl=True, + tabsize=self.tab_size, + ) + + def highlight( + self, + code: str, + line_range: Optional[Tuple[Optional[int], Optional[int]]] = None, + ) -> Text: + """Highlight code and return a Text instance. + + Args: + code (str): Code to highlight. + line_range(Tuple[int, int], optional): Optional line range to highlight. + + Returns: + Text: A text instance containing highlighted syntax. + """ + + base_style = self._get_base_style() + justify: JustifyMethod = ( + "default" if base_style.transparent_background else "left" + ) + + text = Text( + justify=justify, + style=base_style, + tab_size=self.tab_size, + no_wrap=not self.word_wrap, + ) + _get_theme_style = self._theme.get_style_for_token + + lexer = self.lexer or self.default_lexer + + if lexer is None: + text.append(code) + else: + if line_range: + # More complicated path to only stylize a portion of the code + # This speeds up further operations as there are less spans to process + line_start, line_end = line_range + + def line_tokenize() -> Iterable[Tuple[Any, str]]: + """Split tokens to one per line.""" + assert lexer # required to make MyPy happy - we know lexer is not None at this point + + for token_type, token in lexer.get_tokens(code): + while token: + line_token, new_line, token = token.partition("\n") + yield token_type, line_token + new_line + + def tokens_to_spans() -> Iterable[Tuple[str, Optional[Style]]]: + """Convert tokens to spans.""" + tokens = iter(line_tokenize()) + line_no = 0 + _line_start = line_start - 1 if line_start else 0 + + # Skip over tokens until line start + while line_no < _line_start: + try: + _token_type, token = next(tokens) + except StopIteration: + break + yield (token, None) + if token.endswith("\n"): + line_no += 1 + # Generate spans until line end + for token_type, token in tokens: + yield (token, _get_theme_style(token_type)) + if token.endswith("\n"): + line_no += 1 + if line_end and line_no >= line_end: + break + + text.append_tokens(tokens_to_spans()) + + else: + text.append_tokens( + (token, _get_theme_style(token_type)) + for token_type, token in lexer.get_tokens(code) + ) + if self.background_color is not None: + text.stylize(f"on {self.background_color}") + + if self._stylized_ranges: + self._apply_stylized_ranges(text) + + return text + + def stylize_range( + self, + style: StyleType, + start: SyntaxPosition, + end: SyntaxPosition, + style_before: bool = False, + ) -> None: + """ + Adds a custom style on a part of the code, that will be applied to the syntax display when it's rendered. + Line numbers are 1-based, while column indexes are 0-based. + + Args: + style (StyleType): The style to apply. + start (Tuple[int, int]): The start of the range, in the form `[line number, column index]`. + end (Tuple[int, int]): The end of the range, in the form `[line number, column index]`. + style_before (bool): Apply the style before any existing styles. + """ + self._stylized_ranges.append( + _SyntaxHighlightRange(style, start, end, style_before) + ) + + def _get_line_numbers_color(self, blend: float = 0.3) -> Color: + background_style = self._theme.get_background_style() + self.background_style + background_color = background_style.bgcolor + if background_color is None or background_color.is_system_defined: + return Color.default() + foreground_color = self._get_token_color(Token.Text) + if foreground_color is None or foreground_color.is_system_defined: + return foreground_color or Color.default() + new_color = blend_rgb( + background_color.get_truecolor(), + foreground_color.get_truecolor(), + cross_fade=blend, + ) + return Color.from_triplet(new_color) + + @property + def _numbers_column_width(self) -> int: + """Get the number of characters used to render the numbers column.""" + column_width = 0 + if self.line_numbers: + column_width = ( + len(str(self.start_line + self.code.count("\n"))) + + NUMBERS_COLUMN_DEFAULT_PADDING + ) + return column_width + + def _get_number_styles(self, console: Console) -> Tuple[Style, Style, Style]: + """Get background, number, and highlight styles for line numbers.""" + background_style = self._get_base_style() + if background_style.transparent_background: + return Style.null(), Style(dim=True), Style.null() + if console.color_system in ("256", "truecolor"): + number_style = Style.chain( + background_style, + self._theme.get_style_for_token(Token.Text), + Style(color=self._get_line_numbers_color()), + self.background_style, + ) + highlight_number_style = Style.chain( + background_style, + self._theme.get_style_for_token(Token.Text), + Style(bold=True, color=self._get_line_numbers_color(0.9)), + self.background_style, + ) + else: + number_style = background_style + Style(dim=True) + highlight_number_style = background_style + Style(dim=False) + return background_style, number_style, highlight_number_style + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + _, right, _, left = Padding.unpack(self.padding) + padding = left + right + if self.code_width is not None: + width = self.code_width + self._numbers_column_width + padding + 1 + return Measurement(self._numbers_column_width, width) + lines = self.code.splitlines() + width = ( + self._numbers_column_width + + padding + + (max(cell_len(line) for line in lines) if lines else 0) + ) + if self.line_numbers: + width += 1 + return Measurement(self._numbers_column_width, width) + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + segments = Segments(self._get_syntax(console, options)) + if self.padding: + yield Padding(segments, style=self._get_base_style(), pad=self.padding) + else: + yield segments + + def _get_syntax( + self, + console: Console, + options: ConsoleOptions, + ) -> Iterable[Segment]: + """ + Get the Segments for the Syntax object, excluding any vertical/horizontal padding + """ + transparent_background = self._get_base_style().transparent_background + code_width = ( + ( + (options.max_width - self._numbers_column_width - 1) + if self.line_numbers + else options.max_width + ) + if self.code_width is None + else self.code_width + ) + + ends_on_nl, processed_code = self._process_code(self.code) + text = self.highlight(processed_code, self.line_range) + + if not self.line_numbers and not self.word_wrap and not self.line_range: + if not ends_on_nl: + text.remove_suffix("\n") + # Simple case of just rendering text + style = ( + self._get_base_style() + + self._theme.get_style_for_token(Comment) + + Style(dim=True) + + self.background_style + ) + if self.indent_guides and not options.ascii_only: + text = text.with_indent_guides(self.tab_size, style=style) + text.overflow = "crop" + if style.transparent_background: + yield from console.render( + text, options=options.update(width=code_width) + ) + else: + syntax_lines = console.render_lines( + text, + options.update(width=code_width, height=None, justify="left"), + style=self.background_style, + pad=True, + new_lines=True, + ) + for syntax_line in syntax_lines: + yield from syntax_line + return + + start_line, end_line = self.line_range or (None, None) + line_offset = 0 + if start_line: + line_offset = max(0, start_line - 1) + lines: Union[List[Text], Lines] = text.split("\n", allow_blank=ends_on_nl) + if self.line_range: + if line_offset > len(lines): + return + lines = lines[line_offset:end_line] + + if self.indent_guides and not options.ascii_only: + style = ( + self._get_base_style() + + self._theme.get_style_for_token(Comment) + + Style(dim=True) + + self.background_style + ) + lines = ( + Text("\n") + .join(lines) + .with_indent_guides(self.tab_size, style=style + Style(italic=False)) + .split("\n", allow_blank=True) + ) + + numbers_column_width = self._numbers_column_width + render_options = options.update(width=code_width) + + highlight_line = self.highlight_lines.__contains__ + _Segment = Segment + new_line = _Segment("\n") + + line_pointer = "> " if options.legacy_windows else "❱ " + + ( + background_style, + number_style, + highlight_number_style, + ) = self._get_number_styles(console) + + for line_no, line in enumerate(lines, self.start_line + line_offset): + if self.word_wrap: + wrapped_lines = console.render_lines( + line, + render_options.update(height=None, justify="left"), + style=background_style, + pad=not transparent_background, + ) + else: + segments = list(line.render(console, end="")) + if options.no_wrap: + wrapped_lines = [segments] + else: + wrapped_lines = [ + _Segment.adjust_line_length( + segments, + render_options.max_width, + style=background_style, + pad=not transparent_background, + ) + ] + + if self.line_numbers: + wrapped_line_left_pad = _Segment( + " " * numbers_column_width + " ", background_style + ) + for first, wrapped_line in loop_first(wrapped_lines): + if first: + line_column = str(line_no).rjust(numbers_column_width - 2) + " " + if highlight_line(line_no): + yield _Segment(line_pointer, Style(color="red")) + yield _Segment(line_column, highlight_number_style) + else: + yield _Segment(" ", highlight_number_style) + yield _Segment(line_column, number_style) + else: + yield wrapped_line_left_pad + yield from wrapped_line + yield new_line + else: + for wrapped_line in wrapped_lines: + yield from wrapped_line + yield new_line + + def _apply_stylized_ranges(self, text: Text) -> None: + """ + Apply stylized ranges to a text instance, + using the given code to determine the right portion to apply the style to. + + Args: + text (Text): Text instance to apply the style to. + """ + code = text.plain + newlines_offsets = [ + # Let's add outer boundaries at each side of the list: + 0, + # N.B. using "\n" here is much faster than using metacharacters such as "^" or "\Z": + *[ + match.start() + 1 + for match in re.finditer("\n", code, flags=re.MULTILINE) + ], + len(code) + 1, + ] + + for stylized_range in self._stylized_ranges: + start = _get_code_index_for_syntax_position( + newlines_offsets, stylized_range.start + ) + end = _get_code_index_for_syntax_position( + newlines_offsets, stylized_range.end + ) + if start is not None and end is not None: + if stylized_range.style_before: + text.stylize_before(stylized_range.style, start, end) + else: + text.stylize(stylized_range.style, start, end) + + def _process_code(self, code: str) -> Tuple[bool, str]: + """ + Applies various processing to a raw code string + (normalises it so it always ends with a line return, dedents it if necessary, etc.) + + Args: + code (str): The raw code string to process + + Returns: + Tuple[bool, str]: the boolean indicates whether the raw code ends with a line return, + while the string is the processed code. + """ + ends_on_nl = code.endswith("\n") + processed_code = code if ends_on_nl else code + "\n" + processed_code = ( + textwrap.dedent(processed_code) if self.dedent else processed_code + ) + processed_code = processed_code.expandtabs(self.tab_size) + return ends_on_nl, processed_code + + +def _get_code_index_for_syntax_position( + newlines_offsets: Sequence[int], position: SyntaxPosition +) -> Optional[int]: + """ + Returns the index of the code string for the given positions. + + Args: + newlines_offsets (Sequence[int]): The offset of each newline character found in the code snippet. + position (SyntaxPosition): The position to search for. + + Returns: + Optional[int]: The index of the code string for this position, or `None` + if the given position's line number is out of range (if it's the column that is out of range + we silently clamp its value so that it reaches the end of the line) + """ + lines_count = len(newlines_offsets) + + line_number, column_index = position + if line_number > lines_count or len(newlines_offsets) < (line_number + 1): + return None # `line_number` is out of range + line_index = line_number - 1 + line_length = newlines_offsets[line_index + 1] - newlines_offsets[line_index] - 1 + # If `column_index` is out of range: let's silently clamp it: + column_index = min(line_length, column_index) + return newlines_offsets[line_index] + column_index + + +if __name__ == "__main__": # pragma: no cover + import argparse + import sys + + parser = argparse.ArgumentParser( + description="Render syntax to the console with Rich" + ) + parser.add_argument( + "path", + metavar="PATH", + help="path to file, or - for stdin", + ) + parser.add_argument( + "-c", + "--force-color", + dest="force_color", + action="store_true", + default=None, + help="force color for non-terminals", + ) + parser.add_argument( + "-i", + "--indent-guides", + dest="indent_guides", + action="store_true", + default=False, + help="display indent guides", + ) + parser.add_argument( + "-l", + "--line-numbers", + dest="line_numbers", + action="store_true", + help="render line numbers", + ) + parser.add_argument( + "-w", + "--width", + type=int, + dest="width", + default=None, + help="width of output (default will auto-detect)", + ) + parser.add_argument( + "-r", + "--wrap", + dest="word_wrap", + action="store_true", + default=False, + help="word wrap long lines", + ) + parser.add_argument( + "-s", + "--soft-wrap", + action="store_true", + dest="soft_wrap", + default=False, + help="enable soft wrapping mode", + ) + parser.add_argument( + "-t", "--theme", dest="theme", default="monokai", help="pygments theme" + ) + parser.add_argument( + "-b", + "--background-color", + dest="background_color", + default=None, + help="Override background color", + ) + parser.add_argument( + "-x", + "--lexer", + default=None, + dest="lexer_name", + help="Lexer name", + ) + parser.add_argument( + "-p", "--padding", type=int, default=0, dest="padding", help="Padding" + ) + parser.add_argument( + "--highlight-line", + type=int, + default=None, + dest="highlight_line", + help="The line number (not index!) to highlight", + ) + args = parser.parse_args() + + from pip._vendor.rich.console import Console + + console = Console(force_terminal=args.force_color, width=args.width) + + if args.path == "-": + code = sys.stdin.read() + syntax = Syntax( + code=code, + lexer=args.lexer_name, + line_numbers=args.line_numbers, + word_wrap=args.word_wrap, + theme=args.theme, + background_color=args.background_color, + indent_guides=args.indent_guides, + padding=args.padding, + highlight_lines={args.highlight_line}, + ) + else: + syntax = Syntax.from_path( + args.path, + lexer=args.lexer_name, + line_numbers=args.line_numbers, + word_wrap=args.word_wrap, + theme=args.theme, + background_color=args.background_color, + indent_guides=args.indent_guides, + padding=args.padding, + highlight_lines={args.highlight_line}, + ) + console.print(syntax, soft_wrap=args.soft_wrap) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/table.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/table.py new file mode 100644 index 0000000..654c855 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/table.py @@ -0,0 +1,1007 @@ +from dataclasses import dataclass, field, replace +from typing import ( + TYPE_CHECKING, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Sequence, + Tuple, + Union, +) + +from . import box, errors +from ._loop import loop_first_last, loop_last +from ._pick import pick_bool +from ._ratio import ratio_distribute, ratio_reduce +from .align import VerticalAlignMethod +from .jupyter import JupyterMixin +from .measure import Measurement +from .padding import Padding, PaddingDimensions +from .protocol import is_renderable +from .segment import Segment +from .style import Style, StyleType +from .text import Text, TextType + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + JustifyMethod, + OverflowMethod, + RenderableType, + RenderResult, + ) + + +@dataclass +class Column: + """Defines a column within a ~Table. + + Args: + title (Union[str, Text], optional): The title of the table rendered at the top. Defaults to None. + caption (Union[str, Text], optional): The table caption rendered below. Defaults to None. + width (int, optional): The width in characters of the table, or ``None`` to automatically fit. Defaults to None. + min_width (Optional[int], optional): The minimum width of the table, or ``None`` for no minimum. Defaults to None. + box (box.Box, optional): One of the constants in box.py used to draw the edges (see :ref:`appendix_box`), or ``None`` for no box lines. Defaults to box.HEAVY_HEAD. + safe_box (Optional[bool], optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True. + padding (PaddingDimensions, optional): Padding for cells (top, right, bottom, left). Defaults to (0, 1). + collapse_padding (bool, optional): Enable collapsing of padding around cells. Defaults to False. + pad_edge (bool, optional): Enable padding of edge cells. Defaults to True. + expand (bool, optional): Expand the table to fit the available space if ``True``, otherwise the table width will be auto-calculated. Defaults to False. + show_header (bool, optional): Show a header row. Defaults to True. + show_footer (bool, optional): Show a footer row. Defaults to False. + show_edge (bool, optional): Draw a box around the outside of the table. Defaults to True. + show_lines (bool, optional): Draw lines between every row. Defaults to False. + leading (int, optional): Number of blank lines between rows (precludes ``show_lines``). Defaults to 0. + style (Union[str, Style], optional): Default style for the table. Defaults to "none". + row_styles (List[Union, str], optional): Optional list of row styles, if more than one style is given then the styles will alternate. Defaults to None. + header_style (Union[str, Style], optional): Style of the header. Defaults to "table.header". + footer_style (Union[str, Style], optional): Style of the footer. Defaults to "table.footer". + border_style (Union[str, Style], optional): Style of the border. Defaults to None. + title_style (Union[str, Style], optional): Style of the title. Defaults to None. + caption_style (Union[str, Style], optional): Style of the caption. Defaults to None. + title_justify (str, optional): Justify method for title. Defaults to "center". + caption_justify (str, optional): Justify method for caption. Defaults to "center". + highlight (bool, optional): Highlight cell contents (if str). Defaults to False. + """ + + header: "RenderableType" = "" + """RenderableType: Renderable for the header (typically a string)""" + + footer: "RenderableType" = "" + """RenderableType: Renderable for the footer (typically a string)""" + + header_style: StyleType = "" + """StyleType: The style of the header.""" + + footer_style: StyleType = "" + """StyleType: The style of the footer.""" + + style: StyleType = "" + """StyleType: The style of the column.""" + + justify: "JustifyMethod" = "left" + """str: How to justify text within the column ("left", "center", "right", or "full")""" + + vertical: "VerticalAlignMethod" = "top" + """str: How to vertically align content ("top", "middle", or "bottom")""" + + overflow: "OverflowMethod" = "ellipsis" + """str: Overflow method.""" + + width: Optional[int] = None + """Optional[int]: Width of the column, or ``None`` (default) to auto calculate width.""" + + min_width: Optional[int] = None + """Optional[int]: Minimum width of column, or ``None`` for no minimum. Defaults to None.""" + + max_width: Optional[int] = None + """Optional[int]: Maximum width of column, or ``None`` for no maximum. Defaults to None.""" + + ratio: Optional[int] = None + """Optional[int]: Ratio to use when calculating column width, or ``None`` (default) to adapt to column contents.""" + + no_wrap: bool = False + """bool: Prevent wrapping of text within the column. Defaults to ``False``.""" + + highlight: bool = False + """bool: Apply highlighter to column. Defaults to ``False``.""" + + _index: int = 0 + """Index of column.""" + + _cells: List["RenderableType"] = field(default_factory=list) + + def copy(self) -> "Column": + """Return a copy of this Column.""" + return replace(self, _cells=[]) + + @property + def cells(self) -> Iterable["RenderableType"]: + """Get all cells in the column, not including header.""" + yield from self._cells + + @property + def flexible(self) -> bool: + """Check if this column is flexible.""" + return self.ratio is not None + + +@dataclass +class Row: + """Information regarding a row.""" + + style: Optional[StyleType] = None + """Style to apply to row.""" + + end_section: bool = False + """Indicated end of section, which will force a line beneath the row.""" + + +class _Cell(NamedTuple): + """A single cell in a table.""" + + style: StyleType + """Style to apply to cell.""" + renderable: "RenderableType" + """Cell renderable.""" + vertical: VerticalAlignMethod + """Cell vertical alignment.""" + + +class Table(JupyterMixin): + """A console renderable to draw a table. + + Args: + *headers (Union[Column, str]): Column headers, either as a string, or :class:`~rich.table.Column` instance. + title (Union[str, Text], optional): The title of the table rendered at the top. Defaults to None. + caption (Union[str, Text], optional): The table caption rendered below. Defaults to None. + width (int, optional): The width in characters of the table, or ``None`` to automatically fit. Defaults to None. + min_width (Optional[int], optional): The minimum width of the table, or ``None`` for no minimum. Defaults to None. + box (box.Box, optional): One of the constants in box.py used to draw the edges (see :ref:`appendix_box`), or ``None`` for no box lines. Defaults to box.HEAVY_HEAD. + safe_box (Optional[bool], optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True. + padding (PaddingDimensions, optional): Padding for cells (top, right, bottom, left). Defaults to (0, 1). + collapse_padding (bool, optional): Enable collapsing of padding around cells. Defaults to False. + pad_edge (bool, optional): Enable padding of edge cells. Defaults to True. + expand (bool, optional): Expand the table to fit the available space if ``True``, otherwise the table width will be auto-calculated. Defaults to False. + show_header (bool, optional): Show a header row. Defaults to True. + show_footer (bool, optional): Show a footer row. Defaults to False. + show_edge (bool, optional): Draw a box around the outside of the table. Defaults to True. + show_lines (bool, optional): Draw lines between every row. Defaults to False. + leading (int, optional): Number of blank lines between rows (precludes ``show_lines``). Defaults to 0. + style (Union[str, Style], optional): Default style for the table. Defaults to "none". + row_styles (List[Union, str], optional): Optional list of row styles, if more than one style is given then the styles will alternate. Defaults to None. + header_style (Union[str, Style], optional): Style of the header. Defaults to "table.header". + footer_style (Union[str, Style], optional): Style of the footer. Defaults to "table.footer". + border_style (Union[str, Style], optional): Style of the border. Defaults to None. + title_style (Union[str, Style], optional): Style of the title. Defaults to None. + caption_style (Union[str, Style], optional): Style of the caption. Defaults to None. + title_justify (str, optional): Justify method for title. Defaults to "center". + caption_justify (str, optional): Justify method for caption. Defaults to "center". + highlight (bool, optional): Highlight cell contents (if str). Defaults to False. + """ + + columns: List[Column] + rows: List[Row] + + def __init__( + self, + *headers: Union[Column, str], + title: Optional[TextType] = None, + caption: Optional[TextType] = None, + width: Optional[int] = None, + min_width: Optional[int] = None, + box: Optional[box.Box] = box.HEAVY_HEAD, + safe_box: Optional[bool] = None, + padding: PaddingDimensions = (0, 1), + collapse_padding: bool = False, + pad_edge: bool = True, + expand: bool = False, + show_header: bool = True, + show_footer: bool = False, + show_edge: bool = True, + show_lines: bool = False, + leading: int = 0, + style: StyleType = "none", + row_styles: Optional[Iterable[StyleType]] = None, + header_style: Optional[StyleType] = "table.header", + footer_style: Optional[StyleType] = "table.footer", + border_style: Optional[StyleType] = None, + title_style: Optional[StyleType] = None, + caption_style: Optional[StyleType] = None, + title_justify: "JustifyMethod" = "center", + caption_justify: "JustifyMethod" = "center", + highlight: bool = False, + ) -> None: + self.columns: List[Column] = [] + self.rows: List[Row] = [] + self.title = title + self.caption = caption + self.width = width + self.min_width = min_width + self.box = box + self.safe_box = safe_box + self._padding = Padding.unpack(padding) + self.pad_edge = pad_edge + self._expand = expand + self.show_header = show_header + self.show_footer = show_footer + self.show_edge = show_edge + self.show_lines = show_lines + self.leading = leading + self.collapse_padding = collapse_padding + self.style = style + self.header_style = header_style or "" + self.footer_style = footer_style or "" + self.border_style = border_style + self.title_style = title_style + self.caption_style = caption_style + self.title_justify: "JustifyMethod" = title_justify + self.caption_justify: "JustifyMethod" = caption_justify + self.highlight = highlight + self.row_styles: Sequence[StyleType] = list(row_styles or []) + append_column = self.columns.append + for header in headers: + if isinstance(header, str): + self.add_column(header=header) + else: + header._index = len(self.columns) + append_column(header) + + @classmethod + def grid( + cls, + *headers: Union[Column, str], + padding: PaddingDimensions = 0, + collapse_padding: bool = True, + pad_edge: bool = False, + expand: bool = False, + ) -> "Table": + """Get a table with no lines, headers, or footer. + + Args: + *headers (Union[Column, str]): Column headers, either as a string, or :class:`~rich.table.Column` instance. + padding (PaddingDimensions, optional): Get padding around cells. Defaults to 0. + collapse_padding (bool, optional): Enable collapsing of padding around cells. Defaults to True. + pad_edge (bool, optional): Enable padding around edges of table. Defaults to False. + expand (bool, optional): Expand the table to fit the available space if ``True``, otherwise the table width will be auto-calculated. Defaults to False. + + Returns: + Table: A table instance. + """ + return cls( + *headers, + box=None, + padding=padding, + collapse_padding=collapse_padding, + show_header=False, + show_footer=False, + show_edge=False, + pad_edge=pad_edge, + expand=expand, + ) + + @property + def expand(self) -> bool: + """Setting a non-None self.width implies expand.""" + return self._expand or self.width is not None + + @expand.setter + def expand(self, expand: bool) -> None: + """Set expand.""" + self._expand = expand + + @property + def _extra_width(self) -> int: + """Get extra width to add to cell content.""" + width = 0 + if self.box and self.show_edge: + width += 2 + if self.box: + width += len(self.columns) - 1 + return width + + @property + def row_count(self) -> int: + """Get the current number of rows.""" + return len(self.rows) + + def get_row_style(self, console: "Console", index: int) -> StyleType: + """Get the current row style.""" + style = Style.null() + if self.row_styles: + style += console.get_style(self.row_styles[index % len(self.row_styles)]) + row_style = self.rows[index].style + if row_style is not None: + style += console.get_style(row_style) + return style + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + max_width = options.max_width + if self.width is not None: + max_width = self.width + if max_width < 0: + return Measurement(0, 0) + + extra_width = self._extra_width + max_width = sum( + self._calculate_column_widths( + console, options.update_width(max_width - extra_width) + ) + ) + _measure_column = self._measure_column + + measurements = [ + _measure_column(console, options.update_width(max_width), column) + for column in self.columns + ] + minimum_width = ( + sum(measurement.minimum for measurement in measurements) + extra_width + ) + maximum_width = ( + sum(measurement.maximum for measurement in measurements) + extra_width + if (self.width is None) + else self.width + ) + measurement = Measurement(minimum_width, maximum_width) + measurement = measurement.clamp(self.min_width) + return measurement + + @property + def padding(self) -> Tuple[int, int, int, int]: + """Get cell padding.""" + return self._padding + + @padding.setter + def padding(self, padding: PaddingDimensions) -> "Table": + """Set cell padding.""" + self._padding = Padding.unpack(padding) + return self + + def add_column( + self, + header: "RenderableType" = "", + footer: "RenderableType" = "", + *, + header_style: Optional[StyleType] = None, + highlight: Optional[bool] = None, + footer_style: Optional[StyleType] = None, + style: Optional[StyleType] = None, + justify: "JustifyMethod" = "left", + vertical: "VerticalAlignMethod" = "top", + overflow: "OverflowMethod" = "ellipsis", + width: Optional[int] = None, + min_width: Optional[int] = None, + max_width: Optional[int] = None, + ratio: Optional[int] = None, + no_wrap: bool = False, + ) -> None: + """Add a column to the table. + + Args: + header (RenderableType, optional): Text or renderable for the header. + Defaults to "". + footer (RenderableType, optional): Text or renderable for the footer. + Defaults to "". + header_style (Union[str, Style], optional): Style for the header, or None for default. Defaults to None. + highlight (bool, optional): Whether to highlight the text. The default of None uses the value of the table (self) object. + footer_style (Union[str, Style], optional): Style for the footer, or None for default. Defaults to None. + style (Union[str, Style], optional): Style for the column cells, or None for default. Defaults to None. + justify (JustifyMethod, optional): Alignment for cells. Defaults to "left". + vertical (VerticalAlignMethod, optional): Vertical alignment, one of "top", "middle", or "bottom". Defaults to "top". + overflow (OverflowMethod): Overflow method: "crop", "fold", "ellipsis". Defaults to "ellipsis". + width (int, optional): Desired width of column in characters, or None to fit to contents. Defaults to None. + min_width (Optional[int], optional): Minimum width of column, or ``None`` for no minimum. Defaults to None. + max_width (Optional[int], optional): Maximum width of column, or ``None`` for no maximum. Defaults to None. + ratio (int, optional): Flexible ratio for the column (requires ``Table.expand`` or ``Table.width``). Defaults to None. + no_wrap (bool, optional): Set to ``True`` to disable wrapping of this column. + """ + + column = Column( + _index=len(self.columns), + header=header, + footer=footer, + header_style=header_style or "", + highlight=highlight if highlight is not None else self.highlight, + footer_style=footer_style or "", + style=style or "", + justify=justify, + vertical=vertical, + overflow=overflow, + width=width, + min_width=min_width, + max_width=max_width, + ratio=ratio, + no_wrap=no_wrap, + ) + self.columns.append(column) + + def add_row( + self, + *renderables: Optional["RenderableType"], + style: Optional[StyleType] = None, + end_section: bool = False, + ) -> None: + """Add a row of renderables. + + Args: + *renderables (None or renderable): Each cell in a row must be a renderable object (including str), + or ``None`` for a blank cell. + style (StyleType, optional): An optional style to apply to the entire row. Defaults to None. + end_section (bool, optional): End a section and draw a line. Defaults to False. + + Raises: + errors.NotRenderableError: If you add something that can't be rendered. + """ + + def add_cell(column: Column, renderable: "RenderableType") -> None: + column._cells.append(renderable) + + cell_renderables: List[Optional["RenderableType"]] = list(renderables) + + columns = self.columns + if len(cell_renderables) < len(columns): + cell_renderables = [ + *cell_renderables, + *[None] * (len(columns) - len(cell_renderables)), + ] + for index, renderable in enumerate(cell_renderables): + if index == len(columns): + column = Column(_index=index, highlight=self.highlight) + for _ in self.rows: + add_cell(column, Text("")) + self.columns.append(column) + else: + column = columns[index] + if renderable is None: + add_cell(column, "") + elif is_renderable(renderable): + add_cell(column, renderable) + else: + raise errors.NotRenderableError( + f"unable to render {type(renderable).__name__}; a string or other renderable object is required" + ) + self.rows.append(Row(style=style, end_section=end_section)) + + def add_section(self) -> None: + """Add a new section (draw a line after current row).""" + + if self.rows: + self.rows[-1].end_section = True + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if not self.columns: + yield Segment("\n") + return + + max_width = options.max_width + if self.width is not None: + max_width = self.width + + extra_width = self._extra_width + widths = self._calculate_column_widths( + console, options.update_width(max_width - extra_width) + ) + table_width = sum(widths) + extra_width + + render_options = options.update( + width=table_width, highlight=self.highlight, height=None + ) + + def render_annotation( + text: TextType, style: StyleType, justify: "JustifyMethod" = "center" + ) -> "RenderResult": + render_text = ( + console.render_str(text, style=style, highlight=False) + if isinstance(text, str) + else text + ) + return console.render( + render_text, options=render_options.update(justify=justify) + ) + + if self.title: + yield from render_annotation( + self.title, + style=Style.pick_first(self.title_style, "table.title"), + justify=self.title_justify, + ) + yield from self._render(console, render_options, widths) + if self.caption: + yield from render_annotation( + self.caption, + style=Style.pick_first(self.caption_style, "table.caption"), + justify=self.caption_justify, + ) + + def _calculate_column_widths( + self, console: "Console", options: "ConsoleOptions" + ) -> List[int]: + """Calculate the widths of each column, including padding, not including borders.""" + max_width = options.max_width + columns = self.columns + width_ranges = [ + self._measure_column(console, options, column) for column in columns + ] + widths = [_range.maximum or 1 for _range in width_ranges] + get_padding_width = self._get_padding_width + extra_width = self._extra_width + if self.expand: + ratios = [col.ratio or 0 for col in columns if col.flexible] + if any(ratios): + fixed_widths = [ + 0 if column.flexible else _range.maximum + for _range, column in zip(width_ranges, columns) + ] + flex_minimum = [ + (column.width or 1) + get_padding_width(column._index) + for column in columns + if column.flexible + ] + flexible_width = max_width - sum(fixed_widths) + flex_widths = ratio_distribute(flexible_width, ratios, flex_minimum) + iter_flex_widths = iter(flex_widths) + for index, column in enumerate(columns): + if column.flexible: + widths[index] = fixed_widths[index] + next(iter_flex_widths) + table_width = sum(widths) + + if table_width > max_width: + widths = self._collapse_widths( + widths, + [(column.width is None and not column.no_wrap) for column in columns], + max_width, + ) + table_width = sum(widths) + # last resort, reduce columns evenly + if table_width > max_width: + excess_width = table_width - max_width + widths = ratio_reduce(excess_width, [1] * len(widths), widths, widths) + table_width = sum(widths) + + width_ranges = [ + self._measure_column(console, options.update_width(width), column) + for width, column in zip(widths, columns) + ] + widths = [_range.maximum or 0 for _range in width_ranges] + + if (table_width < max_width and self.expand) or ( + self.min_width is not None and table_width < (self.min_width - extra_width) + ): + _max_width = ( + max_width + if self.min_width is None + else min(self.min_width - extra_width, max_width) + ) + pad_widths = ratio_distribute(_max_width - table_width, widths) + widths = [_width + pad for _width, pad in zip(widths, pad_widths)] + + return widths + + @classmethod + def _collapse_widths( + cls, widths: List[int], wrapable: List[bool], max_width: int + ) -> List[int]: + """Reduce widths so that the total is under max_width. + + Args: + widths (List[int]): List of widths. + wrapable (List[bool]): List of booleans that indicate if a column may shrink. + max_width (int): Maximum width to reduce to. + + Returns: + List[int]: A new list of widths. + """ + total_width = sum(widths) + excess_width = total_width - max_width + if any(wrapable): + while total_width and excess_width > 0: + max_column = max( + width for width, allow_wrap in zip(widths, wrapable) if allow_wrap + ) + second_max_column = max( + width if allow_wrap and width != max_column else 0 + for width, allow_wrap in zip(widths, wrapable) + ) + column_difference = max_column - second_max_column + ratios = [ + (1 if (width == max_column and allow_wrap) else 0) + for width, allow_wrap in zip(widths, wrapable) + ] + if not any(ratios) or not column_difference: + break + max_reduce = [min(excess_width, column_difference)] * len(widths) + widths = ratio_reduce(excess_width, ratios, max_reduce, widths) + + total_width = sum(widths) + excess_width = total_width - max_width + return widths + + def _get_cells( + self, console: "Console", column_index: int, column: Column + ) -> Iterable[_Cell]: + """Get all the cells with padding and optional header.""" + + collapse_padding = self.collapse_padding + pad_edge = self.pad_edge + padding = self.padding + any_padding = any(padding) + + first_column = column_index == 0 + last_column = column_index == len(self.columns) - 1 + + _padding_cache: Dict[Tuple[bool, bool], Tuple[int, int, int, int]] = {} + + def get_padding(first_row: bool, last_row: bool) -> Tuple[int, int, int, int]: + cached = _padding_cache.get((first_row, last_row)) + if cached: + return cached + top, right, bottom, left = padding + + if collapse_padding: + if not first_column: + left = max(0, left - right) + if not last_row: + bottom = max(0, top - bottom) + + if not pad_edge: + if first_column: + left = 0 + if last_column: + right = 0 + if first_row: + top = 0 + if last_row: + bottom = 0 + _padding = (top, right, bottom, left) + _padding_cache[(first_row, last_row)] = _padding + return _padding + + raw_cells: List[Tuple[StyleType, "RenderableType"]] = [] + _append = raw_cells.append + get_style = console.get_style + if self.show_header: + header_style = get_style(self.header_style or "") + get_style( + column.header_style + ) + _append((header_style, column.header)) + cell_style = get_style(column.style or "") + for cell in column.cells: + _append((cell_style, cell)) + if self.show_footer: + footer_style = get_style(self.footer_style or "") + get_style( + column.footer_style + ) + _append((footer_style, column.footer)) + + if any_padding: + _Padding = Padding + for first, last, (style, renderable) in loop_first_last(raw_cells): + yield _Cell( + style, + _Padding(renderable, get_padding(first, last)), + getattr(renderable, "vertical", None) or column.vertical, + ) + else: + for style, renderable in raw_cells: + yield _Cell( + style, + renderable, + getattr(renderable, "vertical", None) or column.vertical, + ) + + def _get_padding_width(self, column_index: int) -> int: + """Get extra width from padding.""" + _, pad_right, _, pad_left = self.padding + if self.collapse_padding: + if column_index > 0: + pad_left = max(0, pad_left - pad_right) + return pad_left + pad_right + + def _measure_column( + self, + console: "Console", + options: "ConsoleOptions", + column: Column, + ) -> Measurement: + """Get the minimum and maximum width of the column.""" + + max_width = options.max_width + if max_width < 1: + return Measurement(0, 0) + + padding_width = self._get_padding_width(column._index) + + if column.width is not None: + # Fixed width column + return Measurement( + column.width + padding_width, column.width + padding_width + ).with_maximum(max_width) + # Flexible column, we need to measure contents + min_widths: List[int] = [] + max_widths: List[int] = [] + append_min = min_widths.append + append_max = max_widths.append + get_render_width = Measurement.get + for cell in self._get_cells(console, column._index, column): + _min, _max = get_render_width(console, options, cell.renderable) + append_min(_min) + append_max(_max) + + measurement = Measurement( + max(min_widths) if min_widths else 1, + max(max_widths) if max_widths else max_width, + ).with_maximum(max_width) + measurement = measurement.clamp( + None if column.min_width is None else column.min_width + padding_width, + None if column.max_width is None else column.max_width + padding_width, + ) + return measurement + + def _render( + self, console: "Console", options: "ConsoleOptions", widths: List[int] + ) -> "RenderResult": + table_style = console.get_style(self.style or "") + + border_style = table_style + console.get_style(self.border_style or "") + _column_cells = ( + self._get_cells(console, column_index, column) + for column_index, column in enumerate(self.columns) + ) + row_cells: List[Tuple[_Cell, ...]] = list(zip(*_column_cells)) + _box = ( + self.box.substitute( + options, safe=pick_bool(self.safe_box, console.safe_box) + ) + if self.box + else None + ) + _box = _box.get_plain_headed_box() if _box and not self.show_header else _box + + new_line = Segment.line() + + columns = self.columns + show_header = self.show_header + show_footer = self.show_footer + show_edge = self.show_edge + show_lines = self.show_lines + leading = self.leading + + _Segment = Segment + if _box: + box_segments = [ + ( + _Segment(_box.head_left, border_style), + _Segment(_box.head_right, border_style), + _Segment(_box.head_vertical, border_style), + ), + ( + _Segment(_box.mid_left, border_style), + _Segment(_box.mid_right, border_style), + _Segment(_box.mid_vertical, border_style), + ), + ( + _Segment(_box.foot_left, border_style), + _Segment(_box.foot_right, border_style), + _Segment(_box.foot_vertical, border_style), + ), + ] + if show_edge: + yield _Segment(_box.get_top(widths), border_style) + yield new_line + else: + box_segments = [] + + get_row_style = self.get_row_style + get_style = console.get_style + + for index, (first, last, row_cell) in enumerate(loop_first_last(row_cells)): + header_row = first and show_header + footer_row = last and show_footer + row = ( + self.rows[index - show_header] + if (not header_row and not footer_row) + else None + ) + max_height = 1 + cells: List[List[List[Segment]]] = [] + if header_row or footer_row: + row_style = Style.null() + else: + row_style = get_style( + get_row_style(console, index - 1 if show_header else index) + ) + for width, cell, column in zip(widths, row_cell, columns): + render_options = options.update( + width=width, + justify=column.justify, + no_wrap=column.no_wrap, + overflow=column.overflow, + height=None, + highlight=column.highlight, + ) + lines = console.render_lines( + cell.renderable, + render_options, + style=get_style(cell.style) + row_style, + ) + max_height = max(max_height, len(lines)) + cells.append(lines) + + row_height = max(len(cell) for cell in cells) + + def align_cell( + cell: List[List[Segment]], + vertical: "VerticalAlignMethod", + width: int, + style: Style, + ) -> List[List[Segment]]: + if header_row: + vertical = "bottom" + elif footer_row: + vertical = "top" + + if vertical == "top": + return _Segment.align_top(cell, width, row_height, style) + elif vertical == "middle": + return _Segment.align_middle(cell, width, row_height, style) + return _Segment.align_bottom(cell, width, row_height, style) + + cells[:] = [ + _Segment.set_shape( + align_cell( + cell, + _cell.vertical, + width, + get_style(_cell.style) + row_style, + ), + width, + max_height, + ) + for width, _cell, cell, column in zip(widths, row_cell, cells, columns) + ] + + if _box: + if last and show_footer: + yield _Segment( + _box.get_row(widths, "foot", edge=show_edge), border_style + ) + yield new_line + left, right, _divider = box_segments[0 if first else (2 if last else 1)] + + # If the column divider is whitespace also style it with the row background + divider = ( + _divider + if _divider.text.strip() + else _Segment( + _divider.text, row_style.background_style + _divider.style + ) + ) + for line_no in range(max_height): + if show_edge: + yield left + for last_cell, rendered_cell in loop_last(cells): + yield from rendered_cell[line_no] + if not last_cell: + yield divider + if show_edge: + yield right + yield new_line + else: + for line_no in range(max_height): + for rendered_cell in cells: + yield from rendered_cell[line_no] + yield new_line + if _box and first and show_header: + yield _Segment( + _box.get_row(widths, "head", edge=show_edge), border_style + ) + yield new_line + end_section = row and row.end_section + if _box and (show_lines or leading or end_section): + if ( + not last + and not (show_footer and index >= len(row_cells) - 2) + and not (show_header and header_row) + ): + if leading: + yield _Segment( + _box.get_row(widths, "mid", edge=show_edge) * leading, + border_style, + ) + else: + yield _Segment( + _box.get_row(widths, "row", edge=show_edge), border_style + ) + yield new_line + + if _box and show_edge: + yield _Segment(_box.get_bottom(widths), border_style) + yield new_line + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + from pip._vendor.rich.highlighter import ReprHighlighter + from pip._vendor.rich.table import Table as Table + + from ._timer import timer + + with timer("Table render"): + table = Table( + title="Star Wars Movies", + caption="Rich example table", + caption_justify="right", + ) + + table.add_column( + "Released", header_style="bright_cyan", style="cyan", no_wrap=True + ) + table.add_column("Title", style="magenta") + table.add_column("Box Office", justify="right", style="green") + + table.add_row( + "Dec 20, 2019", + "Star Wars: The Rise of Skywalker", + "$952,110,690", + ) + table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347") + table.add_row( + "Dec 15, 2017", + "Star Wars Ep. V111: The Last Jedi", + "$1,332,539,889", + style="on black", + end_section=True, + ) + table.add_row( + "Dec 16, 2016", + "Rogue One: A Star Wars Story", + "$1,332,439,889", + ) + + def header(text: str) -> None: + console.print() + console.rule(highlight(text)) + console.print() + + console = Console() + highlight = ReprHighlighter() + header("Example Table") + console.print(table, justify="center") + + table.expand = True + header("expand=True") + console.print(table) + + table.width = 50 + header("width=50") + + console.print(table, justify="center") + + table.width = None + table.expand = False + table.row_styles = ["dim", "none"] + header("row_styles=['dim', 'none']") + + console.print(table, justify="center") + + table.width = None + table.expand = False + table.row_styles = ["dim", "none"] + table.leading = 1 + header("leading=1, row_styles=['dim', 'none']") + console.print(table, justify="center") + + table.width = None + table.expand = False + table.row_styles = ["dim", "none"] + table.show_lines = True + table.leading = 0 + header("show_lines=True, row_styles=['dim', 'none']") + console.print(table, justify="center") diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py new file mode 100644 index 0000000..565e9d9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py @@ -0,0 +1,153 @@ +from typing import List, Optional, Tuple + +from .color_triplet import ColorTriplet +from .palette import Palette + +_ColorTuple = Tuple[int, int, int] + + +class TerminalTheme: + """A color theme used when exporting console content. + + Args: + background (Tuple[int, int, int]): The background color. + foreground (Tuple[int, int, int]): The foreground (text) color. + normal (List[Tuple[int, int, int]]): A list of 8 normal intensity colors. + bright (List[Tuple[int, int, int]], optional): A list of 8 bright colors, or None + to repeat normal intensity. Defaults to None. + """ + + def __init__( + self, + background: _ColorTuple, + foreground: _ColorTuple, + normal: List[_ColorTuple], + bright: Optional[List[_ColorTuple]] = None, + ) -> None: + self.background_color = ColorTriplet(*background) + self.foreground_color = ColorTriplet(*foreground) + self.ansi_colors = Palette(normal + (bright or normal)) + + +DEFAULT_TERMINAL_THEME = TerminalTheme( + (255, 255, 255), + (0, 0, 0), + [ + (0, 0, 0), + (128, 0, 0), + (0, 128, 0), + (128, 128, 0), + (0, 0, 128), + (128, 0, 128), + (0, 128, 128), + (192, 192, 192), + ], + [ + (128, 128, 128), + (255, 0, 0), + (0, 255, 0), + (255, 255, 0), + (0, 0, 255), + (255, 0, 255), + (0, 255, 255), + (255, 255, 255), + ], +) + +MONOKAI = TerminalTheme( + (12, 12, 12), + (217, 217, 217), + [ + (26, 26, 26), + (244, 0, 95), + (152, 224, 36), + (253, 151, 31), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (196, 197, 181), + (98, 94, 76), + ], + [ + (244, 0, 95), + (152, 224, 36), + (224, 213, 97), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (246, 246, 239), + ], +) +DIMMED_MONOKAI = TerminalTheme( + (25, 25, 25), + (185, 188, 186), + [ + (58, 61, 67), + (190, 63, 72), + (135, 154, 59), + (197, 166, 53), + (79, 118, 161), + (133, 92, 141), + (87, 143, 164), + (185, 188, 186), + (136, 137, 135), + ], + [ + (251, 0, 31), + (15, 114, 47), + (196, 112, 51), + (24, 109, 227), + (251, 0, 103), + (46, 112, 109), + (253, 255, 185), + ], +) +NIGHT_OWLISH = TerminalTheme( + (255, 255, 255), + (64, 63, 83), + [ + (1, 22, 39), + (211, 66, 62), + (42, 162, 152), + (218, 170, 1), + (72, 118, 214), + (64, 63, 83), + (8, 145, 106), + (122, 129, 129), + (122, 129, 129), + ], + [ + (247, 110, 110), + (73, 208, 197), + (218, 194, 107), + (92, 167, 228), + (105, 112, 152), + (0, 201, 144), + (152, 159, 177), + ], +) + +SVG_EXPORT_THEME = TerminalTheme( + (41, 41, 41), + (197, 200, 198), + [ + (75, 78, 85), + (204, 85, 90), + (152, 168, 75), + (208, 179, 68), + (96, 138, 177), + (152, 114, 159), + (104, 160, 179), + (197, 200, 198), + (154, 155, 153), + ], + [ + (255, 38, 39), + (0, 130, 61), + (208, 132, 66), + (25, 132, 233), + (255, 44, 122), + (57, 130, 128), + (253, 253, 197), + ], +) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/text.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/text.py new file mode 100644 index 0000000..5a0c6b1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/text.py @@ -0,0 +1,1361 @@ +import re +from functools import partial, reduce +from math import gcd +from operator import itemgetter +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Pattern, + Tuple, + Union, +) + +from ._loop import loop_last +from ._pick import pick_bool +from ._wrap import divide_line +from .align import AlignMethod +from .cells import cell_len, set_cell_size +from .containers import Lines +from .control import strip_control_codes +from .emoji import EmojiVariant +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style, StyleType + +if TYPE_CHECKING: # pragma: no cover + from .console import Console, ConsoleOptions, JustifyMethod, OverflowMethod + +DEFAULT_JUSTIFY: "JustifyMethod" = "default" +DEFAULT_OVERFLOW: "OverflowMethod" = "fold" + + +_re_whitespace = re.compile(r"\s+$") + +TextType = Union[str, "Text"] +"""A plain string or a :class:`Text` instance.""" + +GetStyleCallable = Callable[[str], Optional[StyleType]] + + +class Span(NamedTuple): + """A marked up region in some text.""" + + start: int + """Span start index.""" + end: int + """Span end index.""" + style: Union[str, Style] + """Style associated with the span.""" + + def __repr__(self) -> str: + return f"Span({self.start}, {self.end}, {self.style!r})" + + def __bool__(self) -> bool: + return self.end > self.start + + def split(self, offset: int) -> Tuple["Span", Optional["Span"]]: + """Split a span in to 2 from a given offset.""" + + if offset < self.start: + return self, None + if offset >= self.end: + return self, None + + start, end, style = self + span1 = Span(start, min(end, offset), style) + span2 = Span(span1.end, end, style) + return span1, span2 + + def move(self, offset: int) -> "Span": + """Move start and end by a given offset. + + Args: + offset (int): Number of characters to add to start and end. + + Returns: + TextSpan: A new TextSpan with adjusted position. + """ + start, end, style = self + return Span(start + offset, end + offset, style) + + def right_crop(self, offset: int) -> "Span": + """Crop the span at the given offset. + + Args: + offset (int): A value between start and end. + + Returns: + Span: A new (possibly smaller) span. + """ + start, end, style = self + if offset >= end: + return self + return Span(start, min(offset, end), style) + + def extend(self, cells: int) -> "Span": + """Extend the span by the given number of cells. + + Args: + cells (int): Additional space to add to end of span. + + Returns: + Span: A span. + """ + if cells: + start, end, style = self + return Span(start, end + cells, style) + else: + return self + + +class Text(JupyterMixin): + """Text with color / style. + + Args: + text (str, optional): Default unstyled text. Defaults to "". + style (Union[str, Style], optional): Base style for text. Defaults to "". + justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None. + overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None. + no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None. + end (str, optional): Character to end text with. Defaults to "\\\\n". + tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None. + spans (List[Span], optional). A list of predefined style spans. Defaults to None. + """ + + __slots__ = [ + "_text", + "style", + "justify", + "overflow", + "no_wrap", + "end", + "tab_size", + "_spans", + "_length", + ] + + def __init__( + self, + text: str = "", + style: Union[str, Style] = "", + *, + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + no_wrap: Optional[bool] = None, + end: str = "\n", + tab_size: Optional[int] = None, + spans: Optional[List[Span]] = None, + ) -> None: + sanitized_text = strip_control_codes(text) + self._text = [sanitized_text] + self.style = style + self.justify: Optional["JustifyMethod"] = justify + self.overflow: Optional["OverflowMethod"] = overflow + self.no_wrap = no_wrap + self.end = end + self.tab_size = tab_size + self._spans: List[Span] = spans or [] + self._length: int = len(sanitized_text) + + def __len__(self) -> int: + return self._length + + def __bool__(self) -> bool: + return bool(self._length) + + def __str__(self) -> str: + return self.plain + + def __repr__(self) -> str: + return f"" + + def __add__(self, other: Any) -> "Text": + if isinstance(other, (str, Text)): + result = self.copy() + result.append(other) + return result + return NotImplemented + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Text): + return NotImplemented + return self.plain == other.plain and self._spans == other._spans + + def __contains__(self, other: object) -> bool: + if isinstance(other, str): + return other in self.plain + elif isinstance(other, Text): + return other.plain in self.plain + return False + + def __getitem__(self, slice: Union[int, slice]) -> "Text": + def get_text_at(offset: int) -> "Text": + _Span = Span + text = Text( + self.plain[offset], + spans=[ + _Span(0, 1, style) + for start, end, style in self._spans + if end > offset >= start + ], + end="", + ) + return text + + if isinstance(slice, int): + return get_text_at(slice) + else: + start, stop, step = slice.indices(len(self.plain)) + if step == 1: + lines = self.divide([start, stop]) + return lines[1] + else: + # This would be a bit of work to implement efficiently + # For now, its not required + raise TypeError("slices with step!=1 are not supported") + + @property + def cell_len(self) -> int: + """Get the number of cells required to render this text.""" + return cell_len(self.plain) + + @property + def markup(self) -> str: + """Get console markup to render this Text. + + Returns: + str: A string potentially creating markup tags. + """ + from .markup import escape + + output: List[str] = [] + + plain = self.plain + markup_spans = [ + (0, False, self.style), + *((span.start, False, span.style) for span in self._spans), + *((span.end, True, span.style) for span in self._spans), + (len(plain), True, self.style), + ] + markup_spans.sort(key=itemgetter(0, 1)) + position = 0 + append = output.append + for offset, closing, style in markup_spans: + if offset > position: + append(escape(plain[position:offset])) + position = offset + if style: + append(f"[/{style}]" if closing else f"[{style}]") + markup = "".join(output) + return markup + + @classmethod + def from_markup( + cls, + text: str, + *, + style: Union[str, Style] = "", + emoji: bool = True, + emoji_variant: Optional[EmojiVariant] = None, + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + end: str = "\n", + ) -> "Text": + """Create Text instance from markup. + + Args: + text (str): A string containing console markup. + style (Union[str, Style], optional): Base style for text. Defaults to "". + emoji (bool, optional): Also render emoji code. Defaults to True. + emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None. + justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None. + overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None. + end (str, optional): Character to end text with. Defaults to "\\\\n". + + Returns: + Text: A Text instance with markup rendered. + """ + from .markup import render + + rendered_text = render(text, style, emoji=emoji, emoji_variant=emoji_variant) + rendered_text.justify = justify + rendered_text.overflow = overflow + rendered_text.end = end + return rendered_text + + @classmethod + def from_ansi( + cls, + text: str, + *, + style: Union[str, Style] = "", + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + no_wrap: Optional[bool] = None, + end: str = "\n", + tab_size: Optional[int] = 8, + ) -> "Text": + """Create a Text object from a string containing ANSI escape codes. + + Args: + text (str): A string containing escape codes. + style (Union[str, Style], optional): Base style for text. Defaults to "". + justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None. + overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None. + no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None. + end (str, optional): Character to end text with. Defaults to "\\\\n". + tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None. + """ + from .ansi import AnsiDecoder + + joiner = Text( + "\n", + justify=justify, + overflow=overflow, + no_wrap=no_wrap, + end=end, + tab_size=tab_size, + style=style, + ) + decoder = AnsiDecoder() + result = joiner.join(line for line in decoder.decode(text)) + return result + + @classmethod + def styled( + cls, + text: str, + style: StyleType = "", + *, + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + ) -> "Text": + """Construct a Text instance with a pre-applied styled. A style applied in this way won't be used + to pad the text when it is justified. + + Args: + text (str): A string containing console markup. + style (Union[str, Style]): Style to apply to the text. Defaults to "". + justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None. + overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None. + + Returns: + Text: A text instance with a style applied to the entire string. + """ + styled_text = cls(text, justify=justify, overflow=overflow) + styled_text.stylize(style) + return styled_text + + @classmethod + def assemble( + cls, + *parts: Union[str, "Text", Tuple[str, StyleType]], + style: Union[str, Style] = "", + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + no_wrap: Optional[bool] = None, + end: str = "\n", + tab_size: int = 8, + meta: Optional[Dict[str, Any]] = None, + ) -> "Text": + """Construct a text instance by combining a sequence of strings with optional styles. + The positional arguments should be either strings, or a tuple of string + style. + + Args: + style (Union[str, Style], optional): Base style for text. Defaults to "". + justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None. + overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None. + no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None. + end (str, optional): Character to end text with. Defaults to "\\\\n". + tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None. + meta (Dict[str, Any], optional). Meta data to apply to text, or None for no meta data. Default to None + + Returns: + Text: A new text instance. + """ + text = cls( + style=style, + justify=justify, + overflow=overflow, + no_wrap=no_wrap, + end=end, + tab_size=tab_size, + ) + append = text.append + _Text = Text + for part in parts: + if isinstance(part, (_Text, str)): + append(part) + else: + append(*part) + if meta: + text.apply_meta(meta) + return text + + @property + def plain(self) -> str: + """Get the text as a single string.""" + if len(self._text) != 1: + self._text[:] = ["".join(self._text)] + return self._text[0] + + @plain.setter + def plain(self, new_text: str) -> None: + """Set the text to a new value.""" + if new_text != self.plain: + sanitized_text = strip_control_codes(new_text) + self._text[:] = [sanitized_text] + old_length = self._length + self._length = len(sanitized_text) + if old_length > self._length: + self._trim_spans() + + @property + def spans(self) -> List[Span]: + """Get a reference to the internal list of spans.""" + return self._spans + + @spans.setter + def spans(self, spans: List[Span]) -> None: + """Set spans.""" + self._spans = spans[:] + + def blank_copy(self, plain: str = "") -> "Text": + """Return a new Text instance with copied metadata (but not the string or spans).""" + copy_self = Text( + plain, + style=self.style, + justify=self.justify, + overflow=self.overflow, + no_wrap=self.no_wrap, + end=self.end, + tab_size=self.tab_size, + ) + return copy_self + + def copy(self) -> "Text": + """Return a copy of this instance.""" + copy_self = Text( + self.plain, + style=self.style, + justify=self.justify, + overflow=self.overflow, + no_wrap=self.no_wrap, + end=self.end, + tab_size=self.tab_size, + ) + copy_self._spans[:] = self._spans + return copy_self + + def stylize( + self, + style: Union[str, Style], + start: int = 0, + end: Optional[int] = None, + ) -> None: + """Apply a style to the text, or a portion of the text. + + Args: + style (Union[str, Style]): Style instance or style definition to apply. + start (int): Start offset (negative indexing is supported). Defaults to 0. + end (Optional[int], optional): End offset (negative indexing is supported), or None for end of text. Defaults to None. + """ + if style: + length = len(self) + if start < 0: + start = length + start + if end is None: + end = length + if end < 0: + end = length + end + if start >= length or end <= start: + # Span not in text or not valid + return + self._spans.append(Span(start, min(length, end), style)) + + def stylize_before( + self, + style: Union[str, Style], + start: int = 0, + end: Optional[int] = None, + ) -> None: + """Apply a style to the text, or a portion of the text. Styles will be applied before other styles already present. + + Args: + style (Union[str, Style]): Style instance or style definition to apply. + start (int): Start offset (negative indexing is supported). Defaults to 0. + end (Optional[int], optional): End offset (negative indexing is supported), or None for end of text. Defaults to None. + """ + if style: + length = len(self) + if start < 0: + start = length + start + if end is None: + end = length + if end < 0: + end = length + end + if start >= length or end <= start: + # Span not in text or not valid + return + self._spans.insert(0, Span(start, min(length, end), style)) + + def apply_meta( + self, meta: Dict[str, Any], start: int = 0, end: Optional[int] = None + ) -> None: + """Apply metadata to the text, or a portion of the text. + + Args: + meta (Dict[str, Any]): A dict of meta information. + start (int): Start offset (negative indexing is supported). Defaults to 0. + end (Optional[int], optional): End offset (negative indexing is supported), or None for end of text. Defaults to None. + + """ + style = Style.from_meta(meta) + self.stylize(style, start=start, end=end) + + def on(self, meta: Optional[Dict[str, Any]] = None, **handlers: Any) -> "Text": + """Apply event handlers (used by Textual project). + + Example: + >>> from rich.text import Text + >>> text = Text("hello world") + >>> text.on(click="view.toggle('world')") + + Args: + meta (Dict[str, Any]): Mapping of meta information. + **handlers: Keyword args are prefixed with "@" to defined handlers. + + Returns: + Text: Self is returned to method may be chained. + """ + meta = {} if meta is None else meta + meta.update({f"@{key}": value for key, value in handlers.items()}) + self.stylize(Style.from_meta(meta)) + return self + + def remove_suffix(self, suffix: str) -> None: + """Remove a suffix if it exists. + + Args: + suffix (str): Suffix to remove. + """ + if self.plain.endswith(suffix): + self.right_crop(len(suffix)) + + def get_style_at_offset(self, console: "Console", offset: int) -> Style: + """Get the style of a character at give offset. + + Args: + console (~Console): Console where text will be rendered. + offset (int): Offset in to text (negative indexing supported) + + Returns: + Style: A Style instance. + """ + # TODO: This is a little inefficient, it is only used by full justify + if offset < 0: + offset = len(self) + offset + get_style = console.get_style + style = get_style(self.style).copy() + for start, end, span_style in self._spans: + if end > offset >= start: + style += get_style(span_style, default="") + return style + + def extend_style(self, spaces: int) -> None: + """Extend the Text given number of spaces where the spaces have the same style as the last character. + + Args: + spaces (int): Number of spaces to add to the Text. + """ + if spaces <= 0: + return + spans = self.spans + new_spaces = " " * spaces + if spans: + end_offset = len(self) + self._spans[:] = [ + span.extend(spaces) if span.end >= end_offset else span + for span in spans + ] + self._text.append(new_spaces) + self._length += spaces + else: + self.plain += new_spaces + + def highlight_regex( + self, + re_highlight: Union[Pattern[str], str], + style: Optional[Union[GetStyleCallable, StyleType]] = None, + *, + style_prefix: str = "", + ) -> int: + """Highlight text with a regular expression, where group names are + translated to styles. + + Args: + re_highlight (Union[re.Pattern, str]): A regular expression object or string. + style (Union[GetStyleCallable, StyleType]): Optional style to apply to whole match, or a callable + which accepts the matched text and returns a style. Defaults to None. + style_prefix (str, optional): Optional prefix to add to style group names. + + Returns: + int: Number of regex matches + """ + count = 0 + append_span = self._spans.append + _Span = Span + plain = self.plain + if isinstance(re_highlight, str): + re_highlight = re.compile(re_highlight) + for match in re_highlight.finditer(plain): + get_span = match.span + if style: + start, end = get_span() + match_style = style(plain[start:end]) if callable(style) else style + if match_style is not None and end > start: + append_span(_Span(start, end, match_style)) + + count += 1 + for name in match.groupdict().keys(): + start, end = get_span(name) + if start != -1 and end > start: + append_span(_Span(start, end, f"{style_prefix}{name}")) + return count + + def highlight_words( + self, + words: Iterable[str], + style: Union[str, Style], + *, + case_sensitive: bool = True, + ) -> int: + """Highlight words with a style. + + Args: + words (Iterable[str]): Words to highlight. + style (Union[str, Style]): Style to apply. + case_sensitive (bool, optional): Enable case sensitive matching. Defaults to True. + + Returns: + int: Number of words highlighted. + """ + re_words = "|".join(re.escape(word) for word in words) + add_span = self._spans.append + count = 0 + _Span = Span + for match in re.finditer( + re_words, self.plain, flags=0 if case_sensitive else re.IGNORECASE + ): + start, end = match.span(0) + add_span(_Span(start, end, style)) + count += 1 + return count + + def rstrip(self) -> None: + """Strip whitespace from end of text.""" + self.plain = self.plain.rstrip() + + def rstrip_end(self, size: int) -> None: + """Remove whitespace beyond a certain width at the end of the text. + + Args: + size (int): The desired size of the text. + """ + text_length = len(self) + if text_length > size: + excess = text_length - size + whitespace_match = _re_whitespace.search(self.plain) + if whitespace_match is not None: + whitespace_count = len(whitespace_match.group(0)) + self.right_crop(min(whitespace_count, excess)) + + def set_length(self, new_length: int) -> None: + """Set new length of the text, clipping or padding is required.""" + length = len(self) + if length != new_length: + if length < new_length: + self.pad_right(new_length - length) + else: + self.right_crop(length - new_length) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> Iterable[Segment]: + tab_size: int = console.tab_size if self.tab_size is None else self.tab_size + justify = self.justify or options.justify or DEFAULT_JUSTIFY + + overflow = self.overflow or options.overflow or DEFAULT_OVERFLOW + + lines = self.wrap( + console, + options.max_width, + justify=justify, + overflow=overflow, + tab_size=tab_size or 8, + no_wrap=pick_bool(self.no_wrap, options.no_wrap, False), + ) + all_lines = Text("\n").join(lines) + yield from all_lines.render(console, end=self.end) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + text = self.plain + lines = text.splitlines() + max_text_width = max(cell_len(line) for line in lines) if lines else 0 + words = text.split() + min_text_width = ( + max(cell_len(word) for word in words) if words else max_text_width + ) + return Measurement(min_text_width, max_text_width) + + def render(self, console: "Console", end: str = "") -> Iterable["Segment"]: + """Render the text as Segments. + + Args: + console (Console): Console instance. + end (Optional[str], optional): Optional end character. + + Returns: + Iterable[Segment]: Result of render that may be written to the console. + """ + _Segment = Segment + text = self.plain + if not self._spans: + yield Segment(text) + if end: + yield _Segment(end) + return + get_style = partial(console.get_style, default=Style.null()) + + enumerated_spans = list(enumerate(self._spans, 1)) + style_map = {index: get_style(span.style) for index, span in enumerated_spans} + style_map[0] = get_style(self.style) + + spans = [ + (0, False, 0), + *((span.start, False, index) for index, span in enumerated_spans), + *((span.end, True, index) for index, span in enumerated_spans), + (len(text), True, 0), + ] + spans.sort(key=itemgetter(0, 1)) + + stack: List[int] = [] + stack_append = stack.append + stack_pop = stack.remove + + style_cache: Dict[Tuple[Style, ...], Style] = {} + style_cache_get = style_cache.get + combine = Style.combine + + def get_current_style() -> Style: + """Construct current style from stack.""" + styles = tuple(style_map[_style_id] for _style_id in sorted(stack)) + cached_style = style_cache_get(styles) + if cached_style is not None: + return cached_style + current_style = combine(styles) + style_cache[styles] = current_style + return current_style + + for (offset, leaving, style_id), (next_offset, _, _) in zip(spans, spans[1:]): + if leaving: + stack_pop(style_id) + else: + stack_append(style_id) + if next_offset > offset: + yield _Segment(text[offset:next_offset], get_current_style()) + if end: + yield _Segment(end) + + def join(self, lines: Iterable["Text"]) -> "Text": + """Join text together with this instance as the separator. + + Args: + lines (Iterable[Text]): An iterable of Text instances to join. + + Returns: + Text: A new text instance containing join text. + """ + + new_text = self.blank_copy() + + def iter_text() -> Iterable["Text"]: + if self.plain: + for last, line in loop_last(lines): + yield line + if not last: + yield self + else: + yield from lines + + extend_text = new_text._text.extend + append_span = new_text._spans.append + extend_spans = new_text._spans.extend + offset = 0 + _Span = Span + + for text in iter_text(): + extend_text(text._text) + if text.style: + append_span(_Span(offset, offset + len(text), text.style)) + extend_spans( + _Span(offset + start, offset + end, style) + for start, end, style in text._spans + ) + offset += len(text) + new_text._length = offset + return new_text + + def expand_tabs(self, tab_size: Optional[int] = None) -> None: + """Converts tabs to spaces. + + Args: + tab_size (int, optional): Size of tabs. Defaults to 8. + + """ + if "\t" not in self.plain: + return + if tab_size is None: + tab_size = self.tab_size + if tab_size is None: + tab_size = 8 + + new_text: List[Text] = [] + append = new_text.append + + for line in self.split("\n", include_separator=True): + if "\t" not in line.plain: + append(line) + else: + cell_position = 0 + parts = line.split("\t", include_separator=True) + for part in parts: + if part.plain.endswith("\t"): + part._text[-1] = part._text[-1][:-1] + " " + cell_position += part.cell_len + tab_remainder = cell_position % tab_size + if tab_remainder: + spaces = tab_size - tab_remainder + part.extend_style(spaces) + cell_position += spaces + else: + cell_position += part.cell_len + append(part) + + result = Text("").join(new_text) + + self._text = [result.plain] + self._length = len(self.plain) + self._spans[:] = result._spans + + def truncate( + self, + max_width: int, + *, + overflow: Optional["OverflowMethod"] = None, + pad: bool = False, + ) -> None: + """Truncate text if it is longer that a given width. + + Args: + max_width (int): Maximum number of characters in text. + overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None, to use self.overflow. + pad (bool, optional): Pad with spaces if the length is less than max_width. Defaults to False. + """ + _overflow = overflow or self.overflow or DEFAULT_OVERFLOW + if _overflow != "ignore": + length = cell_len(self.plain) + if length > max_width: + if _overflow == "ellipsis": + self.plain = set_cell_size(self.plain, max_width - 1) + "…" + else: + self.plain = set_cell_size(self.plain, max_width) + if pad and length < max_width: + spaces = max_width - length + self._text = [f"{self.plain}{' ' * spaces}"] + self._length = len(self.plain) + + def _trim_spans(self) -> None: + """Remove or modify any spans that are over the end of the text.""" + max_offset = len(self.plain) + _Span = Span + self._spans[:] = [ + ( + span + if span.end < max_offset + else _Span(span.start, min(max_offset, span.end), span.style) + ) + for span in self._spans + if span.start < max_offset + ] + + def pad(self, count: int, character: str = " ") -> None: + """Pad left and right with a given number of characters. + + Args: + count (int): Width of padding. + character (str): The character to pad with. Must be a string of length 1. + """ + assert len(character) == 1, "Character must be a string of length 1" + if count: + pad_characters = character * count + self.plain = f"{pad_characters}{self.plain}{pad_characters}" + _Span = Span + self._spans[:] = [ + _Span(start + count, end + count, style) + for start, end, style in self._spans + ] + + def pad_left(self, count: int, character: str = " ") -> None: + """Pad the left with a given character. + + Args: + count (int): Number of characters to pad. + character (str, optional): Character to pad with. Defaults to " ". + """ + assert len(character) == 1, "Character must be a string of length 1" + if count: + self.plain = f"{character * count}{self.plain}" + _Span = Span + self._spans[:] = [ + _Span(start + count, end + count, style) + for start, end, style in self._spans + ] + + def pad_right(self, count: int, character: str = " ") -> None: + """Pad the right with a given character. + + Args: + count (int): Number of characters to pad. + character (str, optional): Character to pad with. Defaults to " ". + """ + assert len(character) == 1, "Character must be a string of length 1" + if count: + self.plain = f"{self.plain}{character * count}" + + def align(self, align: AlignMethod, width: int, character: str = " ") -> None: + """Align text to a given width. + + Args: + align (AlignMethod): One of "left", "center", or "right". + width (int): Desired width. + character (str, optional): Character to pad with. Defaults to " ". + """ + self.truncate(width) + excess_space = width - cell_len(self.plain) + if excess_space: + if align == "left": + self.pad_right(excess_space, character) + elif align == "center": + left = excess_space // 2 + self.pad_left(left, character) + self.pad_right(excess_space - left, character) + else: + self.pad_left(excess_space, character) + + def append( + self, text: Union["Text", str], style: Optional[Union[str, "Style"]] = None + ) -> "Text": + """Add text with an optional style. + + Args: + text (Union[Text, str]): A str or Text to append. + style (str, optional): A style name. Defaults to None. + + Returns: + Text: Returns self for chaining. + """ + + if not isinstance(text, (str, Text)): + raise TypeError("Only str or Text can be appended to Text") + + if len(text): + if isinstance(text, str): + sanitized_text = strip_control_codes(text) + self._text.append(sanitized_text) + offset = len(self) + text_length = len(sanitized_text) + if style: + self._spans.append(Span(offset, offset + text_length, style)) + self._length += text_length + elif isinstance(text, Text): + _Span = Span + if style is not None: + raise ValueError( + "style must not be set when appending Text instance" + ) + text_length = self._length + if text.style: + self._spans.append( + _Span(text_length, text_length + len(text), text.style) + ) + self._text.append(text.plain) + self._spans.extend( + _Span(start + text_length, end + text_length, style) + for start, end, style in text._spans.copy() + ) + self._length += len(text) + return self + + def append_text(self, text: "Text") -> "Text": + """Append another Text instance. This method is more performant that Text.append, but + only works for Text. + + Args: + text (Text): The Text instance to append to this instance. + + Returns: + Text: Returns self for chaining. + """ + _Span = Span + text_length = self._length + if text.style: + self._spans.append(_Span(text_length, text_length + len(text), text.style)) + self._text.append(text.plain) + self._spans.extend( + _Span(start + text_length, end + text_length, style) + for start, end, style in text._spans.copy() + ) + self._length += len(text) + return self + + def append_tokens( + self, tokens: Iterable[Tuple[str, Optional[StyleType]]] + ) -> "Text": + """Append iterable of str and style. Style may be a Style instance or a str style definition. + + Args: + tokens (Iterable[Tuple[str, Optional[StyleType]]]): An iterable of tuples containing str content and style. + + Returns: + Text: Returns self for chaining. + """ + append_text = self._text.append + append_span = self._spans.append + _Span = Span + offset = len(self) + for content, style in tokens: + content = strip_control_codes(content) + append_text(content) + if style: + append_span(_Span(offset, offset + len(content), style)) + offset += len(content) + self._length = offset + return self + + def copy_styles(self, text: "Text") -> None: + """Copy styles from another Text instance. + + Args: + text (Text): A Text instance to copy styles from, must be the same length. + """ + self._spans.extend(text._spans) + + def split( + self, + separator: str = "\n", + *, + include_separator: bool = False, + allow_blank: bool = False, + ) -> Lines: + """Split rich text in to lines, preserving styles. + + Args: + separator (str, optional): String to split on. Defaults to "\\\\n". + include_separator (bool, optional): Include the separator in the lines. Defaults to False. + allow_blank (bool, optional): Return a blank line if the text ends with a separator. Defaults to False. + + Returns: + List[RichText]: A list of rich text, one per line of the original. + """ + assert separator, "separator must not be empty" + + text = self.plain + if separator not in text: + return Lines([self.copy()]) + + if include_separator: + lines = self.divide( + match.end() for match in re.finditer(re.escape(separator), text) + ) + else: + + def flatten_spans() -> Iterable[int]: + for match in re.finditer(re.escape(separator), text): + start, end = match.span() + yield start + yield end + + lines = Lines( + line for line in self.divide(flatten_spans()) if line.plain != separator + ) + + if not allow_blank and text.endswith(separator): + lines.pop() + + return lines + + def divide(self, offsets: Iterable[int]) -> Lines: + """Divide text in to a number of lines at given offsets. + + Args: + offsets (Iterable[int]): Offsets used to divide text. + + Returns: + Lines: New RichText instances between offsets. + """ + _offsets = list(offsets) + + if not _offsets: + return Lines([self.copy()]) + + text = self.plain + text_length = len(text) + divide_offsets = [0, *_offsets, text_length] + line_ranges = list(zip(divide_offsets, divide_offsets[1:])) + + style = self.style + justify = self.justify + overflow = self.overflow + _Text = Text + new_lines = Lines( + _Text( + text[start:end], + style=style, + justify=justify, + overflow=overflow, + ) + for start, end in line_ranges + ) + if not self._spans: + return new_lines + + _line_appends = [line._spans.append for line in new_lines._lines] + line_count = len(line_ranges) + _Span = Span + + for span_start, span_end, style in self._spans: + lower_bound = 0 + upper_bound = line_count + start_line_no = (lower_bound + upper_bound) // 2 + + while True: + line_start, line_end = line_ranges[start_line_no] + if span_start < line_start: + upper_bound = start_line_no - 1 + elif span_start > line_end: + lower_bound = start_line_no + 1 + else: + break + start_line_no = (lower_bound + upper_bound) // 2 + + if span_end < line_end: + end_line_no = start_line_no + else: + end_line_no = lower_bound = start_line_no + upper_bound = line_count + + while True: + line_start, line_end = line_ranges[end_line_no] + if span_end < line_start: + upper_bound = end_line_no - 1 + elif span_end > line_end: + lower_bound = end_line_no + 1 + else: + break + end_line_no = (lower_bound + upper_bound) // 2 + + for line_no in range(start_line_no, end_line_no + 1): + line_start, line_end = line_ranges[line_no] + new_start = max(0, span_start - line_start) + new_end = min(span_end - line_start, line_end - line_start) + if new_end > new_start: + _line_appends[line_no](_Span(new_start, new_end, style)) + + return new_lines + + def right_crop(self, amount: int = 1) -> None: + """Remove a number of characters from the end of the text.""" + max_offset = len(self.plain) - amount + _Span = Span + self._spans[:] = [ + ( + span + if span.end < max_offset + else _Span(span.start, min(max_offset, span.end), span.style) + ) + for span in self._spans + if span.start < max_offset + ] + self._text = [self.plain[:-amount]] + self._length -= amount + + def wrap( + self, + console: "Console", + width: int, + *, + justify: Optional["JustifyMethod"] = None, + overflow: Optional["OverflowMethod"] = None, + tab_size: int = 8, + no_wrap: Optional[bool] = None, + ) -> Lines: + """Word wrap the text. + + Args: + console (Console): Console instance. + width (int): Number of cells available per line. + justify (str, optional): Justify method: "default", "left", "center", "full", "right". Defaults to "default". + overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None. + tab_size (int, optional): Default tab size. Defaults to 8. + no_wrap (bool, optional): Disable wrapping, Defaults to False. + + Returns: + Lines: Number of lines. + """ + wrap_justify = justify or self.justify or DEFAULT_JUSTIFY + wrap_overflow = overflow or self.overflow or DEFAULT_OVERFLOW + + no_wrap = pick_bool(no_wrap, self.no_wrap, False) or overflow == "ignore" + + lines = Lines() + for line in self.split(allow_blank=True): + if "\t" in line: + line.expand_tabs(tab_size) + if no_wrap: + new_lines = Lines([line]) + else: + offsets = divide_line(str(line), width, fold=wrap_overflow == "fold") + new_lines = line.divide(offsets) + for line in new_lines: + line.rstrip_end(width) + if wrap_justify: + new_lines.justify( + console, width, justify=wrap_justify, overflow=wrap_overflow + ) + for line in new_lines: + line.truncate(width, overflow=wrap_overflow) + lines.extend(new_lines) + return lines + + def fit(self, width: int) -> Lines: + """Fit the text in to given width by chopping in to lines. + + Args: + width (int): Maximum characters in a line. + + Returns: + Lines: Lines container. + """ + lines: Lines = Lines() + append = lines.append + for line in self.split(): + line.set_length(width) + append(line) + return lines + + def detect_indentation(self) -> int: + """Auto-detect indentation of code. + + Returns: + int: Number of spaces used to indent code. + """ + + _indentations = { + len(match.group(1)) + for match in re.finditer(r"^( *)(.*)$", self.plain, flags=re.MULTILINE) + } + + try: + indentation = ( + reduce(gcd, [indent for indent in _indentations if not indent % 2]) or 1 + ) + except TypeError: + indentation = 1 + + return indentation + + def with_indent_guides( + self, + indent_size: Optional[int] = None, + *, + character: str = "│", + style: StyleType = "dim green", + ) -> "Text": + """Adds indent guide lines to text. + + Args: + indent_size (Optional[int]): Size of indentation, or None to auto detect. Defaults to None. + character (str, optional): Character to use for indentation. Defaults to "│". + style (Union[Style, str], optional): Style of indent guides. + + Returns: + Text: New text with indentation guides. + """ + + _indent_size = self.detect_indentation() if indent_size is None else indent_size + + text = self.copy() + text.expand_tabs() + indent_line = f"{character}{' ' * (_indent_size - 1)}" + + re_indent = re.compile(r"^( *)(.*)$") + new_lines: List[Text] = [] + add_line = new_lines.append + blank_lines = 0 + for line in text.split(allow_blank=True): + match = re_indent.match(line.plain) + if not match or not match.group(2): + blank_lines += 1 + continue + indent = match.group(1) + full_indents, remaining_space = divmod(len(indent), _indent_size) + new_indent = f"{indent_line * full_indents}{' ' * remaining_space}" + line.plain = new_indent + line.plain[len(new_indent) :] + line.stylize(style, 0, len(new_indent)) + if blank_lines: + new_lines.extend([Text(new_indent, style=style)] * blank_lines) + blank_lines = 0 + add_line(line) + if blank_lines: + new_lines.extend([Text("", style=style)] * blank_lines) + + new_text = text.blank_copy("\n").join(new_lines) + return new_text + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + + text = Text( + """\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n""" + ) + text.highlight_words(["Lorem"], "bold") + text.highlight_words(["ipsum"], "italic") + + console = Console() + + console.rule("justify='left'") + console.print(text, style="red") + console.print() + + console.rule("justify='center'") + console.print(text, style="green", justify="center") + console.print() + + console.rule("justify='right'") + console.print(text, style="blue", justify="right") + console.print() + + console.rule("justify='full'") + console.print(text, style="magenta", justify="full") + console.print() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/theme.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/theme.py new file mode 100644 index 0000000..227f1d8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/theme.py @@ -0,0 +1,115 @@ +import configparser +from typing import IO, Dict, List, Mapping, Optional + +from .default_styles import DEFAULT_STYLES +from .style import Style, StyleType + + +class Theme: + """A container for style information, used by :class:`~rich.console.Console`. + + Args: + styles (Dict[str, Style], optional): A mapping of style names on to styles. Defaults to None for a theme with no styles. + inherit (bool, optional): Inherit default styles. Defaults to True. + """ + + styles: Dict[str, Style] + + def __init__( + self, styles: Optional[Mapping[str, StyleType]] = None, inherit: bool = True + ): + self.styles = DEFAULT_STYLES.copy() if inherit else {} + if styles is not None: + self.styles.update( + { + name: style if isinstance(style, Style) else Style.parse(style) + for name, style in styles.items() + } + ) + + @property + def config(self) -> str: + """Get contents of a config file for this theme.""" + config = "[styles]\n" + "\n".join( + f"{name} = {style}" for name, style in sorted(self.styles.items()) + ) + return config + + @classmethod + def from_file( + cls, config_file: IO[str], source: Optional[str] = None, inherit: bool = True + ) -> "Theme": + """Load a theme from a text mode file. + + Args: + config_file (IO[str]): An open conf file. + source (str, optional): The filename of the open file. Defaults to None. + inherit (bool, optional): Inherit default styles. Defaults to True. + + Returns: + Theme: A New theme instance. + """ + config = configparser.ConfigParser() + config.read_file(config_file, source=source) + styles = {name: Style.parse(value) for name, value in config.items("styles")} + theme = Theme(styles, inherit=inherit) + return theme + + @classmethod + def read( + cls, path: str, inherit: bool = True, encoding: Optional[str] = None + ) -> "Theme": + """Read a theme from a path. + + Args: + path (str): Path to a config file readable by Python configparser module. + inherit (bool, optional): Inherit default styles. Defaults to True. + encoding (str, optional): Encoding of the config file. Defaults to None. + + Returns: + Theme: A new theme instance. + """ + with open(path, encoding=encoding) as config_file: + return cls.from_file(config_file, source=path, inherit=inherit) + + +class ThemeStackError(Exception): + """Base exception for errors related to the theme stack.""" + + +class ThemeStack: + """A stack of themes. + + Args: + theme (Theme): A theme instance + """ + + def __init__(self, theme: Theme) -> None: + self._entries: List[Dict[str, Style]] = [theme.styles] + self.get = self._entries[-1].get + + def push_theme(self, theme: Theme, inherit: bool = True) -> None: + """Push a theme on the top of the stack. + + Args: + theme (Theme): A Theme instance. + inherit (boolean, optional): Inherit styles from current top of stack. + """ + styles: Dict[str, Style] + styles = ( + {**self._entries[-1], **theme.styles} if inherit else theme.styles.copy() + ) + self._entries.append(styles) + self.get = self._entries[-1].get + + def pop_theme(self) -> None: + """Pop (and discard) the top-most theme.""" + if len(self._entries) == 1: + raise ThemeStackError("Unable to pop base theme") + self._entries.pop() + self.get = self._entries[-1].get + + +if __name__ == "__main__": # pragma: no cover + theme = Theme() + print(theme.config) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/themes.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/themes.py new file mode 100644 index 0000000..bf6db10 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/themes.py @@ -0,0 +1,5 @@ +from .default_styles import DEFAULT_STYLES +from .theme import Theme + + +DEFAULT = Theme(DEFAULT_STYLES) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/traceback.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/traceback.py new file mode 100644 index 0000000..28d742b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/traceback.py @@ -0,0 +1,797 @@ +import inspect +import linecache +import os +import sys +from dataclasses import dataclass, field +from itertools import islice +from traceback import walk_tb +from types import ModuleType, TracebackType +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Optional, + Sequence, + Tuple, + Type, + Union, +) + +from pip._vendor.pygments.lexers import guess_lexer_for_filename +from pip._vendor.pygments.token import Comment, Keyword, Name, Number, Operator, String +from pip._vendor.pygments.token import Text as TextToken +from pip._vendor.pygments.token import Token +from pip._vendor.pygments.util import ClassNotFound + +from . import pretty +from ._loop import loop_last +from .columns import Columns +from .console import Console, ConsoleOptions, ConsoleRenderable, RenderResult, group +from .constrain import Constrain +from .highlighter import RegexHighlighter, ReprHighlighter +from .panel import Panel +from .scope import render_scope +from .style import Style +from .syntax import Syntax +from .text import Text +from .theme import Theme + +WINDOWS = sys.platform == "win32" + +LOCALS_MAX_LENGTH = 10 +LOCALS_MAX_STRING = 80 + + +def install( + *, + console: Optional[Console] = None, + width: Optional[int] = 100, + code_width: Optional[int] = 88, + extra_lines: int = 3, + theme: Optional[str] = None, + word_wrap: bool = False, + show_locals: bool = False, + locals_max_length: int = LOCALS_MAX_LENGTH, + locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: Optional[bool] = None, + indent_guides: bool = True, + suppress: Iterable[Union[str, ModuleType]] = (), + max_frames: int = 100, +) -> Callable[[Type[BaseException], BaseException, Optional[TracebackType]], Any]: + """Install a rich traceback handler. + + Once installed, any tracebacks will be printed with syntax highlighting and rich formatting. + + + Args: + console (Optional[Console], optional): Console to write exception to. Default uses internal Console instance. + width (Optional[int], optional): Width (in characters) of traceback. Defaults to 100. + code_width (Optional[int], optional): Code width (in characters) of traceback. Defaults to 88. + extra_lines (int, optional): Extra lines of code. Defaults to 3. + theme (Optional[str], optional): Pygments theme to use in traceback. Defaults to ``None`` which will pick + a theme appropriate for the platform. + word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to 10. + locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. + locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. + locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. + indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. + suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + + Returns: + Callable: The previous exception handler that was replaced. + + """ + traceback_console = Console(stderr=True) if console is None else console + + locals_hide_sunder = ( + True + if (traceback_console.is_jupyter and locals_hide_sunder is None) + else locals_hide_sunder + ) + + def excepthook( + type_: Type[BaseException], + value: BaseException, + traceback: Optional[TracebackType], + ) -> None: + traceback_console.print( + Traceback.from_exception( + type_, + value, + traceback, + width=width, + code_width=code_width, + extra_lines=extra_lines, + theme=theme, + word_wrap=word_wrap, + show_locals=show_locals, + locals_max_length=locals_max_length, + locals_max_string=locals_max_string, + locals_hide_dunder=locals_hide_dunder, + locals_hide_sunder=bool(locals_hide_sunder), + indent_guides=indent_guides, + suppress=suppress, + max_frames=max_frames, + ) + ) + + def ipy_excepthook_closure(ip: Any) -> None: # pragma: no cover + tb_data = {} # store information about showtraceback call + default_showtraceback = ip.showtraceback # keep reference of default traceback + + def ipy_show_traceback(*args: Any, **kwargs: Any) -> None: + """wrap the default ip.showtraceback to store info for ip._showtraceback""" + nonlocal tb_data + tb_data = kwargs + default_showtraceback(*args, **kwargs) + + def ipy_display_traceback( + *args: Any, is_syntax: bool = False, **kwargs: Any + ) -> None: + """Internally called traceback from ip._showtraceback""" + nonlocal tb_data + exc_tuple = ip._get_exc_info() + + # do not display trace on syntax error + tb: Optional[TracebackType] = None if is_syntax else exc_tuple[2] + + # determine correct tb_offset + compiled = tb_data.get("running_compiled_code", False) + tb_offset = tb_data.get("tb_offset", 1 if compiled else 0) + # remove ipython internal frames from trace with tb_offset + for _ in range(tb_offset): + if tb is None: + break + tb = tb.tb_next + + excepthook(exc_tuple[0], exc_tuple[1], tb) + tb_data = {} # clear data upon usage + + # replace _showtraceback instead of showtraceback to allow ipython features such as debugging to work + # this is also what the ipython docs recommends to modify when subclassing InteractiveShell + ip._showtraceback = ipy_display_traceback + # add wrapper to capture tb_data + ip.showtraceback = ipy_show_traceback + ip.showsyntaxerror = lambda *args, **kwargs: ipy_display_traceback( + *args, is_syntax=True, **kwargs + ) + + try: # pragma: no cover + # if within ipython, use customized traceback + ip = get_ipython() # type: ignore[name-defined] + ipy_excepthook_closure(ip) + return sys.excepthook + except Exception: + # otherwise use default system hook + old_excepthook = sys.excepthook + sys.excepthook = excepthook + return old_excepthook + + +@dataclass +class Frame: + filename: str + lineno: int + name: str + line: str = "" + locals: Optional[Dict[str, pretty.Node]] = None + last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] = None + + +@dataclass +class _SyntaxError: + offset: int + filename: str + line: str + lineno: int + msg: str + + +@dataclass +class Stack: + exc_type: str + exc_value: str + syntax_error: Optional[_SyntaxError] = None + is_cause: bool = False + frames: List[Frame] = field(default_factory=list) + + +@dataclass +class Trace: + stacks: List[Stack] + + +class PathHighlighter(RegexHighlighter): + highlights = [r"(?P.*/)(?P.+)"] + + +class Traceback: + """A Console renderable that renders a traceback. + + Args: + trace (Trace, optional): A `Trace` object produced from `extract`. Defaults to None, which uses + the last exception. + width (Optional[int], optional): Number of characters used to traceback. Defaults to 100. + code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88. + extra_lines (int, optional): Additional lines of code to render. Defaults to 3. + theme (str, optional): Override pygments theme used in traceback. + word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. + locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to 10. + locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. + locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. + locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. + suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. + + """ + + LEXERS = { + "": "text", + ".py": "python", + ".pxd": "cython", + ".pyx": "cython", + ".pxi": "pyrex", + } + + def __init__( + self, + trace: Optional[Trace] = None, + *, + width: Optional[int] = 100, + code_width: Optional[int] = 88, + extra_lines: int = 3, + theme: Optional[str] = None, + word_wrap: bool = False, + show_locals: bool = False, + locals_max_length: int = LOCALS_MAX_LENGTH, + locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: bool = False, + indent_guides: bool = True, + suppress: Iterable[Union[str, ModuleType]] = (), + max_frames: int = 100, + ): + if trace is None: + exc_type, exc_value, traceback = sys.exc_info() + if exc_type is None or exc_value is None or traceback is None: + raise ValueError( + "Value for 'trace' required if not called in except: block" + ) + trace = self.extract( + exc_type, exc_value, traceback, show_locals=show_locals + ) + self.trace = trace + self.width = width + self.code_width = code_width + self.extra_lines = extra_lines + self.theme = Syntax.get_theme(theme or "ansi_dark") + self.word_wrap = word_wrap + self.show_locals = show_locals + self.indent_guides = indent_guides + self.locals_max_length = locals_max_length + self.locals_max_string = locals_max_string + self.locals_hide_dunder = locals_hide_dunder + self.locals_hide_sunder = locals_hide_sunder + + self.suppress: Sequence[str] = [] + for suppress_entity in suppress: + if not isinstance(suppress_entity, str): + assert ( + suppress_entity.__file__ is not None + ), f"{suppress_entity!r} must be a module with '__file__' attribute" + path = os.path.dirname(suppress_entity.__file__) + else: + path = suppress_entity + path = os.path.normpath(os.path.abspath(path)) + self.suppress.append(path) + self.max_frames = max(4, max_frames) if max_frames > 0 else 0 + + @classmethod + def from_exception( + cls, + exc_type: Type[Any], + exc_value: BaseException, + traceback: Optional[TracebackType], + *, + width: Optional[int] = 100, + code_width: Optional[int] = 88, + extra_lines: int = 3, + theme: Optional[str] = None, + word_wrap: bool = False, + show_locals: bool = False, + locals_max_length: int = LOCALS_MAX_LENGTH, + locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: bool = False, + indent_guides: bool = True, + suppress: Iterable[Union[str, ModuleType]] = (), + max_frames: int = 100, + ) -> "Traceback": + """Create a traceback from exception info + + Args: + exc_type (Type[BaseException]): Exception type. + exc_value (BaseException): Exception value. + traceback (TracebackType): Python Traceback object. + width (Optional[int], optional): Number of characters used to traceback. Defaults to 100. + code_width (Optional[int], optional): Number of code characters used to traceback. Defaults to 88. + extra_lines (int, optional): Additional lines of code to render. Defaults to 3. + theme (str, optional): Override pygments theme used in traceback. + word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True. + locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to 10. + locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. + locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. + locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. + suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. + + Returns: + Traceback: A Traceback instance that may be printed. + """ + rich_traceback = cls.extract( + exc_type, + exc_value, + traceback, + show_locals=show_locals, + locals_max_length=locals_max_length, + locals_max_string=locals_max_string, + locals_hide_dunder=locals_hide_dunder, + locals_hide_sunder=locals_hide_sunder, + ) + + return cls( + rich_traceback, + width=width, + code_width=code_width, + extra_lines=extra_lines, + theme=theme, + word_wrap=word_wrap, + show_locals=show_locals, + indent_guides=indent_guides, + locals_max_length=locals_max_length, + locals_max_string=locals_max_string, + locals_hide_dunder=locals_hide_dunder, + locals_hide_sunder=locals_hide_sunder, + suppress=suppress, + max_frames=max_frames, + ) + + @classmethod + def extract( + cls, + exc_type: Type[BaseException], + exc_value: BaseException, + traceback: Optional[TracebackType], + *, + show_locals: bool = False, + locals_max_length: int = LOCALS_MAX_LENGTH, + locals_max_string: int = LOCALS_MAX_STRING, + locals_hide_dunder: bool = True, + locals_hide_sunder: bool = False, + ) -> Trace: + """Extract traceback information. + + Args: + exc_type (Type[BaseException]): Exception type. + exc_value (BaseException): Exception value. + traceback (TracebackType): Python Traceback object. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation. + Defaults to 10. + locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80. + locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True. + locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False. + + Returns: + Trace: A Trace instance which you can use to construct a `Traceback`. + """ + + stacks: List[Stack] = [] + is_cause = False + + from pip._vendor.rich import _IMPORT_CWD + + def safe_str(_object: Any) -> str: + """Don't allow exceptions from __str__ to propagate.""" + try: + return str(_object) + except Exception: + return "" + + while True: + stack = Stack( + exc_type=safe_str(exc_type.__name__), + exc_value=safe_str(exc_value), + is_cause=is_cause, + ) + + if isinstance(exc_value, SyntaxError): + stack.syntax_error = _SyntaxError( + offset=exc_value.offset or 0, + filename=exc_value.filename or "?", + lineno=exc_value.lineno or 0, + line=exc_value.text or "", + msg=exc_value.msg, + ) + + stacks.append(stack) + append = stack.frames.append + + def get_locals( + iter_locals: Iterable[Tuple[str, object]] + ) -> Iterable[Tuple[str, object]]: + """Extract locals from an iterator of key pairs.""" + if not (locals_hide_dunder or locals_hide_sunder): + yield from iter_locals + return + for key, value in iter_locals: + if locals_hide_dunder and key.startswith("__"): + continue + if locals_hide_sunder and key.startswith("_"): + continue + yield key, value + + for frame_summary, line_no in walk_tb(traceback): + filename = frame_summary.f_code.co_filename + + last_instruction: Optional[Tuple[Tuple[int, int], Tuple[int, int]]] + last_instruction = None + if sys.version_info >= (3, 11): + instruction_index = frame_summary.f_lasti // 2 + instruction_position = next( + islice( + frame_summary.f_code.co_positions(), + instruction_index, + instruction_index + 1, + ) + ) + ( + start_line, + end_line, + start_column, + end_column, + ) = instruction_position + if ( + start_line is not None + and end_line is not None + and start_column is not None + and end_column is not None + ): + last_instruction = ( + (start_line, start_column), + (end_line, end_column), + ) + + if filename and not filename.startswith("<"): + if not os.path.isabs(filename): + filename = os.path.join(_IMPORT_CWD, filename) + if frame_summary.f_locals.get("_rich_traceback_omit", False): + continue + + frame = Frame( + filename=filename or "?", + lineno=line_no, + name=frame_summary.f_code.co_name, + locals=( + { + key: pretty.traverse( + value, + max_length=locals_max_length, + max_string=locals_max_string, + ) + for key, value in get_locals(frame_summary.f_locals.items()) + if not (inspect.isfunction(value) or inspect.isclass(value)) + } + if show_locals + else None + ), + last_instruction=last_instruction, + ) + append(frame) + if frame_summary.f_locals.get("_rich_traceback_guard", False): + del stack.frames[:] + + cause = getattr(exc_value, "__cause__", None) + if cause: + exc_type = cause.__class__ + exc_value = cause + # __traceback__ can be None, e.g. for exceptions raised by the + # 'multiprocessing' module + traceback = cause.__traceback__ + is_cause = True + continue + + cause = exc_value.__context__ + if cause and not getattr(exc_value, "__suppress_context__", False): + exc_type = cause.__class__ + exc_value = cause + traceback = cause.__traceback__ + is_cause = False + continue + # No cover, code is reached but coverage doesn't recognize it. + break # pragma: no cover + + trace = Trace(stacks=stacks) + return trace + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + theme = self.theme + background_style = theme.get_background_style() + token_style = theme.get_style_for_token + + traceback_theme = Theme( + { + "pretty": token_style(TextToken), + "pygments.text": token_style(Token), + "pygments.string": token_style(String), + "pygments.function": token_style(Name.Function), + "pygments.number": token_style(Number), + "repr.indent": token_style(Comment) + Style(dim=True), + "repr.str": token_style(String), + "repr.brace": token_style(TextToken) + Style(bold=True), + "repr.number": token_style(Number), + "repr.bool_true": token_style(Keyword.Constant), + "repr.bool_false": token_style(Keyword.Constant), + "repr.none": token_style(Keyword.Constant), + "scope.border": token_style(String.Delimiter), + "scope.equals": token_style(Operator), + "scope.key": token_style(Name), + "scope.key.special": token_style(Name.Constant) + Style(dim=True), + }, + inherit=False, + ) + + highlighter = ReprHighlighter() + for last, stack in loop_last(reversed(self.trace.stacks)): + if stack.frames: + stack_renderable: ConsoleRenderable = Panel( + self._render_stack(stack), + title="[traceback.title]Traceback [dim](most recent call last)", + style=background_style, + border_style="traceback.border", + expand=True, + padding=(0, 1), + ) + stack_renderable = Constrain(stack_renderable, self.width) + with console.use_theme(traceback_theme): + yield stack_renderable + if stack.syntax_error is not None: + with console.use_theme(traceback_theme): + yield Constrain( + Panel( + self._render_syntax_error(stack.syntax_error), + style=background_style, + border_style="traceback.border.syntax_error", + expand=True, + padding=(0, 1), + width=self.width, + ), + self.width, + ) + yield Text.assemble( + (f"{stack.exc_type}: ", "traceback.exc_type"), + highlighter(stack.syntax_error.msg), + ) + elif stack.exc_value: + yield Text.assemble( + (f"{stack.exc_type}: ", "traceback.exc_type"), + highlighter(stack.exc_value), + ) + else: + yield Text.assemble((f"{stack.exc_type}", "traceback.exc_type")) + + if not last: + if stack.is_cause: + yield Text.from_markup( + "\n[i]The above exception was the direct cause of the following exception:\n", + ) + else: + yield Text.from_markup( + "\n[i]During handling of the above exception, another exception occurred:\n", + ) + + @group() + def _render_syntax_error(self, syntax_error: _SyntaxError) -> RenderResult: + highlighter = ReprHighlighter() + path_highlighter = PathHighlighter() + if syntax_error.filename != "": + if os.path.exists(syntax_error.filename): + text = Text.assemble( + (f" {syntax_error.filename}", "pygments.string"), + (":", "pygments.text"), + (str(syntax_error.lineno), "pygments.number"), + style="pygments.text", + ) + yield path_highlighter(text) + syntax_error_text = highlighter(syntax_error.line.rstrip()) + syntax_error_text.no_wrap = True + offset = min(syntax_error.offset - 1, len(syntax_error_text)) + syntax_error_text.stylize("bold underline", offset, offset) + syntax_error_text += Text.from_markup( + "\n" + " " * offset + "[traceback.offset]▲[/]", + style="pygments.text", + ) + yield syntax_error_text + + @classmethod + def _guess_lexer(cls, filename: str, code: str) -> str: + ext = os.path.splitext(filename)[-1] + if not ext: + # No extension, look at first line to see if it is a hashbang + # Note, this is an educated guess and not a guarantee + # If it fails, the only downside is that the code is highlighted strangely + new_line_index = code.index("\n") + first_line = code[:new_line_index] if new_line_index != -1 else code + if first_line.startswith("#!") and "python" in first_line.lower(): + return "python" + try: + return cls.LEXERS.get(ext) or guess_lexer_for_filename(filename, code).name + except ClassNotFound: + return "text" + + @group() + def _render_stack(self, stack: Stack) -> RenderResult: + path_highlighter = PathHighlighter() + theme = self.theme + + def read_code(filename: str) -> str: + """Read files, and cache results on filename. + + Args: + filename (str): Filename to read + + Returns: + str: Contents of file + """ + return "".join(linecache.getlines(filename)) + + def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]: + if frame.locals: + yield render_scope( + frame.locals, + title="locals", + indent_guides=self.indent_guides, + max_length=self.locals_max_length, + max_string=self.locals_max_string, + ) + + exclude_frames: Optional[range] = None + if self.max_frames != 0: + exclude_frames = range( + self.max_frames // 2, + len(stack.frames) - self.max_frames // 2, + ) + + excluded = False + for frame_index, frame in enumerate(stack.frames): + if exclude_frames and frame_index in exclude_frames: + excluded = True + continue + + if excluded: + assert exclude_frames is not None + yield Text( + f"\n... {len(exclude_frames)} frames hidden ...", + justify="center", + style="traceback.error", + ) + excluded = False + + first = frame_index == 0 + frame_filename = frame.filename + suppressed = any(frame_filename.startswith(path) for path in self.suppress) + + if os.path.exists(frame.filename): + text = Text.assemble( + path_highlighter(Text(frame.filename, style="pygments.string")), + (":", "pygments.text"), + (str(frame.lineno), "pygments.number"), + " in ", + (frame.name, "pygments.function"), + style="pygments.text", + ) + else: + text = Text.assemble( + "in ", + (frame.name, "pygments.function"), + (":", "pygments.text"), + (str(frame.lineno), "pygments.number"), + style="pygments.text", + ) + if not frame.filename.startswith("<") and not first: + yield "" + yield text + if frame.filename.startswith("<"): + yield from render_locals(frame) + continue + if not suppressed: + try: + code = read_code(frame.filename) + if not code: + # code may be an empty string if the file doesn't exist, OR + # if the traceback filename is generated dynamically + continue + lexer_name = self._guess_lexer(frame.filename, code) + syntax = Syntax( + code, + lexer_name, + theme=theme, + line_numbers=True, + line_range=( + frame.lineno - self.extra_lines, + frame.lineno + self.extra_lines, + ), + highlight_lines={frame.lineno}, + word_wrap=self.word_wrap, + code_width=self.code_width, + indent_guides=self.indent_guides, + dedent=False, + ) + yield "" + except Exception as error: + yield Text.assemble( + (f"\n{error}", "traceback.error"), + ) + else: + if frame.last_instruction is not None: + start, end = frame.last_instruction + syntax.stylize_range( + style="traceback.error_range", + start=start, + end=end, + style_before=True, + ) + yield ( + Columns( + [ + syntax, + *render_locals(frame), + ], + padding=1, + ) + if frame.locals + else syntax + ) + + +if __name__ == "__main__": # pragma: no cover + install(show_locals=True) + import sys + + def bar( + a: Any, + ) -> None: # 这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑 + one = 1 + print(one / a) + + def foo(a: Any) -> None: + _rich_traceback_guard = True + zed = { + "characters": { + "Paul Atreides", + "Vladimir Harkonnen", + "Thufir Hawat", + "Duncan Idaho", + }, + "atomic_types": (None, False, True), + } + bar(a) + + def error() -> None: + foo(0) + + error() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/rich/tree.py b/backend/venv/Lib/site-packages/pip/_vendor/rich/tree.py new file mode 100644 index 0000000..27c5cf7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/rich/tree.py @@ -0,0 +1,257 @@ +from typing import Iterator, List, Optional, Tuple + +from ._loop import loop_first, loop_last +from .console import Console, ConsoleOptions, RenderableType, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style, StyleStack, StyleType +from .styled import Styled + +GuideType = Tuple[str, str, str, str] + + +class Tree(JupyterMixin): + """A renderable for a tree structure. + + Attributes: + ASCII_GUIDES (GuideType): Guide lines used when Console.ascii_only is True. + TREE_GUIDES (List[GuideType, GuideType, GuideType]): Default guide lines. + + Args: + label (RenderableType): The renderable or str for the tree label. + style (StyleType, optional): Style of this tree. Defaults to "tree". + guide_style (StyleType, optional): Style of the guide lines. Defaults to "tree.line". + expanded (bool, optional): Also display children. Defaults to True. + highlight (bool, optional): Highlight renderable (if str). Defaults to False. + hide_root (bool, optional): Hide the root node. Defaults to False. + """ + + ASCII_GUIDES = (" ", "| ", "+-- ", "`-- ") + TREE_GUIDES = [ + (" ", "│ ", "├── ", "└── "), + (" ", "┃ ", "┣━━ ", "┗━━ "), + (" ", "║ ", "╠══ ", "╚══ "), + ] + + def __init__( + self, + label: RenderableType, + *, + style: StyleType = "tree", + guide_style: StyleType = "tree.line", + expanded: bool = True, + highlight: bool = False, + hide_root: bool = False, + ) -> None: + self.label = label + self.style = style + self.guide_style = guide_style + self.children: List[Tree] = [] + self.expanded = expanded + self.highlight = highlight + self.hide_root = hide_root + + def add( + self, + label: RenderableType, + *, + style: Optional[StyleType] = None, + guide_style: Optional[StyleType] = None, + expanded: bool = True, + highlight: Optional[bool] = False, + ) -> "Tree": + """Add a child tree. + + Args: + label (RenderableType): The renderable or str for the tree label. + style (StyleType, optional): Style of this tree. Defaults to "tree". + guide_style (StyleType, optional): Style of the guide lines. Defaults to "tree.line". + expanded (bool, optional): Also display children. Defaults to True. + highlight (Optional[bool], optional): Highlight renderable (if str). Defaults to False. + + Returns: + Tree: A new child Tree, which may be further modified. + """ + node = Tree( + label, + style=self.style if style is None else style, + guide_style=self.guide_style if guide_style is None else guide_style, + expanded=expanded, + highlight=self.highlight if highlight is None else highlight, + ) + self.children.append(node) + return node + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + stack: List[Iterator[Tuple[bool, Tree]]] = [] + pop = stack.pop + push = stack.append + new_line = Segment.line() + + get_style = console.get_style + null_style = Style.null() + guide_style = get_style(self.guide_style, default="") or null_style + SPACE, CONTINUE, FORK, END = range(4) + + _Segment = Segment + + def make_guide(index: int, style: Style) -> Segment: + """Make a Segment for a level of the guide lines.""" + if options.ascii_only: + line = self.ASCII_GUIDES[index] + else: + guide = 1 if style.bold else (2 if style.underline2 else 0) + line = self.TREE_GUIDES[0 if options.legacy_windows else guide][index] + return _Segment(line, style) + + levels: List[Segment] = [make_guide(CONTINUE, guide_style)] + push(iter(loop_last([self]))) + + guide_style_stack = StyleStack(get_style(self.guide_style)) + style_stack = StyleStack(get_style(self.style)) + remove_guide_styles = Style(bold=False, underline2=False) + + depth = 0 + + while stack: + stack_node = pop() + try: + last, node = next(stack_node) + except StopIteration: + levels.pop() + if levels: + guide_style = levels[-1].style or null_style + levels[-1] = make_guide(FORK, guide_style) + guide_style_stack.pop() + style_stack.pop() + continue + push(stack_node) + if last: + levels[-1] = make_guide(END, levels[-1].style or null_style) + + guide_style = guide_style_stack.current + get_style(node.guide_style) + style = style_stack.current + get_style(node.style) + prefix = levels[(2 if self.hide_root else 1) :] + renderable_lines = console.render_lines( + Styled(node.label, style), + options.update( + width=options.max_width + - sum(level.cell_length for level in prefix), + highlight=self.highlight, + height=None, + ), + pad=options.justify is not None, + ) + + if not (depth == 0 and self.hide_root): + for first, line in loop_first(renderable_lines): + if prefix: + yield from _Segment.apply_style( + prefix, + style.background_style, + post_style=remove_guide_styles, + ) + yield from line + yield new_line + if first and prefix: + prefix[-1] = make_guide( + SPACE if last else CONTINUE, prefix[-1].style or null_style + ) + + if node.expanded and node.children: + levels[-1] = make_guide( + SPACE if last else CONTINUE, levels[-1].style or null_style + ) + levels.append( + make_guide(END if len(node.children) == 1 else FORK, guide_style) + ) + style_stack.push(get_style(node.style)) + guide_style_stack.push(get_style(node.guide_style)) + push(iter(loop_last(node.children))) + depth += 1 + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + stack: List[Iterator[Tree]] = [iter([self])] + pop = stack.pop + push = stack.append + minimum = 0 + maximum = 0 + measure = Measurement.get + level = 0 + while stack: + iter_tree = pop() + try: + tree = next(iter_tree) + except StopIteration: + level -= 1 + continue + push(iter_tree) + min_measure, max_measure = measure(console, options, tree.label) + indent = level * 4 + minimum = max(min_measure + indent, minimum) + maximum = max(max_measure + indent, maximum) + if tree.expanded and tree.children: + push(iter(tree.children)) + level += 1 + return Measurement(minimum, maximum) + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Group + from pip._vendor.rich.markdown import Markdown + from pip._vendor.rich.panel import Panel + from pip._vendor.rich.syntax import Syntax + from pip._vendor.rich.table import Table + + table = Table(row_styles=["", "dim"]) + + table.add_column("Released", style="cyan", no_wrap=True) + table.add_column("Title", style="magenta") + table.add_column("Box Office", justify="right", style="green") + + table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$952,110,690") + table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347") + table.add_row("Dec 15, 2017", "Star Wars Ep. V111: The Last Jedi", "$1,332,539,889") + table.add_row("Dec 16, 2016", "Rogue One: A Star Wars Story", "$1,332,439,889") + + code = """\ +class Segment(NamedTuple): + text: str = "" + style: Optional[Style] = None + is_control: bool = False +""" + syntax = Syntax(code, "python", theme="monokai", line_numbers=True) + + markdown = Markdown( + """\ +### example.md +> Hello, World! +> +> Markdown _all_ the things +""" + ) + + root = Tree("🌲 [b green]Rich Tree", highlight=True, hide_root=True) + + node = root.add(":file_folder: Renderables", guide_style="red") + simple_node = node.add(":file_folder: [bold yellow]Atomic", guide_style="uu green") + simple_node.add(Group("📄 Syntax", syntax)) + simple_node.add(Group("📄 Markdown", Panel(markdown, border_style="green"))) + + containers_node = node.add( + ":file_folder: [bold magenta]Containers", guide_style="bold magenta" + ) + containers_node.expanded = True + panel = Panel.fit("Just a panel", border_style="red") + containers_node.add(Group("📄 Panels", panel)) + + containers_node.add(Group("📄 [b magenta]Table", table)) + + console = Console() + + console.print(root) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__init__.py new file mode 100644 index 0000000..2b08d6e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__init__.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021 Taneli Hukkinen +# Licensed to PSF under a Contributor Agreement. + +__all__ = ("loads", "load", "TOMLDecodeError") +__version__ = "2.2.1" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT + +from ._parser import TOMLDecodeError, load, loads diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06d5fb03ee6afc0de8aa30bbdb81a3d870bff59a GIT binary patch literal 344 zcmZ8dJxjzu5S`5?o?JYw#8$9M;e}jzh>hBv3St!&mc8r}7PHwfiIG^{zwkHM_($xl zB&~(m9b9MS2DEXC_c8Ez!@N!=V{miya--)2;A1d<CA{%0&9i;0?)8qZ?{ZYy$Cvr1R7t1P9(xUr_tF?V6za6YZNe*45&d0(hg+;NS= d`SpQ=H6?_s#}LM=(fjWHD*S}x4H6t4`U9L^Uf}=$ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fb96e96bc9c58466024a94b657cb499755775ea GIT binary patch literal 29358 zcmd6Qd30OXdFOk0*Z~40!A+z{fs05&rl{SLC0R1XMW#hjvM70><-iahC_&<)Jb;!& zgAVOFW6)76C`%1boP=qdhB|gzb()?iXL6>p<0P8SIdcGmuIOjBqfFg1@tjT%9WoPF z=}hML-M3&7WV`7<^CaGP-`&@5zZd_dsL0OYY5db8phS5hje722FSyN6e#^K?{pBjaWx*gSJuopncRa z=ooblI@LTygGHiQw2Zh$-GlDY;=$t4lEISE(!tVE&!A_tY_JUJ%%XLqe6(V)VzhFw zaX|)hahrc?p zNDI;4lNOE}T*FFqQHjAdtW38ak8v9GviRbx_>!FXdKO>G;=O|n?90Qx>IWOySD6~u z#J8!`Bv; zV?A=T>!oaEVH*&(Q4ib3!ZsmnbI_@me6M&=-135PaJ!8w{7>u`w<3Orcu3ra_kDQZ zi}z0Pu(%!XU3l-ndw1d7Hcot4ybtmB7m62;h&vItM;s7$;k{QpD(=Sn0le?WyQ5&9 zW8xmf?JF4fh`1MVo#F#x$E$p93h_~KA4aPSWp^S?xA>UYg?A6WyYb#HJ}&m){UFlq z$GbN-xAG+piVq_0A@K>Z7w-e&aq%I%`z{E+CqJaA^6|1GFg7+G2}DBUV_|$+dm}+9 zaAG9bkB{PmfwN~rVK?@Gs=eEL$c5@c0o4vgvJ6Rvb{er8WfLCoE-^% zNSoPbmK{gB{aqbLyN~uB?3SJQ=sVQe(Z{}Q`077)a9{TkxnwjD89L>UjQhnvBp3;e z2IW#cXk>gSFv7yzdf3>+=!u}@6J+5)@PceV9FW4no{{lDL>3N@hb1d2mrD3IGd;9kfsUU{>%K>n5jRZmoS{>kcfYB)Tq?_ZW_=uh^%4>`N5BZk?S}&Fu zxeMH%2}$G zjtop1Y<9U`i#&J?Gsng=FPXebOVZbSwEGCk(MymUwWv()I}?>_i8>D*JlNfTRIA-< zlPyON9qjWzIw13Q*`xaX9sOOH(?_W-lZN$v*|o0&tLZ@Z<66ds7P*8zd;5Ej_M$zk zH?r%&?#H@%_xGyh%e+!*VPHtc%cCaKsxK_nruPC&EF|8wh*F;Ba7KB;pN7C%xi?g!P1=vr=$~?NhrK z&)J|98W+9e!(JMnuHewP80?m$aj7Nj9hQQ@^~2-RC>1a ze*fsWI59$gr{DkiiNJ^&WAXdN@gcwe3b#ysld8#~-NKxG@PvVXxfi%!8hFzVX@?e* zGZrcy;FsGGojVpmBmEl|a^aO|6b&zcQUPQ#$?m)!1$JU=JI1_0>Yi5$glLpP!`^@w zEoI&FhQeMzG4IoXk&ws+q}|R&sY4XQ-pHw-cX)hcWc(ZrWFQieLMJ97K}3vu9|??1 zDC4%1Wf%>g-03}v3=?BCfJltGl!`}#;V^b7ONNS-WYpA5Gfo7l2DW8IWtPUnO1jXP z7(7q2g`D1Vr-D+DC8OlSfzU`$Nj`$LFgC8_AisBLT#|y}v*TkTr9^wrj)z&nL*pY_ zLU<=e$37t`fdcI@!-M(bm%9MB0Q`*MjoE-NqT+SX9jZ_AX2lx{#20793lY68Er0mQ z2(1_PoF*8Z_lSH%rE5X)7~T*xOwV&sA>z~$Pwp6g7$FGp*PrXr~%x z9;=87D1(4>-jiF#Bt~Eg`688CvZV`q_qjxq(&GG!UFiq@#<>zrtdn!nC{!#HJ$ z^7yhxEpQ$9wnki9{?jFzFY}IaQL8p97+pTf`StOQ8t_%5rA4bbzg||A4f&V8==Mpb6k8r~|T~*zP?%5)6cc-f%GDZNbiK@wSE|lCRC%f?cA1 zcmrdiw*|`{-=VRHF9XuN<6|Qi+CQXq3Z!fgM}S2~f=>rWq-F$36fV)ynsfu9s#}ji zi%ApPTa&gnY#O$ACQaVfK*THaK3|D!4~0WxC~a&gC<|zhETCT5dM+T1VH1XBBl!T% zGXVKfC5k~v*`5I@1aL!Rp$LGiX=r=`rI-QB0SIJaBseAu=&~%JtFnOp$!2BuQ&Q}0 zpG`J~gCoPzL)4E0XYmFQGNE8Gs69hHZ!-9Kjw1g7+Y3 zvMLX-wrkBhg4poASaH+bN5x!G$)cw=G4$G&c~46r-v`dJO9y8TE*bceNB9ql8y0F- z|H@`6axFQzV$XbaTgu(GP+1+HOdP#D888+Bomsee0mDoC4GTWIhX`S1YDrt+E7aS$=hhN&YP*$0!zr25@`xZQn-&*&|y4j<1 zo92en)tgggn`7O#9Imf6#)rPr`qJKoRqJLRx>e(yt(djW*{-g=TA5sRU+f{25Z{(C zB~B-f&y^%g?unTft)(}uH7RRNqHDH!-s-#MsfZabS{HI(6{`{GSSYWK8Gql-uwcK> z%I4~J9oCFD>WzS2e&SA?|D-aP0~m2Op_6qWUOy>0afcFtP@h@aLjJAfY$NAhau{x= z>6NyV!w@n<+B@l!oc;IiV<_$ndE@8nZuT zun~||$pt+c9zBH+q1DVDfF&LXLPbmiAmlUXriqh^crJr#M4g5g4bL0Sap#4{xpTbF zIJuVb4Gc1YP8tV^?gw6q|e zf^FVl`^k2q*}P9tg4UMd@$q&d+gkv^q!TT^r~0L%XgNq4qZAB?vRPzgn(XS(Xb?uR z$u{Dx6t4*bDuzL;8U6m@v(hnSm-!PiA7%tSZD_WiWh14N{D^)Ye_>iA)7&kq^O9}G z_9e%3$CANhDqCzH@6C5>$#uh=+e^)ETWRJQ1m*t+C0uNbnj=+OzNa~*sN7j45HtG*%pG{Nxm$q5Y+3 zzx@m#ic}O?tCc1?s79^6=lMvB7Q@2Tjagv4^UHDOmII1On~DE{O|6#0Wo_?a12%XQ zHn=(mpu&XAW{>JpvO*Lls3YSy1dW~&O&M^2x+=6DpnOO&9|uKz8dO~Vb9!BV2*(X@ z8d%9I#{?;%4GcqM z1Td;+^Hs_&rtDPeBq0tcHzTA}0k}xxv&w?s zA69^~5SE4%%1jtXm&~UC=!24Mq_)bAFaZ9Ts5G3IA4ZXBKwNqPA5gxjc`(+w;4E8k zxaU1hDM!;{sdv^hJ2bcDs`(lU?22_Rmaa|=%r?GuE?v4|rgNdFBtG!c6H5l6sBvN4 z`njR29am0XX^T5hY*F#0-kIK;&gPV}dEVK&;I2*#z2mN5tZSbOU+ui+N!Q(f*%22m zKk`9dNc@q4l`NLlCmXh14PWa_mp+hmKCoiu+%<_UvqIX{gkG5o_6nI6iud2}+!z8j z^SG8c187n+XLH6rKVwC%0FUwcc%_mns(H0H>1fu`pR4tavbmwxSKajOP5JgFTOYX2 zC!PE5M2Wvy*~}FKYw{RVXUS3z&pF+fcFgR!bpOo#Nn_PgFOQhttWZy?#)tDcP;l;i4`@xZ8!Cla&Nb6>8=)jQfuqp zBmCrk9_~+hM~_?hsf#DK)Yh{__~~XI?hp#mA7E#C_~p;R&B$S(If7J5G(bZn1Wlrm zWc#9N(9FKf?8_xuASt#$D`3UjD!N1)-ZrsVwBv0TOQ6Fs4m!kA(TTV7LXpoSokB5_ zKDLh`a{)g!8aT^j79_$Hz1X1P4J2g>L*5w-w<}PHc7<&2IdW*QyPvUZa#8nVhx>Xv zA+RF}u1dg-jmO+k!+o zNlY|2BZ=|Oe+m)7;L#1kx+H)k5=tKo(loNmLO>L+2&}=ffYFtWtYcKQ24W!I7e%d$ zlO;+ovV#6Q(uS+ypd(hN!uQ;?u1Q(f02GL`j(4qXjO@>u1vAp45`H-b&)xdd#XSjP zhtVYb6r>Ax>z~NKVbCZFh}vt6L`$OF{O7ce`7<#Y>IiZOp}z-wi48*12`L&Rc$l9vCcRM>tZ6T z;{%DNxwWwe-*s+W61eL1pue>ttWR0%-?cU>gQqV-l%+3*r}1&O!NY(-cr5bO9EP!& z$T|`vJ7_@?16iVSKji`(BC_jek!{6eO&0`Gz`V7*uNJLVI zvpyqRPtq4DzzF0Ok@+)uyoYUK3|q$^7#W##D!|5!Cjm%&P=^mT(RJ(Oz@YtCw8PfO*36f7Ou1!=*w1g$vR_=d*VkfS0sAt8t*UnLg6 zLV%IpY(y1y!g$e#u{Zw?r7>{DPaZj%sy!C#idW6_1A@gK zn{i#~O;xsD+n%y^-n8ydS@+)nR6dxykkGiyMtlt)SV(-BzW|wNA=rcMN88cBwj(%0 z$e)c-LEVl#@rN{RSYQT7f!V?U4@p}Ue4{d@;4y2lP{0qfl;A>}|lzZ!Y zl{E_xC7w!oTCmBBXp_4*NZh2$+hf)RhbJCMIcg~HsaNWd7cgPx?8#J3d(zYXj_1*< zP1n{XyB|sId^EZF(WLXy1$P;n#{Me?2vUQQ35a2h{o`XnNX7_WNhBapRx*)N($~p( z70wl7R=ggH^{<grv1!UTrC$h~LW0@}8`V!9{Roi>)kzq)q%V0>HJxO&-W zFzsBn@}~96X2I07Y&V;{%f&WRKfhApHkGq6WW^1kB>ho=EWf-JK^a<6w1_+?JWz|G zkZq$NT16x56O5uwG$Gz}!R)h3Cy_OWRL}{wQdVd#!KRTjyc9;P^cfY8Z^LfNB^`V*$=^b+QVWbzc$381wR1|SXG%?5HWazj7}{#Ldg2wq@Jvd@$S9KM4D z49+VMolt5PBq%)zPTMi8h2NRis3kptS`G6IW{Mk;9qIXcOt7<4vfO_=e{ zsSP^{PZuOdx~N*KmjjQY)k%muL>flaL(7Q~V#?HRfOcDv(s;+At%lC^RA9_YGYB=> z1g1EDrcKiKP=Z7=Eq#}qKZYZlVXgxyN6uU`bZ#99K-hsLB182BUpQ~dJxWGD%{5u% zP@>7YtT`_bzm_K5k7^m3zv*sHxtnLhb6e*2&7M!YH-hei*dZ6tmsKUIF89Z}X_|wt z9i8{AW7B*%UGZ?T_+hZrm-=S<5~c4tSKq4hCXNzTf2m&q`O?2fO*vqgEn)(`3Ycaq z{~Jo8Efh*%Oi_~%2d9h|?frbpB?^H+#_n2nz_-$1Gc_n6l|et`*B>3EHXtYiQi=Tz0-(|&0Lv{X4EO~Tx;Km< z))+}59|Qb^;$gj!k72$=3GxsH%TCTF>PrzkU*s0-WoaX%JjE~cDb1w#!u;uB#3<7I zDBBxgIUxTf5}L`$K^m2c4DfA1LR)K{hR0gJjO*A0LyQn$I5` zAC@f;HT$6t57T@ww4_p~iVPT9^w5a(1H|p61wud{3#8a&I>IlMmcQ(~>`U}OQ(W2_ zvj7)4%WgXAQjWSr80^QnHD|J} z`+E3BXWDf*X+6B)D4p*Ac*Vn3n1EUrOUp^a9J9RVsDuP^ws&rLZZO%f<67f2$W8a( zIGS`m{E@&ptCmcZ{C1eA)aOe(O1L*mS~_+KZ|>yb>a+?X$v{V0i6ii2Z%Cjm7?d%! zQe_sB!rH)kLRu(AjCip}G`?ZdR8|8>amQ9AH3c_CGk=dh^WZCokekgpQzi6VF-YI1 zkiUe3%}aZjjlR^R1n9e2I*)+dz5IDfOwKWyssVUtFGIJuP=gtHWk<{ivK35Q`1xlR z-K%IWJn_#H=Rfb;bK}^GU?{djh-;%feH!Hu}ysh9yXMaMrBznVPG=)CT&B&7?kp{hiyEy#3`O6a%}hk1O~W^EvihB z0W7Hn8CZ97fSem^*?%Gka~S9~pvA};BDp$S$q)voAo?Mv3S97?3rjyjc>x+Zg7Uz! zcGp66ZOpx>NciU)?@hb5$Am>!wJsP3tc!1W$5Btl3J)zgAns-$Uk7v4BOT1OqF2QC zYS8_69Tio^N0v@hcHUDEJPH|`uhTSrd5;EO!|Q&>GF^EE;!`UVz>qc|dqhxT&<+aU zV4zl;eSp`(J@IJyGH(#{cI~TBPuM0@!8T8Na>MB|Eq&&Fx-#R}e9*IE>gjMRv_aq6QPX)J_v8Dj zx=J!c6T&ml#QOg|G?9uk7ADHhzk{qQyzg~*K^<0}oZVSC*QY^?0&qYS-Y{xVNQD*^ zT8)|aX<}0Io}Bh@r)%?~@hO^fpoMPF2`G}a=K=fjp+&V;mI^I0Ibj!i7ieMamx#H! z-JpVl(Frms@P$?OQ_9*jI{;{h73QJU zCpfU@x^P`F@%p#If!3N%ANONlRTnP|=`<3CL?>Bq0}i|>yy$$H%cUoxMyBaAA}yZd zz=>1*OU^0Nj1!V|p_;>6k-k`_%rlUR6ULf?);{JOhHB&mYlhqvO&RKJMn6HQVZzKw z!YNzS24UVX%CX-CqZg3ZMD3r9(Y1PVpouwZhedWilU5im6oMw7u}{Wn$= zJ<^7|^t@h)&vs{o87HlvPwu~Hd&8cAx3KX;dkJo-%u+s`l!1IXeaNAc9Ex$34=3rE zFm2@N5hmixk&4sCfs9Hy9`iMWehv+oc8Z@d%m^ZyP|Z;X)Dvhf?F1TQIGET65+Q1! zMA$$&N6r`FsIY5#S~2@3vT?E=R8y8|RQqmrx-Pt@T|ZFvDnYh2Nc*vJn5?cZb>D%j z9f_ysgt>il56@ZNU9$lp%Biy7D=p_0p+L0?-lZT8EYWe53|N=mrWO%YKguXW*wvTm zB%Ioqvw@H#o20UUL=RX@m$JI5rBp%_PgW|Y=-eq zg+KN@pbYv56;ICBXjsp{`R8d47EG1*z_v=b`oxV*^A!i5J4EDSEXY{lSwmvS?7&>< zw;zpLryp7msL>q{DI-Y>f+W`$|{rTb>? zBh#Zq)oa^sHr|_Rym#KQ9U_Qi)1GVRuboad^xoK#JUoytg$Uv(cxW554!&uvOj8c$F;B^f(0^CjUFjU52r>J=t8lY^GSP)@~+{OgC%>kV~Gxp2; z{gZ7O+Ub5USgKtn)-PGE2S`P!WvL!Ah8w;_Ne5A553r|J*~^SLGxK5#q;Udy~d$#^o?^aE{oB@bG0*M;Z5KnWLjY zc(a~|TUd4kq4uXO76|5s`5aXrO}xJJG80ed9`$7fI|6lC!C*z<&oiRo48_A1QGv2@ zDXhHZizP*EQY_p*y{wCUSY~F7348QqX2dcZ(3hEjW!A1N9HZ>Yz;pN_SyVU^^qVp( zMlm5_iS!kdr-D+J;dNC0Gg>M{kWX`qWw08V6VhdE&mF|9RxK1)#h%IMz#$gH0 zRm(A>tz?#?X4QtX3YH2lb%8&&RVm`!KQ?u2;@;fk=-4Z~xrc{acpbfiUge8(Gtx)U zN!3wWLpp$A^R7}qkYK5DBqoI(N_ftjX$Ta3S++%Kmw^9&Sa}*MNS9bLV*!)MpZy30vQwn{ELNT zvVxQ6sTOkHqviGc@Dvn9Uwk%Ysl}PFm`z&%d(y7WF#(6z;++ZGY-6&lIq7arTALRv z4n=OwjHc7>bxG?wJ*)+E(?Ht2DQVrbXkV4A?z%p7V@uk8C}}+O@k)6iAvQsy=S>|| z+?!R7j%MM_wLILytB3~d?sD7gGqf-sz}(o8o|#6D;z)Ujh7r`MTNzk=JR#=Shf=-L zKpD6Nx+Z{AhQC$}1V6x}AiFwDiq;Z=fY}Nr4G7&(*vgMZtkvqH5Ct*ZY7<^%Q z7c>?Hw$&G`1ktA|)HKo-z#*WVO;Z4$LJxMDnAE%{YSNe$2tv_D<)MwIZ4PP=fU{a( zb@maWyjI}IjG)p8Ix{93Sy}4VRmCfy8*}cP$g8c8sq829{^A#WCS{tXze4+EzHQQV zY;0&`oZTis@)B4C{0K49o8+X(xk3&h{KA-BHZeJiECBn<{LmekT|58BQb`}6oPVO_ z@jg7*S7y#+RfMH^_^KuuVYN;!FpF$LB>EGhuU)1Z3Y2n0eh~H3MFSflxV9HYn*m_-lOgi;#Szh z)^j$+iFOgi3AT}b$w z0EjuT5C@&U(l&iy(OL4P{R9-V)kuZGqT^;&YpSX>>26J0TM0T=E61s7uAfR*ADVF! zbd0ZMgm12GHLQI|I6xXGCUbVQFtI?-_3-szvO(pkO39{{NM~41cmJRW=%rhtj#^Nw|78HVF!@u63@eQWnCyRUAI_0BtY=rBCD z_K)siw7QEcuA-A#WS{}q&op70IR;VgWQhTJ8~4^~PxmVBC#$NuHwirwAuyflB62_{ zU=FK(e?63MZo4Rz08rQIu%{g9vXq$hT}H;dGTkL{t*E( zryO`)bqpJNC~y|X%vz4ODB=!q2{`YmNGc7-CqASm;!>w$AJRy{_&Wny7$3rUPoWM~DX77dsboEugCIcPy(G-MIV% zd^fK#H3fr7XmgmS%RS0AUG=5Pb|>Atlh)lIudGr}Ke8t6i=X?l3)`(|&2Lt!RpH%X zMc2IZTIY37+SPqyYtnj%bj^pcBMAe(ZrbPM-s0{1)^Kk*i}tM+-m2lrT~oDh`(0Qf z(iY@P^Rf??F)Qk$Y`h86=>Ex$~4X|N;847I>U2wAW}xAlN^5sZDpF70H2vTKaP!~7=3(L zjE+xk=vH@TMiQW2*A?&{8w=6JWnQF!If;@B97!+oN$cQ{6=8S+=f-iaNU`tepwLR3 zP?=D&`jxDTNud6G|Dq+6SFSrVnzijHONqcVhlvbi&O!U&OHWD@KNc9aB(E?2Y5*h(N=c(T;v3&o!4URcZ!t{#Xt&U^2>VT4_u!#v$d;LNQUqiBK^M|0BH zoZE52aeBww@Rif?f|twWutvDILsW(GIJ8kO8uMke&?XaNU=L$Bw4q{*dlbwNnb0c2 zhADo`BU({{zULSgHNT`&&3U=DQYE zJSUsP;7Djxw!nak4U$R)f11HB;9A=LlroJv55rJ7&WwN9mw?nzg6a37X8Q~VoRI!$B zHMrI^U$J+_0h;-djE%(FSj(Bb)k+H;PY&$}tHu9?uu0FcG02p0FDp1wb|(rEh9s_Lo8q?6(9j_LU;5lY zsY`oDMuI1EMAyJc^%PGefaE2I5fK@}k+zM`mPZ~k%W1ht*#HXZ7nTGp0tQAI#i+)L zDz#DQ>NeVfY#&b3hN(k#oXNBlFM77dtcz7UW{N)WtRr80tZ1RgJ>A1#uBsI|2-Ys= z@(-v*-t(*`YVqOA=Vr|iragW&ob>HVd3Pl%cO{E=VJ}>IcIMec5Y|L)-zOym^v=3N zM7dU^6!JLVY-h5fHRWuL^}JWl7}j+Cjua$xopG2VmBvR?&c;~JLRC$ySGj&9z5}N~ z8IO7I)yUOT$%ehxJ=cfQr4J>Y59uIa$(N&oIjFF8+hL=Rl>2Vr&bU5e>kfj5q?PeU zrhPTsTQybtU=OatcZBP>WCiO5xFqX9-kC0pvnL~@!_Ab)pggb=He~J)dLFk<(V8Ra z4xI&7_h1{KzK$8RoLG^7^xB?~T)7$;(e#E{Te;ahkiB(w-vL!kQXLcsm3o=FN&rgufp9kqR8Eo-&XAXe2m0tHiG^m(z2 z#vZhfJ!%)r0j&wQurNS*L)5Nu3t2hXia-t$qE@ImSQyLU$j*_m`4TJHT&S@7c^+_H z->rc2W_CmcI%o(hzpv>Vk%kPP*n>2lDN9y)p6v3XmgfyP;$nH$a*o$>`>OgUcd=W0 zRly@uVT3m@>0OxJP^!oVy`wm>p&Z1-kxVacyBI$Q1r9L{R!Ce9HVV?xPBfgo7Uvbt#=7$Ic?2nXJ+jrgROu7b;TiI&_AS z_7HJEH;@j?!dPI8e))mBZM+BHa1n6ZxSsjf!#`Q16{Xm0c%(AQ>^h=ci84N>T$ja= z)|-f-!+MHtPa)zzps-(%Ll9Ipv76T=lG!L{yLM8j0D4a%!I?x_0g2#=L~Nd~prBR3 zaW1V(epaOH)W31)Rpx`TTfgsJOQBr$u6{X&LlPZKJ%wv#WxMi$bForkv88 zJgMlpD;jPB>sKiHxr)uxhu*VPEVz-dA?0pJyPM{lcU)VOZthLGdz04Q6+2f}`|{q) zdzpcUr)|3LJ&R|-U31gDCgom}cGthQ_v-HJHR;BKN%uiIj9}(K$P6VqL2K_%mNrcv zSg@4F$5NIiBHp1xe8n+)0G1p{_r|1kBfD}2-7k4%d$Obv7Il`AWcjv~Wm_ikL+Ppw zN%w}Nb;AetRf!E`nU}V2O&Yg;ymA5edg=B;Us8^l{br?)SFJxV7C92-hm+3!-w^F_ z2(*U}%kG<|{Wk7xvtxe^_cNPgf0gjFN}k*r+y3ps&zfBOHw!=8Y=S?>D3o9z{`ln{ zcwWX4;V2~0=M877Iot=rjJ}wE%rJzTMQ}q1Zb2Yhjl48QNm{DL4EKt4fJvV~g-b&ZPD|dx>N!b%72usJ? z!)-WJKNO(bTLIq5#r1^B-RkGYCr0SVy>~Qp9uS|74JpDwJQqAuu~efz3$6#L7>phDRX^C1;81 zCQ=b~FO_mu&sT#fOU7h+K{%>7=dq&=V&v;I|5%REjU9 z(x~>^E?Uh`K%m*?#jmkEi43%vl;*LP=t-qkvFV+iD68NM`7MN*O!I zp>|G|<<_o`dZ9vC$9y#Eckg&kcWB)IwGArHY7hame^UXpn4Y}L8X-kj)`YIR`)c~< zoFS7wAtfW1GmC_!{8vs$_Htl5z({u>WK9`sGq!DJO4+>7zVIESUqBh2z!g&X1r&+! zl0&aakk|0hk!bl?cGfX81{pL?Su{3fK=2NjCc2 zM+pSn$#DsQ%_CYOOvn`8Wr$ zFu5Skc>aIeIll29xTg2HqW3xb-*OHAja#4Q*1ylWe{HnzhF^2!6mz^U#kDR~aJ8Eg zoi|r+O0C|MUcDvBmBzc%+?Jo0)u!-6OTnxA-Uy{@ccja9{P4av2X1(N{8)Ndf2yp1 z+K$V(xPHi&8``dft{Gn+Pu1U_kpX3^6kD-8DYwk^Q04$iM5{2IRD zBM#0=7mr_&hz+iwkP=)}#=DnFJ-lbZ=3El+zJ<35Z&3fZg2zHWJ27t#@;NzA^50-nEClZ<$stn-IS2b@Oe@O-1}+e%Wi_?_IK2@(nCA zy(u%jDKot(Gv2pM<;y0#m$t6q+tl{8sqJfHi7A{CX)fX8jc+gKUQLuD`zHIsR$ XYVxqc$g}*If#)COSFEMHqMrPJO1`^= literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e47be2326ece4992aacc9785f21b91c26235b122 GIT binary patch literal 4045 zcmahMYi}FJaqq#`krYKyFUxj(s$xf{ShQrvi7mTPZ9U>5wh~BoP*4=86YnHZA$i2! z(Y5G1gararY6@6x3Rs0)R6v5lg^a?51JpqC0}2!cWXNdbtBM9_i^AXN%IJrDX=j%_ zidJ2DK@MkUXJ>XEJG1;lFeo4x9lst;B?AckjZB>3DkIGH9D~p;bOk9$VbUnW#2AL) zY?{q*F)qW#*bE=zGp?8`t_PEmiOduA>1Y<#MR z@akE*p~UD= zV(jv$JPF!_9s%|UB8+Q<_gwd|+&w)3v_yZ+T9>6%W{hB!g(FN`{F z=p2s~CM2_ym?FI-uO#qKjbS8>MQwUoS0O<_={WUv0a~|i!JHHC6a84C; zc4rxdw;D_zt}}cNrzx0z)90Mdie#HiFAf{D4-lR?a(#CV;9?cViWnhhp=_fWGV9H- z*BOA$C(a^+6r;bG(WKz`dF7jkl5XiL{ zl~cN^iyz48ygGz2@TI0jV^*z*Q#4qFQYj`ij8z@3g+f%w;#E1FQfTs0F|f~37Nvxd zCvG^j&GcZ>J|qScFG*h8J%hD;PPaL@@0cenuJl}9H*6m*rAopmU}CP#<&7jJftMO> z7q!jy&Z{y`=mxfZ87*tfQq-f!^Az#UYWec2kV$3phFV_M)g(oLn8cb+abF>y&L?P* z50!62LQl

        6$~RN()ywYJ~FSAaE*j2%Ccg*gRpk-DMt|1Epj_6xys&&>O)H;_cnz zoA^LqJcqRzEN5WvO#J(rmeevC6(`k13gVnKG&~=ll9L~*StSnhtMQAeskojp)b1Qm zC~|VR-?IjJ52qSFtmgd9NY^hc@w_+p8yn5=~d*byAfCn zd{XyxU%=(w^ww{B!<*g^MH(mq5GXD5v+wUMZOf-VwLVYYkv_|Qk$mvl{q#~~;c#(q z(-T_vv}}bUOM}aYS0fvt!|UF|Tdn(-FRTPV*YEUw_R*KzgLi%xSn60fQXG67J@w{}8)4~Du@t1|Bs3o_*whcb$KC8!RLJ*OQU2>8XO6tQH}llQe`mvz-G3 z3L9L$4?7XUtir;T<}A*r7P^|Uz}1u>>mJ2KW4;#Clxj3J&&A9^Z z5^}lR_&5l7t|yQ)QP+J5$V+#vP90XN{!YJ%+htYtzjA})$2}sq| zHMBjuiRoG+-hu&P;74#1V7Qq8TAz5_LU7`7ypI4m!@f!_q~*FEIBix(E=mS0=#+v759`9nYD zmM(l6ysfYHt$g$ackiA1fd|tY{-Je#s2rlo^BkljL`mvdkcHsaF+P;7u; zq+?ZN;`4++skJ#osox<>b=7t9$ddNkLLxDp2jyxafgyN^c0Jk~X%?1i0ntEvD7Z79 zO&Xe()-icm*eoXhO6GIWJ}{A3{*&NN07=!$+Q{3&4kZ#b|9TP$+XI~@mrAR)=Yyfq z^Y4uf;V{|WKtO~5(kseUg(NX`{I3x8A1yex_iRQ}@@e&LOmdslP5qAmN*u#5{}vF_ z@lQ1T6&n5vI`n7c`zt#55A;eYfLxcD5{H=Jg1U`ZhAnwf<10(YZ}r{mE3qLLUlNf& zc%y5v>sd!bBU|(>oZLnYz;*<+v@cEFn!7o-dSIhDS_~|x8z{QjbZBYxR_tc1#PWg* zWVsuPBPGN|n3B%}!s;Di5uuqa`WLQjBY|PJ+eGFf^YkKvSpU)+kC@hfu^z^~%^`MQ RiDHc$Gt4{-a7;Tj_rLT*sjmP4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..357321ca153c6c3f143b64fabed5779054d847e2 GIT binary patch literal 372 zcmXv|ze~eF6u!%)v5iCrL2wiY?O=;*5kU$fC{olZ1WMXG!|7cvT+&LmcI%i;{{o2TD~Qj z&nN*4?3e<5u=cRWuK@!)vewFh4ZmKnru|hdYBIyllfu-yp%CFffT`V&QUR@-X2Upn zk@6(g)k$qvP(v^*%e8TPq0Zn!s4zF|3JSw`f~=>qH?qPm^3(5jf>f(mhf?B};904m zk`nX~`aBs!k}F*VgK+o+Nfe+S2iJTMWITuC6tiIrS&;Iy-N#y_bURm4@OB@cf~=L| z&!;z%SD5c*np+|FaxOB+YZkd(vdRIQqz5R*1a5iV%a%XlqRTH*w K8dIh{ocaR=SZa&_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/_parser.py b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_parser.py new file mode 100644 index 0000000..b548e8b --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_parser.py @@ -0,0 +1,770 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021 Taneli Hukkinen +# Licensed to PSF under a Contributor Agreement. + +from __future__ import annotations + +from collections.abc import Iterable +import string +import sys +from types import MappingProxyType +from typing import IO, Any, Final, NamedTuple +import warnings + +from ._re import ( + RE_DATETIME, + RE_LOCALTIME, + RE_NUMBER, + match_to_datetime, + match_to_localtime, + match_to_number, +) +from ._types import Key, ParseFloat, Pos + +# Inline tables/arrays are implemented using recursion. Pathologically +# nested documents cause pure Python to raise RecursionError (which is OK), +# but mypyc binary wheels will crash unrecoverably (not OK). According to +# mypyc docs this will be fixed in the future: +# https://mypyc.readthedocs.io/en/latest/differences_from_python.html#stack-overflows +# Before mypyc's fix is in, recursion needs to be limited by this library. +# Choosing `sys.getrecursionlimit()` as maximum inline table/array nesting +# level, as it allows more nesting than pure Python, but still seems a far +# lower number than where mypyc binaries crash. +MAX_INLINE_NESTING: Final = sys.getrecursionlimit() + +ASCII_CTRL: Final = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) + +# Neither of these sets include quotation mark or backslash. They are +# currently handled as separate cases in the parser functions. +ILLEGAL_BASIC_STR_CHARS: Final = ASCII_CTRL - frozenset("\t") +ILLEGAL_MULTILINE_BASIC_STR_CHARS: Final = ASCII_CTRL - frozenset("\t\n") + +ILLEGAL_LITERAL_STR_CHARS: Final = ILLEGAL_BASIC_STR_CHARS +ILLEGAL_MULTILINE_LITERAL_STR_CHARS: Final = ILLEGAL_MULTILINE_BASIC_STR_CHARS + +ILLEGAL_COMMENT_CHARS: Final = ILLEGAL_BASIC_STR_CHARS + +TOML_WS: Final = frozenset(" \t") +TOML_WS_AND_NEWLINE: Final = TOML_WS | frozenset("\n") +BARE_KEY_CHARS: Final = frozenset(string.ascii_letters + string.digits + "-_") +KEY_INITIAL_CHARS: Final = BARE_KEY_CHARS | frozenset("\"'") +HEXDIGIT_CHARS: Final = frozenset(string.hexdigits) + +BASIC_STR_ESCAPE_REPLACEMENTS: Final = MappingProxyType( + { + "\\b": "\u0008", # backspace + "\\t": "\u0009", # tab + "\\n": "\u000A", # linefeed + "\\f": "\u000C", # form feed + "\\r": "\u000D", # carriage return + '\\"': "\u0022", # quote + "\\\\": "\u005C", # backslash + } +) + + +class DEPRECATED_DEFAULT: + """Sentinel to be used as default arg during deprecation + period of TOMLDecodeError's free-form arguments.""" + + +class TOMLDecodeError(ValueError): + """An error raised if a document is not valid TOML. + + Adds the following attributes to ValueError: + msg: The unformatted error message + doc: The TOML document being parsed + pos: The index of doc where parsing failed + lineno: The line corresponding to pos + colno: The column corresponding to pos + """ + + def __init__( + self, + msg: str | type[DEPRECATED_DEFAULT] = DEPRECATED_DEFAULT, + doc: str | type[DEPRECATED_DEFAULT] = DEPRECATED_DEFAULT, + pos: Pos | type[DEPRECATED_DEFAULT] = DEPRECATED_DEFAULT, + *args: Any, + ): + if ( + args + or not isinstance(msg, str) + or not isinstance(doc, str) + or not isinstance(pos, int) + ): + warnings.warn( + "Free-form arguments for TOMLDecodeError are deprecated. " + "Please set 'msg' (str), 'doc' (str) and 'pos' (int) arguments only.", + DeprecationWarning, + stacklevel=2, + ) + if pos is not DEPRECATED_DEFAULT: + args = pos, *args + if doc is not DEPRECATED_DEFAULT: + args = doc, *args + if msg is not DEPRECATED_DEFAULT: + args = msg, *args + ValueError.__init__(self, *args) + return + + lineno = doc.count("\n", 0, pos) + 1 + if lineno == 1: + colno = pos + 1 + else: + colno = pos - doc.rindex("\n", 0, pos) + + if pos >= len(doc): + coord_repr = "end of document" + else: + coord_repr = f"line {lineno}, column {colno}" + errmsg = f"{msg} (at {coord_repr})" + ValueError.__init__(self, errmsg) + + self.msg = msg + self.doc = doc + self.pos = pos + self.lineno = lineno + self.colno = colno + + +def load(__fp: IO[bytes], *, parse_float: ParseFloat = float) -> dict[str, Any]: + """Parse TOML from a binary file object.""" + b = __fp.read() + try: + s = b.decode() + except AttributeError: + raise TypeError( + "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`" + ) from None + return loads(s, parse_float=parse_float) + + +def loads(__s: str, *, parse_float: ParseFloat = float) -> dict[str, Any]: # noqa: C901 + """Parse TOML from a string.""" + + # The spec allows converting "\r\n" to "\n", even in string + # literals. Let's do so to simplify parsing. + try: + src = __s.replace("\r\n", "\n") + except (AttributeError, TypeError): + raise TypeError( + f"Expected str object, not '{type(__s).__qualname__}'" + ) from None + pos = 0 + out = Output(NestedDict(), Flags()) + header: Key = () + parse_float = make_safe_parse_float(parse_float) + + # Parse one statement at a time + # (typically means one line in TOML source) + while True: + # 1. Skip line leading whitespace + pos = skip_chars(src, pos, TOML_WS) + + # 2. Parse rules. Expect one of the following: + # - end of file + # - end of line + # - comment + # - key/value pair + # - append dict to list (and move to its namespace) + # - create dict (and move to its namespace) + # Skip trailing whitespace when applicable. + try: + char = src[pos] + except IndexError: + break + if char == "\n": + pos += 1 + continue + if char in KEY_INITIAL_CHARS: + pos = key_value_rule(src, pos, out, header, parse_float) + pos = skip_chars(src, pos, TOML_WS) + elif char == "[": + try: + second_char: str | None = src[pos + 1] + except IndexError: + second_char = None + out.flags.finalize_pending() + if second_char == "[": + pos, header = create_list_rule(src, pos, out) + else: + pos, header = create_dict_rule(src, pos, out) + pos = skip_chars(src, pos, TOML_WS) + elif char != "#": + raise TOMLDecodeError("Invalid statement", src, pos) + + # 3. Skip comment + pos = skip_comment(src, pos) + + # 4. Expect end of line or end of file + try: + char = src[pos] + except IndexError: + break + if char != "\n": + raise TOMLDecodeError( + "Expected newline or end of document after a statement", src, pos + ) + pos += 1 + + return out.data.dict + + +class Flags: + """Flags that map to parsed keys/namespaces.""" + + # Marks an immutable namespace (inline array or inline table). + FROZEN: Final = 0 + # Marks a nest that has been explicitly created and can no longer + # be opened using the "[table]" syntax. + EXPLICIT_NEST: Final = 1 + + def __init__(self) -> None: + self._flags: dict[str, dict] = {} + self._pending_flags: set[tuple[Key, int]] = set() + + def add_pending(self, key: Key, flag: int) -> None: + self._pending_flags.add((key, flag)) + + def finalize_pending(self) -> None: + for key, flag in self._pending_flags: + self.set(key, flag, recursive=False) + self._pending_flags.clear() + + def unset_all(self, key: Key) -> None: + cont = self._flags + for k in key[:-1]: + if k not in cont: + return + cont = cont[k]["nested"] + cont.pop(key[-1], None) + + def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003 + cont = self._flags + key_parent, key_stem = key[:-1], key[-1] + for k in key_parent: + if k not in cont: + cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}} + cont = cont[k]["nested"] + if key_stem not in cont: + cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}} + cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag) + + def is_(self, key: Key, flag: int) -> bool: + if not key: + return False # document root has no flags + cont = self._flags + for k in key[:-1]: + if k not in cont: + return False + inner_cont = cont[k] + if flag in inner_cont["recursive_flags"]: + return True + cont = inner_cont["nested"] + key_stem = key[-1] + if key_stem in cont: + inner_cont = cont[key_stem] + return flag in inner_cont["flags"] or flag in inner_cont["recursive_flags"] + return False + + +class NestedDict: + def __init__(self) -> None: + # The parsed content of the TOML document + self.dict: dict[str, Any] = {} + + def get_or_create_nest( + self, + key: Key, + *, + access_lists: bool = True, + ) -> dict: + cont: Any = self.dict + for k in key: + if k not in cont: + cont[k] = {} + cont = cont[k] + if access_lists and isinstance(cont, list): + cont = cont[-1] + if not isinstance(cont, dict): + raise KeyError("There is no nest behind this key") + return cont + + def append_nest_to_list(self, key: Key) -> None: + cont = self.get_or_create_nest(key[:-1]) + last_key = key[-1] + if last_key in cont: + list_ = cont[last_key] + if not isinstance(list_, list): + raise KeyError("An object other than list found behind this key") + list_.append({}) + else: + cont[last_key] = [{}] + + +class Output(NamedTuple): + data: NestedDict + flags: Flags + + +def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: + try: + while src[pos] in chars: + pos += 1 + except IndexError: + pass + return pos + + +def skip_until( + src: str, + pos: Pos, + expect: str, + *, + error_on: frozenset[str], + error_on_eof: bool, +) -> Pos: + try: + new_pos = src.index(expect, pos) + except ValueError: + new_pos = len(src) + if error_on_eof: + raise TOMLDecodeError(f"Expected {expect!r}", src, new_pos) from None + + if not error_on.isdisjoint(src[pos:new_pos]): + while src[pos] not in error_on: + pos += 1 + raise TOMLDecodeError(f"Found invalid character {src[pos]!r}", src, pos) + return new_pos + + +def skip_comment(src: str, pos: Pos) -> Pos: + try: + char: str | None = src[pos] + except IndexError: + char = None + if char == "#": + return skip_until( + src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False + ) + return pos + + +def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos: + while True: + pos_before_skip = pos + pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) + pos = skip_comment(src, pos) + if pos == pos_before_skip: + return pos + + +def create_dict_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: + pos += 1 # Skip "[" + pos = skip_chars(src, pos, TOML_WS) + pos, key = parse_key(src, pos) + + if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN): + raise TOMLDecodeError(f"Cannot declare {key} twice", src, pos) + out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) + try: + out.data.get_or_create_nest(key) + except KeyError: + raise TOMLDecodeError("Cannot overwrite a value", src, pos) from None + + if not src.startswith("]", pos): + raise TOMLDecodeError( + "Expected ']' at the end of a table declaration", src, pos + ) + return pos + 1, key + + +def create_list_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: + pos += 2 # Skip "[[" + pos = skip_chars(src, pos, TOML_WS) + pos, key = parse_key(src, pos) + + if out.flags.is_(key, Flags.FROZEN): + raise TOMLDecodeError(f"Cannot mutate immutable namespace {key}", src, pos) + # Free the namespace now that it points to another empty list item... + out.flags.unset_all(key) + # ...but this key precisely is still prohibited from table declaration + out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) + try: + out.data.append_nest_to_list(key) + except KeyError: + raise TOMLDecodeError("Cannot overwrite a value", src, pos) from None + + if not src.startswith("]]", pos): + raise TOMLDecodeError( + "Expected ']]' at the end of an array declaration", src, pos + ) + return pos + 2, key + + +def key_value_rule( + src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat +) -> Pos: + pos, key, value = parse_key_value_pair(src, pos, parse_float, nest_lvl=0) + key_parent, key_stem = key[:-1], key[-1] + abs_key_parent = header + key_parent + + relative_path_cont_keys = (header + key[:i] for i in range(1, len(key))) + for cont_key in relative_path_cont_keys: + # Check that dotted key syntax does not redefine an existing table + if out.flags.is_(cont_key, Flags.EXPLICIT_NEST): + raise TOMLDecodeError(f"Cannot redefine namespace {cont_key}", src, pos) + # Containers in the relative path can't be opened with the table syntax or + # dotted key/value syntax in following table sections. + out.flags.add_pending(cont_key, Flags.EXPLICIT_NEST) + + if out.flags.is_(abs_key_parent, Flags.FROZEN): + raise TOMLDecodeError( + f"Cannot mutate immutable namespace {abs_key_parent}", src, pos + ) + + try: + nest = out.data.get_or_create_nest(abs_key_parent) + except KeyError: + raise TOMLDecodeError("Cannot overwrite a value", src, pos) from None + if key_stem in nest: + raise TOMLDecodeError("Cannot overwrite a value", src, pos) + # Mark inline table and array namespaces recursively immutable + if isinstance(value, (dict, list)): + out.flags.set(header + key, Flags.FROZEN, recursive=True) + nest[key_stem] = value + return pos + + +def parse_key_value_pair( + src: str, pos: Pos, parse_float: ParseFloat, nest_lvl: int +) -> tuple[Pos, Key, Any]: + pos, key = parse_key(src, pos) + try: + char: str | None = src[pos] + except IndexError: + char = None + if char != "=": + raise TOMLDecodeError("Expected '=' after a key in a key/value pair", src, pos) + pos += 1 + pos = skip_chars(src, pos, TOML_WS) + pos, value = parse_value(src, pos, parse_float, nest_lvl) + return pos, key, value + + +def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]: + pos, key_part = parse_key_part(src, pos) + key: Key = (key_part,) + pos = skip_chars(src, pos, TOML_WS) + while True: + try: + char: str | None = src[pos] + except IndexError: + char = None + if char != ".": + return pos, key + pos += 1 + pos = skip_chars(src, pos, TOML_WS) + pos, key_part = parse_key_part(src, pos) + key += (key_part,) + pos = skip_chars(src, pos, TOML_WS) + + +def parse_key_part(src: str, pos: Pos) -> tuple[Pos, str]: + try: + char: str | None = src[pos] + except IndexError: + char = None + if char in BARE_KEY_CHARS: + start_pos = pos + pos = skip_chars(src, pos, BARE_KEY_CHARS) + return pos, src[start_pos:pos] + if char == "'": + return parse_literal_str(src, pos) + if char == '"': + return parse_one_line_basic_str(src, pos) + raise TOMLDecodeError("Invalid initial character for a key part", src, pos) + + +def parse_one_line_basic_str(src: str, pos: Pos) -> tuple[Pos, str]: + pos += 1 + return parse_basic_str(src, pos, multiline=False) + + +def parse_array( + src: str, pos: Pos, parse_float: ParseFloat, nest_lvl: int +) -> tuple[Pos, list]: + pos += 1 + array: list = [] + + pos = skip_comments_and_array_ws(src, pos) + if src.startswith("]", pos): + return pos + 1, array + while True: + pos, val = parse_value(src, pos, parse_float, nest_lvl) + array.append(val) + pos = skip_comments_and_array_ws(src, pos) + + c = src[pos : pos + 1] + if c == "]": + return pos + 1, array + if c != ",": + raise TOMLDecodeError("Unclosed array", src, pos) + pos += 1 + + pos = skip_comments_and_array_ws(src, pos) + if src.startswith("]", pos): + return pos + 1, array + + +def parse_inline_table( + src: str, pos: Pos, parse_float: ParseFloat, nest_lvl: int +) -> tuple[Pos, dict]: + pos += 1 + nested_dict = NestedDict() + flags = Flags() + + pos = skip_chars(src, pos, TOML_WS) + if src.startswith("}", pos): + return pos + 1, nested_dict.dict + while True: + pos, key, value = parse_key_value_pair(src, pos, parse_float, nest_lvl) + key_parent, key_stem = key[:-1], key[-1] + if flags.is_(key, Flags.FROZEN): + raise TOMLDecodeError(f"Cannot mutate immutable namespace {key}", src, pos) + try: + nest = nested_dict.get_or_create_nest(key_parent, access_lists=False) + except KeyError: + raise TOMLDecodeError("Cannot overwrite a value", src, pos) from None + if key_stem in nest: + raise TOMLDecodeError(f"Duplicate inline table key {key_stem!r}", src, pos) + nest[key_stem] = value + pos = skip_chars(src, pos, TOML_WS) + c = src[pos : pos + 1] + if c == "}": + return pos + 1, nested_dict.dict + if c != ",": + raise TOMLDecodeError("Unclosed inline table", src, pos) + if isinstance(value, (dict, list)): + flags.set(key, Flags.FROZEN, recursive=True) + pos += 1 + pos = skip_chars(src, pos, TOML_WS) + + +def parse_basic_str_escape( + src: str, pos: Pos, *, multiline: bool = False +) -> tuple[Pos, str]: + escape_id = src[pos : pos + 2] + pos += 2 + if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}: + # Skip whitespace until next non-whitespace character or end of + # the doc. Error if non-whitespace is found before newline. + if escape_id != "\\\n": + pos = skip_chars(src, pos, TOML_WS) + try: + char = src[pos] + except IndexError: + return pos, "" + if char != "\n": + raise TOMLDecodeError("Unescaped '\\' in a string", src, pos) + pos += 1 + pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) + return pos, "" + if escape_id == "\\u": + return parse_hex_char(src, pos, 4) + if escape_id == "\\U": + return parse_hex_char(src, pos, 8) + try: + return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id] + except KeyError: + raise TOMLDecodeError("Unescaped '\\' in a string", src, pos) from None + + +def parse_basic_str_escape_multiline(src: str, pos: Pos) -> tuple[Pos, str]: + return parse_basic_str_escape(src, pos, multiline=True) + + +def parse_hex_char(src: str, pos: Pos, hex_len: int) -> tuple[Pos, str]: + hex_str = src[pos : pos + hex_len] + if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str): + raise TOMLDecodeError("Invalid hex value", src, pos) + pos += hex_len + hex_int = int(hex_str, 16) + if not is_unicode_scalar_value(hex_int): + raise TOMLDecodeError( + "Escaped character is not a Unicode scalar value", src, pos + ) + return pos, chr(hex_int) + + +def parse_literal_str(src: str, pos: Pos) -> tuple[Pos, str]: + pos += 1 # Skip starting apostrophe + start_pos = pos + pos = skip_until( + src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True + ) + return pos + 1, src[start_pos:pos] # Skip ending apostrophe + + +def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> tuple[Pos, str]: + pos += 3 + if src.startswith("\n", pos): + pos += 1 + + if literal: + delim = "'" + end_pos = skip_until( + src, + pos, + "'''", + error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS, + error_on_eof=True, + ) + result = src[pos:end_pos] + pos = end_pos + 3 + else: + delim = '"' + pos, result = parse_basic_str(src, pos, multiline=True) + + # Add at maximum two extra apostrophes/quotes if the end sequence + # is 4 or 5 chars long instead of just 3. + if not src.startswith(delim, pos): + return pos, result + pos += 1 + if not src.startswith(delim, pos): + return pos, result + delim + pos += 1 + return pos, result + (delim * 2) + + +def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> tuple[Pos, str]: + if multiline: + error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS + parse_escapes = parse_basic_str_escape_multiline + else: + error_on = ILLEGAL_BASIC_STR_CHARS + parse_escapes = parse_basic_str_escape + result = "" + start_pos = pos + while True: + try: + char = src[pos] + except IndexError: + raise TOMLDecodeError("Unterminated string", src, pos) from None + if char == '"': + if not multiline: + return pos + 1, result + src[start_pos:pos] + if src.startswith('"""', pos): + return pos + 3, result + src[start_pos:pos] + pos += 1 + continue + if char == "\\": + result += src[start_pos:pos] + pos, parsed_escape = parse_escapes(src, pos) + result += parsed_escape + start_pos = pos + continue + if char in error_on: + raise TOMLDecodeError(f"Illegal character {char!r}", src, pos) + pos += 1 + + +def parse_value( # noqa: C901 + src: str, pos: Pos, parse_float: ParseFloat, nest_lvl: int +) -> tuple[Pos, Any]: + if nest_lvl > MAX_INLINE_NESTING: + # Pure Python should have raised RecursionError already. + # This ensures mypyc binaries eventually do the same. + raise RecursionError( # pragma: no cover + "TOML inline arrays/tables are nested more than the allowed" + f" {MAX_INLINE_NESTING} levels" + ) + + try: + char: str | None = src[pos] + except IndexError: + char = None + + # IMPORTANT: order conditions based on speed of checking and likelihood + + # Basic strings + if char == '"': + if src.startswith('"""', pos): + return parse_multiline_str(src, pos, literal=False) + return parse_one_line_basic_str(src, pos) + + # Literal strings + if char == "'": + if src.startswith("'''", pos): + return parse_multiline_str(src, pos, literal=True) + return parse_literal_str(src, pos) + + # Booleans + if char == "t": + if src.startswith("true", pos): + return pos + 4, True + if char == "f": + if src.startswith("false", pos): + return pos + 5, False + + # Arrays + if char == "[": + return parse_array(src, pos, parse_float, nest_lvl + 1) + + # Inline tables + if char == "{": + return parse_inline_table(src, pos, parse_float, nest_lvl + 1) + + # Dates and times + datetime_match = RE_DATETIME.match(src, pos) + if datetime_match: + try: + datetime_obj = match_to_datetime(datetime_match) + except ValueError as e: + raise TOMLDecodeError("Invalid date or datetime", src, pos) from e + return datetime_match.end(), datetime_obj + localtime_match = RE_LOCALTIME.match(src, pos) + if localtime_match: + return localtime_match.end(), match_to_localtime(localtime_match) + + # Integers and "normal" floats. + # The regex will greedily match any type starting with a decimal + # char, so needs to be located after handling of dates and times. + number_match = RE_NUMBER.match(src, pos) + if number_match: + return number_match.end(), match_to_number(number_match, parse_float) + + # Special floats + first_three = src[pos : pos + 3] + if first_three in {"inf", "nan"}: + return pos + 3, parse_float(first_three) + first_four = src[pos : pos + 4] + if first_four in {"-inf", "+inf", "-nan", "+nan"}: + return pos + 4, parse_float(first_four) + + raise TOMLDecodeError("Invalid value", src, pos) + + +def is_unicode_scalar_value(codepoint: int) -> bool: + return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111) + + +def make_safe_parse_float(parse_float: ParseFloat) -> ParseFloat: + """A decorator to make `parse_float` safe. + + `parse_float` must not return dicts or lists, because these types + would be mixed with parsed TOML tables and arrays, thus confusing + the parser. The returned decorated callable raises `ValueError` + instead of returning illegal types. + """ + # The default `float` callable never returns illegal types. Optimize it. + if parse_float is float: + return float + + def safe_parse_float(float_str: str) -> Any: + float_value = parse_float(float_str) + if isinstance(float_value, (dict, list)): + raise ValueError("parse_float must not return dicts or lists") + return float_value + + return safe_parse_float diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/_re.py b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_re.py new file mode 100644 index 0000000..5134866 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_re.py @@ -0,0 +1,112 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021 Taneli Hukkinen +# Licensed to PSF under a Contributor Agreement. + +from __future__ import annotations + +from datetime import date, datetime, time, timedelta, timezone, tzinfo +from functools import lru_cache +import re +from typing import Any, Final + +from ._types import ParseFloat + +# E.g. +# - 00:32:00.999999 +# - 00:32:00 +_TIME_RE_STR: Final = ( + r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" +) + +RE_NUMBER: Final = re.compile( + r""" +0 +(?: + x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex + | + b[01](?:_?[01])* # bin + | + o[0-7](?:_?[0-7])* # oct +) +| +[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part +(?P + (?:\.[0-9](?:_?[0-9])*)? # optional fractional part + (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part +) +""", + flags=re.VERBOSE, +) +RE_LOCALTIME: Final = re.compile(_TIME_RE_STR) +RE_DATETIME: Final = re.compile( + rf""" +([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 +(?: + [Tt ] + {_TIME_RE_STR} + (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset +)? +""", + flags=re.VERBOSE, +) + + +def match_to_datetime(match: re.Match) -> datetime | date: + """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. + + Raises ValueError if the match does not correspond to a valid date + or datetime. + """ + ( + year_str, + month_str, + day_str, + hour_str, + minute_str, + sec_str, + micros_str, + zulu_time, + offset_sign_str, + offset_hour_str, + offset_minute_str, + ) = match.groups() + year, month, day = int(year_str), int(month_str), int(day_str) + if hour_str is None: + return date(year, month, day) + hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) + micros = int(micros_str.ljust(6, "0")) if micros_str else 0 + if offset_sign_str: + tz: tzinfo | None = cached_tz( + offset_hour_str, offset_minute_str, offset_sign_str + ) + elif zulu_time: + tz = timezone.utc + else: # local date-time + tz = None + return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) + + +# No need to limit cache size. This is only ever called on input +# that matched RE_DATETIME, so there is an implicit bound of +# 24 (hours) * 60 (minutes) * 2 (offset direction) = 2880. +@lru_cache(maxsize=None) +def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: + sign = 1 if sign_str == "+" else -1 + return timezone( + timedelta( + hours=sign * int(hour_str), + minutes=sign * int(minute_str), + ) + ) + + +def match_to_localtime(match: re.Match) -> time: + hour_str, minute_str, sec_str, micros_str = match.groups() + micros = int(micros_str.ljust(6, "0")) if micros_str else 0 + return time(int(hour_str), int(minute_str), int(sec_str), micros) + + +def match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: + if match.group("floatpart"): + return parse_float(match.group()) + return int(match.group(), 0) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/_types.py b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_types.py new file mode 100644 index 0000000..d949412 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/tomli/_types.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021 Taneli Hukkinen +# Licensed to PSF under a Contributor Agreement. + +from typing import Any, Callable, Tuple + +# Type annotations +ParseFloat = Callable[[str], Any] +Key = Tuple[str, ...] +Pos = int diff --git a/backend/venv/Lib/site-packages/pip/_vendor/tomli/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/tomli/py.typed new file mode 100644 index 0000000..7632ecf --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/tomli/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__init__.py new file mode 100644 index 0000000..e468bf8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__init__.py @@ -0,0 +1,36 @@ +"""Verify certificates using native system trust stores""" + +import sys as _sys + +if _sys.version_info < (3, 10): + raise ImportError("truststore requires Python 3.10 or later") + +# Detect Python runtimes which don't implement SSLObject.get_unverified_chain() API +# This API only became public in Python 3.13 but was available in CPython and PyPy since 3.10. +if _sys.version_info < (3, 13): + try: + import ssl as _ssl + except ImportError: + raise ImportError("truststore requires the 'ssl' module") + else: + _sslmem = _ssl.MemoryBIO() + _sslobj = _ssl.create_default_context().wrap_bio( + _sslmem, + _sslmem, + ) + try: + while not hasattr(_sslobj, "get_unverified_chain"): + _sslobj = _sslobj._sslobj # type: ignore[attr-defined] + except AttributeError: + raise ImportError( + "truststore requires peer certificate chain APIs to be available" + ) from None + + del _ssl, _sslobj, _sslmem # noqa: F821 + +from ._api import SSLContext, extract_from_ssl, inject_into_ssl # noqa: E402 + +del _api, _sys # type: ignore[name-defined] # noqa: F821 + +__all__ = ["SSLContext", "inject_into_ssl", "extract_from_ssl"] +__version__ = "0.10.0" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c428d9c76f36fdd6e1835224d21700056373640e GIT binary patch literal 1350 zcmZ`%&u<$=6rTNId;M$UtW&$S)UYM4f~Cd|0*NYuq;|z2Qh`DxB-WNzYwy@u*Slk8 z$9C-#%KhP@|hk)X2FA+VU+)Tp(l}q2+v1+O1Y4vvJd*A!!do%lM zJRU(1E04dh#v($`{KYI_J&E%HhtNZ0A`O|G$+tL-$9yw5qrG~Y!hIegD)9)5rg#8d ze(ZAp!wyW?T6n4&(1OqxY|7KF`FwD((0t`!Q<<+#zh{i*rPpg%!qNfw@buSdNw@Gi*j$vb~@!*a+q8XZnLFyaF_flAOv{h?_X(jd4F9q@w zQjZ#Ky=svul~kKvXvc63#;7M3AzRfB!_zH9-Dq1=!@k#vYu~2PYJttDuFu@*KcjOX zpcnPq8DrEpqUfa(;%zvLhQr_MRjg+lH+OTu#=5R#F-&{ztFFQ25YK57hCKl(kjIm%r7vG7A-KlHbN(#sR{ zkJRQ^M)Ae{)kh!vg|-gS)~P7%W&ez9eG?kVsc)nIj<2A^@^d7Bl5%yF`21Yplk#aY zJr3~k%VPoX|Hf$)OFu_kpv0ZXSB9BeM{;o}6=7IFUbtx({IOWNfquEZT*{y)nT1kL LcydE7Z3r&`5M^=~ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e363f83afe56d8890704762d261b98e01bd78d65 GIT binary patch literal 16779 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 O@3D>tER+#%;eP>+V}@w} literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcf5c9a9845e68ddc5b809ee41c2588e21b8e7be GIT binary patch literal 18993 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf198e2f36830bf2ae54b263fe1417b9a0cbd762 GIT binary patch literal 2211 zcmZ`)O>7fK6rNeH|C89xKY`MPq^VrwxIby3P(sth5vVi=LVIvcSDW2&yvE+OW+w?w z6M_&@iBu`gr3t-I^-zK6pL*)CoOpgb`Xq8q#nHWotdoV%HY3g4_GDKDQUM;uz9| zFL2f`AR-j&ykuLw=DPv;c*_O}D#mO2cBzTPS8Uwwsp*=Zh{fg|{CF2Q^P(2GB;ME@ z&PKH$se>8y;169AvkhUS)obCWWR8#+iSsO46lUS6AZUIK=R;cEC4V+i#mR<0dFJ7y zIF(2frlu{clvW94Jrz=(YH?kavwE79tS$HcME!!duS14C;T^h!TUB8 zZ4t4D<3+)Zc|>@3HG`*dkVFiowo8i&ivRmbvBCDps z6y307UTMp2x1KWHZjuN3<)ITNGtdtYo*3*uof)wO)3QZ3VL-R|Htd#?sc7E9B@=+7 zn}(J2Q6FDEw7Ij|ZY=JTB58uqSdS_0gQAGm@%+R~aK#uA*1cu&|+-G|lL^#VnXb(z0102HZ?frD`|w{g!PrN$7iX6aT|M^MvDI|u z$HGtMO>;H<-g+py7V26Fb=?ki{~bYXFI*nF7fZ}f&P~prpF6*lza4vS9Wup}EAixa zt;_M`YW&chc#9K+&<7FZkNj(KFkS3F@>V;(+1CM*a-=>%6Mjz{UxEONfULEhC{px$ zqg(wn@?d1)D&9u19jLMu3*d(LWd^g5muV+rOh1Gu0C^VxQxFk6KEA1;fdWy_N|Ob` z3WQ2Euu0^c4rP%PLz6t*NiOar-H;#<0xCphM3eF+Ei0^N=yWnb>tP3!bIkVZmZnoX zSb{WMX_t@pj~veo$^)5Gr(JLk_rH^oPi1UB%vK9Y!M#sgG?X&2_>&?@l)u!Je@0yK z5-3(5hzscVX#M=bxr6gZ=Z-G5u12NxSo6Jj<6>kXvh><7@%@*@d(qCdXmTZ*yw-I) zn!eN2=J-*f(+Qxu#0F$Qb`)^t0n3i?lgVlU*k#8oLV=8O!L%6Pi^?myy}1?UZ`vY| z`#K)Jj({?|!KQn-cm{;W7WV)^V2|8{(*(FH>*Y#`?t{o9JQ_X;a3-e#`NOmWbowla zWFu?~7!SZN>7(w=+5#n%2ipNwtpNKd$D|zu0#<;~w2fO0o0H0l0bHYYWMt&zKrN3Q zI>884fNL(5;1y!j7Dr99@?zQk(JFjF+}%+LGS;@lOJRrJD4W`NiS*GFnEVT1 zeGkI%VT|vh#9b72f04VW{(d0bCM=^Srxoq#UV8cJ;VXxiyWhOEyMGzALm7m+HQcd+ zI~<`6N0tVz4qq8|5UAHCzMZ{3`vY4^58mhYh7Sq5-5{qoh!dZ`;vnd*^=|Oa=|G*& x{}l}4@Oq+oaqq%j#|Qea@#at7U5Gk<&|#(4T}!3@c-|2+Tz literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8aa4cb83275fc43a1e9755cbf71a94adc7b502fa GIT binary patch literal 1105 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/_api.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_api.py new file mode 100644 index 0000000..aeb023a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_api.py @@ -0,0 +1,316 @@ +import os +import platform +import socket +import ssl +import sys +import typing + +import _ssl # type: ignore[import-not-found] + +from ._ssl_constants import ( + _original_SSLContext, + _original_super_SSLContext, + _truststore_SSLContext_dunder_class, + _truststore_SSLContext_super_class, +) + +if platform.system() == "Windows": + from ._windows import _configure_context, _verify_peercerts_impl +elif platform.system() == "Darwin": + from ._macos import _configure_context, _verify_peercerts_impl +else: + from ._openssl import _configure_context, _verify_peercerts_impl + +if typing.TYPE_CHECKING: + from pip._vendor.typing_extensions import Buffer + +# From typeshed/stdlib/ssl.pyi +_StrOrBytesPath: typing.TypeAlias = str | bytes | os.PathLike[str] | os.PathLike[bytes] +_PasswordType: typing.TypeAlias = str | bytes | typing.Callable[[], str | bytes] + + +def inject_into_ssl() -> None: + """Injects the :class:`truststore.SSLContext` into the ``ssl`` + module by replacing :class:`ssl.SSLContext`. + """ + setattr(ssl, "SSLContext", SSLContext) + # urllib3 holds on to its own reference of ssl.SSLContext + # so we need to replace that reference too. + try: + import pip._vendor.urllib3.util.ssl_ as urllib3_ssl + + setattr(urllib3_ssl, "SSLContext", SSLContext) + except ImportError: + pass + + +def extract_from_ssl() -> None: + """Restores the :class:`ssl.SSLContext` class to its original state""" + setattr(ssl, "SSLContext", _original_SSLContext) + try: + import pip._vendor.urllib3.util.ssl_ as urllib3_ssl + + urllib3_ssl.SSLContext = _original_SSLContext # type: ignore[assignment] + except ImportError: + pass + + +class SSLContext(_truststore_SSLContext_super_class): # type: ignore[misc] + """SSLContext API that uses system certificates on all platforms""" + + @property # type: ignore[misc] + def __class__(self) -> type: + # Dirty hack to get around isinstance() checks + # for ssl.SSLContext instances in aiohttp/trustme + # when using non-CPython implementations. + return _truststore_SSLContext_dunder_class or SSLContext + + def __init__(self, protocol: int = None) -> None: # type: ignore[assignment] + self._ctx = _original_SSLContext(protocol) + + class TruststoreSSLObject(ssl.SSLObject): + # This object exists because wrap_bio() doesn't + # immediately do the handshake so we need to do + # certificate verifications after SSLObject.do_handshake() + + def do_handshake(self) -> None: + ret = super().do_handshake() + _verify_peercerts(self, server_hostname=self.server_hostname) + return ret + + self._ctx.sslobject_class = TruststoreSSLObject + + def wrap_socket( + self, + sock: socket.socket, + server_side: bool = False, + do_handshake_on_connect: bool = True, + suppress_ragged_eofs: bool = True, + server_hostname: str | None = None, + session: ssl.SSLSession | None = None, + ) -> ssl.SSLSocket: + # Use a context manager here because the + # inner SSLContext holds on to our state + # but also does the actual handshake. + with _configure_context(self._ctx): + ssl_sock = self._ctx.wrap_socket( + sock, + server_side=server_side, + server_hostname=server_hostname, + do_handshake_on_connect=do_handshake_on_connect, + suppress_ragged_eofs=suppress_ragged_eofs, + session=session, + ) + try: + _verify_peercerts(ssl_sock, server_hostname=server_hostname) + except Exception: + ssl_sock.close() + raise + return ssl_sock + + def wrap_bio( + self, + incoming: ssl.MemoryBIO, + outgoing: ssl.MemoryBIO, + server_side: bool = False, + server_hostname: str | None = None, + session: ssl.SSLSession | None = None, + ) -> ssl.SSLObject: + with _configure_context(self._ctx): + ssl_obj = self._ctx.wrap_bio( + incoming, + outgoing, + server_hostname=server_hostname, + server_side=server_side, + session=session, + ) + return ssl_obj + + def load_verify_locations( + self, + cafile: str | bytes | os.PathLike[str] | os.PathLike[bytes] | None = None, + capath: str | bytes | os.PathLike[str] | os.PathLike[bytes] | None = None, + cadata: typing.Union[str, "Buffer", None] = None, + ) -> None: + return self._ctx.load_verify_locations( + cafile=cafile, capath=capath, cadata=cadata + ) + + def load_cert_chain( + self, + certfile: _StrOrBytesPath, + keyfile: _StrOrBytesPath | None = None, + password: _PasswordType | None = None, + ) -> None: + return self._ctx.load_cert_chain( + certfile=certfile, keyfile=keyfile, password=password + ) + + def load_default_certs( + self, purpose: ssl.Purpose = ssl.Purpose.SERVER_AUTH + ) -> None: + return self._ctx.load_default_certs(purpose) + + def set_alpn_protocols(self, alpn_protocols: typing.Iterable[str]) -> None: + return self._ctx.set_alpn_protocols(alpn_protocols) + + def set_npn_protocols(self, npn_protocols: typing.Iterable[str]) -> None: + return self._ctx.set_npn_protocols(npn_protocols) + + def set_ciphers(self, __cipherlist: str) -> None: + return self._ctx.set_ciphers(__cipherlist) + + def get_ciphers(self) -> typing.Any: + return self._ctx.get_ciphers() + + def session_stats(self) -> dict[str, int]: + return self._ctx.session_stats() + + def cert_store_stats(self) -> dict[str, int]: + raise NotImplementedError() + + def set_default_verify_paths(self) -> None: + self._ctx.set_default_verify_paths() + + @typing.overload + def get_ca_certs( + self, binary_form: typing.Literal[False] = ... + ) -> list[typing.Any]: ... + + @typing.overload + def get_ca_certs(self, binary_form: typing.Literal[True] = ...) -> list[bytes]: ... + + @typing.overload + def get_ca_certs(self, binary_form: bool = ...) -> typing.Any: ... + + def get_ca_certs(self, binary_form: bool = False) -> list[typing.Any] | list[bytes]: + raise NotImplementedError() + + @property + def check_hostname(self) -> bool: + return self._ctx.check_hostname + + @check_hostname.setter + def check_hostname(self, value: bool) -> None: + self._ctx.check_hostname = value + + @property + def hostname_checks_common_name(self) -> bool: + return self._ctx.hostname_checks_common_name + + @hostname_checks_common_name.setter + def hostname_checks_common_name(self, value: bool) -> None: + self._ctx.hostname_checks_common_name = value + + @property + def keylog_filename(self) -> str: + return self._ctx.keylog_filename + + @keylog_filename.setter + def keylog_filename(self, value: str) -> None: + self._ctx.keylog_filename = value + + @property + def maximum_version(self) -> ssl.TLSVersion: + return self._ctx.maximum_version + + @maximum_version.setter + def maximum_version(self, value: ssl.TLSVersion) -> None: + _original_super_SSLContext.maximum_version.__set__( # type: ignore[attr-defined] + self._ctx, value + ) + + @property + def minimum_version(self) -> ssl.TLSVersion: + return self._ctx.minimum_version + + @minimum_version.setter + def minimum_version(self, value: ssl.TLSVersion) -> None: + _original_super_SSLContext.minimum_version.__set__( # type: ignore[attr-defined] + self._ctx, value + ) + + @property + def options(self) -> ssl.Options: + return self._ctx.options + + @options.setter + def options(self, value: ssl.Options) -> None: + _original_super_SSLContext.options.__set__( # type: ignore[attr-defined] + self._ctx, value + ) + + @property + def post_handshake_auth(self) -> bool: + return self._ctx.post_handshake_auth + + @post_handshake_auth.setter + def post_handshake_auth(self, value: bool) -> None: + self._ctx.post_handshake_auth = value + + @property + def protocol(self) -> ssl._SSLMethod: + return self._ctx.protocol + + @property + def security_level(self) -> int: + return self._ctx.security_level + + @property + def verify_flags(self) -> ssl.VerifyFlags: + return self._ctx.verify_flags + + @verify_flags.setter + def verify_flags(self, value: ssl.VerifyFlags) -> None: + _original_super_SSLContext.verify_flags.__set__( # type: ignore[attr-defined] + self._ctx, value + ) + + @property + def verify_mode(self) -> ssl.VerifyMode: + return self._ctx.verify_mode + + @verify_mode.setter + def verify_mode(self, value: ssl.VerifyMode) -> None: + _original_super_SSLContext.verify_mode.__set__( # type: ignore[attr-defined] + self._ctx, value + ) + + +# Python 3.13+ makes get_unverified_chain() a public API that only returns DER +# encoded certificates. We detect whether we need to call public_bytes() for 3.10->3.12 +# Pre-3.13 returned None instead of an empty list from get_unverified_chain() +if sys.version_info >= (3, 13): + + def _get_unverified_chain_bytes(sslobj: ssl.SSLObject) -> list[bytes]: + unverified_chain = sslobj.get_unverified_chain() or () # type: ignore[attr-defined] + return [ + cert if isinstance(cert, bytes) else cert.public_bytes(_ssl.ENCODING_DER) + for cert in unverified_chain + ] + +else: + + def _get_unverified_chain_bytes(sslobj: ssl.SSLObject) -> list[bytes]: + unverified_chain = sslobj.get_unverified_chain() or () # type: ignore[attr-defined] + return [cert.public_bytes(_ssl.ENCODING_DER) for cert in unverified_chain] + + +def _verify_peercerts( + sock_or_sslobj: ssl.SSLSocket | ssl.SSLObject, server_hostname: str | None +) -> None: + """ + Verifies the peer certificates from an SSLSocket or SSLObject + against the certificates in the OS trust store. + """ + sslobj: ssl.SSLObject = sock_or_sslobj # type: ignore[assignment] + try: + while not hasattr(sslobj, "get_unverified_chain"): + sslobj = sslobj._sslobj # type: ignore[attr-defined] + except AttributeError: + pass + + cert_bytes = _get_unverified_chain_bytes(sslobj) + _verify_peercerts_impl( + sock_or_sslobj.context, cert_bytes, server_hostname=server_hostname + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/_macos.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_macos.py new file mode 100644 index 0000000..3450307 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_macos.py @@ -0,0 +1,571 @@ +import contextlib +import ctypes +import platform +import ssl +import typing +from ctypes import ( + CDLL, + POINTER, + c_bool, + c_char_p, + c_int32, + c_long, + c_uint32, + c_ulong, + c_void_p, +) +from ctypes.util import find_library + +from ._ssl_constants import _set_ssl_context_verify_mode + +_mac_version = platform.mac_ver()[0] +_mac_version_info = tuple(map(int, _mac_version.split("."))) +if _mac_version_info < (10, 8): + raise ImportError( + f"Only OS X 10.8 and newer are supported, not {_mac_version_info[0]}.{_mac_version_info[1]}" + ) + +_is_macos_version_10_14_or_later = _mac_version_info >= (10, 14) + + +def _load_cdll(name: str, macos10_16_path: str) -> CDLL: + """Loads a CDLL by name, falling back to known path on 10.16+""" + try: + # Big Sur is technically 11 but we use 10.16 due to the Big Sur + # beta being labeled as 10.16. + path: str | None + if _mac_version_info >= (10, 16): + path = macos10_16_path + else: + path = find_library(name) + if not path: + raise OSError # Caught and reraised as 'ImportError' + return CDLL(path, use_errno=True) + except OSError: + raise ImportError(f"The library {name} failed to load") from None + + +Security = _load_cdll( + "Security", "/System/Library/Frameworks/Security.framework/Security" +) +CoreFoundation = _load_cdll( + "CoreFoundation", + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", +) + +Boolean = c_bool +CFIndex = c_long +CFStringEncoding = c_uint32 +CFData = c_void_p +CFString = c_void_p +CFArray = c_void_p +CFMutableArray = c_void_p +CFError = c_void_p +CFType = c_void_p +CFTypeID = c_ulong +CFTypeRef = POINTER(CFType) +CFAllocatorRef = c_void_p + +OSStatus = c_int32 + +CFErrorRef = POINTER(CFError) +CFDataRef = POINTER(CFData) +CFStringRef = POINTER(CFString) +CFArrayRef = POINTER(CFArray) +CFMutableArrayRef = POINTER(CFMutableArray) +CFArrayCallBacks = c_void_p +CFOptionFlags = c_uint32 + +SecCertificateRef = POINTER(c_void_p) +SecPolicyRef = POINTER(c_void_p) +SecTrustRef = POINTER(c_void_p) +SecTrustResultType = c_uint32 +SecTrustOptionFlags = c_uint32 + +try: + Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef] + Security.SecCertificateCreateWithData.restype = SecCertificateRef + + Security.SecCertificateCopyData.argtypes = [SecCertificateRef] + Security.SecCertificateCopyData.restype = CFDataRef + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef] + Security.SecTrustSetAnchorCertificates.restype = OSStatus + + Security.SecTrustSetAnchorCertificatesOnly.argtypes = [SecTrustRef, Boolean] + Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus + + Security.SecPolicyCreateRevocation.argtypes = [CFOptionFlags] + Security.SecPolicyCreateRevocation.restype = SecPolicyRef + + Security.SecPolicyCreateSSL.argtypes = [Boolean, CFStringRef] + Security.SecPolicyCreateSSL.restype = SecPolicyRef + + Security.SecTrustCreateWithCertificates.argtypes = [ + CFTypeRef, + CFTypeRef, + POINTER(SecTrustRef), + ] + Security.SecTrustCreateWithCertificates.restype = OSStatus + + Security.SecTrustGetTrustResult.argtypes = [ + SecTrustRef, + POINTER(SecTrustResultType), + ] + Security.SecTrustGetTrustResult.restype = OSStatus + + Security.SecTrustEvaluate.argtypes = [ + SecTrustRef, + POINTER(SecTrustResultType), + ] + Security.SecTrustEvaluate.restype = OSStatus + + Security.SecTrustRef = SecTrustRef # type: ignore[attr-defined] + Security.SecTrustResultType = SecTrustResultType # type: ignore[attr-defined] + Security.OSStatus = OSStatus # type: ignore[attr-defined] + + kSecRevocationUseAnyAvailableMethod = 3 + kSecRevocationRequirePositiveResponse = 8 + + CoreFoundation.CFRelease.argtypes = [CFTypeRef] + CoreFoundation.CFRelease.restype = None + + CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef] + CoreFoundation.CFGetTypeID.restype = CFTypeID + + CoreFoundation.CFStringCreateWithCString.argtypes = [ + CFAllocatorRef, + c_char_p, + CFStringEncoding, + ] + CoreFoundation.CFStringCreateWithCString.restype = CFStringRef + + CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding] + CoreFoundation.CFStringGetCStringPtr.restype = c_char_p + + CoreFoundation.CFStringGetCString.argtypes = [ + CFStringRef, + c_char_p, + CFIndex, + CFStringEncoding, + ] + CoreFoundation.CFStringGetCString.restype = c_bool + + CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex] + CoreFoundation.CFDataCreate.restype = CFDataRef + + CoreFoundation.CFDataGetLength.argtypes = [CFDataRef] + CoreFoundation.CFDataGetLength.restype = CFIndex + + CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef] + CoreFoundation.CFDataGetBytePtr.restype = c_void_p + + CoreFoundation.CFArrayCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreate.restype = CFArrayRef + + CoreFoundation.CFArrayCreateMutable.argtypes = [ + CFAllocatorRef, + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef + + CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p] + CoreFoundation.CFArrayAppendValue.restype = None + + CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef] + CoreFoundation.CFArrayGetCount.restype = CFIndex + + CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex] + CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p + + CoreFoundation.CFErrorGetCode.argtypes = [CFErrorRef] + CoreFoundation.CFErrorGetCode.restype = CFIndex + + CoreFoundation.CFErrorCopyDescription.argtypes = [CFErrorRef] + CoreFoundation.CFErrorCopyDescription.restype = CFStringRef + + CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll( # type: ignore[attr-defined] + CoreFoundation, "kCFAllocatorDefault" + ) + CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll( # type: ignore[attr-defined] + CoreFoundation, "kCFTypeArrayCallBacks" + ) + + CoreFoundation.CFTypeRef = CFTypeRef # type: ignore[attr-defined] + CoreFoundation.CFArrayRef = CFArrayRef # type: ignore[attr-defined] + CoreFoundation.CFStringRef = CFStringRef # type: ignore[attr-defined] + CoreFoundation.CFErrorRef = CFErrorRef # type: ignore[attr-defined] + +except AttributeError as e: + raise ImportError(f"Error initializing ctypes: {e}") from None + +# SecTrustEvaluateWithError is macOS 10.14+ +if _is_macos_version_10_14_or_later: + try: + Security.SecTrustEvaluateWithError.argtypes = [ + SecTrustRef, + POINTER(CFErrorRef), + ] + Security.SecTrustEvaluateWithError.restype = c_bool + except AttributeError as e: + raise ImportError(f"Error initializing ctypes: {e}") from None + + +def _handle_osstatus(result: OSStatus, _: typing.Any, args: typing.Any) -> typing.Any: + """ + Raises an error if the OSStatus value is non-zero. + """ + if int(result) == 0: + return args + + # Returns a CFString which we need to transform + # into a UTF-8 Python string. + error_message_cfstring = None + try: + error_message_cfstring = Security.SecCopyErrorMessageString(result, None) + + # First step is convert the CFString into a C string pointer. + # We try the fast no-copy way first. + error_message_cfstring_c_void_p = ctypes.cast( + error_message_cfstring, ctypes.POINTER(ctypes.c_void_p) + ) + message = CoreFoundation.CFStringGetCStringPtr( + error_message_cfstring_c_void_p, CFConst.kCFStringEncodingUTF8 + ) + + # Quoting the Apple dev docs: + # + # "A pointer to a C string or NULL if the internal + # storage of theString does not allow this to be + # returned efficiently." + # + # So we need to get our hands dirty. + if message is None: + buffer = ctypes.create_string_buffer(1024) + result = CoreFoundation.CFStringGetCString( + error_message_cfstring_c_void_p, + buffer, + 1024, + CFConst.kCFStringEncodingUTF8, + ) + if not result: + raise OSError("Error copying C string from CFStringRef") + message = buffer.value + + finally: + if error_message_cfstring is not None: + CoreFoundation.CFRelease(error_message_cfstring) + + # If no message can be found for this status we come + # up with a generic one that forwards the status code. + if message is None or message == "": + message = f"SecureTransport operation returned a non-zero OSStatus: {result}" + + raise ssl.SSLError(message) + + +Security.SecTrustCreateWithCertificates.errcheck = _handle_osstatus # type: ignore[assignment] +Security.SecTrustSetAnchorCertificates.errcheck = _handle_osstatus # type: ignore[assignment] +Security.SecTrustSetAnchorCertificatesOnly.errcheck = _handle_osstatus # type: ignore[assignment] +Security.SecTrustGetTrustResult.errcheck = _handle_osstatus # type: ignore[assignment] +Security.SecTrustEvaluate.errcheck = _handle_osstatus # type: ignore[assignment] + + +class CFConst: + """CoreFoundation constants""" + + kCFStringEncodingUTF8 = CFStringEncoding(0x08000100) + + errSecIncompleteCertRevocationCheck = -67635 + errSecHostNameMismatch = -67602 + errSecCertificateExpired = -67818 + errSecNotTrusted = -67843 + + +def _bytes_to_cf_data_ref(value: bytes) -> CFDataRef: # type: ignore[valid-type] + return CoreFoundation.CFDataCreate( # type: ignore[no-any-return] + CoreFoundation.kCFAllocatorDefault, value, len(value) + ) + + +def _bytes_to_cf_string(value: bytes) -> CFString: + """ + Given a Python binary data, create a CFString. + The string must be CFReleased by the caller. + """ + c_str = ctypes.c_char_p(value) + cf_str = CoreFoundation.CFStringCreateWithCString( + CoreFoundation.kCFAllocatorDefault, + c_str, + CFConst.kCFStringEncodingUTF8, + ) + return cf_str # type: ignore[no-any-return] + + +def _cf_string_ref_to_str(cf_string_ref: CFStringRef) -> str | None: # type: ignore[valid-type] + """ + Creates a Unicode string from a CFString object. Used entirely for error + reporting. + Yes, it annoys me quite a lot that this function is this complex. + """ + + string = CoreFoundation.CFStringGetCStringPtr( + cf_string_ref, CFConst.kCFStringEncodingUTF8 + ) + if string is None: + buffer = ctypes.create_string_buffer(1024) + result = CoreFoundation.CFStringGetCString( + cf_string_ref, buffer, 1024, CFConst.kCFStringEncodingUTF8 + ) + if not result: + raise OSError("Error copying C string from CFStringRef") + string = buffer.value + if string is not None: + string = string.decode("utf-8") + return string # type: ignore[no-any-return] + + +def _der_certs_to_cf_cert_array(certs: list[bytes]) -> CFMutableArrayRef: # type: ignore[valid-type] + """Builds a CFArray of SecCertificateRefs from a list of DER-encoded certificates. + Responsibility of the caller to call CoreFoundation.CFRelease on the CFArray. + """ + cf_array = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cf_array: + raise MemoryError("Unable to allocate memory!") + + for cert_data in certs: + cf_data = None + sec_cert_ref = None + try: + cf_data = _bytes_to_cf_data_ref(cert_data) + sec_cert_ref = Security.SecCertificateCreateWithData( + CoreFoundation.kCFAllocatorDefault, cf_data + ) + CoreFoundation.CFArrayAppendValue(cf_array, sec_cert_ref) + finally: + if cf_data: + CoreFoundation.CFRelease(cf_data) + if sec_cert_ref: + CoreFoundation.CFRelease(sec_cert_ref) + + return cf_array # type: ignore[no-any-return] + + +@contextlib.contextmanager +def _configure_context(ctx: ssl.SSLContext) -> typing.Iterator[None]: + check_hostname = ctx.check_hostname + verify_mode = ctx.verify_mode + ctx.check_hostname = False + _set_ssl_context_verify_mode(ctx, ssl.CERT_NONE) + try: + yield + finally: + ctx.check_hostname = check_hostname + _set_ssl_context_verify_mode(ctx, verify_mode) + + +def _verify_peercerts_impl( + ssl_context: ssl.SSLContext, + cert_chain: list[bytes], + server_hostname: str | None = None, +) -> None: + certs = None + policies = None + trust = None + try: + # Only set a hostname on the policy if we're verifying the hostname + # on the leaf certificate. + if server_hostname is not None and ssl_context.check_hostname: + cf_str_hostname = None + try: + cf_str_hostname = _bytes_to_cf_string(server_hostname.encode("ascii")) + ssl_policy = Security.SecPolicyCreateSSL(True, cf_str_hostname) + finally: + if cf_str_hostname: + CoreFoundation.CFRelease(cf_str_hostname) + else: + ssl_policy = Security.SecPolicyCreateSSL(True, None) + + policies = ssl_policy + if ssl_context.verify_flags & ssl.VERIFY_CRL_CHECK_CHAIN: + # Add explicit policy requiring positive revocation checks + policies = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + CoreFoundation.CFArrayAppendValue(policies, ssl_policy) + CoreFoundation.CFRelease(ssl_policy) + revocation_policy = Security.SecPolicyCreateRevocation( + kSecRevocationUseAnyAvailableMethod + | kSecRevocationRequirePositiveResponse + ) + CoreFoundation.CFArrayAppendValue(policies, revocation_policy) + CoreFoundation.CFRelease(revocation_policy) + elif ssl_context.verify_flags & ssl.VERIFY_CRL_CHECK_LEAF: + raise NotImplementedError("VERIFY_CRL_CHECK_LEAF not implemented for macOS") + + certs = None + try: + certs = _der_certs_to_cf_cert_array(cert_chain) + + # Now that we have certificates loaded and a SecPolicy + # we can finally create a SecTrust object! + trust = Security.SecTrustRef() + Security.SecTrustCreateWithCertificates( + certs, policies, ctypes.byref(trust) + ) + + finally: + # The certs are now being held by SecTrust so we can + # release our handles for the array. + if certs: + CoreFoundation.CFRelease(certs) + + # If there are additional trust anchors to load we need to transform + # the list of DER-encoded certificates into a CFArray. + ctx_ca_certs_der: list[bytes] | None = ssl_context.get_ca_certs( + binary_form=True + ) + if ctx_ca_certs_der: + ctx_ca_certs = None + try: + ctx_ca_certs = _der_certs_to_cf_cert_array(ctx_ca_certs_der) + Security.SecTrustSetAnchorCertificates(trust, ctx_ca_certs) + finally: + if ctx_ca_certs: + CoreFoundation.CFRelease(ctx_ca_certs) + + # We always want system certificates. + Security.SecTrustSetAnchorCertificatesOnly(trust, False) + + # macOS 10.13 and earlier don't support SecTrustEvaluateWithError() + # so we use SecTrustEvaluate() which means we need to construct error + # messages ourselves. + if _is_macos_version_10_14_or_later: + _verify_peercerts_impl_macos_10_14(ssl_context, trust) + else: + _verify_peercerts_impl_macos_10_13(ssl_context, trust) + finally: + if policies: + CoreFoundation.CFRelease(policies) + if trust: + CoreFoundation.CFRelease(trust) + + +def _verify_peercerts_impl_macos_10_13( + ssl_context: ssl.SSLContext, sec_trust_ref: typing.Any +) -> None: + """Verify using 'SecTrustEvaluate' API for macOS 10.13 and earlier. + macOS 10.14 added the 'SecTrustEvaluateWithError' API. + """ + sec_trust_result_type = Security.SecTrustResultType() + Security.SecTrustEvaluate(sec_trust_ref, ctypes.byref(sec_trust_result_type)) + + try: + sec_trust_result_type_as_int = int(sec_trust_result_type.value) + except (ValueError, TypeError): + sec_trust_result_type_as_int = -1 + + # Apple doesn't document these values in their own API docs. + # See: https://github.com/xybp888/iOS-SDKs/blob/master/iPhoneOS13.0.sdk/System/Library/Frameworks/Security.framework/Headers/SecTrust.h#L84 + if ( + ssl_context.verify_mode == ssl.CERT_REQUIRED + and sec_trust_result_type_as_int not in (1, 4) + ): + # Note that we're not able to ignore only hostname errors + # for macOS 10.13 and earlier, so check_hostname=False will + # still return an error. + sec_trust_result_type_to_message = { + 0: "Invalid trust result type", + # 1: "Trust evaluation succeeded", + 2: "User confirmation required", + 3: "User specified that certificate is not trusted", + # 4: "Trust result is unspecified", + 5: "Recoverable trust failure occurred", + 6: "Fatal trust failure occurred", + 7: "Other error occurred, certificate may be revoked", + } + error_message = sec_trust_result_type_to_message.get( + sec_trust_result_type_as_int, + f"Unknown trust result: {sec_trust_result_type_as_int}", + ) + + err = ssl.SSLCertVerificationError(error_message) + err.verify_message = error_message + err.verify_code = sec_trust_result_type_as_int + raise err + + +def _verify_peercerts_impl_macos_10_14( + ssl_context: ssl.SSLContext, sec_trust_ref: typing.Any +) -> None: + """Verify using 'SecTrustEvaluateWithError' API for macOS 10.14+.""" + cf_error = CoreFoundation.CFErrorRef() + sec_trust_eval_result = Security.SecTrustEvaluateWithError( + sec_trust_ref, ctypes.byref(cf_error) + ) + # sec_trust_eval_result is a bool (0 or 1) + # where 1 means that the certs are trusted. + if sec_trust_eval_result == 1: + is_trusted = True + elif sec_trust_eval_result == 0: + is_trusted = False + else: + raise ssl.SSLError( + f"Unknown result from Security.SecTrustEvaluateWithError: {sec_trust_eval_result!r}" + ) + + cf_error_code = 0 + if not is_trusted: + cf_error_code = CoreFoundation.CFErrorGetCode(cf_error) + + # If the error is a known failure that we're + # explicitly okay with from SSLContext configuration + # we can set is_trusted accordingly. + if ssl_context.verify_mode != ssl.CERT_REQUIRED and ( + cf_error_code == CFConst.errSecNotTrusted + or cf_error_code == CFConst.errSecCertificateExpired + ): + is_trusted = True + + # If we're still not trusted then we start to + # construct and raise the SSLCertVerificationError. + if not is_trusted: + cf_error_string_ref = None + try: + cf_error_string_ref = CoreFoundation.CFErrorCopyDescription(cf_error) + + # Can this ever return 'None' if there's a CFError? + cf_error_message = ( + _cf_string_ref_to_str(cf_error_string_ref) + or "Certificate verification failed" + ) + + # TODO: Not sure if we need the SecTrustResultType for anything? + # We only care whether or not it's a success or failure for now. + sec_trust_result_type = Security.SecTrustResultType() + Security.SecTrustGetTrustResult( + sec_trust_ref, ctypes.byref(sec_trust_result_type) + ) + + err = ssl.SSLCertVerificationError(cf_error_message) + err.verify_message = cf_error_message + err.verify_code = cf_error_code + raise err + finally: + if cf_error_string_ref: + CoreFoundation.CFRelease(cf_error_string_ref) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/_openssl.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_openssl.py new file mode 100644 index 0000000..9951cf7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_openssl.py @@ -0,0 +1,66 @@ +import contextlib +import os +import re +import ssl +import typing + +# candidates based on https://github.com/tiran/certifi-system-store by Christian Heimes +_CA_FILE_CANDIDATES = [ + # Alpine, Arch, Fedora 34+, OpenWRT, RHEL 9+, BSD + "/etc/ssl/cert.pem", + # Fedora <= 34, RHEL <= 9, CentOS <= 9 + "/etc/pki/tls/cert.pem", + # Debian, Ubuntu (requires ca-certificates) + "/etc/ssl/certs/ca-certificates.crt", + # SUSE + "/etc/ssl/ca-bundle.pem", +] + +_HASHED_CERT_FILENAME_RE = re.compile(r"^[0-9a-fA-F]{8}\.[0-9]$") + + +@contextlib.contextmanager +def _configure_context(ctx: ssl.SSLContext) -> typing.Iterator[None]: + # First, check whether the default locations from OpenSSL + # seem like they will give us a usable set of CA certs. + # ssl.get_default_verify_paths already takes care of: + # - getting cafile from either the SSL_CERT_FILE env var + # or the path configured when OpenSSL was compiled, + # and verifying that that path exists + # - getting capath from either the SSL_CERT_DIR env var + # or the path configured when OpenSSL was compiled, + # and verifying that that path exists + # In addition we'll check whether capath appears to contain certs. + defaults = ssl.get_default_verify_paths() + if defaults.cafile or (defaults.capath and _capath_contains_certs(defaults.capath)): + ctx.set_default_verify_paths() + else: + # cafile from OpenSSL doesn't exist + # and capath from OpenSSL doesn't contain certs. + # Let's search other common locations instead. + for cafile in _CA_FILE_CANDIDATES: + if os.path.isfile(cafile): + ctx.load_verify_locations(cafile=cafile) + break + + yield + + +def _capath_contains_certs(capath: str) -> bool: + """Check whether capath exists and contains certs in the expected format.""" + if not os.path.isdir(capath): + return False + for name in os.listdir(capath): + if _HASHED_CERT_FILENAME_RE.match(name): + return True + return False + + +def _verify_peercerts_impl( + ssl_context: ssl.SSLContext, + cert_chain: list[bytes], + server_hostname: str | None = None, +) -> None: + # This is a no-op because we've enabled SSLContext's built-in + # verification via verify_mode=CERT_REQUIRED, and don't need to repeat it. + pass diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/_ssl_constants.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_ssl_constants.py new file mode 100644 index 0000000..b1ee7a3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_ssl_constants.py @@ -0,0 +1,31 @@ +import ssl +import sys +import typing + +# Hold on to the original class so we can create it consistently +# even if we inject our own SSLContext into the ssl module. +_original_SSLContext = ssl.SSLContext +_original_super_SSLContext = super(_original_SSLContext, _original_SSLContext) + +# CPython is known to be good, but non-CPython implementations +# may implement SSLContext differently so to be safe we don't +# subclass the SSLContext. + +# This is returned by truststore.SSLContext.__class__() +_truststore_SSLContext_dunder_class: typing.Optional[type] + +# This value is the superclass of truststore.SSLContext. +_truststore_SSLContext_super_class: type + +if sys.implementation.name == "cpython": + _truststore_SSLContext_super_class = _original_SSLContext + _truststore_SSLContext_dunder_class = None +else: + _truststore_SSLContext_super_class = object + _truststore_SSLContext_dunder_class = _original_SSLContext + + +def _set_ssl_context_verify_mode( + ssl_context: ssl.SSLContext, verify_mode: ssl.VerifyMode +) -> None: + _original_super_SSLContext.verify_mode.__set__(ssl_context, verify_mode) # type: ignore[attr-defined] diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/_windows.py b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_windows.py new file mode 100644 index 0000000..a9bf9ab --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/truststore/_windows.py @@ -0,0 +1,567 @@ +import contextlib +import ssl +import typing +from ctypes import WinDLL # type: ignore +from ctypes import WinError # type: ignore +from ctypes import ( + POINTER, + Structure, + c_char_p, + c_ulong, + c_void_p, + c_wchar_p, + cast, + create_unicode_buffer, + pointer, + sizeof, +) +from ctypes.wintypes import ( + BOOL, + DWORD, + HANDLE, + LONG, + LPCSTR, + LPCVOID, + LPCWSTR, + LPFILETIME, + LPSTR, + LPWSTR, +) +from typing import TYPE_CHECKING, Any + +from ._ssl_constants import _set_ssl_context_verify_mode + +HCERTCHAINENGINE = HANDLE +HCERTSTORE = HANDLE +HCRYPTPROV_LEGACY = HANDLE + + +class CERT_CONTEXT(Structure): + _fields_ = ( + ("dwCertEncodingType", DWORD), + ("pbCertEncoded", c_void_p), + ("cbCertEncoded", DWORD), + ("pCertInfo", c_void_p), + ("hCertStore", HCERTSTORE), + ) + + +PCERT_CONTEXT = POINTER(CERT_CONTEXT) +PCCERT_CONTEXT = POINTER(PCERT_CONTEXT) + + +class CERT_ENHKEY_USAGE(Structure): + _fields_ = ( + ("cUsageIdentifier", DWORD), + ("rgpszUsageIdentifier", POINTER(LPSTR)), + ) + + +PCERT_ENHKEY_USAGE = POINTER(CERT_ENHKEY_USAGE) + + +class CERT_USAGE_MATCH(Structure): + _fields_ = ( + ("dwType", DWORD), + ("Usage", CERT_ENHKEY_USAGE), + ) + + +class CERT_CHAIN_PARA(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("RequestedUsage", CERT_USAGE_MATCH), + ("RequestedIssuancePolicy", CERT_USAGE_MATCH), + ("dwUrlRetrievalTimeout", DWORD), + ("fCheckRevocationFreshnessTime", BOOL), + ("dwRevocationFreshnessTime", DWORD), + ("pftCacheResync", LPFILETIME), + ("pStrongSignPara", c_void_p), + ("dwStrongSignFlags", DWORD), + ) + + +if TYPE_CHECKING: + PCERT_CHAIN_PARA = pointer[CERT_CHAIN_PARA] # type: ignore[misc] +else: + PCERT_CHAIN_PARA = POINTER(CERT_CHAIN_PARA) + + +class CERT_TRUST_STATUS(Structure): + _fields_ = ( + ("dwErrorStatus", DWORD), + ("dwInfoStatus", DWORD), + ) + + +class CERT_CHAIN_ELEMENT(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("pCertContext", PCERT_CONTEXT), + ("TrustStatus", CERT_TRUST_STATUS), + ("pRevocationInfo", c_void_p), + ("pIssuanceUsage", PCERT_ENHKEY_USAGE), + ("pApplicationUsage", PCERT_ENHKEY_USAGE), + ("pwszExtendedErrorInfo", LPCWSTR), + ) + + +PCERT_CHAIN_ELEMENT = POINTER(CERT_CHAIN_ELEMENT) + + +class CERT_SIMPLE_CHAIN(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("TrustStatus", CERT_TRUST_STATUS), + ("cElement", DWORD), + ("rgpElement", POINTER(PCERT_CHAIN_ELEMENT)), + ("pTrustListInfo", c_void_p), + ("fHasRevocationFreshnessTime", BOOL), + ("dwRevocationFreshnessTime", DWORD), + ) + + +PCERT_SIMPLE_CHAIN = POINTER(CERT_SIMPLE_CHAIN) + + +class CERT_CHAIN_CONTEXT(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("TrustStatus", CERT_TRUST_STATUS), + ("cChain", DWORD), + ("rgpChain", POINTER(PCERT_SIMPLE_CHAIN)), + ("cLowerQualityChainContext", DWORD), + ("rgpLowerQualityChainContext", c_void_p), + ("fHasRevocationFreshnessTime", BOOL), + ("dwRevocationFreshnessTime", DWORD), + ) + + +PCERT_CHAIN_CONTEXT = POINTER(CERT_CHAIN_CONTEXT) +PCCERT_CHAIN_CONTEXT = POINTER(PCERT_CHAIN_CONTEXT) + + +class SSL_EXTRA_CERT_CHAIN_POLICY_PARA(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("dwAuthType", DWORD), + ("fdwChecks", DWORD), + ("pwszServerName", LPCWSTR), + ) + + +class CERT_CHAIN_POLICY_PARA(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("dwFlags", DWORD), + ("pvExtraPolicyPara", c_void_p), + ) + + +PCERT_CHAIN_POLICY_PARA = POINTER(CERT_CHAIN_POLICY_PARA) + + +class CERT_CHAIN_POLICY_STATUS(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("dwError", DWORD), + ("lChainIndex", LONG), + ("lElementIndex", LONG), + ("pvExtraPolicyStatus", c_void_p), + ) + + +PCERT_CHAIN_POLICY_STATUS = POINTER(CERT_CHAIN_POLICY_STATUS) + + +class CERT_CHAIN_ENGINE_CONFIG(Structure): + _fields_ = ( + ("cbSize", DWORD), + ("hRestrictedRoot", HCERTSTORE), + ("hRestrictedTrust", HCERTSTORE), + ("hRestrictedOther", HCERTSTORE), + ("cAdditionalStore", DWORD), + ("rghAdditionalStore", c_void_p), + ("dwFlags", DWORD), + ("dwUrlRetrievalTimeout", DWORD), + ("MaximumCachedCertificates", DWORD), + ("CycleDetectionModulus", DWORD), + ("hExclusiveRoot", HCERTSTORE), + ("hExclusiveTrustedPeople", HCERTSTORE), + ("dwExclusiveFlags", DWORD), + ) + + +PCERT_CHAIN_ENGINE_CONFIG = POINTER(CERT_CHAIN_ENGINE_CONFIG) +PHCERTCHAINENGINE = POINTER(HCERTCHAINENGINE) + +X509_ASN_ENCODING = 0x00000001 +PKCS_7_ASN_ENCODING = 0x00010000 +CERT_STORE_PROV_MEMORY = b"Memory" +CERT_STORE_ADD_USE_EXISTING = 2 +USAGE_MATCH_TYPE_OR = 1 +OID_PKIX_KP_SERVER_AUTH = c_char_p(b"1.3.6.1.5.5.7.3.1") +CERT_CHAIN_REVOCATION_CHECK_END_CERT = 0x10000000 +CERT_CHAIN_REVOCATION_CHECK_CHAIN = 0x20000000 +CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS = 0x00000007 +CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG = 0x00000008 +CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG = 0x00000010 +CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG = 0x00000040 +CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG = 0x00000020 +CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG = 0x00000080 +CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS = 0x00000F00 +CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG = 0x00008000 +CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG = 0x00004000 +SECURITY_FLAG_IGNORE_CERT_CN_INVALID = 0x00001000 +AUTHTYPE_SERVER = 2 +CERT_CHAIN_POLICY_SSL = 4 +FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 +FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200 + +# Flags to set for SSLContext.verify_mode=CERT_NONE +CERT_CHAIN_POLICY_VERIFY_MODE_NONE_FLAGS = ( + CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS + | CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG + | CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG + | CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG + | CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG + | CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG + | CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS + | CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG + | CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG +) + +wincrypt = WinDLL("crypt32.dll") +kernel32 = WinDLL("kernel32.dll") + + +def _handle_win_error(result: bool, _: Any, args: Any) -> Any: + if not result: + # Note, actually raises OSError after calling GetLastError and FormatMessage + raise WinError() + return args + + +CertCreateCertificateChainEngine = wincrypt.CertCreateCertificateChainEngine +CertCreateCertificateChainEngine.argtypes = ( + PCERT_CHAIN_ENGINE_CONFIG, + PHCERTCHAINENGINE, +) +CertCreateCertificateChainEngine.errcheck = _handle_win_error + +CertOpenStore = wincrypt.CertOpenStore +CertOpenStore.argtypes = (LPCSTR, DWORD, HCRYPTPROV_LEGACY, DWORD, c_void_p) +CertOpenStore.restype = HCERTSTORE +CertOpenStore.errcheck = _handle_win_error + +CertAddEncodedCertificateToStore = wincrypt.CertAddEncodedCertificateToStore +CertAddEncodedCertificateToStore.argtypes = ( + HCERTSTORE, + DWORD, + c_char_p, + DWORD, + DWORD, + PCCERT_CONTEXT, +) +CertAddEncodedCertificateToStore.restype = BOOL + +CertCreateCertificateContext = wincrypt.CertCreateCertificateContext +CertCreateCertificateContext.argtypes = (DWORD, c_char_p, DWORD) +CertCreateCertificateContext.restype = PCERT_CONTEXT +CertCreateCertificateContext.errcheck = _handle_win_error + +CertGetCertificateChain = wincrypt.CertGetCertificateChain +CertGetCertificateChain.argtypes = ( + HCERTCHAINENGINE, + PCERT_CONTEXT, + LPFILETIME, + HCERTSTORE, + PCERT_CHAIN_PARA, + DWORD, + c_void_p, + PCCERT_CHAIN_CONTEXT, +) +CertGetCertificateChain.restype = BOOL +CertGetCertificateChain.errcheck = _handle_win_error + +CertVerifyCertificateChainPolicy = wincrypt.CertVerifyCertificateChainPolicy +CertVerifyCertificateChainPolicy.argtypes = ( + c_ulong, + PCERT_CHAIN_CONTEXT, + PCERT_CHAIN_POLICY_PARA, + PCERT_CHAIN_POLICY_STATUS, +) +CertVerifyCertificateChainPolicy.restype = BOOL + +CertCloseStore = wincrypt.CertCloseStore +CertCloseStore.argtypes = (HCERTSTORE, DWORD) +CertCloseStore.restype = BOOL +CertCloseStore.errcheck = _handle_win_error + +CertFreeCertificateChain = wincrypt.CertFreeCertificateChain +CertFreeCertificateChain.argtypes = (PCERT_CHAIN_CONTEXT,) + +CertFreeCertificateContext = wincrypt.CertFreeCertificateContext +CertFreeCertificateContext.argtypes = (PCERT_CONTEXT,) + +CertFreeCertificateChainEngine = wincrypt.CertFreeCertificateChainEngine +CertFreeCertificateChainEngine.argtypes = (HCERTCHAINENGINE,) + +FormatMessageW = kernel32.FormatMessageW +FormatMessageW.argtypes = ( + DWORD, + LPCVOID, + DWORD, + DWORD, + LPWSTR, + DWORD, + c_void_p, +) +FormatMessageW.restype = DWORD + + +def _verify_peercerts_impl( + ssl_context: ssl.SSLContext, + cert_chain: list[bytes], + server_hostname: str | None = None, +) -> None: + """Verify the cert_chain from the server using Windows APIs.""" + + # If the peer didn't send any certificates then + # we can't do verification. Raise an error. + if not cert_chain: + raise ssl.SSLCertVerificationError("Peer sent no certificates to verify") + + pCertContext = None + hIntermediateCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, None, 0, None) + try: + # Add intermediate certs to an in-memory cert store + for cert_bytes in cert_chain[1:]: + CertAddEncodedCertificateToStore( + hIntermediateCertStore, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + cert_bytes, + len(cert_bytes), + CERT_STORE_ADD_USE_EXISTING, + None, + ) + + # Cert context for leaf cert + leaf_cert = cert_chain[0] + pCertContext = CertCreateCertificateContext( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, leaf_cert, len(leaf_cert) + ) + + # Chain params to match certs for serverAuth extended usage + cert_enhkey_usage = CERT_ENHKEY_USAGE() + cert_enhkey_usage.cUsageIdentifier = 1 + cert_enhkey_usage.rgpszUsageIdentifier = (c_char_p * 1)(OID_PKIX_KP_SERVER_AUTH) + cert_usage_match = CERT_USAGE_MATCH() + cert_usage_match.Usage = cert_enhkey_usage + chain_params = CERT_CHAIN_PARA() + chain_params.RequestedUsage = cert_usage_match + chain_params.cbSize = sizeof(chain_params) + pChainPara = pointer(chain_params) + + if ssl_context.verify_flags & ssl.VERIFY_CRL_CHECK_CHAIN: + chain_flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN + elif ssl_context.verify_flags & ssl.VERIFY_CRL_CHECK_LEAF: + chain_flags = CERT_CHAIN_REVOCATION_CHECK_END_CERT + else: + chain_flags = 0 + + try: + # First attempt to verify using the default Windows system trust roots + # (default chain engine). + _get_and_verify_cert_chain( + ssl_context, + None, + hIntermediateCertStore, + pCertContext, + pChainPara, + server_hostname, + chain_flags=chain_flags, + ) + except ssl.SSLCertVerificationError as e: + # If that fails but custom CA certs have been added + # to the SSLContext using load_verify_locations, + # try verifying using a custom chain engine + # that trusts the custom CA certs. + custom_ca_certs: list[bytes] | None = ssl_context.get_ca_certs( + binary_form=True + ) + if custom_ca_certs: + try: + _verify_using_custom_ca_certs( + ssl_context, + custom_ca_certs, + hIntermediateCertStore, + pCertContext, + pChainPara, + server_hostname, + chain_flags=chain_flags, + ) + # Raise the original error, not the new error. + except ssl.SSLCertVerificationError: + raise e from None + else: + raise + finally: + CertCloseStore(hIntermediateCertStore, 0) + if pCertContext: + CertFreeCertificateContext(pCertContext) + + +def _get_and_verify_cert_chain( + ssl_context: ssl.SSLContext, + hChainEngine: HCERTCHAINENGINE | None, + hIntermediateCertStore: HCERTSTORE, + pPeerCertContext: c_void_p, + pChainPara: PCERT_CHAIN_PARA, # type: ignore[valid-type] + server_hostname: str | None, + chain_flags: int, +) -> None: + ppChainContext = None + try: + # Get cert chain + ppChainContext = pointer(PCERT_CHAIN_CONTEXT()) + CertGetCertificateChain( + hChainEngine, # chain engine + pPeerCertContext, # leaf cert context + None, # current system time + hIntermediateCertStore, # additional in-memory cert store + pChainPara, # chain-building parameters + chain_flags, + None, # reserved + ppChainContext, # the resulting chain context + ) + pChainContext = ppChainContext.contents + + # Verify cert chain + ssl_extra_cert_chain_policy_para = SSL_EXTRA_CERT_CHAIN_POLICY_PARA() + ssl_extra_cert_chain_policy_para.cbSize = sizeof( + ssl_extra_cert_chain_policy_para + ) + ssl_extra_cert_chain_policy_para.dwAuthType = AUTHTYPE_SERVER + ssl_extra_cert_chain_policy_para.fdwChecks = 0 + if ssl_context.check_hostname is False: + ssl_extra_cert_chain_policy_para.fdwChecks = ( + SECURITY_FLAG_IGNORE_CERT_CN_INVALID + ) + if server_hostname: + ssl_extra_cert_chain_policy_para.pwszServerName = c_wchar_p(server_hostname) + + chain_policy = CERT_CHAIN_POLICY_PARA() + chain_policy.pvExtraPolicyPara = cast( + pointer(ssl_extra_cert_chain_policy_para), c_void_p + ) + if ssl_context.verify_mode == ssl.CERT_NONE: + chain_policy.dwFlags |= CERT_CHAIN_POLICY_VERIFY_MODE_NONE_FLAGS + chain_policy.cbSize = sizeof(chain_policy) + + pPolicyPara = pointer(chain_policy) + policy_status = CERT_CHAIN_POLICY_STATUS() + policy_status.cbSize = sizeof(policy_status) + pPolicyStatus = pointer(policy_status) + CertVerifyCertificateChainPolicy( + CERT_CHAIN_POLICY_SSL, + pChainContext, + pPolicyPara, + pPolicyStatus, + ) + + # Check status + error_code = policy_status.dwError + if error_code: + # Try getting a human readable message for an error code. + error_message_buf = create_unicode_buffer(1024) + error_message_chars = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + None, + error_code, + 0, + error_message_buf, + sizeof(error_message_buf), + None, + ) + + # See if we received a message for the error, + # otherwise we use a generic error with the + # error code and hope that it's search-able. + if error_message_chars <= 0: + error_message = f"Certificate chain policy error {error_code:#x} [{policy_status.lElementIndex}]" + else: + error_message = error_message_buf.value.strip() + + err = ssl.SSLCertVerificationError(error_message) + err.verify_message = error_message + err.verify_code = error_code + raise err from None + finally: + if ppChainContext: + CertFreeCertificateChain(ppChainContext.contents) + + +def _verify_using_custom_ca_certs( + ssl_context: ssl.SSLContext, + custom_ca_certs: list[bytes], + hIntermediateCertStore: HCERTSTORE, + pPeerCertContext: c_void_p, + pChainPara: PCERT_CHAIN_PARA, # type: ignore[valid-type] + server_hostname: str | None, + chain_flags: int, +) -> None: + hChainEngine = None + hRootCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, None, 0, None) + try: + # Add custom CA certs to an in-memory cert store + for cert_bytes in custom_ca_certs: + CertAddEncodedCertificateToStore( + hRootCertStore, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + cert_bytes, + len(cert_bytes), + CERT_STORE_ADD_USE_EXISTING, + None, + ) + + # Create a custom cert chain engine which exclusively trusts + # certs from our hRootCertStore + cert_chain_engine_config = CERT_CHAIN_ENGINE_CONFIG() + cert_chain_engine_config.cbSize = sizeof(cert_chain_engine_config) + cert_chain_engine_config.hExclusiveRoot = hRootCertStore + pConfig = pointer(cert_chain_engine_config) + phChainEngine = pointer(HCERTCHAINENGINE()) + CertCreateCertificateChainEngine( + pConfig, + phChainEngine, + ) + hChainEngine = phChainEngine.contents + + # Get and verify a cert chain using the custom chain engine + _get_and_verify_cert_chain( + ssl_context, + hChainEngine, + hIntermediateCertStore, + pPeerCertContext, + pChainPara, + server_hostname, + chain_flags, + ) + finally: + if hChainEngine: + CertFreeCertificateChainEngine(hChainEngine) + CertCloseStore(hRootCertStore, 0) + + +@contextlib.contextmanager +def _configure_context(ctx: ssl.SSLContext) -> typing.Iterator[None]: + check_hostname = ctx.check_hostname + verify_mode = ctx.verify_mode + ctx.check_hostname = False + _set_ssl_context_verify_mode(ctx, ssl.CERT_NONE) + try: + yield + finally: + ctx.check_hostname = check_hostname + _set_ssl_context_verify_mode(ctx, verify_mode) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/truststore/py.typed b/backend/venv/Lib/site-packages/pip/_vendor/truststore/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/typing_extensions.py b/backend/venv/Lib/site-packages/pip/_vendor/typing_extensions.py new file mode 100644 index 0000000..e429384 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/typing_extensions.py @@ -0,0 +1,3641 @@ +import abc +import collections +import collections.abc +import contextlib +import functools +import inspect +import operator +import sys +import types as _types +import typing +import warnings + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'Buffer', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsAbs', + 'SupportsBytes', + 'SupportsComplex', + 'SupportsFloat', + 'SupportsIndex', + 'SupportsInt', + 'SupportsRound', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'deprecated', + 'Doc', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_original_bases', + 'get_protocol_members', + 'get_type_hints', + 'IntVar', + 'is_protocol', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeAliasType', + 'TypeGuard', + 'TypeIs', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'ReadOnly', + 'Required', + 'NotRequired', + + # Pure aliases, have always been in typing + 'AbstractSet', + 'AnyStr', + 'BinaryIO', + 'Callable', + 'Collection', + 'Container', + 'Dict', + 'ForwardRef', + 'FrozenSet', + 'Generator', + 'Generic', + 'Hashable', + 'IO', + 'ItemsView', + 'Iterable', + 'Iterator', + 'KeysView', + 'List', + 'Mapping', + 'MappingView', + 'Match', + 'MutableMapping', + 'MutableSequence', + 'MutableSet', + 'NoDefault', + 'Optional', + 'Pattern', + 'Reversible', + 'Sequence', + 'Set', + 'Sized', + 'TextIO', + 'Tuple', + 'Union', + 'ValuesView', + 'cast', + 'no_type_check', + 'no_type_check_decorator', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type +_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta") + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + + +class _Sentinel: + def __repr__(self): + return "" + + +_marker = _Sentinel() + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + + +class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + +Final = typing.Final + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 +if sys.version_info >= (3, 10, 1): + Literal = typing.Literal +else: + def _flatten_literal_params(parameters): + """An internal helper for Literal creation: flatten Literals among parameters""" + params = [] + for p in parameters: + if isinstance(p, _LiteralGenericAlias): + params.extend(p.__args__) + else: + params.append(p) + return tuple(params) + + def _value_and_type_iter(params): + for p in params: + yield p, type(p) + + class _LiteralGenericAlias(typing._GenericAlias, _root=True): + def __eq__(self, other): + if not isinstance(other, _LiteralGenericAlias): + return NotImplemented + these_args_deduped = set(_value_and_type_iter(self.__args__)) + other_args_deduped = set(_value_and_type_iter(other.__args__)) + return these_args_deduped == other_args_deduped + + def __hash__(self): + return hash(frozenset(_value_and_type_iter(self.__args__))) + + class _LiteralForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, doc: str): + self._name = 'Literal' + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + + parameters = _flatten_literal_params(parameters) + + val_type_pairs = list(_value_and_type_iter(parameters)) + try: + deduped_pairs = set(val_type_pairs) + except TypeError: + # unhashable parameters + pass + else: + # similar logic to typing._deduplicate on Python 3.9+ + if len(deduped_pairs) < len(val_type_pairs): + new_parameters = [] + for pair in val_type_pairs: + if pair in deduped_pairs: + new_parameters.append(pair[0]) + deduped_pairs.remove(pair) + assert not deduped_pairs, deduped_pairs + parameters = tuple(new_parameters) + + return _LiteralGenericAlias(self, parameters) + + Literal = _LiteralForm(doc="""\ + A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +DefaultDict = typing.DefaultDict +OrderedDict = typing.OrderedDict +Counter = typing.Counter +ChainMap = typing.ChainMap +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +if sys.version_info >= (3, 13, 0, "beta"): + from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator +else: + def _is_dunder(attr): + return attr.startswith('__') and attr.endswith('__') + + # Python <3.9 doesn't have typing._SpecialGenericAlias + _special_generic_alias_base = getattr( + typing, "_SpecialGenericAlias", typing._GenericAlias + ) + + class _SpecialGenericAlias(_special_generic_alias_base, _root=True): + def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()): + if _special_generic_alias_base is typing._GenericAlias: + # Python <3.9 + self.__origin__ = origin + self._nparams = nparams + super().__init__(origin, nparams, special=True, inst=inst, name=name) + else: + # Python >= 3.9 + super().__init__(origin, nparams, inst=inst, name=name) + self._defaults = defaults + + def __setattr__(self, attr, val): + allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'} + if _special_generic_alias_base is typing._GenericAlias: + # Python <3.9 + allowed_attrs.add("__origin__") + if _is_dunder(attr) or attr in allowed_attrs: + object.__setattr__(self, attr, val) + else: + setattr(self.__origin__, attr, val) + + @typing._tp_cache + def __getitem__(self, params): + if not isinstance(params, tuple): + params = (params,) + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) + if ( + self._defaults + and len(params) < self._nparams + and len(params) + len(self._defaults) >= self._nparams + ): + params = (*params, *self._defaults[len(params) - self._nparams:]) + actual_len = len(params) + + if actual_len != self._nparams: + if self._defaults: + expected = f"at least {self._nparams - len(self._defaults)}" + else: + expected = str(self._nparams) + if not self._nparams: + raise TypeError(f"{self} is not a generic class") + raise TypeError( + f"Too {'many' if actual_len > self._nparams else 'few'}" + f" arguments for {self};" + f" actual {actual_len}, expected {expected}" + ) + return self.copy_with(params) + + _NoneType = type(None) + Generator = _SpecialGenericAlias( + collections.abc.Generator, 3, defaults=(_NoneType, _NoneType) + ) + AsyncGenerator = _SpecialGenericAlias( + collections.abc.AsyncGenerator, 2, defaults=(_NoneType,) + ) + ContextManager = _SpecialGenericAlias( + contextlib.AbstractContextManager, + 2, + name="ContextManager", + defaults=(typing.Optional[bool],) + ) + AsyncContextManager = _SpecialGenericAlias( + contextlib.AbstractAsyncContextManager, + 2, + name="AsyncContextManager", + defaults=(typing.Optional[bool],) + ) + + +_PROTO_ALLOWLIST = { + 'collections.abc': [ + 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', + ], + 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'typing_extensions': ['Buffer'], +} + + +_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | { + "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__", + "__final__", +} + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in {'Protocol', 'Generic'}: + continue + annotations = getattr(base, '__annotations__', {}) + for attr in (*base.__dict__, *annotations): + if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): + attrs.add(attr) + return attrs + + +def _caller(depth=2): + try: + return sys._getframe(depth).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + +# `__match_args__` attribute was removed from protocol members in 3.13, +# we want to backport this change to older Python versions. +if sys.version_info >= (3, 13): + Protocol = typing.Protocol +else: + def _allow_reckless_class_checks(depth=3): + """Allow instance and class checks for special stdlib modules. + The abc and functools modules indiscriminately call isinstance() and + issubclass() on the whole MRO of a user class, which may contain protocols. + """ + return _caller(depth) in {'abc', 'functools', None} + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + def _type_check_issubclass_arg_1(arg): + """Raise TypeError if `arg` is not an instance of `type` + in `issubclass(arg, )`. + + In most cases, this is verified by type.__subclasscheck__. + Checking it again unnecessarily would slow down issubclass() checks, + so, we don't perform this check unless we absolutely have to. + + For various error paths, however, + we want to ensure that *this* error message is shown to the user + where relevant, rather than a typing.py-specific error message. + """ + if not isinstance(arg, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + + # Inheriting from typing._ProtocolMeta isn't actually desirable, + # but is necessary to allow typing.Protocol and typing_extensions.Protocol + # to mix without getting TypeErrors about "metaclass conflict" + class _ProtocolMeta(type(typing.Protocol)): + # This metaclass is somewhat unfortunate, + # but is necessary for several reasons... + # + # NOTE: DO NOT call super() in any methods in this class + # That would call the methods on typing._ProtocolMeta on Python 3.8-3.11 + # and those are slow + def __new__(mcls, name, bases, namespace, **kwargs): + if name == "Protocol" and len(bases) < 2: + pass + elif {Protocol, typing.Protocol} & set(bases): + for base in bases: + if not ( + base in {object, typing.Generic, Protocol, typing.Protocol} + or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) + or is_protocol(base) + ): + raise TypeError( + f"Protocols can only inherit from other protocols, " + f"got {base!r}" + ) + return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) + + def __init__(cls, *args, **kwargs): + abc.ABCMeta.__init__(cls, *args, **kwargs) + if getattr(cls, "_is_protocol", False): + cls.__protocol_attrs__ = _get_protocol_attrs(cls) + + def __subclasscheck__(cls, other): + if cls is Protocol: + return type.__subclasscheck__(cls, other) + if ( + getattr(cls, '_is_protocol', False) + and not _allow_reckless_class_checks() + ): + if not getattr(cls, '_is_runtime_protocol', False): + _type_check_issubclass_arg_1(other) + raise TypeError( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) + if ( + # this attribute is set by @runtime_checkable: + cls.__non_callable_proto_members__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): + _type_check_issubclass_arg_1(other) + non_method_attrs = sorted(cls.__non_callable_proto_members__) + raise TypeError( + "Protocols with non-method members don't support issubclass()." + f" Non-method members: {str(non_method_attrs)[1:-1]}." + ) + return abc.ABCMeta.__subclasscheck__(cls, other) + + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if cls is Protocol: + return type.__instancecheck__(cls, instance) + if not getattr(cls, "_is_protocol", False): + # i.e., it's a concrete subclass of a protocol + return abc.ABCMeta.__instancecheck__(cls, instance) + + if ( + not getattr(cls, '_is_runtime_protocol', False) and + not _allow_reckless_class_checks() + ): + raise TypeError("Instance and class checks can only be used with" + " @runtime_checkable protocols") + + if abc.ABCMeta.__instancecheck__(cls, instance): + return True + + for attr in cls.__protocol_attrs__: + try: + val = inspect.getattr_static(instance, attr) + except AttributeError: + break + # this attribute is set by @runtime_checkable: + if val is None and attr not in cls.__non_callable_proto_members__: + break + else: + return True + + return False + + def __eq__(cls, other): + # Hack so that typing.Generic.__class_getitem__ + # treats typing_extensions.Protocol + # as equivalent to typing.Protocol + if abc.ABCMeta.__eq__(cls, other) is True: + return True + return cls is Protocol and other is typing.Protocol + + # This has to be defined, or the abc-module cache + # complains about classes with this metaclass being unhashable, + # if we define only __eq__! + def __hash__(cls) -> int: + return type.__hash__(cls) + + @classmethod + def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if ( + isinstance(annotations, collections.abc.Mapping) + and attr in annotations + and is_protocol(other) + ): + break + else: + return NotImplemented + return True + + class Protocol(typing.Generic, metaclass=_ProtocolMeta): + __doc__ = typing.Protocol.__doc__ + __slots__ = () + _is_protocol = True + _is_runtime_protocol = False + + def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', False): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: + cls.__init__ = _no_init + + +if sys.version_info >= (3, 13): + runtime_checkable = typing.runtime_checkable +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol. + + Such protocol can be used with isinstance() and issubclass(). + Raise TypeError if applied to a non-protocol class. + This allows a simple-minded structural check very similar to + one trick ponies in collections.abc such as Iterable. + + For example:: + + @runtime_checkable + class Closable(Protocol): + def close(self): ... + + assert isinstance(open('/some/file'), Closable) + + Warning: this will check only the presence of the required methods, + not their type signatures! + """ + if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False): + raise TypeError(f'@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + + # typing.Protocol classes on <=3.11 break if we execute this block, + # because typing.Protocol classes on <=3.11 don't have a + # `__protocol_attrs__` attribute, and this block relies on the + # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+ + # break if we *don't* execute this block, because *they* assume that all + # protocol classes have a `__non_callable_proto_members__` attribute + # (which this block sets) + if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2): + # PEP 544 prohibits using issubclass() + # with protocols that have non-method members. + # See gh-113320 for why we compute this attribute here, + # rather than in `_ProtocolMeta.__init__` + cls.__non_callable_proto_members__ = set() + for attr in cls.__protocol_attrs__: + try: + is_callable = callable(getattr(cls, attr, None)) + except Exception as e: + raise TypeError( + f"Failed to determine whether protocol member {attr!r} " + "is a method member" + ) from e + else: + if not is_callable: + cls.__non_callable_proto_members__.add(attr) + + return cls + + +# The "runtime" alias exists for backwards compatibility. +runtime = runtime_checkable + + +# Our version of runtime-checkable protocols is faster on Python 3.8-3.11 +if sys.version_info >= (3, 12): + SupportsInt = typing.SupportsInt + SupportsFloat = typing.SupportsFloat + SupportsComplex = typing.SupportsComplex + SupportsBytes = typing.SupportsBytes + SupportsIndex = typing.SupportsIndex + SupportsAbs = typing.SupportsAbs + SupportsRound = typing.SupportsRound +else: + @runtime_checkable + class SupportsInt(Protocol): + """An ABC with one abstract method __int__.""" + __slots__ = () + + @abc.abstractmethod + def __int__(self) -> int: + pass + + @runtime_checkable + class SupportsFloat(Protocol): + """An ABC with one abstract method __float__.""" + __slots__ = () + + @abc.abstractmethod + def __float__(self) -> float: + pass + + @runtime_checkable + class SupportsComplex(Protocol): + """An ABC with one abstract method __complex__.""" + __slots__ = () + + @abc.abstractmethod + def __complex__(self) -> complex: + pass + + @runtime_checkable + class SupportsBytes(Protocol): + """An ABC with one abstract method __bytes__.""" + __slots__ = () + + @abc.abstractmethod + def __bytes__(self) -> bytes: + pass + + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + @runtime_checkable + class SupportsAbs(Protocol[T_co]): + """ + An ABC with one abstract method __abs__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __abs__(self) -> T_co: + pass + + @runtime_checkable + class SupportsRound(Protocol[T_co]): + """ + An ABC with one abstract method __round__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __round__(self, ndigits: int = 0) -> T_co: + pass + + +def _ensure_subclassable(mro_entries): + def inner(func): + if sys.implementation.name == "pypy" and sys.version_info < (3, 9): + cls_dict = { + "__call__": staticmethod(func), + "__mro_entries__": staticmethod(mro_entries) + } + t = type(func.__name__, (), cls_dict) + return functools.update_wrapper(t(), func) + else: + func.__mro_entries__ = mro_entries + return func + return inner + + +# Update this to something like >=3.13.0b1 if and when +# PEP 728 is implemented in CPython +_PEP_728_IMPLEMENTED = False + +if _PEP_728_IMPLEMENTED: + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + # Aaaand on 3.12 we add __orig_bases__ to TypedDict + # to enable better runtime introspection. + # On 3.13 we deprecate some odd ways of creating TypedDicts. + # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier. + # PEP 728 (still pending) makes more changes. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + # 3.10.0 and later + _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters + + def _get_typeddict_qualifiers(annotation_type): + while True: + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + else: + break + elif annotation_origin is Required: + yield Required + annotation_type, = get_args(annotation_type) + elif annotation_origin is NotRequired: + yield NotRequired + annotation_type, = get_args(annotation_type) + elif annotation_origin is ReadOnly: + yield ReadOnly + annotation_type, = get_args(annotation_type) + else: + break + + class _TypedDictMeta(type): + def __new__(cls, name, bases, ns, *, total=True, closed=False): + """Create new typed dict class object. + + This method is called when TypedDict is subclassed, + or when TypedDict is instantiated. This way + TypedDict supports all three syntax forms described in its docstring. + Subclasses and instances of TypedDict return actual dictionaries. + """ + for base in bases: + if type(base) is not _TypedDictMeta and base is not typing.Generic: + raise TypeError('cannot inherit from both a TypedDict type ' + 'and a non-TypedDict base class') + + if any(issubclass(b, typing.Generic) for b in bases): + generic_base = (typing.Generic,) + else: + generic_base = () + + # typing.py generally doesn't let you inherit from plain Generic, unless + # the name of the class happens to be "Protocol" + tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) + tp_dict.__name__ = name + if tp_dict.__qualname__ == "Protocol": + tp_dict.__qualname__ = name + + if not hasattr(tp_dict, '__orig_bases__'): + tp_dict.__orig_bases__ = bases + + annotations = {} + if "__annotations__" in ns: + own_annotations = ns["__annotations__"] + elif "__annotate__" in ns: + # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated + own_annotations = ns["__annotate__"](1) + else: + own_annotations = {} + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + if _TAKES_MODULE: + own_annotations = { + n: typing._type_check(tp, msg, module=tp_dict.__module__) + for n, tp in own_annotations.items() + } + else: + own_annotations = { + n: typing._type_check(tp, msg) + for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + readonly_keys = set() + mutable_keys = set() + extra_items_type = None + + for base in bases: + base_dict = base.__dict__ + + annotations.update(base_dict.get('__annotations__', {})) + required_keys.update(base_dict.get('__required_keys__', ())) + optional_keys.update(base_dict.get('__optional_keys__', ())) + readonly_keys.update(base_dict.get('__readonly_keys__', ())) + mutable_keys.update(base_dict.get('__mutable_keys__', ())) + base_extra_items_type = base_dict.get('__extra_items__', None) + if base_extra_items_type is not None: + extra_items_type = base_extra_items_type + + if closed and extra_items_type is None: + extra_items_type = Never + if closed and "__extra_items__" in own_annotations: + annotation_type = own_annotations.pop("__extra_items__") + qualifiers = set(_get_typeddict_qualifiers(annotation_type)) + if Required in qualifiers: + raise TypeError( + "Special key __extra_items__ does not support " + "Required" + ) + if NotRequired in qualifiers: + raise TypeError( + "Special key __extra_items__ does not support " + "NotRequired" + ) + extra_items_type = annotation_type + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + qualifiers = set(_get_typeddict_qualifiers(annotation_type)) + + if Required in qualifiers: + required_keys.add(annotation_key) + elif NotRequired in qualifiers: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + if ReadOnly in qualifiers: + mutable_keys.discard(annotation_key) + readonly_keys.add(annotation_key) + else: + mutable_keys.add(annotation_key) + readonly_keys.discard(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + tp_dict.__readonly_keys__ = frozenset(readonly_keys) + tp_dict.__mutable_keys__ = frozenset(mutable_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + tp_dict.__closed__ = closed + tp_dict.__extra_items__ = extra_items_type + return tp_dict + + __call__ = dict # static method + + def __subclasscheck__(cls, other): + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + + __instancecheck__ = __subclasscheck__ + + _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) + + @_ensure_subclassable(lambda bases: (_TypedDict,)) + def TypedDict(typename, fields=_marker, /, *, total=True, closed=False, **kwargs): + """A simple typed namespace. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type such that a type checker will expect all + instances to have a certain set of keys, where each key is + associated with a value of a consistent type. This expectation + is not checked at runtime. + + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports an additional equivalent form:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + By default, all keys must be present in a TypedDict. It is possible + to override this by specifying totality:: + + class Point2D(TypedDict, total=False): + x: int + y: int + + This means that a Point2D TypedDict can have any of the keys omitted. A type + checker is only expected to support a literal False or True as the value of + the total argument. True is the default, and makes all items defined in the + class body be required. + + The Required and NotRequired special forms can also be used to mark + individual keys as being required or not required:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + See PEP 655 for more details on Required and NotRequired. + """ + if fields is _marker or fields is None: + if fields is _marker: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + + example = f"`{typename} = TypedDict({typename!r}, {{}})`" + deprecation_msg = ( + f"{deprecated_thing} is deprecated and will be disallowed in " + "Python 3.15. To create a TypedDict class with 0 fields " + "using the functional syntax, pass an empty dictionary, e.g. " + ) + example + "." + warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) + if closed is not False and closed is not True: + kwargs["closed"] = closed + closed = False + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + if kwargs: + if sys.version_info >= (3, 13): + raise TypeError("TypedDict takes no keyword arguments") + warnings.warn( + "The kwargs-based syntax for TypedDict definitions is deprecated " + "in Python 3.11, will be removed in Python 3.13, and may not be " + "understood by third-party type checkers.", + DeprecationWarning, + stacklevel=2, + ) + + ns = {'__annotations__': dict(fields)} + module = _caller() + if module is not None: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = module + + td = _TypedDictMeta(typename, (), ns, total=total, closed=closed) + td.__orig_bases__ = (TypedDict,) + return td + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + # On 3.8, this would otherwise return True + if hasattr(typing, "TypedDict") and tp is typing.TypedDict: + return False + return isinstance(tp, _TYPEDDICT_TYPES) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(val, typ, /): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return val + + +if hasattr(typing, "ReadOnly"): # 3.13+ + get_type_hints = typing.get_type_hints +else: # <=3.13 + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return _types.GenericAlias(t.__origin__, stripped_args) + if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): # 3.9+ + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: # 3.8 + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__, *self.__metadata__) + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.8-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__, *tp.__metadata__) + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.8 +else: + TypeAlias = _ExtensionsSpecialForm( + 'TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""" + ) + + +if hasattr(typing, "NoDefault"): + NoDefault = typing.NoDefault +else: + class NoDefaultTypeMeta(type): + def __setattr__(cls, attr, value): + # TypeError is consistent with the behavior of NoneType + raise TypeError( + f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" + ) + + class NoDefaultType(metaclass=NoDefaultTypeMeta): + """The type of the NoDefault singleton.""" + + __slots__ = () + + def __new__(cls): + return globals().get("NoDefault") or object.__new__(cls) + + def __repr__(self): + return "typing_extensions.NoDefault" + + def __reduce__(self): + return "NoDefault" + + NoDefault = NoDefaultType() + del NoDefaultType, NoDefaultTypeMeta + + +def _set_default(type_param, default): + type_param.has_default = lambda: default is not NoDefault + type_param.__default__ = default + + +def _set_module(typevarlike): + # for pickling: + def_mod = _caller(depth=3) + if def_mod != 'typing_extensions': + typevarlike.__module__ = def_mod + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + __init__ = _set_default + + +# Classes using this metaclass must provide a _backported_typevarlike ClassVar +class _TypeVarLikeMeta(type): + def __instancecheck__(cls, __instance: Any) -> bool: + return isinstance(__instance, cls._backported_typevarlike) + + +if _PEP_696_IMPLEMENTED: + from typing import TypeVar +else: + # Add default and infer_variance parameters from PEP 696 and 695 + class TypeVar(metaclass=_TypeVarLikeMeta): + """Type variable.""" + + _backported_typevarlike = typing.TypeVar + + def __new__(cls, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=NoDefault, infer_variance=False): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant, + infer_variance=infer_variance) + else: + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant) + if infer_variance and (covariant or contravariant): + raise ValueError("Variance cannot be specified with infer_variance.") + typevar.__infer_variance__ = infer_variance + + _set_default(typevar, default) + _set_module(typevar) + + def _tvar_prepare_subst(alias, args): + if ( + typevar.has_default() + and alias.__parameters__.index(typevar) == len(args) + ): + args += (typevar.__default__,) + return args + + typevar.__typing_prepare_subst__ = _tvar_prepare_subst + return typevar + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.8-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + + +if _PEP_696_IMPLEMENTED: + from typing import ParamSpec + +# 3.10+ +elif hasattr(typing, 'ParamSpec'): + + # Add default parameter - PEP 696 + class ParamSpec(metaclass=_TypeVarLikeMeta): + """Parameter specification.""" + + _backported_typevarlike = typing.ParamSpec + + def __new__(cls, name, *, bound=None, + covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented, can pass infer_variance to typing.TypeVar + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant, + infer_variance=infer_variance) + else: + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant) + paramspec.__infer_variance__ = infer_variance + + _set_default(paramspec, default) + _set_module(paramspec) + + def _paramspec_prepare_subst(alias, args): + params = alias.__parameters__ + i = params.index(paramspec) + if i == len(args) and paramspec.has_default(): + args = [*args, paramspec.__default__] + if i >= len(args): + raise TypeError(f"Too few arguments for {alias}") + # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. + if len(params) == 1 and not typing._is_param_expr(args[0]): + assert i == 0 + args = (args,) + # Convert lists to tuples to help other libraries cache the results. + elif isinstance(args[i], list): + args = (*args[:i], tuple(args[i]), *args[i + 1:]) + return args + + paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst + return paramspec + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") + +# 3.8-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + list.__init__(self, [self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + self.__infer_variance__ = bool(infer_variance) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__infer_variance__: + prefix = '' + elif self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.8-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.8-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.8 +else: + class _ConcatenateForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.8 +else: + class _TypeGuardForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + +# 3.13+ +if hasattr(typing, 'TypeIs'): + TypeIs = typing.TypeIs +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeIs(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type narrower function. ``TypeIs`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeIs[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeIs`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the intersection of the type inside ``TypeGuard`` and the argument's + previously known type. + + For example:: + + def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: + return hasattr(val, '__await__') + + def f(val: Union[int, Awaitable[int]]) -> int: + if is_awaitable(val): + assert_type(val, Awaitable[int]) + else: + assert_type(val, int) + + ``TypeIs`` also works with type variables. For more information, see + PEP 742 (Narrowing types with TypeIs). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.8 +else: + class _TypeIsForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeIs = _TypeIsForm( + 'TypeIs', + doc="""Special typing form used to annotate the return type of a user-defined + type narrower function. ``TypeIs`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeIs[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeIs`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the intersection of the type inside ``TypeGuard`` and the argument's + previously known type. + + For example:: + + def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: + return hasattr(val, '__await__') + + def f(val: Union[int, Awaitable[int]]) -> int: + if is_awaitable(val): + assert_type(val, Awaitable[int]) + else: + assert_type(val, int) + + ``TypeIs`` also works with type variables. For more information, see + PEP 742 (Narrowing types with TypeIs). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): # 3.11+ + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from pip._vendor.typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): # 3.11+ + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): # 3.11+ + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from pip._vendor.typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): # 3.11+ + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): # 3.9-3.10 + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: # 3.8 + class _RequiredForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +if hasattr(typing, 'ReadOnly'): + ReadOnly = typing.ReadOnly +elif sys.version_info[:2] >= (3, 9): # 3.9-3.12 + @_ExtensionsSpecialForm + def ReadOnly(self, parameters): + """A special typing construct to mark an item of a TypedDict as read-only. + + For example: + + class Movie(TypedDict): + title: ReadOnly[str] + year: int + + def mutate_movie(m: Movie) -> None: + m["year"] = 1992 # allowed + m["title"] = "The Matrix" # typechecker error + + There is no runtime checking for this property. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: # 3.8 + class _ReadOnlyForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + ReadOnly = _ReadOnlyForm( + 'ReadOnly', + doc="""A special typing construct to mark a key of a TypedDict as read-only. + + For example: + + class Movie(TypedDict): + title: ReadOnly[str] + year: int + + def mutate_movie(m: Movie) -> None: + m["year"] = 1992 # allowed + m["title"] = "The Matrix" # typechecker error + + There is no runtime checking for this propery. + """) + + +_UNPACK_DOC = """\ +Type unpack operator. + +The type unpack operator takes the child types from some container type, +such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For +example: + + # For some generic class `Foo`: + Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] + + Ts = TypeVarTuple('Ts') + # Specifies that `Bar` is generic in an arbitrary number of types. + # (Think of `Ts` as a tuple of an arbitrary number of individual + # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the + # `Generic[]`.) + class Bar(Generic[Unpack[Ts]]): ... + Bar[int] # Valid + Bar[int, str] # Also valid + +From Python 3.11, this can also be done using the `*` operator: + + Foo[*tuple[int, str]] + class Bar(Generic[*Ts]): ... + +The operator can also be used along with a `TypedDict` to annotate +`**kwargs` in a function signature. For instance: + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + +Note that there is only some runtime checking of this operator. Not +everything the runtime allows may be accepted by static type checkers. + +For more information, see PEP 646 and PEP 692. +""" + + +if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[] + Unpack = typing.Unpack + + def _is_unpack(obj): + return get_origin(obj) is Unpack + +elif sys.version_info[:2] >= (3, 9): # 3.9+ + class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, getitem): + super().__init__(getitem) + self.__doc__ = _UNPACK_DOC + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @property + def __typing_unpacked_tuple_args__(self): + assert self.__origin__ is Unpack + assert len(self.__args__) == 1 + arg, = self.__args__ + if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)): + if arg.__origin__ is not tuple: + raise TypeError("Unpack[...] must be used with a tuple type") + return arg.__args__ + return None + + @_UnpackSpecialForm + def Unpack(self, parameters): + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: # 3.8 + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm('Unpack', doc=_UNPACK_DOC) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if _PEP_696_IMPLEMENTED: + from typing import TypeVarTuple + +elif hasattr(typing, "TypeVarTuple"): # 3.11+ + + def _unpack_args(*args): + newargs = [] + for arg in args: + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs is not None and not (subargs and subargs[-1] is ...): + newargs.extend(subargs) + else: + newargs.append(arg) + return newargs + + # Add default parameter - PEP 696 + class TypeVarTuple(metaclass=_TypeVarLikeMeta): + """Type variable tuple.""" + + _backported_typevarlike = typing.TypeVarTuple + + def __new__(cls, name, *, default=NoDefault): + tvt = typing.TypeVarTuple(name) + _set_default(tvt, default) + _set_module(tvt) + + def _typevartuple_prepare_subst(alias, args): + params = alias.__parameters__ + typevartuple_index = params.index(tvt) + for param in params[typevartuple_index + 1:]: + if isinstance(param, TypeVarTuple): + raise TypeError( + f"More than one TypeVarTuple parameter in {alias}" + ) + + alen = len(args) + plen = len(params) + left = typevartuple_index + right = plen - typevartuple_index - 1 + var_tuple_index = None + fillarg = None + for k, arg in enumerate(args): + if not isinstance(arg, type): + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs and len(subargs) == 2 and subargs[-1] is ...: + if var_tuple_index is not None: + raise TypeError( + "More than one unpacked " + "arbitrary-length tuple argument" + ) + var_tuple_index = k + fillarg = subargs[0] + if var_tuple_index is not None: + left = min(left, var_tuple_index) + right = min(right, alen - var_tuple_index - 1) + elif left + right > alen: + raise TypeError(f"Too few arguments for {alias};" + f" actual {alen}, expected at least {plen - 1}") + if left == alen - right and tvt.has_default(): + replacement = _unpack_args(tvt.__default__) + else: + replacement = args[left: alen - right] + + return ( + *args[:left], + *([fillarg] * (typevartuple_index - left)), + replacement, + *([fillarg] * (plen - right - left - typevartuple_index - 1)), + *args[alen - right:], + ) + + tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst + return tvt + + def __init_subclass__(self, *args, **kwds): + raise TypeError("Cannot subclass special typing classes") + +else: # <=3.10 + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=NoDefault): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): # 3.11+ + reveal_type = typing.reveal_type +else: # <=3.10 + def reveal_type(obj: T, /) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) + return obj + + +if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"): # 3.11+ + _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH +else: # <=3.10 + _ASSERT_NEVER_REPR_MAX_LENGTH = 100 + + +if hasattr(typing, "assert_never"): # 3.11+ + assert_never = typing.assert_never +else: # <=3.10 + def assert_never(arg: Never, /) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + value = repr(arg) + if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: + value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...' + raise AssertionError(f"Expected code to be unreachable, but got: {value}") + + +if sys.version_info >= (3, 12): # 3.12+ + # dataclass_transform exists in 3.11 but lacks the frozen_default parameter + dataclass_transform = typing.dataclass_transform +else: # <=3.11 + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + frozen_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from pip._vendor.typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "frozen_default": frozen_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): # 3.12+ + override = typing.override +else: # <=3.11 + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(arg: _F, /) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + There is no runtime checking of these properties. The decorator + sets the ``__override__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + + See PEP 698 for details. + + """ + try: + arg.__override__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return arg + + +if hasattr(warnings, "deprecated"): + deprecated = warnings.deprecated +else: + _T = typing.TypeVar("_T") + + class deprecated: + """Indicate that a class, function or overload is deprecated. + + When this decorator is applied to an object, the type checker + will generate a diagnostic on usage of the deprecated object. + + Usage: + + @deprecated("Use B instead") + class A: + pass + + @deprecated("Use g instead") + def f(): + pass + + @overload + @deprecated("int support is deprecated") + def g(x: int) -> int: ... + @overload + def g(x: str) -> int: ... + + The warning specified by *category* will be emitted at runtime + on use of deprecated objects. For functions, that happens on calls; + for classes, on instantiation and on creation of subclasses. + If the *category* is ``None``, no warning is emitted at runtime. + The *stacklevel* determines where the + warning is emitted. If it is ``1`` (the default), the warning + is emitted at the direct caller of the deprecated object; if it + is higher, it is emitted further up the stack. + Static type checker behavior is not affected by the *category* + and *stacklevel* arguments. + + The deprecation message passed to the decorator is saved in the + ``__deprecated__`` attribute on the decorated object. + If applied to an overload, the decorator + must be after the ``@overload`` decorator for the attribute to + exist on the overload as returned by ``get_overloads()``. + + See PEP 702 for details. + + """ + def __init__( + self, + message: str, + /, + *, + category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, + stacklevel: int = 1, + ) -> None: + if not isinstance(message, str): + raise TypeError( + "Expected an object of type str for 'message', not " + f"{type(message).__name__!r}" + ) + self.message = message + self.category = category + self.stacklevel = stacklevel + + def __call__(self, arg: _T, /) -> _T: + # Make sure the inner functions created below don't + # retain a reference to self. + msg = self.message + category = self.category + stacklevel = self.stacklevel + if category is None: + arg.__deprecated__ = msg + return arg + elif isinstance(arg, type): + import functools + from types import MethodType + + original_new = arg.__new__ + + @functools.wraps(original_new) + def __new__(cls, *args, **kwargs): + if cls is arg: + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + if original_new is not object.__new__: + return original_new(cls, *args, **kwargs) + # Mirrors a similar check in object.__new__. + elif cls.__init__ is object.__init__ and (args or kwargs): + raise TypeError(f"{cls.__name__}() takes no arguments") + else: + return original_new(cls) + + arg.__new__ = staticmethod(__new__) + + original_init_subclass = arg.__init_subclass__ + # We need slightly different behavior if __init_subclass__ + # is a bound method (likely if it was implemented in Python) + if isinstance(original_init_subclass, MethodType): + original_init_subclass = original_init_subclass.__func__ + + @functools.wraps(original_init_subclass) + def __init_subclass__(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return original_init_subclass(*args, **kwargs) + + arg.__init_subclass__ = classmethod(__init_subclass__) + # Or otherwise, which likely means it's a builtin such as + # object's implementation of __init_subclass__. + else: + @functools.wraps(original_init_subclass) + def __init_subclass__(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return original_init_subclass(*args, **kwargs) + + arg.__init_subclass__ = __init_subclass__ + + arg.__deprecated__ = __new__.__deprecated__ = msg + __init_subclass__.__deprecated__ = msg + return arg + elif callable(arg): + import functools + + @functools.wraps(arg) + def wrapper(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return arg(*args, **kwargs) + + arg.__deprecated__ = wrapper.__deprecated__ = msg + return wrapper + else: + raise TypeError( + "@deprecated decorator with non-None category must be applied to " + f"a class or callable, not {arg!r}" + ) + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + expect_val = elen + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + + # deal with TypeVarLike defaults + # required TypeVarLikes cannot appear after a defaulted one. + if alen < elen: + # since we validate TypeVarLike default in _collect_type_vars + # or _collect_parameters we can safely check parameters[alen] + if ( + getattr(parameters[alen], '__default__', NoDefault) + is not NoDefault + ): + return + + num_default_tv = sum(getattr(p, '__default__', NoDefault) + is not NoDefault for p in parameters) + + elen -= num_default_tv + + expect_val = f"at least {elen}" + + things = "arguments" if sys.version_info >= (3, 10) else "parameters" + raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}" + f" for {cls}; actual {alen}, expected {expect_val}") +else: + # Python 3.11+ + + def _check_generic(cls, parameters, elen): + """Check correct count for parameters of a generic cls (internal helper). + + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + alen = len(parameters) + if alen != elen: + expect_val = elen + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + + # deal with TypeVarLike defaults + # required TypeVarLikes cannot appear after a defaulted one. + if alen < elen: + # since we validate TypeVarLike default in _collect_type_vars + # or _collect_parameters we can safely check parameters[alen] + if ( + getattr(parameters[alen], '__default__', NoDefault) + is not NoDefault + ): + return + + num_default_tv = sum(getattr(p, '__default__', NoDefault) + is not NoDefault for p in parameters) + + elen -= num_default_tv + + expect_val = f"at least {elen}" + + raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments" + f" for {cls}; actual {alen}, expected {expect_val}") + +if not _PEP_696_IMPLEMENTED: + typing._check_generic = _check_generic + + +def _has_generic_or_protocol_as_origin() -> bool: + try: + frame = sys._getframe(2) + # - Catch AttributeError: not all Python implementations have sys._getframe() + # - Catch ValueError: maybe we're called from an unexpected module + # and the call stack isn't deep enough + except (AttributeError, ValueError): + return False # err on the side of leniency + else: + # If we somehow get invoked from outside typing.py, + # also err on the side of leniency + if frame.f_globals.get("__name__") != "typing": + return False + origin = frame.f_locals.get("origin") + # Cannot use "in" because origin may be an object with a buggy __eq__ that + # throws an error. + return origin is typing.Generic or origin is Protocol or origin is typing.Protocol + + +_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)} + + +def _is_unpacked_typevartuple(x) -> bool: + if get_origin(x) is not Unpack: + return False + args = get_args(x) + return ( + bool(args) + and len(args) == 1 + and type(args[0]) in _TYPEVARTUPLE_TYPES + ) + + +# Python 3.11+ _collect_type_vars was renamed to _collect_parameters +if hasattr(typing, '_collect_type_vars'): + def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + + # A required TypeVarLike cannot appear after a TypeVarLike with a default + # if it was a direct call to `Generic[]` or `Protocol[]` + enforce_default_ordering = _has_generic_or_protocol_as_origin() + default_encountered = False + + # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple + type_var_tuple_encountered = False + + for t in types: + if _is_unpacked_typevartuple(t): + type_var_tuple_encountered = True + elif isinstance(t, typevar_types) and t not in tvars: + if enforce_default_ordering: + has_default = getattr(t, '__default__', NoDefault) is not NoDefault + if has_default: + if type_var_tuple_encountered: + raise TypeError('Type parameter with a default' + ' follows TypeVarTuple') + default_encountered = True + elif default_encountered: + raise TypeError(f'Type parameter {t!r} without a default' + ' follows type parameter with a default') + + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + typing._collect_type_vars = _collect_type_vars +else: + def _collect_parameters(args): + """Collect all type variables and parameter specifications in args + in order of first appearance (lexicographic order). + + For example:: + + assert _collect_parameters((T, Callable[P, T])) == (T, P) + """ + parameters = [] + + # A required TypeVarLike cannot appear after a TypeVarLike with default + # if it was a direct call to `Generic[]` or `Protocol[]` + enforce_default_ordering = _has_generic_or_protocol_as_origin() + default_encountered = False + + # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple + type_var_tuple_encountered = False + + for t in args: + if isinstance(t, type): + # We don't want __parameters__ descriptor of a bare Python class. + pass + elif isinstance(t, tuple): + # `t` might be a tuple, when `ParamSpec` is substituted with + # `[T, int]`, or `[int, *Ts]`, etc. + for x in t: + for collected in _collect_parameters([x]): + if collected not in parameters: + parameters.append(collected) + elif hasattr(t, '__typing_subst__'): + if t not in parameters: + if enforce_default_ordering: + has_default = ( + getattr(t, '__default__', NoDefault) is not NoDefault + ) + + if type_var_tuple_encountered and has_default: + raise TypeError('Type parameter with a default' + ' follows TypeVarTuple') + + if has_default: + default_encountered = True + elif default_encountered: + raise TypeError(f'Type parameter {t!r} without a default' + ' follows type parameter with a default') + + parameters.append(t) + else: + if _is_unpacked_typevartuple(t): + type_var_tuple_encountered = True + for x in getattr(t, '__parameters__', ()): + if x not in parameters: + parameters.append(x) + + return tuple(parameters) + + if not _PEP_696_IMPLEMENTED: + typing._collect_parameters = _collect_parameters + +# Backport typing.NamedTuple as it exists in Python 3.13. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +# On 3.12, we added __orig_bases__ to call-based NamedTuples +# On 3.13, we deprecated kwargs-based NamedTuples +if sys.version_info >= (3, 13): + NamedTuple = typing.NamedTuple +else: + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + if "__annotations__" in ns: + types = ns["__annotations__"] + elif "__annotate__" in ns: + # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated + types = ns["__annotate__"](1) + else: + types = {} + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + if hasattr(typing, '_generic_class_getitem'): # 3.12+ + nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) + else: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key, val in ns.items(): + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields: + if key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + try: + set_name = type(val).__set_name__ + except AttributeError: + pass + else: + try: + set_name(val, nm_tpl, key) + except BaseException as e: + msg = ( + f"Error calling __set_name__ on {type(val).__name__!r} " + f"instance {key!r} in {typename!r}" + ) + # BaseException.add_note() existed on py311, + # but the __set_name__ machinery didn't start + # using add_note() until py312. + # Making sure exceptions are raised in the same way + # as in "normal" classes seems most important here. + if sys.version_info >= (3, 12): + e.add_note(msg) + raise + else: + raise RuntimeError(msg) from e + + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + @_ensure_subclassable(_namedtuple_mro_entries) + def NamedTuple(typename, fields=_marker, /, **kwargs): + """Typed version of namedtuple. + + Usage:: + + class Employee(NamedTuple): + name: str + id: int + + This is equivalent to:: + + Employee = collections.namedtuple('Employee', ['name', 'id']) + + The resulting class has an extra __annotations__ attribute, giving a + dict that maps field names to types. (The field names are also in + the _fields attribute, which is part of the namedtuple API.) + An alternative equivalent functional syntax is also accepted:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + """ + if fields is _marker: + if kwargs: + deprecated_thing = "Creating NamedTuple classes using keyword arguments" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "Use the class-based or functional syntax instead." + ) + else: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif fields is None: + if kwargs: + raise TypeError( + "Cannot pass `None` as the 'fields' parameter " + "and also specify fields using keyword arguments" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + if fields is _marker or fields is None: + warnings.warn( + deprecation_msg.format(name=deprecated_thing, remove="3.15"), + DeprecationWarning, + stacklevel=2, + ) + fields = kwargs.items() + nt = _make_nmtuple(typename, fields, module=_caller()) + nt.__orig_bases__ = (NamedTuple,) + return nt + + +if hasattr(collections.abc, "Buffer"): + Buffer = collections.abc.Buffer +else: + class Buffer(abc.ABC): # noqa: B024 + """Base class for classes that implement the buffer protocol. + + The buffer protocol allows Python objects to expose a low-level + memory buffer interface. Before Python 3.12, it is not possible + to implement the buffer protocol in pure Python code, or even + to check whether a class implements the buffer protocol. In + Python 3.12 and higher, the ``__buffer__`` method allows access + to the buffer protocol from Python code, and the + ``collections.abc.Buffer`` ABC allows checking whether a class + implements the buffer protocol. + + To indicate support for the buffer protocol in earlier versions, + inherit from this ABC, either in a stub file or at runtime, + or use ABC registration. This ABC provides no methods, because + there is no Python-accessible methods shared by pre-3.12 buffer + classes. It is useful primarily for static checks. + + """ + + # As a courtesy, register the most common stdlib buffer classes. + Buffer.register(memoryview) + Buffer.register(bytearray) + Buffer.register(bytes) + + +# Backport of types.get_original_bases, available on 3.12+ in CPython +if hasattr(_types, "get_original_bases"): + get_original_bases = _types.get_original_bases +else: + def get_original_bases(cls, /): + """Return the class's "original" bases prior to modification by `__mro_entries__`. + + Examples:: + + from typing import TypeVar, Generic + from pip._vendor.typing_extensions import NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert get_original_bases(Bar) == (Foo[int], float) + assert get_original_bases(Baz) == (list[str],) + assert get_original_bases(Eggs) == (NamedTuple,) + assert get_original_bases(Spam) == (TypedDict,) + assert get_original_bases(int) == (object,) + """ + try: + return cls.__dict__.get("__orig_bases__", cls.__bases__) + except AttributeError: + raise TypeError( + f'Expected an instance of type, not {type(cls).__name__!r}' + ) from None + + +# NewType is a class on Python 3.10+, making it pickleable +# The error message for subclassing instances of NewType was improved on 3.11+ +if sys.version_info >= (3, 11): + NewType = typing.NewType +else: + class NewType: + """NewType creates simple unique types with almost zero + runtime overhead. NewType(name, tp) is considered a subtype of tp + by static type checkers. At runtime, NewType(name, tp) returns + a dummy callable that simply returns its argument. Usage:: + UserId = NewType('UserId', int) + def name_by_id(user_id: UserId) -> str: + ... + UserId('user') # Fails type check + name_by_id(42) # Fails type check + name_by_id(UserId(42)) # OK + num = UserId(5) + 1 # type: int + """ + + def __call__(self, obj, /): + return obj + + def __init__(self, name, tp): + self.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] + self.__name__ = name + self.__supertype__ = tp + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __mro_entries__(self, bases): + # We defined __mro_entries__ to get a better error message + # if a user attempts to subclass a NewType instance. bpo-46170 + supercls_name = self.__name__ + + class Dummy: + def __init_subclass__(cls): + subcls_name = cls.__name__ + raise TypeError( + f"Cannot subclass an instance of NewType. " + f"Perhaps you were looking for: " + f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" + ) + + return (Dummy,) + + def __repr__(self): + return f'{self.__module__}.{self.__qualname__}' + + def __reduce__(self): + return self.__qualname__ + + if sys.version_info >= (3, 10): + # PEP 604 methods + # It doesn't make sense to have these methods on Python <3.10 + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + +if hasattr(typing, "TypeAliasType"): + TypeAliasType = typing.TypeAliasType +else: + def _is_unionable(obj): + """Corresponds to is_unionable() in unionobject.c in CPython.""" + return obj is None or isinstance(obj, ( + type, + _types.GenericAlias, + _types.UnionType, + TypeAliasType, + )) + + class TypeAliasType: + """Create named, parameterized type aliases. + + This provides a backport of the new `type` statement in Python 3.12: + + type ListOrSet[T] = list[T] | set[T] + + is equivalent to: + + T = TypeVar("T") + ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) + + The name ListOrSet can then be used as an alias for the type it refers to. + + The type_params argument should contain all the type parameters used + in the value of the type alias. If the alias is not generic, this + argument is omitted. + + Static type checkers should only support type aliases declared using + TypeAliasType that follow these rules: + + - The first argument (the name) must be a string literal. + - The TypeAliasType instance must be immediately assigned to a variable + of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, + as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). + + """ + + def __init__(self, name: str, value, *, type_params=()): + if not isinstance(name, str): + raise TypeError("TypeAliasType name must be a string") + self.__value__ = value + self.__type_params__ = type_params + + parameters = [] + for type_param in type_params: + if isinstance(type_param, TypeVarTuple): + parameters.extend(type_param) + else: + parameters.append(type_param) + self.__parameters__ = tuple(parameters) + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + # Setting this attribute closes the TypeAliasType from further modification + self.__name__ = name + + def __setattr__(self, name: str, value: object, /) -> None: + if hasattr(self, "__name__"): + self._raise_attribute_error(name) + super().__setattr__(name, value) + + def __delattr__(self, name: str, /) -> Never: + self._raise_attribute_error(name) + + def _raise_attribute_error(self, name: str) -> Never: + # Match the Python 3.12 error messages exactly + if name == "__name__": + raise AttributeError("readonly attribute") + elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}: + raise AttributeError( + f"attribute '{name}' of 'typing.TypeAliasType' objects " + "is not writable" + ) + else: + raise AttributeError( + f"'typing.TypeAliasType' object has no attribute '{name}'" + ) + + def __repr__(self) -> str: + return self.__name__ + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + parameters = [ + typing._type_check( + item, f'Subscripting {self.__name__} requires a type.' + ) + for item in parameters + ] + return typing._GenericAlias(self, tuple(parameters)) + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + "type 'typing_extensions.TypeAliasType' is not an acceptable base type" + ) + + # The presence of this method convinces typing._type_check + # that TypeAliasTypes are types. + def __call__(self): + raise TypeError("Type alias is not callable") + + if sys.version_info >= (3, 10): + def __or__(self, right): + # For forward compatibility with 3.12, reject Unions + # that are not accepted by the built-in Union. + if not _is_unionable(right): + return NotImplemented + return typing.Union[self, right] + + def __ror__(self, left): + if not _is_unionable(left): + return NotImplemented + return typing.Union[left, self] + + +if hasattr(typing, "is_protocol"): + is_protocol = typing.is_protocol + get_protocol_members = typing.get_protocol_members +else: + def is_protocol(tp: type, /) -> bool: + """Return True if the given type is a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, is_protocol + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> is_protocol(P) + True + >>> is_protocol(int) + False + """ + return ( + isinstance(tp, type) + and getattr(tp, '_is_protocol', False) + and tp is not Protocol + and tp is not typing.Protocol + ) + + def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: + """Return the set of members defined in a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) + + Raise a TypeError for arguments that are not Protocols. + """ + if not is_protocol(tp): + raise TypeError(f'{tp!r} is not a Protocol') + if hasattr(tp, '__protocol_attrs__'): + return frozenset(tp.__protocol_attrs__) + return frozenset(_get_protocol_attrs(tp)) + + +if hasattr(typing, "Doc"): + Doc = typing.Doc +else: + 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:: + + >>> from typing_extensions import Annotated, Doc + >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... + """ + 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 + + +_CapsuleType = getattr(_types, "CapsuleType", None) + +if _CapsuleType is None: + try: + import _socket + except ImportError: + pass + else: + _CAPI = getattr(_socket, "CAPI", None) + if _CAPI is not None: + _CapsuleType = type(_CAPI) + +if _CapsuleType is not None: + CapsuleType = _CapsuleType + __all__.append("CapsuleType") + + +# Aliases for items that have always been in typing. +# Explicitly assign these (rather than using `from typing import *` at the top), +# so that we get a CI error if one of these is deleted from typing.py +# in a future version of Python +AbstractSet = typing.AbstractSet +AnyStr = typing.AnyStr +BinaryIO = typing.BinaryIO +Callable = typing.Callable +Collection = typing.Collection +Container = typing.Container +Dict = typing.Dict +ForwardRef = typing.ForwardRef +FrozenSet = typing.FrozenSet +Generic = typing.Generic +Hashable = typing.Hashable +IO = typing.IO +ItemsView = typing.ItemsView +Iterable = typing.Iterable +Iterator = typing.Iterator +KeysView = typing.KeysView +List = typing.List +Mapping = typing.Mapping +MappingView = typing.MappingView +Match = typing.Match +MutableMapping = typing.MutableMapping +MutableSequence = typing.MutableSequence +MutableSet = typing.MutableSet +Optional = typing.Optional +Pattern = typing.Pattern +Reversible = typing.Reversible +Sequence = typing.Sequence +Set = typing.Set +Sized = typing.Sized +TextIO = typing.TextIO +Tuple = typing.Tuple +Union = typing.Union +ValuesView = typing.ValuesView +cast = typing.cast +no_type_check = typing.no_type_check +no_type_check_decorator = typing.no_type_check_decorator diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py new file mode 100644 index 0000000..c6fa382 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py @@ -0,0 +1,102 @@ +""" +Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more +""" +from __future__ import absolute_import + +# Set default logging handler to avoid "No handler found" warnings. +import logging +import warnings +from logging import NullHandler + +from . import exceptions +from ._version import __version__ +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url +from .filepost import encode_multipart_formdata +from .poolmanager import PoolManager, ProxyManager, proxy_from_url +from .response import HTTPResponse +from .util.request import make_headers +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host + +# === NOTE TO REPACKAGERS AND VENDORS === +# Please delete this block, this logic is only +# for urllib3 being distributed via PyPI. +# See: https://github.com/urllib3/urllib3/issues/2680 +try: + import urllib3_secure_extra # type: ignore # noqa: F401 +except ImportError: + pass +else: + warnings.warn( + "'urllib3[secure]' extra is deprecated and will be removed " + "in a future release of urllib3 2.x. Read more in this issue: " + "https://github.com/urllib3/urllib3/issues/2680", + category=DeprecationWarning, + stacklevel=2, + ) + +__author__ = "Andrey Petrov (andrey.petrov@shazow.net)" +__license__ = "MIT" +__version__ = __version__ + +__all__ = ( + "HTTPConnectionPool", + "HTTPSConnectionPool", + "PoolManager", + "ProxyManager", + "HTTPResponse", + "Retry", + "Timeout", + "add_stderr_logger", + "connection_from_url", + "disable_warnings", + "encode_multipart_formdata", + "get_host", + "make_headers", + "proxy_from_url", +) + +logging.getLogger(__name__).addHandler(NullHandler()) + + +def add_stderr_logger(level=logging.DEBUG): + """ + Helper for quickly adding a StreamHandler to the logger. Useful for + debugging. + + Returns the handler after adding it. + """ + # This method needs to be in this __init__.py to get the __name__ correct + # even if urllib3 is vendored within another package. + logger = logging.getLogger(__name__) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s")) + logger.addHandler(handler) + logger.setLevel(level) + logger.debug("Added a stderr logging handler to logger: %s", __name__) + return handler + + +# ... Clean up. +del NullHandler + + +# All warning filters *must* be appended unless you're really certain that they +# shouldn't be: otherwise, it's very hard for users to use most Python +# mechanisms to silence them. +# SecurityWarning's always go off by default. +warnings.simplefilter("always", exceptions.SecurityWarning, append=True) +# SubjectAltNameWarning's should go off once per host +warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True) +# InsecurePlatformWarning's don't vary between requests, so we keep it default. +warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True) +# SNIMissingWarnings should go off only once. +warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True) + + +def disable_warnings(category=exceptions.HTTPWarning): + """ + Helper for quickly disabling all urllib3 warnings. + """ + warnings.simplefilter("ignore", category) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4948682394c20a4fa3682c03fac9e58b42d2e4c GIT binary patch literal 3411 zcmb7G-ESMm5#J+^-y$hdq9t0Eys|zlrZ(lKZjlO3T=^rBT}f6YrFAZ94@cgTJY|o^ z?A=MCY6CP-G%tDZLxHqFfVwF9P&nw{kOCJ}T%w$tQ5$ zPyLeL9YslmQKWu7AO&D9payAB4@n`H57Dq5ks>Z1rcpg6#q=JjM~_Q!R~MlPJt-w! zK1zG_KB-SnNh!Tw>UVW9I-sYew9EIyFTrZx2dSt2whrw3r3>nSG)}-{H7!kmrGMjY*TUn-)Kj6& zZ`|{A-4Uz;PdlQwPT)H&ch`7aQBcqPLXfg=23#-KJbiam2T5q-$6eXu)S(YDUC+PP z`Yc%A_iVc3H?WqvRvz~atk*r8?s(D~{QFsV&f_31!w{D%HUBswV-tw^1@s1bx3Pt` z{coTxA$x9zM3-w;*{I<8wY6nTwLDW;4R2{y8CzvW6!o&H6bUXEl?o|X8Z4|D2GuI1 zOSq^}0+MNA)2>zxW?jOzNf<6NjZ{=xyM&dBigkmL=yUE-R&bI^-ZZFf5n0o@#S-XZ zOE#tRu#^(^oF@e6qGY>3s{A;UuaM)+|`>$4lRQ}PCwVJo>q3fmW#~L zWt&mhE<-8>LnX3qQ%kEV%#w=+(^bV%VDlK?Zc(WyCBmGZWoB&GJSkD-((#>o_^B(z ztb(5ecJ9%Yw}@PZsDZm62Udv1YQTinG@Tf>1#GxPEV&F(+xf#q@CPFPoi|NVuo?O3 zMNGCWreMv)DycG3P%NUlLEO?P#d(4m(Tz>eX%(#CqHTc{=qOQ4f{h~X?1x{>ZRhX` zxZy^hueQptsb-osnZ;$xs+zMiGbMOrJD)2U`b@|0XmnSaGcSJcr7OsweUR5)dJSFm$!YYt~CW~>KeolHh zNdPHyAO%>2H~@24IvfJ+d&oMP+u)Zv^;x2)@Zjd5aLgj;&2~o*o*w!h_%`^RPJPF$ z-6nBzS{1x=yiq_8gbf~%Q{MyMi4{Ctr@ja1#0nnEQ=jTPcE8T;;XL0e%KCSH8O89; z6I$ivYcTw_t-%Y|FuVi=8ggyb0xZxwRf;VG5{lsV*MTuNfYj0FDU?Vz5``Syqh#{vrdC@an|Xv zEsf?FdD|vn&2iI-c2v--To~@G;dKZ-s}0IwcMXKo#am~f6Ii+3x@5O;IUwX1B1baZdqJy5H{d&BjYJbl_^nB7df+p zP<0V7jAOfK;?i`0TaT}?+bJKmV-H(7G8 z-MtUH-+%H_7ZskiV`G!xDD&hwC(rrMfBnv1e_v5i&f)6#k0-*BUXJ@GdN421xLNyO zxS8W*PUa(Alpo=Fu8f{+5nEIk5u)}HyHO)VoKe?^i>J4ah$C7yQigk{?242}-6L*x zUl#F1D@H2VeR-rZ>K*Y$t46Bu?3O*_wvlQZr__98e0s!Z;|_6h#hZAm*gq2V>XBMj zTZvjvUTxj9w}Vr}PEMsS(fk~_`JLu&oS5P+38%R!-e`q6uyO1dNBqcUjO{|pvt~$H;JBilnFvn|1n^Fds{@m2BoZFoJ`f1SBM~K(2*+bu|HO2*ED*q8iW&$c zy=;;FR)vQqNlbHT-PAklQZ9u8iRlR?TSj*mgON$x zCe&a^p}A``oP66{&9i$>IG$5%a+p}TdbC?JE4R?;mGtWnj#Oy zV~Jomrl{G3NYq>n&j7qFJWy4>19d@!H2Mg+w^B0{i)H~A5V3`QSu$|6da>_Ay2 zJ5iR)E|hM$45dddM_Dm#^Lx}b3>KWl8p?^{FRAg1VOi0npp-bLVkLcAa7>Y8%%v|9 zzMx1UbE?wRxp3&56ve!0?wT|?AtmB$kh5o_!An{=shmA4(ZZ=|M4@HOvoHG~2?Fy4 z#K^p8_nBCo!_6F*;!|9}e8;71c(SxfiaT#Ab*lx(naUO|t#K11n(WGZYxSMxnCSW) zkSl}QSx^4bvL1_bha%u_Xc2>vnH**95vWJMpbNdz7((sD2Q``k_RNy-aEwX##*$(I z<)gnJpsrg`K=(AZrR_H=mRoz$_WQ1;$ITlbHg8>Q-n!J>hkEa$+NPU_()PE@nB0a; z*+Ey1WSCL%&u{}ua_6bG=-SEg^d`Tb(V`S>Q~XB;^)K6KFG}@G@y}s|lr3a~(ZWB| z6!F|iu7lggY5bIp=T76hJU4BaFrEH_+KrxS7mBPf5uY$ADnPihcH+!Ja=HTnuoBfn zXSP3yqE?eXz_{8oD6VpkE2`f){nqJaU&GwDX212&*R|;Dn%9q$ozFJt#4Pz6Uw3FWt)AOS~l$QFL9{kG*Is-Sa#dtfEWie`GU9 zJOh5ZY`-iNa{xvovs84cEh!=M2V>#_(s+VW+OIYBI_5K9INmjxvZ$$>ln)@Rel zmOFa#nDTQMSLK`8L9Dyv?UR+_%4h;#{Hnc4SSGTx zpqm2sjg|R!On_;0mFBCv_qs831_BU3XzmS9(%kIzN$N(hk`uzAZ@I9pk{Zsx5eppCWHu&2N0UMDQq2fJQEs?1$C|6Ya@R;t~3 z%dNsZjO!!gFN;|V%s<8`VP@2(EBt=$bsr1{88hONqAQgr%Qx!mr4|1`zC1gaJVX75 zwS>A6!|6VS7=k0N<_mY$p@%8!XE7f}XbORM6 z|5>OVIUWiG)F!IhOog9{ek#a2RQFIpKCJpJDu@x(160t6d2uu;B^FlFjYi((o7`tM zx9D1F=4#un9$mAGV(V(9C^oKER)~G88%1&RYNbu=S#=3w`D(dK^sm+0#O=CBqq}vP zN_njrJN-TEY7SljxYC&B#&|$1Wg~V(!W<%EJ4y$OgqX7P0mi?4l3HRj_+OkOK{@ZCBBxJK$_09qpr z?41|y8s#cHHz|!H&G_Gf|E>7HL9RyaM!5!Mo9sg=$+alkr!YoWDtxFwNkE-H7Uqi1{28v!ZIb5OFrPTOF6p<&`!ry2=*8QX(`eNc`V`(?jdOk=tpx^f+2mZVj8l2F=qXWM$0*SHqXDt z%C%{P;Fp-8o>E~}HJz9MKh6bd8`N0qu=xVq)rK2n>OR(q~OZ>Sd75sB$iNF^o6N zyOEVKKyx}bXmOxH467N{hl<3tgfYQ=`}RqOgh_iDm*sH09zXkVUK3hrPxnbB(Ki&2 zUkEGRy;ApBJid1{sCGZ0F+!xikkxoJnB4ou^s&oK`#)Un%~4eoy1Ixzprbe3O1e=#%PCIeP%<~}l9U^oH7@b7HBlG==3paOF=DQ3*t&&R_t^%QOkX+e%&30hb%;rrBM zD+`+9JA5nr-i5`=Eop)1FnxVGnBb_ z=TDqJpC4`DC0!;TgNO4sUw_G6G`4gw(D#P2-5E8enrcE3eqlhyNj+tHikvZ*?zYdoJooDCt2a;2^Y0F$^0#Ytw7S;T&i{W|ta=t-Q-df9 z)~G6|`I@WiL>IO?AU-efc67qh7QG<(X+G9 zVqw0`3*OBOuFbmk$^X7JyI%Aw&^{&gr77WtWrx-zX)KAEFkB*8ziy8hRQeN|Wi<-g zq#EmhV8PWUBilKpVT4! zp6poGPEJbx7BIA>l&i-e(f^7*8V$k(dJbtnDd&EWhL40$q)DU<3y?F!fUwc+kpL7upiV_8=ENK%;D2#ZLB>=F95GVDMDx!S^ z%prir3eMiHF*)`s~$+Yl(^DkPQ!k-prbJJgn(nG^ z#Z$7Ta1f%yPf@SY)?ejTDqUqw%e9Re-|Ug}ffWx|T{m-brVRQcee}!EE4Zr0RZb{t zS@zavI&b&g>Ra@7FIUwq`gD0n6jrt zcG4=AJZ;X8{P<~{jwJubpe$3mOb!i1%Wh4LVS^{4^?2HiQtps2kLF&vD?30pusZy*IltzM&;zgrLg=@pH~ z!hanvpsHc8y5+BC%Ml$J+@5tHHIBkpN6rUVDelacK_mk#0?WF9`q25XrfPVjIZ)7` z=JBuqAY`3%pza|xK7<17Q^VCY&K;ROa`VM>*>Y_|#y7Jk?Ru;SUJt$gMX&#^|Ksm0 zdH1F5%Whw0$D+Hq!lrS+h)<&R<3#^fa0?0f&?eEAP2g z5b(J<9vsvrI~TiJ@Kq}x!EB{&NC_}(7@0{|=`kTovhj=ZOD!=JA-P)zt9txWB6xvv1QSve_@}f@Li(Hu z-2>B~)U)k+zWdZ=-R}CCx1*mE(TUNp-_2aPY}qL+oSEUQ1GI<+6S~tbp;5Ms4u$bQ zs;O7-%shGZ9Np0vS&_Z+JN4``JDnw{$LVd93i2?SD$*@7$vRUyrcpkIigiw{zP^9P zE6oYN^(yx{P9(kQ#9O;(-uV9BM>Q=gHom&&S3Ujr96!=N-tp1&QqS%+QSeo+a6&~T z(ob63GKu$g-{t>wACgO6{uAe2H7$PXuA5Qb|HJ$4-sRSI%3=A3*1lQSj4*SOKsVQ{ z3y?|ZLDeQWXdC)Jt!T)I?@!&Y=>A1R>x__Vq0A56I{%=`k5-KvKCP&oc_nl3enrP} zL+e~}Hu;0pliGH!Ik>jY*>ZgEmAug&R8iJMTPJcVTH0^--s=6c{_8KKhi2+XZyvsW zc;;kg^8=5BueJDf%}M@)dD(Hp{E2^y8{MBM!cS-ql1zx6*jGkbgBN=5n=q9;BvSrTn;zR^uM}8%lY@~A1=}*68 z^@>?+uS6#j)A}GV*VKbNP1C9~Tiwq@gDfQTo=G47@^g1d zhq0mQPvBAJTt0ON)v&El5kz=W#M`Dy@^3FvDNF#0G-e^HF_^XZeClTC3q22K2;?qt}mS>LLBm5Df!xv(oPM&J&3xQvqYRDR7=F2(T0c`W_b#yiBw1{0;wpiX#F{f z{=!dW=s-6B11)Xy_V@NYZ0TQW>Ho3)<5PbV`0K#Z&Vvu0I<(+Dyx=;llOP{!u^{~) zVFZdyAQF(%C&7X_k$`_kq+=H{JW0gZWqKp3JC8(GZYO26j`Jyj&RF2ll+cUtUjRE4 zUnV)}Y~{ww1VQL=ov3~fHM+eWq&rK2nQE)hkeUZjMpSzgU6M`392bfkCtJNl+Cyk_ zmHP#v*rDZ`hPl4kzIkD(rZYW6s94AQiTmEpPwSgA+i!+pzIq4l?)-TBy=TpYP92N? znWyJ7H&@%Vo&$+&i~|qjW)8pc$#btQ9yAwE8mkmylLMq-ZulI~#Q2Mr2#CgmKUw5R z#bZi7E|ay>Vw1ii5>Vw1TKpz-11?|H{H}fG)Xnmnp0v2^s(9#XTy!;NYVW%?E_-X! zp3>_go@9qbPduu$p>J9lFT7{o?Mwcnn6 z<_H`xI=N?Ae`G^-jRcDbQqcK+C^E@(tUNgp2}38MDc%@1QFr?2jK*ZBUfeSi$UL(m zhWcZ?Og0u#({cfK6G@*(6NYpBldl0RrDv%Z7{cX-mds%0`J0!(P~fa>v*Q_UCbGo5 zt48TF5oXfBz;-`dh<`gVHY5A@ag#@OoKvwhKhzdqrCG{kxg6Q)u5{c;n;_eB$9C3M zJcn(tvuzNQd!Dcj*a1SX$u1VsAGr?j9ROta>s#PLgJ-jd!W9F%4F?&28(J3X?;434Mcus z|J?BG@KSB(QXY(*ulQ*R0{*W(jehvWBu;|HNuu~tPB7%{GFZr-vX@#%&M2rmQi4{Q zQ~a_mWl!Qu<_fPt_3IMLLQwItBPFKrV=rb7>|bR^sl}L$dNUJn7&9qhCS*~z!eQ$R zC1D2o?pJ+pEDt2Ram5bJ3=r8eW3c1SSPq$ zt!ePPBqI_AD$7e*zAQO#m?g3S7LFytu}M8MnbNO-084O>kh?Rf8Kdu!Hfz8BKe*Ie zAVZel!vq0<)i6DlBPBykXw+A2p$ZX+LE#Df!2}X&3RQk*RtVw8O-^Gr+2;7D2Ingx zvr}4pUy+fp%`)rsL6KgIXrJl2oftqP%>w_8F5TnzQ0hm(Smn9{-u#zGh%x^X{o(t2 zxUOvru1(7|wQ1+$+LpQF?;Z!duY+I#q2*aL@g*{5R+S`uu;2EcQIVuxV)KQ0DpB7nf^W zA2)5d-F&MVB3!-HwABm@eeVokAI=QT*L~P>r{#kU3oQc=JWs8(adn-aZK5Au?0PG; z;A&w8P4_Umi*ig=@(1+Hm}ls&p9<(#PJNw<7!{P5uePGd3NM|0S|uM#&y=Oy%dA6Z z1(kxUyj0Y!^f*lg0}3d%*PWXixXYF^Wym%tTZelXG5`&sb5NWH2jWLmsLwi41n^cR zs98Nq#k*86Z9*!NsgSIjW#s6txB5d=XDf^>osbfV1OjmIUqUT&MZe8Z76Q$L9o7lVRvWc5kUA*XDb?{>Us>6wF*cx8!LXhrqe{bsA)UvPr zp>NBgZ%f*>T-Wiiu79zvKVANh-nzFgT|K;N=f%!dhafg1k6P+kL$Bbz3QnH zH>^s{V*AQ7TxahZSB~`C#wxLPrHiX+y86O$YsZ4U2^m3G_v1_6`m2X%s3ZKU!y)ck ztrEn#)pAknSgo`pS=Xb_$5H*6tx0TM6F5ip=XA%meb`@5KfE2A#K{d#2USv%S#SPN zi-V&f9mk=K&ARc^0Q|^W2Y}pp?eJq@_Ult@k^Zw>GNIXW{8(6-pukJhrPXErrdj70 zkNMb-U*6_%4N{x2tC-JUU=(#56)Z`l`d{z}@#D1XC~#82 z^S|V}R_p@5<5%`wD~>Y0`j_^$-_&z_=l|q3|B`F^71#gRy=kFy$3pqetIp3HT$%SR z*H!Uz#}S_2o*Dj}qrabj$975JTW9|8H~57g-}>dsF@baWa2`UVZeO%-rw{G;-;h_T zb@J6;AX&P4jYF{_;_-LPtxUTHecY^Lu#5Y|S25Tje6oqBvdcU8jPS`W9_9Z9K7$(e literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6b9e2e50e36de067a89cf9a922b0662c57df38d GIT binary patch literal 224 zcmX@j%ge<81j_4zG97^QV-N=h7@>^M96-i&h7^VWHa^HWN5QtgV^fOdkMS`6~Z2WCb_#s_@jjod{nKrR3Z>Of`y literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2d8954189470d3cb33a8a5644301816712d4164 GIT binary patch literal 20409 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 YX3D>|`j0wb%7 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0ce347d82d128f03f52e18e41f5ee0932c70067 GIT binary patch literal 13499 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 S^?ikbz8V_xzwbK8^8W?w1WaH6 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6774f3b24beb7415666189bd8acae6a6c8adc9c9 GIT binary patch literal 4018 zcmbVP|8En?6`%Fj^_Rr44dF|G>|G$m5IY5~2TA!NdI4QH0==WZ)XK?O?~ciaU9XuP zCpdDd^n_ZcK^LETDnUXjr#tBmp{x31|ADGMRH_m=SJJ&8QIS^VH%jh@(x3Wf*J~$f zXlX~>k_g9M~LX z{sCvtY}lU+>-Wpo84 z+>@7r0<_CTB48~m5+WLglE12!k_Oy{iUooTswiO%=c$m>iJ&POrn;^gDQQ&K4V=m9 z#k?$%Qpytav<;3iy`mv0O2TjQStW1LrhgRQP?cQCbm@laFA^~?>l*PhZuj?pc+~XC zSkh$-m&!X54R&Y3Kc%<&hYLi%N<>Wq)rKc@UD7oT6A3Jq9|y&BQX0;R(lwlyhhaWG zd{M~`8w$nA0<4Nxu`ygw3cVS4C+noQNK{qH9_!61DlX^-O%+OJWYgD>?QnJk9^*~u zrqMS%YTNlR(zzJv{LJ-v@RQ&dM?Y-UJ13%9sk+!<#@;KGasF~cf1xqT;Z2P z@#)KJuoFoQ!^4D`xeK1PKS1{m;x;%&8PSGoJg8Ho{Xe@#88r;b|&zEWQjuRSYWVIpN^79$`Eo&>}dRA%I5+vLaEV$08Y% z0bJJBen|z#>>v42-FB(E;PqiSQa|Pr_+3x|FE*%{m$2z!LTyhAfKL#3G{f{TlCWqq zLph>r8C#2l+w|G8O-?brHp$``f`n{i+%dK>W4*}e*)a?X69HZ@$T6-!_c!zp@Rv5k z$Ew|T_b>T7SHh9Gp_!ri?ppY@8E!S)R&AfXSmB;TV-@d8XnPgk9bO6@T8{0QeP=bc z?_uoFV(ict=N4i|YvH4R51?55g~9av;B42~1Kb9G^1!kMGAa=3L1s%|+9Pu}(X0B? z0D1s2S-S$TaTAr%`jv!ROoC%uwn?P~85ana!0K{;zi=e=rfu)RmwLhvMzJ8uvO*O- z&m7^E%qwW(HENlx41&$EDEA0O0}K6(sek0(%{9^^OpGeh zC}0~clDzTi9wyWc{y#dj4UHQt$EscIBLSY=J04 zEXwY4m+qtcZqt?ew#i*Hxp8BIZw5|Y#d&xz`8L_(q@mKQ$*^AdKv1-2vz}=uHx^^4~N* z$#$_Ivo#KN-x>diRHF;1=chh7_3QSft`oIL-vZzFXLfom)V<*8Chf38Y5+G( zSWaV?v~~$r*9WB&P|Uc~LCScn)>!A7!Px|G0Po*|OSsFfF(!FaYeK%vmAOg4i3jzB zBRTx1|eE2{yAhF7><`geNwh z

        _%vj%fQUZ;Xlz>)$d0g{9IdH6`XUKE@i!i1u#LKX`Q?^wAZ+h5yIx(@!$a-m-8 zZ7TDiW?REs#_v(Ssg znMhAomrJCRoq2@K!;+q-Py}0htU|#yn~ie2u;nJ1h6iMr$*t2*!0t2f7=MKhFs~hj zeGvK`yYqf<}S=!sM4kIp2zmV)#G3B9nbcnSkE&7 zc>_Pa@Z$@&u2=Wm+qoD$REr#5^7O36+ZT59{pRh(9Rs!ax#^3KLy@^tGpAMQgqw8EP2?)BJccC*yaj5 z(-iy>)@`op`n6(#^s+rH;4QbXQVd~tZYM#8bhe53lbS9UReYK-YcTXS&O`Ui&2ii# z)cpiSzD6xyqrfB7{ud-XLc1QJj>m!aO8ea2nZ4DCTA=eDw-|VR+V|Y&=e9lH7UhmT RKN#V@_09e+E@6G~zX0tOs22bL literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca1105946fd1a73e9e5eea1652a5c627483b6833 GIT binary patch literal 20435 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aea2eb88ab6bf89a9ed013c216ac1ab6f1df85f8 GIT binary patch literal 33949 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py new file mode 100644 index 0000000..bceb845 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py @@ -0,0 +1,355 @@ +from __future__ import absolute_import + +try: + from collections.abc import Mapping, MutableMapping +except ImportError: + from collections import Mapping, MutableMapping +try: + from threading import RLock +except ImportError: # Platform-specific: No threads available + + class RLock: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +from collections import OrderedDict + +from .exceptions import InvalidHeader +from .packages import six +from .packages.six import iterkeys, itervalues + +__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"] + + +_Null = object() + + +class RecentlyUsedContainer(MutableMapping): + """ + Provides a thread-safe dict-like container which maintains up to + ``maxsize`` keys while throwing away the least-recently-used keys beyond + ``maxsize``. + + :param maxsize: + Maximum number of recent elements to retain. + + :param dispose_func: + Every time an item is evicted from the container, + ``dispose_func(value)`` is called. Callback which will get called + """ + + ContainerCls = OrderedDict + + def __init__(self, maxsize=10, dispose_func=None): + self._maxsize = maxsize + self.dispose_func = dispose_func + + self._container = self.ContainerCls() + self.lock = RLock() + + def __getitem__(self, key): + # Re-insert the item, moving it to the end of the eviction line. + with self.lock: + item = self._container.pop(key) + self._container[key] = item + return item + + def __setitem__(self, key, value): + evicted_value = _Null + with self.lock: + # Possibly evict the existing value of 'key' + evicted_value = self._container.get(key, _Null) + self._container[key] = value + + # If we didn't evict an existing value, we might have to evict the + # least recently used item from the beginning of the container. + if len(self._container) > self._maxsize: + _key, evicted_value = self._container.popitem(last=False) + + if self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) + + def __delitem__(self, key): + with self.lock: + value = self._container.pop(key) + + if self.dispose_func: + self.dispose_func(value) + + def __len__(self): + with self.lock: + return len(self._container) + + def __iter__(self): + raise NotImplementedError( + "Iteration over this class is unlikely to be threadsafe." + ) + + def clear(self): + with self.lock: + # Copy pointers to all values, then wipe the mapping + values = list(itervalues(self._container)) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self.lock: + return list(iterkeys(self._container)) + + +class HTTPHeaderDict(MutableMapping): + """ + :param headers: + An iterable of field-value pairs. Must not contain multiple field names + when compared case-insensitively. + + :param kwargs: + Additional field-value pairs to pass in to ``dict.update``. + + A ``dict`` like container for storing HTTP Headers. + + Field names are stored and compared case-insensitively in compliance with + RFC 7230. Iteration provides the first case-sensitive key seen for each + case-insensitive pair. + + Using ``__setitem__`` syntax overwrites fields that compare equal + case-insensitively in order to maintain ``dict``'s api. For fields that + compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` + in a loop. + + If multiple fields that are equal case-insensitively are passed to the + constructor or ``.update``, the behavior is undefined and some will be + lost. + + >>> headers = HTTPHeaderDict() + >>> headers.add('Set-Cookie', 'foo=bar') + >>> headers.add('set-cookie', 'baz=quxx') + >>> headers['content-length'] = '7' + >>> headers['SET-cookie'] + 'foo=bar, baz=quxx' + >>> headers['Content-Length'] + '7' + """ + + def __init__(self, headers=None, **kwargs): + super(HTTPHeaderDict, self).__init__() + self._container = OrderedDict() + if headers is not None: + if isinstance(headers, HTTPHeaderDict): + self._copy_from(headers) + else: + self.extend(headers) + if kwargs: + self.extend(kwargs) + + def __setitem__(self, key, val): + self._container[key.lower()] = [key, val] + return self._container[key.lower()] + + def __getitem__(self, key): + val = self._container[key.lower()] + return ", ".join(val[1:]) + + def __delitem__(self, key): + del self._container[key.lower()] + + def __contains__(self, key): + return key.lower() in self._container + + def __eq__(self, other): + if not isinstance(other, Mapping) and not hasattr(other, "keys"): + return False + if not isinstance(other, type(self)): + other = type(self)(other) + return dict((k.lower(), v) for k, v in self.itermerged()) == dict( + (k.lower(), v) for k, v in other.itermerged() + ) + + def __ne__(self, other): + return not self.__eq__(other) + + if six.PY2: # Python 2 + iterkeys = MutableMapping.iterkeys + itervalues = MutableMapping.itervalues + + __marker = object() + + def __len__(self): + return len(self._container) + + def __iter__(self): + # Only provide the originally cased names + for vals in self._container.values(): + yield vals[0] + + def pop(self, key, default=__marker): + """D.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + """ + # Using the MutableMapping function directly fails due to the private marker. + # Using ordinary dict.pop would expose the internal structures. + # So let's reinvent the wheel. + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def discard(self, key): + try: + del self[key] + except KeyError: + pass + + def add(self, key, val): + """Adds a (name, value) pair, doesn't overwrite the value if it already + exists. + + >>> headers = HTTPHeaderDict(foo='bar') + >>> headers.add('Foo', 'baz') + >>> headers['foo'] + 'bar, baz' + """ + key_lower = key.lower() + new_vals = [key, val] + # Keep the common case aka no item present as fast as possible + vals = self._container.setdefault(key_lower, new_vals) + if new_vals is not vals: + vals.append(val) + + def extend(self, *args, **kwargs): + """Generic import function for any type of header-like object. + Adapted version of MutableMapping.update in order to insert items + with self.add instead of self.__setitem__ + """ + if len(args) > 1: + raise TypeError( + "extend() takes at most 1 positional " + "arguments ({0} given)".format(len(args)) + ) + other = args[0] if len(args) >= 1 else () + + if isinstance(other, HTTPHeaderDict): + for key, val in other.iteritems(): + self.add(key, val) + elif isinstance(other, Mapping): + for key in other: + self.add(key, other[key]) + elif hasattr(other, "keys"): + for key in other.keys(): + self.add(key, other[key]) + else: + for key, value in other: + self.add(key, value) + + for key, value in kwargs.items(): + self.add(key, value) + + def getlist(self, key, default=__marker): + """Returns a list of all the values for the named field. Returns an + empty list if the key doesn't exist.""" + try: + vals = self._container[key.lower()] + except KeyError: + if default is self.__marker: + return [] + return default + else: + return vals[1:] + + def _prepare_for_method_change(self): + """ + Remove content-specific header fields before changing the request + method to GET or HEAD according to RFC 9110, Section 15.4. + """ + content_specific_headers = [ + "Content-Encoding", + "Content-Language", + "Content-Location", + "Content-Type", + "Content-Length", + "Digest", + "Last-Modified", + ] + for header in content_specific_headers: + self.discard(header) + return self + + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist + iget = getlist + + # Backwards compatibility for http.cookiejar + get_all = getlist + + def __repr__(self): + return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) + + def _copy_from(self, other): + for key in other: + val = other.getlist(key) + if isinstance(val, list): + # Don't need to convert tuples + val = list(val) + self._container[key.lower()] = [key] + val + + def copy(self): + clone = type(self)() + clone._copy_from(self) + return clone + + def iteritems(self): + """Iterate over all header lines, including duplicate ones.""" + for key in self: + vals = self._container[key.lower()] + for val in vals[1:]: + yield vals[0], val + + def itermerged(self): + """Iterate over all headers, merging duplicate ones together.""" + for key in self: + val = self._container[key.lower()] + yield val[0], ", ".join(val[1:]) + + def items(self): + return list(self.iteritems()) + + @classmethod + def from_httplib(cls, message): # Python 2 + """Read headers from a Python 2 httplib message object.""" + # python2.7 does not expose a proper API for exporting multiheaders + # efficiently. This function re-reads raw lines from the message + # object and extracts the multiheaders properly. + obs_fold_continued_leaders = (" ", "\t") + headers = [] + + for line in message.headers: + if line.startswith(obs_fold_continued_leaders): + if not headers: + # We received a header line that starts with OWS as described + # in RFC-7230 S3.2.4. This indicates a multiline header, but + # there exists no previous header to which we can attach it. + raise InvalidHeader( + "Header continuation with no previous header: %s" % line + ) + else: + key, value = headers[-1] + headers[-1] = (key, value + " " + line.strip()) + continue + + key, value = line.split(":", 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py new file mode 100644 index 0000000..d49df2a --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py @@ -0,0 +1,2 @@ +# This file is protected via CODEOWNERS +__version__ = "1.26.20" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connection.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connection.py new file mode 100644 index 0000000..de35b63 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connection.py @@ -0,0 +1,572 @@ +from __future__ import absolute_import + +import datetime +import logging +import os +import re +import socket +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 +from .util.proxy import create_proxy_ssl_context + +try: # Compiled with SSL? + import ssl + + BaseSSLError = ssl.SSLError +except (ImportError, AttributeError): # Platform-specific: No SSL. + ssl = None + + class BaseSSLError(BaseException): + pass + + +try: + # Python 3: not a no-op, we're adding this to the namespace so it can be imported. + ConnectionError = ConnectionError +except NameError: + # Python 2 + class ConnectionError(Exception): + pass + + +try: # Python 3: + # Not a no-op, we're adding this to the namespace so it can be imported. + BrokenPipeError = BrokenPipeError +except NameError: # Python 2: + + class BrokenPipeError(Exception): + pass + + +from ._collections import HTTPHeaderDict # noqa (historical, removed in v2) +from ._version import __version__ +from .exceptions import ( + ConnectTimeoutError, + NewConnectionError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection +from .util.ssl_ import ( + assert_fingerprint, + create_urllib3_context, + is_ipaddress, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .util.ssl_match_hostname import CertificateError, match_hostname + +log = logging.getLogger(__name__) + +port_by_scheme = {"http": 80, "https": 443} + +# When it comes time to update this value as a part of regular maintenance +# (ie test_recent_date is failing) update it to ~6 months before the current date. +RECENT_DATE = datetime.date(2024, 1, 1) + +_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on :class:`http.client.HTTPConnection` but provides an extra constructor + backwards-compatibility layer between older and newer Pythons. + + Additional keyword parameters are used to configure attributes of the connection. + Accepted parameters include: + + - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` + - ``source_address``: Set the source address for the current connection. + - ``socket_options``: Set specific options on the underlying socket. If not specified, then + defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling + Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. + + For example, if you wish to enable TCP Keep Alive in addition to the defaults, + you might pass: + + .. code-block:: python + + HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), + ] + + Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). + """ + + default_port = port_by_scheme["http"] + + #: Disable Nagle's algorithm by default. + #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` + default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] + + #: Whether this connection verifies the host's certificate. + is_verified = False + + #: Whether this proxy connection (if used) verifies the proxy host's + #: certificate. + proxy_is_verified = None + + def __init__(self, *args, **kw): + if not six.PY2: + kw.pop("strict", None) + + # Pre-set source_address. + self.source_address = kw.get("source_address") + + #: The socket options provided by the user. If no options are + #: provided, we use the default options. + self.socket_options = kw.pop("socket_options", self.default_socket_options) + + # Proxy options provided by the user. + self.proxy = kw.pop("proxy", None) + self.proxy_config = kw.pop("proxy_config", None) + + _HTTPConnection.__init__(self, *args, **kw) + + @property + def host(self): + """ + Getter method to remove any trailing dots that indicate the hostname is an FQDN. + + In general, SSL certificates don't include the trailing dot indicating a + fully-qualified domain name, and thus, they don't validate properly when + checked against a domain name that includes the dot. In addition, some + servers may not expect to receive the trailing dot when provided. + + However, the hostname with trailing dot is critical to DNS resolution; doing a + lookup with the trailing dot will properly only resolve the appropriate FQDN, + whereas a lookup without a trailing dot will search the system's search domain + list. Thus, it's important to keep the original host around for use only in + those cases where it's appropriate (i.e., when doing DNS lookup to establish the + actual TCP connection across which we're going to send HTTP requests). + """ + return self._dns_host.rstrip(".") + + @host.setter + def host(self, value): + """ + Setter for the `host` property. + + We assume that only urllib3 uses the _dns_host attribute; httplib itself + only uses `host`, and it seems reasonable that other libraries follow suit. + """ + self._dns_host = value + + def _new_conn(self): + """Establish a socket connection and set nodelay settings on it. + + :return: New socket connection. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = connection.create_connection( + (self._dns_host, self.port), self.timeout, **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except SocketError as e: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + def _is_using_tunnel(self): + # Google App Engine's httplib does not define _tunnel_host + return getattr(self, "_tunnel_host", None) + + def _prepare_conn(self, conn): + self.sock = conn + if self._is_using_tunnel(): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + def putrequest(self, method, url, *args, **kwargs): + """ """ + # Empty docstring because the indentation of CPython's implementation + # is broken but we don't want this method in our documentation. + match = _CONTAINS_CONTROL_CHAR_RE.search(method) + if match: + raise ValueError( + "Method cannot contain non-token characters %r (found at least %r)" + % (method, match.group()) + ) + + return _HTTPConnection.putrequest(self, method, url, *args, **kwargs) + + def putheader(self, header, *values): + """ """ + if not any(isinstance(v, str) and v == SKIP_HEADER for v in values): + _HTTPConnection.putheader(self, header, *values) + elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS: + raise ValueError( + "urllib3.util.SKIP_HEADER only supports '%s'" + % ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),) + ) + + def request(self, method, url, body=None, headers=None): + # Update the inner socket's timeout value to send the request. + # This only triggers if the connection is re-used. + if getattr(self, "sock", None) is not None: + self.sock.settimeout(self.timeout) + + if headers is None: + headers = {} + else: + # Avoid modifying the headers passed into .request() + headers = headers.copy() + if "user-agent" not in (six.ensure_str(k.lower()) for k in headers): + headers["User-Agent"] = _get_default_user_agent() + super(HTTPConnection, self).request(method, url, body=body, headers=headers) + + def request_chunked(self, method, url, body=None, headers=None): + """ + Alternative to the common request method, which sends the + body with chunked encoding and not as one block + """ + headers = headers or {} + header_keys = set([six.ensure_str(k.lower()) for k in headers]) + skip_accept_encoding = "accept-encoding" in header_keys + skip_host = "host" in header_keys + self.putrequest( + method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host + ) + if "user-agent" not in header_keys: + self.putheader("User-Agent", _get_default_user_agent()) + for header, value in headers.items(): + self.putheader(header, value) + if "transfer-encoding" not in header_keys: + self.putheader("Transfer-Encoding", "chunked") + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (bytes,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, bytes): + chunk = chunk.encode("utf8") + len_str = hex(len(chunk))[2:] + to_send = bytearray(len_str.encode()) + to_send += b"\r\n" + to_send += chunk + to_send += b"\r\n" + self.send(to_send) + + # After the if clause, to always have a closed body + self.send(b"0\r\n\r\n") + + +class HTTPSConnection(HTTPConnection): + """ + Many of the parameters to this constructor are passed to the underlying SSL + socket by means of :py:func:`urllib3.util.ssl_wrap_socket`. + """ + + default_port = port_by_scheme["https"] + + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ca_cert_data = None + ssl_version = None + assert_fingerprint = None + tls_in_tls_required = False + + def __init__( + self, + host, + port=None, + key_file=None, + cert_file=None, + key_password=None, + strict=None, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, + server_hostname=None, + **kw + ): + + HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.key_password = key_password + self.ssl_context = ssl_context + self.server_hostname = server_hostname + + # Required property for Google AppEngine 1.9.0 which otherwise causes + # HTTPS requests to go out as HTTP. (See Issue #356) + self._protocol = "https" + + def set_cert( + self, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + ca_cert_data=None, + ): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also + # have an SSLContext object in which case we'll use its verify_mode. + if cert_reqs is None: + if self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + else: + cert_reqs = resolve_cert_reqs(None) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + self.ca_certs = ca_certs and os.path.expanduser(ca_certs) + self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) + self.ca_cert_data = ca_cert_data + + def connect(self): + # Add certificate verification + self.sock = conn = self._new_conn() + hostname = self.host + tls_in_tls = False + + if self._is_using_tunnel(): + if self.tls_in_tls_required: + self.sock = conn = self._connect_tls_proxy(hostname, conn) + tls_in_tls = True + + # Calls self._set_hostport(), so self.host is + # self._tunnel_host below. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + # Override the host with the one we're requesting data from. + hostname = self._tunnel_host + + server_hostname = hostname + if self.server_hostname is not None: + server_hostname = self.server_hostname + + is_time_off = datetime.date.today() < RECENT_DATE + if is_time_off: + warnings.warn( + ( + "System time is way off (before {0}). This will probably " + "lead to SSL verification errors" + ).format(RECENT_DATE), + SystemTimeWarning, + ) + + # Wrap socket using verification with the root certs in + # trusted_root_certs + default_ssl_context = False + if self.ssl_context is None: + default_ssl_context = True + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(self.ssl_version), + cert_reqs=resolve_cert_reqs(self.cert_reqs), + ) + + context = self.ssl_context + context.verify_mode = resolve_cert_reqs(self.cert_reqs) + + # Try to load OS default certs if none are given. + # Works well on Windows (requires Python3.4+) + if ( + not self.ca_certs + and not self.ca_cert_dir + and not self.ca_cert_data + and default_ssl_context + and hasattr(context, "load_default_certs") + ): + context.load_default_certs() + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + key_password=self.key_password, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=server_hostname, + ssl_context=context, + tls_in_tls=tls_in_tls, + ) + + # If we're using all defaults and the connection + # is TLSv1 or TLSv1.1 we throw a DeprecationWarning + # for the host. + if ( + default_ssl_context + and self.ssl_version is None + and hasattr(self.sock, "version") + and self.sock.version() in {"TLSv1", "TLSv1.1"} + ): # Defensive: + warnings.warn( + "Negotiating TLSv1/TLSv1.1 by default is deprecated " + "and will be disabled in urllib3 v2.0.0. Connecting to " + "'%s' with '%s' can be enabled by explicitly opting-in " + "with 'ssl_version'" % (self.host, self.sock.version()), + DeprecationWarning, + ) + + if self.assert_fingerprint: + assert_fingerprint( + self.sock.getpeercert(binary_form=True), self.assert_fingerprint + ) + elif ( + context.verify_mode != ssl.CERT_NONE + and not getattr(context, "check_hostname", False) + and self.assert_hostname is not False + ): + # While urllib3 attempts to always turn off hostname matching from + # the TLS library, this cannot always be done. So we check whether + # the TLS Library still thinks it's matching hostnames. + cert = self.sock.getpeercert() + if not cert.get("subjectAltName", ()): + warnings.warn( + ( + "Certificate for {0} has no `subjectAltName`, falling back to check for a " + "`commonName` for now. This feature is being removed by major browsers and " + "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " + "for details.)".format(hostname) + ), + SubjectAltNameWarning, + ) + _match_hostname(cert, self.assert_hostname or server_hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED + or self.assert_fingerprint is not None + ) + + def _connect_tls_proxy(self, hostname, conn): + """ + Establish a TLS connection to the proxy using the provided SSL context. + """ + proxy_config = self.proxy_config + ssl_context = proxy_config.ssl_context + if ssl_context: + # If the user provided a proxy context, we assume CA and client + # certificates have already been set + return ssl_wrap_socket( + sock=conn, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + ssl_context = create_proxy_ssl_context( + self.ssl_version, + self.cert_reqs, + self.ca_certs, + self.ca_cert_dir, + self.ca_cert_data, + ) + + # If no cert was provided, use only the default options for server + # certificate validation + socket = ssl_wrap_socket( + sock=conn, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + if ssl_context.verify_mode != ssl.CERT_NONE and not getattr( + ssl_context, "check_hostname", False + ): + # While urllib3 attempts to always turn off hostname matching from + # the TLS library, this cannot always be done. So we check whether + # the TLS Library still thinks it's matching hostnames. + cert = socket.getpeercert() + if not cert.get("subjectAltName", ()): + warnings.warn( + ( + "Certificate for {0} has no `subjectAltName`, falling back to check for a " + "`commonName` for now. This feature is being removed by major browsers and " + "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " + "for details.)".format(hostname) + ), + SubjectAltNameWarning, + ) + _match_hostname(cert, hostname) + + self.proxy_is_verified = ssl_context.verify_mode == ssl.CERT_REQUIRED + return socket + + +def _match_hostname(cert, asserted_hostname): + # Our upstream implementation of ssl.match_hostname() + # only applies this normalization to IP addresses so it doesn't + # match DNS SANs so we do the same thing! + stripped_hostname = asserted_hostname.strip("u[]") + if is_ipaddress(stripped_hostname): + asserted_hostname = stripped_hostname + + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.warning( + "Certificate did not match expected hostname: %s. Certificate: %s", + asserted_hostname, + cert, + ) + # Add cert to exception and reraise so client code can inspect + # the cert when catching the exception, if they want to + e._peer_cert = cert + raise + + +def _get_default_user_agent(): + return "python-urllib3/%s" % __version__ + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + + pass + + +if not ssl: + HTTPSConnection = DummyConnection # noqa: F811 + + +VerifiedHTTPSConnection = HTTPSConnection diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py new file mode 100644 index 0000000..0872ed7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py @@ -0,0 +1,1140 @@ +from __future__ import absolute_import + +import errno +import logging +import re +import socket +import sys +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from ._collections import HTTPHeaderDict +from .connection import ( + BaseSSLError, + BrokenPipeError, + DummyConnection, + HTTPConnection, + HTTPException, + HTTPSConnection, + VerifiedHTTPSConnection, + port_by_scheme, +) +from .exceptions import ( + ClosedPoolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + InsecureRequestWarning, + LocationValueError, + MaxRetryError, + NewConnectionError, + ProtocolError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, +) +from .packages import six +from .packages.six.moves import queue +from .request import RequestMethods +from .response import HTTPResponse +from .util.connection import is_connection_dropped +from .util.proxy import connection_requires_http_tunnel +from .util.queue import LifoQueue +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.ssl_match_hostname import CertificateError +from .util.timeout import Timeout +from .util.url import Url, _encode_target +from .util.url import _normalize_host as normalize_host +from .util.url import get_host, parse_url + +try: # Platform-specific: Python 3 + import weakref + + weakref_finalize = weakref.finalize +except AttributeError: # Platform-specific: Python 2 + from .packages.backports.weakref_finalize import weakref_finalize + +xrange = six.moves.xrange + +log = logging.getLogger(__name__) + +_Default = object() + + +# Pool objects +class ConnectionPool(object): + """ + Base class for all connection pools, such as + :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. + + .. note:: + ConnectionPool.urlopen() does not normalize or percent-encode target URIs + which is useful if your target server doesn't support percent-encoded + target URIs. + """ + + scheme = None + QueueCls = LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _normalize_host(host, scheme=self.scheme) + self._proxy_host = host.lower() + self.port = port + + def __str__(self): + return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + # Return False to re-raise any potential exceptions + return False + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + pass + + +# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 +_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK} + + +class HTTPConnectionPool(ConnectionPool, RequestMethods): + """ + Thread-safe connection pool for one host. + + :param host: + Host used for this HTTP Connection (e.g. "localhost"), passed into + :class:`http.client.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`http.client.HTTPConnection`. + + :param strict: + Causes BadStatusLine to be raised if the status line can't be parsed + as a valid HTTP/1.0 or 1.1 status line, passed into + :class:`http.client.HTTPConnection`. + + .. note:: + Only works in Python 2. This parameter is ignored in Python 3. + + :param timeout: + Socket timeout in seconds for each individual connection. This can + be a float or integer, which sets the timeout for the HTTP request, + or an instance of :class:`urllib3.util.Timeout` which gives you more + fine-grained control over request timeouts. After the constructor has + been parsed, this is always a `urllib3.util.Timeout` object. + + :param maxsize: + Number of connections to save that can be reused. More than 1 is useful + in multithreaded situations. If ``block`` is set to False, more + connections will be created but they will not be saved once they've + been used. + + :param block: + If set to True, no more than ``maxsize`` connections will be used at + a time. When no free connections are available, the call will block + until a connection has been released. This is a useful side effect for + particular multithreaded situations where one does not want to use more + than maxsize connections per host to prevent flooding. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param retries: + Retry configuration to use by default with requests in this pool. + + :param _proxy: + Parsed proxy URL, should not be used directly, instead, see + :class:`urllib3.ProxyManager` + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.ProxyManager` + + :param \\**conn_kw: + Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, + :class:`urllib3.connection.HTTPSConnection` instances. + """ + + scheme = "http" + ConnectionCls = HTTPConnection + ResponseCls = HTTPResponse + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + _proxy_config=None, + **conn_kw + ): + ConnectionPool.__init__(self, host, port) + RequestMethods.__init__(self, headers) + + self.strict = strict + + if not isinstance(timeout, Timeout): + timeout = Timeout.from_float(timeout) + + if retries is None: + retries = Retry.DEFAULT + + self.timeout = timeout + self.retries = retries + + self.pool = self.QueueCls(maxsize) + self.block = block + + self.proxy = _proxy + self.proxy_headers = _proxy_headers or {} + self.proxy_config = _proxy_config + + # Fill the queue up so that doing get() on it will block properly + for _ in xrange(maxsize): + self.pool.put(None) + + # These are mostly for testing and debugging purposes. + self.num_connections = 0 + self.num_requests = 0 + self.conn_kw = conn_kw + + if self.proxy: + # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. + # We cannot know if the user has added default socket options, so we cannot replace the + # list. + self.conn_kw.setdefault("socket_options", []) + + self.conn_kw["proxy"] = self.proxy + self.conn_kw["proxy_config"] = self.proxy_config + + # Do not pass 'self' as callback to 'finalize'. + # Then the 'finalize' would keep an endless living (leak) to self. + # By just passing a reference to the pool allows the garbage collector + # to free self if nobody else has a reference to it. + pool = self.pool + + # Close all the HTTPConnections in the pool before the + # HTTPConnectionPool object is garbage collected. + weakref_finalize(self, _close_pool_connections, pool) + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTP connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "80", + ) + + conn = self.ConnectionCls( + host=self.host, + port=self.port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + **self.conn_kw + ) + return conn + + def _get_conn(self, timeout=None): + """ + Get a connection. Will return a pooled connection if one is available. + + If no connections are available and :prop:`.block` is ``False``, then a + fresh connection is returned. + + :param timeout: + Seconds to wait before giving up and raising + :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and + :prop:`.block` is ``True``. + """ + conn = None + try: + conn = self.pool.get(block=self.block, timeout=timeout) + + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") + + except queue.Empty: + if self.block: + raise EmptyPoolError( + self, + "Pool reached maximum size and no more connections are allowed.", + ) + pass # Oh well, we'll create a new connection then + + # If this is a persistent connection, check if it got disconnected + if conn and is_connection_dropped(conn): + log.debug("Resetting dropped connection: %s", self.host) + conn.close() + if getattr(conn, "auto_open", 1) == 0: + # This is a proxied connection that has been mutated by + # http.client._tunnel() and cannot be reused (since it would + # attempt to bypass the proxy) + conn = None + + return conn or self._new_conn() + + def _put_conn(self, conn): + """ + Put a connection back into the pool. + + :param conn: + Connection object for the current host and port as returned by + :meth:`._new_conn` or :meth:`._get_conn`. + + If the pool is already full, the connection is closed and discarded + because we exceeded maxsize. If connections are discarded frequently, + then maxsize should be increased. + + If the pool is closed, then the connection will be closed and discarded. + """ + try: + self.pool.put(conn, block=False) + return # Everything is dandy, done. + except AttributeError: + # self.pool is None. + pass + except queue.Full: + # This should never happen if self.block == True + log.warning( + "Connection pool is full, discarding connection: %s. Connection pool size: %s", + self.host, + self.pool.qsize(), + ) + # Connection never got put back into the pool, close it. + if conn: + conn.close() + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + pass + + def _prepare_proxy(self, conn): + # Nothing to do for HTTP connections. + pass + + def _get_timeout(self, timeout): + """Helper that always returns a :class:`urllib3.util.Timeout`""" + if timeout is _Default: + return self.timeout.clone() + + if isinstance(timeout, Timeout): + return timeout.clone() + else: + # User passed us an int/float. This is for backwards compatibility, + # can be removed later + return Timeout.from_float(timeout) + + def _raise_timeout(self, err, url, timeout_value): + """Is the error actually a timeout? Will raise a ReadTimeout or pass""" + + if isinstance(err, SocketTimeout): + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # See the above comment about EAGAIN in Python 3. In Python 2 we have + # to specifically catch it and throw the timeout error + if hasattr(err, "errno") and err.errno in _blocking_errnos: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # Catch possible read timeouts thrown as SSL errors. If not the + # case, rethrow the original. We need to do this because of: + # http://bugs.python.org/issue10272 + if "timed out" in str(err) or "did not complete (read)" in str( + err + ): # Python < 2.7.4 + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + def _make_request( + self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw + ): + """ + Perform a request on a given urllib connection object taken from our + pool. + + :param conn: + a connection from one of our connection pools + + :param timeout: + Socket timeout in seconds for the request. This can be a + float or integer, which will set the same timeout value for + the socket connect and the socket read, or an instance of + :class:`urllib3.util.Timeout`, which gives you more fine-grained + control over your timeouts. + """ + self.num_requests += 1 + + timeout_obj = self._get_timeout(timeout) + timeout_obj.start_connect() + conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) + + # Trigger any extra validation we need to do. + try: + self._validate_conn(conn) + except (SocketTimeout, BaseSSLError) as e: + # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. + self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) + raise + + # conn.request() calls http.client.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + try: + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # We are swallowing BrokenPipeError (errno.EPIPE) since the server is + # legitimately able to close the connection after sending a valid response. + # With this behaviour, the received response is still readable. + except BrokenPipeError: + # Python 3 + pass + except IOError as e: + # Python 2 and macOS/Linux + # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE/ECONNRESET are needed on macOS + # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ + if e.errno not in { + errno.EPIPE, + errno.ESHUTDOWN, + errno.EPROTOTYPE, + errno.ECONNRESET, + }: + raise + + # Reset the timeout for the recv() on the socket + read_timeout = timeout_obj.read_timeout + + # App Engine doesn't have a sock attr + if getattr(conn, "sock", None): + # In Python 3 socket.py will catch EAGAIN and return None when you + # try and read into the file pointer created by http.client, which + # instead raises a BadStatusLine exception. Instead of catching + # the exception and assuming all BadStatusLine exceptions are read + # timeouts, check for a zero timeout before making the request. + if read_timeout == 0: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % read_timeout + ) + if read_timeout is Timeout.DEFAULT_TIMEOUT: + conn.sock.settimeout(socket.getdefaulttimeout()) + else: # None or a value + conn.sock.settimeout(read_timeout) + + # Receive the response from the server + try: + try: + # Python 2.7, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: + # Python 3 + try: + httplib_response = conn.getresponse() + except BaseException as e: + # Remove the TypeError from the exception chain in + # Python 3 (including for exceptions like SystemExit). + # Otherwise it looks like a bug in the code. + six.raise_from(e, None) + except (SocketTimeout, BaseSSLError, SocketError) as e: + self._raise_timeout(err=e, url=url, timeout_value=read_timeout) + raise + + # AppEngine doesn't have a version attr. + http_version = getattr(conn, "_http_vsn_str", "HTTP/?") + log.debug( + '%s://%s:%s "%s %s %s" %s %s', + self.scheme, + self.host, + self.port, + method, + url, + http_version, + httplib_response.status, + httplib_response.length, + ) + + try: + assert_header_parsing(httplib_response.msg) + except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3 + log.warning( + "Failed to parse headers (url=%s): %s", + self._absolute_url(url), + hpe, + exc_info=True, + ) + + return httplib_response + + def _absolute_url(self, path): + return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + if self.pool is None: + return + # Disable access to the pool + old_pool, self.pool = self.pool, None + + # Close all the HTTPConnections in the pool. + _close_pool_connections(old_pool) + + def is_same_host(self, url): + """ + Check if the given ``url`` is a member of the same host as this + connection pool. + """ + if url.startswith("/"): + return True + + # TODO: Add optional support for socket.gethostbyname checking. + scheme, host, port = get_host(url) + if host is not None: + host = _normalize_host(host, scheme=scheme) + + # Use explicit default port for comparison when none is given + if self.port and not port: + port = port_by_scheme.get(scheme) + elif not self.port and port == port_by_scheme.get(scheme): + port = None + + return (scheme, host, port) == (self.scheme, self.host, self.port) + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + assert_same_host=True, + timeout=_Default, + pool_timeout=None, + release_conn=None, + chunked=False, + body_pos=None, + **response_kw + ): + """ + Get a connection from the pool and perform an HTTP request. This is the + lowest level call for making a request, so you'll need to specify all + the raw details. + + .. note:: + + More commonly, it's appropriate to use a convenience method provided + by :class:`.RequestMethods`, such as :meth:`request`. + + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + + :param url: + The URL to perform the request on. + + :param body: + Data to send in the request body, either :class:`str`, :class:`bytes`, + an iterable of :class:`str`/:class:`bytes`, or a file-like object. + + :param headers: + Dictionary of custom headers to send, such as User-Agent, + If-None-Match, etc. If None, pool headers are used. If provided, + these headers completely replace any pool-specific headers. + + :param retries: + Configure the number of retries to allow before raising a + :class:`~urllib3.exceptions.MaxRetryError` exception. + + Pass ``None`` to retry until you receive a response. Pass a + :class:`~urllib3.util.retry.Retry` object for fine-grained control + over different types of retries. + Pass an integer number to retry connection errors that many times, + but no other types of errors. Pass zero to never retry. + + If ``False``, then retries are disabled and any exception is raised + immediately. Also, instead of raising a MaxRetryError on redirects, + the redirect response will be returned. + + :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. + + :param redirect: + If True, automatically handle redirects (status codes 301, 302, + 303, 307, 308). Each redirect counts as a retry. Disabling retries + will disable redirect, too. + + :param assert_same_host: + If ``True``, will make sure that the host of the pool requests is + consistent else will raise HostChangedError. When ``False``, you can + use the pool on an HTTP proxy and request foreign hosts. + + :param timeout: + If specified, overrides the default timeout for this one + request. It may be a float (in seconds) or an instance of + :class:`urllib3.util.Timeout`. + + :param pool_timeout: + If set and the pool is set to block=True, then this method will + block for ``pool_timeout`` seconds and raise EmptyPoolError if no + connection is available within the time period. + + :param release_conn: + If False, then the urlopen call will not release the connection + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of + ``response_kw.get('preload_content', True)``. + + :param chunked: + If True, urllib3 will send the body using chunked transfer + encoding. Otherwise, urllib3 will send the body using the standard + content-length form. Defaults to False. + + :param int body_pos: + Position to seek to in file-like body in the event of a retry or + redirect. Typically this won't need to be set because urllib3 will + auto-populate the value when needed. + + :param \\**response_kw: + Additional parameters are passed to + :meth:`urllib3.response.HTTPResponse.from_httplib` + """ + + parsed_url = parse_url(url) + destination_scheme = parsed_url.scheme + + if headers is None: + headers = self.headers + + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if release_conn is None: + release_conn = response_kw.get("preload_content", True) + + # Check host + if assert_same_host and not self.is_same_host(url): + raise HostChangedError(self, url, retries) + + # Ensure that the URL we're connecting to is properly encoded + if url.startswith("/"): + url = six.ensure_str(_encode_target(url)) + else: + url = six.ensure_str(parsed_url.url) + + conn = None + + # Track whether `conn` needs to be released before + # returning/raising/recursing. Update this variable if necessary, and + # leave `release_conn` constant throughout the function. That way, if + # the function recurses, the original value of `release_conn` will be + # passed down into the recursive call, and its value will be respected. + # + # See issue #651 [1] for details. + # + # [1] + release_this_conn = release_conn + + http_tunnel_required = connection_requires_http_tunnel( + self.proxy, self.proxy_config, destination_scheme + ) + + # Merge the proxy headers. Only done when not using HTTP CONNECT. We + # have to copy the headers dict so we can safely change it without those + # changes being reflected in anyone else's copy. + if not http_tunnel_required: + headers = headers.copy() + headers.update(self.proxy_headers) + + # Must keep the exception bound to a separate variable or else Python 3 + # complains about UnboundLocalError. + err = None + + # Keep track of whether we cleanly exited the except block. This + # ensures we do proper cleanup in finally. + clean_exit = False + + # Rewind body position, if needed. Record current position + # for future rewinds in the event of a redirect/retry. + body_pos = set_file_position(body, body_pos) + + try: + # Request a connection from the queue. + timeout_obj = self._get_timeout(timeout) + conn = self._get_conn(timeout=pool_timeout) + + conn.timeout = timeout_obj.connect_timeout + + is_new_proxy_conn = self.proxy is not None and not getattr( + conn, "sock", None + ) + if is_new_proxy_conn and http_tunnel_required: + self._prepare_proxy(conn) + + # Make the request on the httplib connection object. + httplib_response = self._make_request( + conn, + method, + url, + timeout=timeout_obj, + body=body, + headers=headers, + chunked=chunked, + ) + + # If we're going to release the connection in ``finally:``, then + # the response doesn't need to know about the connection. Otherwise + # it will also try to release it and we'll have a double-release + # mess. + response_conn = conn if not release_conn else None + + # Pass method to Response for length checking + response_kw["request_method"] = method + + # Import httplib's response into our own wrapper object + response = self.ResponseCls.from_httplib( + httplib_response, + pool=self, + connection=response_conn, + retries=retries, + **response_kw + ) + + # Everything went great! + clean_exit = True + + except EmptyPoolError: + # Didn't get a connection from the pool, no need to clean up + clean_exit = True + release_this_conn = False + raise + + except ( + TimeoutError, + HTTPException, + SocketError, + ProtocolError, + BaseSSLError, + SSLError, + CertificateError, + ) as e: + # Discard the connection for these exceptions. It will be + # replaced during the next _get_conn() call. + clean_exit = False + + def _is_ssl_error_message_from_http_proxy(ssl_error): + # We're trying to detect the message 'WRONG_VERSION_NUMBER' but + # SSLErrors are kinda all over the place when it comes to the message, + # so we try to cover our bases here! + message = " ".join(re.split("[^a-z]", str(ssl_error).lower())) + return ( + "wrong version number" in message + or "unknown protocol" in message + or "record layer failure" in message + ) + + # Try to detect a common user error with proxies which is to + # set an HTTP proxy to be HTTPS when it should be 'http://' + # (ie {'http': 'http://proxy', 'https': 'https://proxy'}) + # Instead we add a nice error message and point to a URL. + if ( + isinstance(e, BaseSSLError) + and self.proxy + and _is_ssl_error_message_from_http_proxy(e) + and conn.proxy + and conn.proxy.scheme == "https" + ): + e = ProxyError( + "Your proxy appears to only use HTTP and not HTTPS, " + "try changing your proxy URL to be HTTP. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#https-proxy-error-http-proxy", + SSLError(e), + ) + elif isinstance(e, (BaseSSLError, CertificateError)): + e = SSLError(e) + elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy: + e = ProxyError("Cannot connect to proxy.", e) + elif isinstance(e, (SocketError, HTTPException)): + e = ProtocolError("Connection aborted.", e) + + retries = retries.increment( + method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2] + ) + retries.sleep() + + # Keep track of the error for the retry warning. + err = e + + finally: + if not clean_exit: + # We hit some kind of exception, handled or otherwise. We need + # to throw the connection away unless explicitly told not to. + # Close the connection, set the variable to None, and make sure + # we put the None back in the pool to avoid leaking it. + conn = conn and conn.close() + release_this_conn = True + + if release_this_conn: + # Put the connection back to be reused. If the connection is + # expired then it will be None, which will get replaced with a + # fresh connection during _get_conn. + self._put_conn(conn) + + if not conn: + # Try again + log.warning( + "Retrying (%r) after connection broken by '%r': %s", retries, err, url + ) + return self.urlopen( + method, + url, + body, + headers, + retries, + redirect, + assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Handle redirect? + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: + # Change the method according to RFC 9110, Section 15.4.4. + method = "GET" + # And lose the body not to transfer anything sensitive. + body = None + headers = HTTPHeaderDict(headers)._prepare_for_method_change() + + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep_for_retry(response) + log.debug("Redirecting %s -> %s", url, redirect_location) + return self.urlopen( + method, + redirect_location, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(response.headers.get("Retry-After")) + if retries.is_retry(method, response.status, has_retry_after): + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_status: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep(response) + log.debug("Retry: %s", url) + return self.urlopen( + method, + url, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + :class:`.HTTPSConnection` uses one of ``assert_fingerprint``, + ``assert_hostname`` and ``host`` in this order to verify connections. + If ``assert_hostname`` is False, no verification is done. + + The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, + ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl` + is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade + the connection socket into an SSL socket. + """ + + scheme = "https" + ConnectionCls = HTTPSConnection + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + ssl_version=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + **conn_kw + ): + + HTTPConnectionPool.__init__( + self, + host, + port, + strict, + timeout, + maxsize, + block, + headers, + retries, + _proxy, + _proxy_headers, + **conn_kw + ) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.ca_certs = ca_certs + self.ca_cert_dir = ca_cert_dir + self.ssl_version = ssl_version + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + + def _prepare_conn(self, conn): + """ + Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` + and establish the tunnel if proxy is used. + """ + + if isinstance(conn, VerifiedHTTPSConnection): + conn.set_cert( + key_file=self.key_file, + key_password=self.key_password, + cert_file=self.cert_file, + cert_reqs=self.cert_reqs, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + assert_hostname=self.assert_hostname, + assert_fingerprint=self.assert_fingerprint, + ) + conn.ssl_version = self.ssl_version + return conn + + def _prepare_proxy(self, conn): + """ + Establishes a tunnel connection through HTTP CONNECT. + + Tunnel connection is established early because otherwise httplib would + improperly set Host: header to proxy's IP:port. + """ + + conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers) + + if self.proxy.scheme == "https": + conn.tls_in_tls_required = True + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`http.client.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTPS connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "443", + ) + + if not self.ConnectionCls or self.ConnectionCls is DummyConnection: + raise SSLError( + "Can't connect to HTTPS URL because the SSL module is not available." + ) + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + conn = self.ConnectionCls( + host=actual_host, + port=actual_port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + cert_file=self.cert_file, + key_file=self.key_file, + key_password=self.key_password, + **self.conn_kw + ) + + return self._prepare_conn(conn) + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + super(HTTPSConnectionPool, self)._validate_conn(conn) + + # Force connect early to allow us to validate the connection. + if not getattr(conn, "sock", None): # AppEngine might not have `.sock` + conn.connect() + + if not conn.is_verified: + warnings.warn( + ( + "Unverified HTTPS request is being made to host '%s'. " + "Adding certificate verification is strongly advised. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings" % conn.host + ), + InsecureRequestWarning, + ) + + if getattr(conn, "proxy_is_verified", None) is False: + warnings.warn( + ( + "Unverified HTTPS connection done to an HTTPS proxy. " + "Adding certificate verification is strongly advised. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings" + ), + InsecureRequestWarning, + ) + + +def connection_from_url(url, **kw): + """ + Given a url, return an :class:`.ConnectionPool` instance of its host. + + This is a shortcut for not having to parse out the scheme, host, and port + of the url before creating an :class:`.ConnectionPool` instance. + + :param url: + Absolute URL string that must include the scheme. Port is optional. + + :param \\**kw: + Passes additional parameters to the constructor of the appropriate + :class:`.ConnectionPool`. Useful for specifying things like + timeout, maxsize, headers, etc. + + Example:: + + >>> conn = connection_from_url('http://google.com/') + >>> r = conn.request('GET', '/') + """ + scheme, host, port = get_host(url) + port = port or port_by_scheme.get(scheme, 80) + if scheme == "https": + return HTTPSConnectionPool(host, port=port, **kw) + else: + return HTTPConnectionPool(host, port=port, **kw) + + +def _normalize_host(host, scheme): + """ + Normalize hosts for comparisons and use with sockets. + """ + + host = normalize_host(host, scheme) + + # httplib doesn't like it when we include brackets in IPv6 addresses + # Specifically, if we include brackets but also pass the port then + # httplib crazily doubles up the square brackets on the Host header. + # Instead, we need to make sure we never pass ``None`` as the port. + # However, for backward compatibility reasons we can't actually + # *assert* that. See http://bugs.python.org/issue28539 + if host.startswith("[") and host.endswith("]"): + host = host[1:-1] + return host + + +def _close_pool_connections(pool): + """Drains a queue of connections and closes each one.""" + try: + while True: + conn = pool.get(block=False) + if conn: + conn.close() + except queue.Empty: + pass # Done. diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..223ae75a523111e48d66b29f8bc825c9b4776495 GIT binary patch literal 204 zcmX@j%ge<81j_4zGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!%67JjDJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`nFadsK)ICsBK^{$oSe)gWBug(ypp2KB>i}xF_|Ut@p=W7w>WHa^HWN5QtgUZ Vfp#+jaWRPTk(rT^v4|PS0svbFImiG2 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70db7235f0c7f916b1110e0359e98cb63bd5f2b2 GIT binary patch literal 1854 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 Gp8pGGOLxft literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fdec3609cfa503e0b37ddbb0bfd23af3ade2528 GIT binary patch literal 5720 zcmd5Ae{2)i`JH{X&u7PWoL>Zz@F=0+5FDTqMS;?#Nr05#wh*B8(w#28!@1<_bMMZC zxQ>=hNHr22@W(`|YHBu3T2QKy{#B+)>;9QkZGX%rnPT0jRH^G9{1*n*s{Xa_o$u^4 zq+^>jX)nsV_rCYu_v?M%_rA}6s;grWw4J{`BQ4b<^aYvN&1DT9&B5Rn5>Olol;Du5 zlq2q-$k-`6<4*X}GM#e8T_(&WyHoDC8^&(IBYRRzoH56Y>`k$8mO>6BIwzWKBDJsJ z75$5j%G})L66+SJ$~+!$pc6=7uOPuEGK)?N8k}}U{J9^pv611^n9u6tVp^9Hye_4a zIHM?XH%=&NU6sbNx+vhWX)LPJWI_}~Rnt{I&9Xz9mKE{N1N*zNCW^gyT-P(bJv|9U z5Ti*&Ny=h0p`>~;Jy}(jrLpIFByvFO5k#GrcB4O^W)kl1z#!Oz5;OrydXyVbXANWaQPe{YpA5CUi+jzY6>kBpbl|PEf(fxQKUK zEC55MNKt}}2)P@l6d@~%SkkZ{W>gUr0Mhbl0Z&P?jK@T*iYet1z@#*`u;5Dvqx%6a zi@YXwSD}C+t>~B^19ZBAwQPn6f+ZbiR3#&-@-!AeVX&maK_#tWS<(nKz-+3fqCyRH zn3VMK?3k%OTY2`^QsTjbhYv>a&_z70WHGObn8#U7RIzdq>*K(QC054d5pFV-g6k!e z;GQuVgVqRXawXA3#Uv`dWgqC#OE7;2Y*$2a3hdV*P++f)I9)&&!FsPSahE_}L24EhyiK|dYv%D3xn|g=y%Zll)8m<%O?=hEpI_6kKP48&eIagyM9Ui zgrZR1nMa(h2b8B^R>hj9CVcBCSVQ95w*Sqz^KQY}3M&(JPwrf_K!DR@ufl!@*$*(L z3Uk2BYtN?Xh%5I8Q%<5c;;x_zVzoR5XB3naK6hpqgQCd&f+2w3V93LjYsCC?@DsRh z@M5CmXcduZGq8o6x*!3bDb2K_ZgOZ0OnKV2nSobM_YK8H$$>PV67fYvP4RjSQ)Y^g zB6u>qrcEiTK(?3wa;CP?phh2%TTsab#3HQW0#6ZDmBdnm;W#NR=^STxEEx@t%1;pt zurDJ^y5R!9f|(m+=B2bjn`@5DRD>~TO_VRHBs{7uq=TT044PMyn&F^-Kh+|p5?uldU@+ssc>>#g|B_&hz&FE{Ne zu;pevUw<>T+8il0N0yuS!X96_v19J7o2OyuEr%Nm^t+x%KmjGH?g0~Gp2P_r9e0x_ zEDsJn0n?35pmJd52?tkQsJYgJ{R~#u5E8(!H^T!^ptG?7wCWPIwMEMv;c;{dv_#EN zf@{VhxM!St)j7WtpTCC39)0MkIxj6SItdwOn;^Hdp#k3T1`tdaEzRXX1_&6AqX2t~ z9=v(VrV1g4o@ja!tH5q9zW_99I)Jmp+&45k(9F1W5?joccTH@y$F;A``;7Z39Q)vW zTkV`Z0%(Ulu6^x9gL;}C{CRgx4^QEs4ruMD(XdBCz?Pwg33TM*NCYrj-kq<6-KkT+zmEHETel9IGTuV3f;d6 z)VFB)=Zs%q^8Wuz+pRv+o5qs=kwyNy9#gZn|ITi09|bE5Y(+I}oBNs2IQcxhYA=4r zY7?#JF5%jW07a<{|;_@|?#cxl7A6oDtuGf<(vTB2UViUJOK>Ck97y&1Xa{ z0~tD`QaZ0^%@tV8HCEy4j^tXZP=VKZf(3s+8jZgBKp>(zy72?zW;vHhH|IN-7B6Qi z`B*LtwSYybg0UAr_!KrvH{m@2EmaaZRh+2oS1Szn;we=D-H}|zOvWJ5va_yS%LQ`{ zmPih0qwmEAg>%g{4Pp=+@;gZz7llZx5lm-OTOc=l}Hi9waTlaRkvm^OS+&e`l3v>+vP!(*w@ za98wfxGSZRLBm%t92YZc1Hs`Pyqpj-8I~&RybV zup^`X37A1?MzC^;{o}kWi|M3j1Y%-R(IwE^ahZqIlrfK`w4_GL1v3Y=JGGtg<>k`i zlzBP1Hlpd;C6c-~T3sa}Ui$?E%vrSNM&7zrrtKcnHcyq99e-ik?lZpY-mBiSzpv~M zt@?4vk700q=;{#p3|}37>~(qBwE$|w^KHd&wBRW>b&~9HPr>)MV8{HxuZDg;v^4PX z&__cn!D9s)NNnHpVdrYsaH(t9Lh;Dy*vmddj_qv0bAv50+a3cSenPew-o4PW!W<|w z{_Fm${u}4!20j>mZ+M||$+N;7E(gM^fsRt3V>y5e&inOEHxjodZ%!`PKT~j9d>6xA z3;lOqzWwrD=O^rM*cGO~y0B;AS-@PK?p-*0=k?pKFC`Y=Tw#u^F(}+za9(o*za5?P zr%LVnSKAMj+7B)1%k4*t%+_)nE;6lut>0PbD+fb2!Z&slvU8s0;P!Iou6cfbY<{p5 z+Og(B;ZDHdZ!h{fKMQX&o`320$3H!CZ{R{P^g2l05LiQwy1-)=?d@6ZI#udARra@= z+9)x*3&FV#P(SN`P$0C@b%o)+}zoFL43b?dl8>oZa!ZOod=EFO?)!(+lfzi{<-UqUB$L@%i;4y z|M}1Bn~3VG=(|>!z2#s-!KadECPAW!-AJixRvRZ_KuYyIJ?oIr3@uQ3TBzjH_TF_F zB^2+F@so@jigr5hg51lqXcgA*-Z*0_Nf%WNUBs!9#J*B!dZ2uUA7#=JuNeRgcS?je zL@=BHH|Q}%n6AVGh+gm;7&tehih=~c59vk-N=8xDIStBSj=U=>$%!>0fbF-lrsJx| z0hHUiiOX8VHFEA4bYFwVHX?sR;l*J(2fp!SGudkqo z4u^{YrwcUA9)C>xT}^*)>!VzaYcU53gv+7Ea;Uys-&AgG|3`h$1+fA;lYbLYB&5Cu zXb966vwBtq0aPNB!9ew%hIBzQJn$|hVWiRkue?G?B^PdV*tK_5lP*Wek9Jy={3HZL zz63S9`F0sJL1csntl#?JMY&MHti}kwy`&>@-9{Cz%mB6{A2Uu9n9>H|2O3LY~kK XX4&03>wN4^QWRTk?fwdpfl2e9>-I-A literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db2f69ff0b5b2ccd8f1d48cbd76f3c16c8d89bc4 GIT binary patch literal 24454 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70807189aa9ccde383f48e7759ee8f524dc6ea21 GIT binary patch literal 7517 zcmb_hZ)_XKm7nD<$>mZcC6d-(TiRNdEyfn*I#L?zWXFpC)JAGqXFF}oI-n@-%368J zWoB2FB~VuAv%91u%f1x2bu`?WH}n3_o8N5yEfSFkJl(%ItNlX~o>1ep**n;15=OVFiP~r<8*PTs7PX}|+BL^_6IIwnXcuUN z*7`Gku*wfw2QxvA_=xJCZuA^h|5XBN@B^RI=g4bhmR#j8kXg><<_B(kru_nWQ}ZaP z*4*oULZtIknkg3yWky%!yiv4rTG5nC)VQLVno-Q@vN=;K8Pt*|4Jw~IbM%FCNWH45 zraVcFf;_8PQ(94)p}MY3Je`);^K+M)&bonp?(c})n=8udRZA_R4B41;38{T@uBb>% z${?^ZWVM)^0L3&5q|Frb7E?*H=Jv@d$W^Hf+FChXm&fML8Trem3`%-KpqDARmZ6q1 zERe^?O`JDAj`C?PErA16*DkG4($#_rK0rC1;U-%*IRipyu6RjBbzN)aNi}E9P}NM! zrz|~8HG(6x^B#B#Y?ULZ~BlV_0@ebK8_BZ%L3Cwdzf|uxuO34bUHmgo~lih zd$*YP$h1Kg51Fb3!&2pAqvy6-HaPXTb-Iy4XVy(Ko!Hd8 zGcZ!$18K)$gZ2DD4*O(ipJAI~y*v{HerGG4TrHSOn1$ox;8+$X@DA=`ce|ku8(b&N zYLMR(DtMv@ne61evszQo^=P`YRcrc#|6Z9Q+h+!$+)y06c1?=b?U& z35)LxEG}AFK4+=m8@G5cW&ccbSvoUwF;xx^4SQlX+5Q<8?-XapauY0L)hv`Fh}h_7 zSk{5ibWAPbektbXzLTRxNW}S%oL%NsXh=t|Fkxsk$bIGmw;(!I4g6x1FqW{<6^|oS z^C8(Rsd;S@OxAU%uWmt2%kl}>i3I~Tl~#n^U0`hXK}M+Zlx3Ans0v>3r?7dzZ;FvO z)0)w*7W==RKJZNXYCj$a^}jOICZK|9!wJD#>twS9}VW;TOpypqA@mMo{?cB;#KsSGi2! z97zdwj0LPNb^e=di;T!69g0bx1!t0sCe*48Y&llS@{TJ^`HGf<;^V}frDK|L$OB@k zJ#eg(82qii1kK-aH%Zwyy`Jt)RJae^(K5-_=oYSKkLBSpQYL>LC#1}2!09L4-*6n6 zBPrjg9nG>>W}SpGQ+}H-86}#4<+dNP5(3+V?_xHq6*ViH1s4dWs!!TNj$ShDz~x!? z8_H($I&9%=)hgWWkhgV@T*$|L03?O)1 z9f0;G(Z~WU1rrbq2sytoOV( z7-dl1>pQ=bzDd-*VdE(F6uu4G$Iyf)(ELxJ1)e|)K7l5>wCEOkhTaX9IZWdPU)gt# zbQ7xvr~!EQa>T*}W>1+Y($?O2hf~5p*@8b%8vf4jf$`Tk%e@{DGM)7J)_*}FUEs_7 zG-lzZho0Sfd_l0#Joc1@y7rz-y66Ad0=THT(ufi%3-gdeo-D9$BbDDsRiX?0U-7e? zwcXiKt?DZ zIYoh^(ZoJf56dfGcEqV>fCTYcVoPj&7O{!)-@SX=J)YfM~$$chGG!F;rSQXnXq-y!1(3HWrzO3S_OnZU+i?z%Nd;@F!Kd8oYi%vm>oICJm;RL z6sv(Pjo~fEIa?*yvv2^|5?mzll2**CG=dYu&SK}p_0tv{6WMJndwJFtP`J&h6bqG! zhY`k3rkG`RC<_5+>dm)3Qm{SJd0hAlIMA+<6_F&H7sYBgb|>8Vak#UZ>bsK~uB3(+ zPcCoksWj}q_gKn`us0OFn`ph0c&d_ks@k;eX4?UDMB={iv9I`H98rR#8YW3RUEN~PnOYU}n}4R1HxZvy@+ zagyk`pMbZ;V=FIlq%pY|ez-OQFFPI(KWG>4`F&&ZUZUmZ!5j8;};wu5t*z{KUjdHcM4aMB>-%adTQh)ODCyA%;w)g$M zbvxK}>)<;F-&207{}{Qo4FI=}X5hB18Mt-yfr87OCx16s=^R_-eMs>EMI*)Y$QW@Tl&tYGZP_`N*%nUTHoCQ&34?B>LqF57aNr-4M5b ze7@nRNPaDj_)fI&zmZ1zj(>yymv1yc=eK<9M4bO^+z;=t(Ew5)p3Y`%DVudJ`S9M5 z&Au{|(_Kn1n*}JE&9W1oK8pzyagjz|)%9%lXB=(EWI^zAgk>1RE3A0|34nUY!|UX} z&*vA{M4$h;{}!M1Cn?r4HYpD;wa0@{tGFHNkZ_Iz1e#>ox(S_*rg(Y~=F%Z-{sNkx z5r;P>J3ZnxKY|yw6Rwl0AUZRUxV3aV%<9rrJ|i#KNE`;=$7n$^|UhwDSwuB4*c5WpU0?o1enuf*lbej1dd_z4*b=W z>h+XD$_Ax)7{F)s8E7`6cvVpSitk-tCJ+Juh5r4V!|z`5C=cAHa(yh z-Zt3-_riuzn;W7CdhGy%6@w@2pz|_y-W?inM+S29sTZA3ynt^M)lw;3_Pno$-u7W1 z?0U>pfXcv?ehnK0RJ0qLUD)(sgRni-NKqNMV8Rz1z%?aZvus{hiy)bOKBW7Q+%$If z%u5%t=P!&M&$3-L_~_7pEqyzu&!`Th36;E$v^0&v`mx!D%}H#~>vnSq3aWFJRn6?g zT-FhpiZGBv@j71D*$x$F3RzrX+QBLKassf^j@L^7BOxLRux}6wJ&Vg_Y|vT{t-5z_ z=O9CTg=oopt~rMqDmUN$NS&(PaeoeU^8lpU!)s(MPU0O)2X8m^EC%j{6U*U__rzs+ z|A*iH`|tkpyUT;$swUfSzVO2r?j(CE$)5M}x06pT9={ul-x&PC{L){(@x5x#Qx~6<~T@S=z2MHdgmthP`r}?kY0F33h`@(Kc_f1I*hwvS9l%a%O+3h*;g-Um6a0O+qVhycJRlJinfOm3eNSk*cJlkDUp>7d z_#$UHxT1vG*CIiG03zy_Ryttfmn#Eo4adc*QuMW>Xh7@>6AgVs7#Sx2Bs||u{&{%U S^D_TYckuZ>{-b>ywEqhq^?$(t literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py new file mode 100644 index 0000000..8765b90 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py @@ -0,0 +1,36 @@ +""" +This module provides means to detect the App Engine environment. +""" + +import os + + +def is_appengine(): + return is_local_appengine() or is_prod_appengine() + + +def is_appengine_sandbox(): + """Reports if the app is running in the first generation sandbox. + + The second generation runtimes are technically still in a sandbox, but it + is much less restrictive, so generally you shouldn't need to check for it. + see https://cloud.google.com/appengine/docs/standard/runtimes + """ + return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27" + + +def is_local_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Development/") + + +def is_prod_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Google App Engine/") + + +def is_prod_appengine_mvms(): + """Deprecated.""" + return False diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7ff4344e7a6d67c422c822cb7825da7aca16e3e GIT binary patch literal 221 zcmZ8by@~=s4Bk0CI0T=<%EFt%?hqSWv9KN(c4xy9Zf7!NW|als!)LJZMSKHWpFr%c zx@_wQNxq*Da+^*kg&r=j@uTirFIlDW2J2Z*D+)+ kLyE*%Te*wb+V9xkzgC{=u7x#!$}>tT4dgjeO7Te8KLo)*+W-In literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b347d5496bb85ae9797c06ec9dca87a817f2826b GIT binary patch literal 17433 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 J&|`?*zXI5v6bS$T literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py new file mode 100644 index 0000000..264d564 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py @@ -0,0 +1,519 @@ +""" +This module uses ctypes to bind a whole bunch of functions and constants from +SecureTransport. The goal here is to provide the low-level API to +SecureTransport. These are essentially the C-level functions and constants, and +they're pretty gross to work with. + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + + Copyright (c) 2015-2016 Will Bond + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +""" +from __future__ import absolute_import + +import platform +from ctypes import ( + CDLL, + CFUNCTYPE, + POINTER, + c_bool, + c_byte, + c_char_p, + c_int32, + c_long, + c_size_t, + c_uint32, + c_ulong, + c_void_p, +) +from ctypes.util import find_library + +from ...packages.six import raise_from + +if platform.system() != "Darwin": + raise ImportError("Only macOS is supported") + +version = platform.mac_ver()[0] +version_info = tuple(map(int, version.split("."))) +if version_info < (10, 8): + raise OSError( + "Only OS X 10.8 and newer are supported, not %s.%s" + % (version_info[0], version_info[1]) + ) + + +def load_cdll(name, macos10_16_path): + """Loads a CDLL by name, falling back to known path on 10.16+""" + try: + # Big Sur is technically 11 but we use 10.16 due to the Big Sur + # beta being labeled as 10.16. + if version_info >= (10, 16): + path = macos10_16_path + else: + path = find_library(name) + if not path: + raise OSError # Caught and reraised as 'ImportError' + return CDLL(path, use_errno=True) + except OSError: + raise_from(ImportError("The library %s failed to load" % name), None) + + +Security = load_cdll( + "Security", "/System/Library/Frameworks/Security.framework/Security" +) +CoreFoundation = load_cdll( + "CoreFoundation", + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", +) + + +Boolean = c_bool +CFIndex = c_long +CFStringEncoding = c_uint32 +CFData = c_void_p +CFString = c_void_p +CFArray = c_void_p +CFMutableArray = c_void_p +CFDictionary = c_void_p +CFError = c_void_p +CFType = c_void_p +CFTypeID = c_ulong + +CFTypeRef = POINTER(CFType) +CFAllocatorRef = c_void_p + +OSStatus = c_int32 + +CFDataRef = POINTER(CFData) +CFStringRef = POINTER(CFString) +CFArrayRef = POINTER(CFArray) +CFMutableArrayRef = POINTER(CFMutableArray) +CFDictionaryRef = POINTER(CFDictionary) +CFArrayCallBacks = c_void_p +CFDictionaryKeyCallBacks = c_void_p +CFDictionaryValueCallBacks = c_void_p + +SecCertificateRef = POINTER(c_void_p) +SecExternalFormat = c_uint32 +SecExternalItemType = c_uint32 +SecIdentityRef = POINTER(c_void_p) +SecItemImportExportFlags = c_uint32 +SecItemImportExportKeyParameters = c_void_p +SecKeychainRef = POINTER(c_void_p) +SSLProtocol = c_uint32 +SSLCipherSuite = c_uint32 +SSLContextRef = POINTER(c_void_p) +SecTrustRef = POINTER(c_void_p) +SSLConnectionRef = c_uint32 +SecTrustResultType = c_uint32 +SecTrustOptionFlags = c_uint32 +SSLProtocolSide = c_uint32 +SSLConnectionType = c_uint32 +SSLSessionOption = c_uint32 + + +try: + Security.SecItemImport.argtypes = [ + CFDataRef, + CFStringRef, + POINTER(SecExternalFormat), + POINTER(SecExternalItemType), + SecItemImportExportFlags, + POINTER(SecItemImportExportKeyParameters), + SecKeychainRef, + POINTER(CFArrayRef), + ] + Security.SecItemImport.restype = OSStatus + + Security.SecCertificateGetTypeID.argtypes = [] + Security.SecCertificateGetTypeID.restype = CFTypeID + + Security.SecIdentityGetTypeID.argtypes = [] + Security.SecIdentityGetTypeID.restype = CFTypeID + + Security.SecKeyGetTypeID.argtypes = [] + Security.SecKeyGetTypeID.restype = CFTypeID + + Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef] + Security.SecCertificateCreateWithData.restype = SecCertificateRef + + Security.SecCertificateCopyData.argtypes = [SecCertificateRef] + Security.SecCertificateCopyData.restype = CFDataRef + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SecIdentityCreateWithCertificate.argtypes = [ + CFTypeRef, + SecCertificateRef, + POINTER(SecIdentityRef), + ] + Security.SecIdentityCreateWithCertificate.restype = OSStatus + + Security.SecKeychainCreate.argtypes = [ + c_char_p, + c_uint32, + c_void_p, + Boolean, + c_void_p, + POINTER(SecKeychainRef), + ] + Security.SecKeychainCreate.restype = OSStatus + + Security.SecKeychainDelete.argtypes = [SecKeychainRef] + Security.SecKeychainDelete.restype = OSStatus + + Security.SecPKCS12Import.argtypes = [ + CFDataRef, + CFDictionaryRef, + POINTER(CFArrayRef), + ] + Security.SecPKCS12Import.restype = OSStatus + + SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t)) + SSLWriteFunc = CFUNCTYPE( + OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t) + ) + + Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc] + Security.SSLSetIOFuncs.restype = OSStatus + + Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerID.restype = OSStatus + + Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetCertificate.restype = OSStatus + + Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean] + Security.SSLSetCertificateAuthorities.restype = OSStatus + + Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef] + Security.SSLSetConnection.restype = OSStatus + + Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerDomainName.restype = OSStatus + + Security.SSLHandshake.argtypes = [SSLContextRef] + Security.SSLHandshake.restype = OSStatus + + Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLRead.restype = OSStatus + + Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLWrite.restype = OSStatus + + Security.SSLClose.argtypes = [SSLContextRef] + Security.SSLClose.restype = OSStatus + + Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberSupportedCiphers.restype = OSStatus + + Security.SSLGetSupportedCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetSupportedCiphers.restype = OSStatus + + Security.SSLSetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + c_size_t, + ] + Security.SSLSetEnabledCiphers.restype = OSStatus + + Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberEnabledCiphers.restype = OSStatus + + Security.SSLGetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetEnabledCiphers.restype = OSStatus + + Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)] + Security.SSLGetNegotiatedCipher.restype = OSStatus + + Security.SSLGetNegotiatedProtocolVersion.argtypes = [ + SSLContextRef, + POINTER(SSLProtocol), + ] + Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus + + Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)] + Security.SSLCopyPeerTrust.restype = OSStatus + + Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef] + Security.SecTrustSetAnchorCertificates.restype = OSStatus + + Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean] + Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus + + Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)] + Security.SecTrustEvaluate.restype = OSStatus + + Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef] + Security.SecTrustGetCertificateCount.restype = CFIndex + + Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex] + Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef + + Security.SSLCreateContext.argtypes = [ + CFAllocatorRef, + SSLProtocolSide, + SSLConnectionType, + ] + Security.SSLCreateContext.restype = SSLContextRef + + Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean] + Security.SSLSetSessionOption.restype = OSStatus + + Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMin.restype = OSStatus + + Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMax.restype = OSStatus + + try: + Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetALPNProtocols.restype = OSStatus + except AttributeError: + # Supported only in 10.12+ + pass + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SSLReadFunc = SSLReadFunc + Security.SSLWriteFunc = SSLWriteFunc + Security.SSLContextRef = SSLContextRef + Security.SSLProtocol = SSLProtocol + Security.SSLCipherSuite = SSLCipherSuite + Security.SecIdentityRef = SecIdentityRef + Security.SecKeychainRef = SecKeychainRef + Security.SecTrustRef = SecTrustRef + Security.SecTrustResultType = SecTrustResultType + Security.SecExternalFormat = SecExternalFormat + Security.OSStatus = OSStatus + + Security.kSecImportExportPassphrase = CFStringRef.in_dll( + Security, "kSecImportExportPassphrase" + ) + Security.kSecImportItemIdentity = CFStringRef.in_dll( + Security, "kSecImportItemIdentity" + ) + + # CoreFoundation time! + CoreFoundation.CFRetain.argtypes = [CFTypeRef] + CoreFoundation.CFRetain.restype = CFTypeRef + + CoreFoundation.CFRelease.argtypes = [CFTypeRef] + CoreFoundation.CFRelease.restype = None + + CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef] + CoreFoundation.CFGetTypeID.restype = CFTypeID + + CoreFoundation.CFStringCreateWithCString.argtypes = [ + CFAllocatorRef, + c_char_p, + CFStringEncoding, + ] + CoreFoundation.CFStringCreateWithCString.restype = CFStringRef + + CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding] + CoreFoundation.CFStringGetCStringPtr.restype = c_char_p + + CoreFoundation.CFStringGetCString.argtypes = [ + CFStringRef, + c_char_p, + CFIndex, + CFStringEncoding, + ] + CoreFoundation.CFStringGetCString.restype = c_bool + + CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex] + CoreFoundation.CFDataCreate.restype = CFDataRef + + CoreFoundation.CFDataGetLength.argtypes = [CFDataRef] + CoreFoundation.CFDataGetLength.restype = CFIndex + + CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef] + CoreFoundation.CFDataGetBytePtr.restype = c_void_p + + CoreFoundation.CFDictionaryCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + POINTER(CFTypeRef), + CFIndex, + CFDictionaryKeyCallBacks, + CFDictionaryValueCallBacks, + ] + CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef + + CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef] + CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef + + CoreFoundation.CFArrayCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreate.restype = CFArrayRef + + CoreFoundation.CFArrayCreateMutable.argtypes = [ + CFAllocatorRef, + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef + + CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p] + CoreFoundation.CFArrayAppendValue.restype = None + + CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef] + CoreFoundation.CFArrayGetCount.restype = CFIndex + + CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex] + CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p + + CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll( + CoreFoundation, "kCFAllocatorDefault" + ) + CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeArrayCallBacks" + ) + CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryKeyCallBacks" + ) + CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryValueCallBacks" + ) + + CoreFoundation.CFTypeRef = CFTypeRef + CoreFoundation.CFArrayRef = CFArrayRef + CoreFoundation.CFStringRef = CFStringRef + CoreFoundation.CFDictionaryRef = CFDictionaryRef + +except (AttributeError): + raise ImportError("Error initializing ctypes") + + +class CFConst(object): + """ + A class object that acts as essentially a namespace for CoreFoundation + constants. + """ + + kCFStringEncodingUTF8 = CFStringEncoding(0x08000100) + + +class SecurityConst(object): + """ + A class object that acts as essentially a namespace for Security constants. + """ + + kSSLSessionOptionBreakOnServerAuth = 0 + + kSSLProtocol2 = 1 + kSSLProtocol3 = 2 + kTLSProtocol1 = 4 + kTLSProtocol11 = 7 + kTLSProtocol12 = 8 + # SecureTransport does not support TLS 1.3 even if there's a constant for it + kTLSProtocol13 = 10 + kTLSProtocolMaxSupported = 999 + + kSSLClientSide = 1 + kSSLStreamType = 0 + + kSecFormatPEMSequence = 10 + + kSecTrustResultInvalid = 0 + kSecTrustResultProceed = 1 + # This gap is present on purpose: this was kSecTrustResultConfirm, which + # is deprecated. + kSecTrustResultDeny = 3 + kSecTrustResultUnspecified = 4 + kSecTrustResultRecoverableTrustFailure = 5 + kSecTrustResultFatalTrustFailure = 6 + kSecTrustResultOtherError = 7 + + errSSLProtocol = -9800 + errSSLWouldBlock = -9803 + errSSLClosedGraceful = -9805 + errSSLClosedNoNotify = -9816 + errSSLClosedAbort = -9806 + + errSSLXCertChainInvalid = -9807 + errSSLCrypto = -9809 + errSSLInternal = -9810 + errSSLCertExpired = -9814 + errSSLCertNotYetValid = -9815 + errSSLUnknownRootCert = -9812 + errSSLNoRootCert = -9813 + errSSLHostNameMismatch = -9843 + errSSLPeerHandshakeFail = -9824 + errSSLPeerUserCancelled = -9839 + errSSLWeakPeerEphemeralDHKey = -9850 + errSSLServerAuthCompleted = -9841 + errSSLRecordOverflow = -9847 + + errSecVerifyFailed = -67808 + errSecNoTrustSettings = -25263 + errSecItemNotFound = -25300 + errSecInvalidTrustSettings = -25262 + + # Cipher suites. We only pick the ones our default cipher string allows. + # Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035 + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F + TLS_AES_128_GCM_SHA256 = 0x1301 + TLS_AES_256_GCM_SHA384 = 0x1302 + TLS_AES_128_CCM_8_SHA256 = 0x1305 + TLS_AES_128_CCM_SHA256 = 0x1304 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py new file mode 100644 index 0000000..fa0b245 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py @@ -0,0 +1,397 @@ +""" +Low-level helpers for the SecureTransport bindings. + +These are Python functions that are not directly related to the high-level APIs +but are necessary to get them to work. They include a whole bunch of low-level +CoreFoundation messing about and memory management. The concerns in this module +are almost entirely about trying to avoid memory leaks and providing +appropriate and useful assistance to the higher-level code. +""" +import base64 +import ctypes +import itertools +import os +import re +import ssl +import struct +import tempfile + +from .bindings import CFConst, CoreFoundation, Security + +# This regular expression is used to grab PEM data out of a PEM bundle. +_PEM_CERTS_RE = re.compile( + b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL +) + + +def _cf_data_from_bytes(bytestring): + """ + Given a bytestring, create a CFData object from it. This CFData object must + be CFReleased by the caller. + """ + return CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring) + ) + + +def _cf_dictionary_from_tuples(tuples): + """ + Given a list of Python tuples, create an associated CFDictionary. + """ + dictionary_size = len(tuples) + + # We need to get the dictionary keys and values out in the same order. + keys = (t[0] for t in tuples) + values = (t[1] for t in tuples) + cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys) + cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values) + + return CoreFoundation.CFDictionaryCreate( + CoreFoundation.kCFAllocatorDefault, + cf_keys, + cf_values, + dictionary_size, + CoreFoundation.kCFTypeDictionaryKeyCallBacks, + CoreFoundation.kCFTypeDictionaryValueCallBacks, + ) + + +def _cfstr(py_bstr): + """ + Given a Python binary data, create a CFString. + The string must be CFReleased by the caller. + """ + c_str = ctypes.c_char_p(py_bstr) + cf_str = CoreFoundation.CFStringCreateWithCString( + CoreFoundation.kCFAllocatorDefault, + c_str, + CFConst.kCFStringEncodingUTF8, + ) + return cf_str + + +def _create_cfstring_array(lst): + """ + Given a list of Python binary data, create an associated CFMutableArray. + The array must be CFReleased by the caller. + + Raises an ssl.SSLError on failure. + """ + cf_arr = None + try: + cf_arr = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cf_arr: + raise MemoryError("Unable to allocate memory!") + for item in lst: + cf_str = _cfstr(item) + if not cf_str: + raise MemoryError("Unable to allocate memory!") + try: + CoreFoundation.CFArrayAppendValue(cf_arr, cf_str) + finally: + CoreFoundation.CFRelease(cf_str) + except BaseException as e: + if cf_arr: + CoreFoundation.CFRelease(cf_arr) + raise ssl.SSLError("Unable to allocate array: %s" % (e,)) + return cf_arr + + +def _cf_string_to_unicode(value): + """ + Creates a Unicode string from a CFString object. Used entirely for error + reporting. + + Yes, it annoys me quite a lot that this function is this complex. + """ + value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p)) + + string = CoreFoundation.CFStringGetCStringPtr( + value_as_void_p, CFConst.kCFStringEncodingUTF8 + ) + if string is None: + buffer = ctypes.create_string_buffer(1024) + result = CoreFoundation.CFStringGetCString( + value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8 + ) + if not result: + raise OSError("Error copying C string from CFStringRef") + string = buffer.value + if string is not None: + string = string.decode("utf-8") + return string + + +def _assert_no_error(error, exception_class=None): + """ + Checks the return code and throws an exception if there is an error to + report + """ + if error == 0: + return + + cf_error_string = Security.SecCopyErrorMessageString(error, None) + output = _cf_string_to_unicode(cf_error_string) + CoreFoundation.CFRelease(cf_error_string) + + if output is None or output == u"": + output = u"OSStatus %s" % error + + if exception_class is None: + exception_class = ssl.SSLError + + raise exception_class(output) + + +def _cert_array_from_pem(pem_bundle): + """ + Given a bundle of certs in PEM format, turns them into a CFArray of certs + that can be used to validate a cert chain. + """ + # Normalize the PEM bundle's line endings. + pem_bundle = pem_bundle.replace(b"\r\n", b"\n") + + der_certs = [ + base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle) + ] + if not der_certs: + raise ssl.SSLError("No root certificates specified") + + cert_array = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cert_array: + raise ssl.SSLError("Unable to allocate memory!") + + try: + for der_bytes in der_certs: + certdata = _cf_data_from_bytes(der_bytes) + if not certdata: + raise ssl.SSLError("Unable to allocate memory!") + cert = Security.SecCertificateCreateWithData( + CoreFoundation.kCFAllocatorDefault, certdata + ) + CoreFoundation.CFRelease(certdata) + if not cert: + raise ssl.SSLError("Unable to build cert object!") + + CoreFoundation.CFArrayAppendValue(cert_array, cert) + CoreFoundation.CFRelease(cert) + except Exception: + # We need to free the array before the exception bubbles further. + # We only want to do that if an error occurs: otherwise, the caller + # should free. + CoreFoundation.CFRelease(cert_array) + raise + + return cert_array + + +def _is_cert(item): + """ + Returns True if a given CFTypeRef is a certificate. + """ + expected = Security.SecCertificateGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _is_identity(item): + """ + Returns True if a given CFTypeRef is an identity. + """ + expected = Security.SecIdentityGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _temporary_keychain(): + """ + This function creates a temporary Mac keychain that we can use to work with + credentials. This keychain uses a one-time password and a temporary file to + store the data. We expect to have one keychain per socket. The returned + SecKeychainRef must be freed by the caller, including calling + SecKeychainDelete. + + Returns a tuple of the SecKeychainRef and the path to the temporary + directory that contains it. + """ + # Unfortunately, SecKeychainCreate requires a path to a keychain. This + # means we cannot use mkstemp to use a generic temporary file. Instead, + # we're going to create a temporary directory and a filename to use there. + # This filename will be 8 random bytes expanded into base64. We also need + # some random bytes to password-protect the keychain we're creating, so we + # ask for 40 random bytes. + random_bytes = os.urandom(40) + filename = base64.b16encode(random_bytes[:8]).decode("utf-8") + password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8 + tempdirectory = tempfile.mkdtemp() + + keychain_path = os.path.join(tempdirectory, filename).encode("utf-8") + + # We now want to create the keychain itself. + keychain = Security.SecKeychainRef() + status = Security.SecKeychainCreate( + keychain_path, len(password), password, False, None, ctypes.byref(keychain) + ) + _assert_no_error(status) + + # Having created the keychain, we want to pass it off to the caller. + return keychain, tempdirectory + + +def _load_items_from_file(keychain, path): + """ + Given a single file, loads all the trust objects from it into arrays and + the keychain. + Returns a tuple of lists: the first list is a list of identities, the + second a list of certs. + """ + certificates = [] + identities = [] + result_array = None + + with open(path, "rb") as f: + raw_filedata = f.read() + + try: + filedata = CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata) + ) + result_array = CoreFoundation.CFArrayRef() + result = Security.SecItemImport( + filedata, # cert data + None, # Filename, leaving it out for now + None, # What the type of the file is, we don't care + None, # what's in the file, we don't care + 0, # import flags + None, # key params, can include passphrase in the future + keychain, # The keychain to insert into + ctypes.byref(result_array), # Results + ) + _assert_no_error(result) + + # A CFArray is not very useful to us as an intermediary + # representation, so we are going to extract the objects we want + # and then free the array. We don't need to keep hold of keys: the + # keychain already has them! + result_count = CoreFoundation.CFArrayGetCount(result_array) + for index in range(result_count): + item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index) + item = ctypes.cast(item, CoreFoundation.CFTypeRef) + + if _is_cert(item): + CoreFoundation.CFRetain(item) + certificates.append(item) + elif _is_identity(item): + CoreFoundation.CFRetain(item) + identities.append(item) + finally: + if result_array: + CoreFoundation.CFRelease(result_array) + + CoreFoundation.CFRelease(filedata) + + return (identities, certificates) + + +def _load_client_cert_chain(keychain, *paths): + """ + Load certificates and maybe keys from a number of files. Has the end goal + of returning a CFArray containing one SecIdentityRef, and then zero or more + SecCertificateRef objects, suitable for use as a client certificate trust + chain. + """ + # Ok, the strategy. + # + # This relies on knowing that macOS will not give you a SecIdentityRef + # unless you have imported a key into a keychain. This is a somewhat + # artificial limitation of macOS (for example, it doesn't necessarily + # affect iOS), but there is nothing inside Security.framework that lets you + # get a SecIdentityRef without having a key in a keychain. + # + # So the policy here is we take all the files and iterate them in order. + # Each one will use SecItemImport to have one or more objects loaded from + # it. We will also point at a keychain that macOS can use to work with the + # private key. + # + # Once we have all the objects, we'll check what we actually have. If we + # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise, + # we'll take the first certificate (which we assume to be our leaf) and + # ask the keychain to give us a SecIdentityRef with that cert's associated + # key. + # + # We'll then return a CFArray containing the trust chain: one + # SecIdentityRef and then zero-or-more SecCertificateRef objects. The + # responsibility for freeing this CFArray will be with the caller. This + # CFArray must remain alive for the entire connection, so in practice it + # will be stored with a single SSLSocket, along with the reference to the + # keychain. + certificates = [] + identities = [] + + # Filter out bad paths. + paths = (path for path in paths if path) + + try: + for file_path in paths: + new_identities, new_certs = _load_items_from_file(keychain, file_path) + identities.extend(new_identities) + certificates.extend(new_certs) + + # Ok, we have everything. The question is: do we have an identity? If + # not, we want to grab one from the first cert we have. + if not identities: + new_identity = Security.SecIdentityRef() + status = Security.SecIdentityCreateWithCertificate( + keychain, certificates[0], ctypes.byref(new_identity) + ) + _assert_no_error(status) + identities.append(new_identity) + + # We now want to release the original certificate, as we no longer + # need it. + CoreFoundation.CFRelease(certificates.pop(0)) + + # We now need to build a new CFArray that holds the trust chain. + trust_chain = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + for item in itertools.chain(identities, certificates): + # ArrayAppendValue does a CFRetain on the item. That's fine, + # because the finally block will release our other refs to them. + CoreFoundation.CFArrayAppendValue(trust_chain, item) + + return trust_chain + finally: + for obj in itertools.chain(identities, certificates): + CoreFoundation.CFRelease(obj) + + +TLS_PROTOCOL_VERSIONS = { + "SSLv2": (0, 2), + "SSLv3": (3, 0), + "TLSv1": (3, 1), + "TLSv1.1": (3, 2), + "TLSv1.2": (3, 3), +} + + +def _build_tls_unknown_ca_alert(version): + """ + Builds a TLS alert record for an unknown CA. + """ + ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version] + severity_fatal = 0x02 + description_unknown_ca = 0x30 + msg = struct.pack(">BB", severity_fatal, description_unknown_ca) + msg_len = len(msg) + record_type_alert = 0x15 + record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg + return record diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py new file mode 100644 index 0000000..1717ee2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py @@ -0,0 +1,314 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service `_. + +Example usage:: + + from pip._vendor.urllib3 import PoolManager + from pip._vendor.urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox + + if is_appengine_sandbox(): + # AppEngineManager uses AppEngine's URLFetch API behind the scenes + http = AppEngineManager() + else: + # PoolManager uses a socket-level API behind the scenes + http = PoolManager() + + r = http.request('GET', 'https://google.com/') + +There are `limitations `_ to the URLFetch service and it may not be +the best choice for your application. There are three options for using +urllib3 on Google App Engine: + +1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is + cost-effective in many circumstances as long as your usage is within the + limitations. +2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. + Sockets also have `limitations and restrictions + `_ and have a lower free quota than URLFetch. + To use sockets, be sure to specify the following in your ``app.yaml``:: + + env_variables: + GAE_USE_SOCKETS_HTTPLIB : 'true' + +3. If you are using `App Engine Flexible +`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import + +import io +import logging +import warnings + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + SSLError, + TimeoutError, +) +from ..packages.six.moves.urllib.parse import urljoin +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.retry import Retry +from ..util.timeout import Timeout +from . import _appengine_environ + +try: + from google.appengine.api import urlfetch +except ImportError: + urlfetch = None + + +log = logging.getLogger(__name__) + + +class AppEnginePlatformWarning(HTTPWarning): + pass + + +class AppEnginePlatformError(HTTPError): + pass + + +class AppEngineManager(RequestMethods): + """ + Connection manager for Google App Engine sandbox applications. + + This manager uses the URLFetch service directly instead of using the + emulated httplib, and is subject to URLFetch limitations as described in + the App Engine documentation `here + `_. + + Notably it will raise an :class:`AppEnginePlatformError` if: + * URLFetch is not available. + * If you attempt to use this on App Engine Flexible, as full socket + support is available. + * If a request size is more than 10 megabytes. + * If a response size is more than 32 megabytes. + * If you use an unsupported request method such as OPTIONS. + + Beyond those cases, it will raise normal urllib3 errors. + """ + + def __init__( + self, + headers=None, + retries=None, + validate_certificate=True, + urlfetch_retries=True, + ): + if not urlfetch: + raise AppEnginePlatformError( + "URLFetch is not available in this environment." + ) + + warnings.warn( + "urllib3 is using URLFetch on Google App Engine sandbox instead " + "of sockets. To use sockets directly instead of URLFetch see " + "https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.", + AppEnginePlatformWarning, + ) + + RequestMethods.__init__(self, headers) + self.validate_certificate = validate_certificate + self.urlfetch_retries = urlfetch_retries + + self.retries = retries or Retry.DEFAULT + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Return False to re-raise any potential exceptions + return False + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + timeout=Timeout.DEFAULT_TIMEOUT, + **response_kw + ): + + retries = self._get_retries(retries, redirect) + + try: + follow_redirects = redirect and retries.redirect != 0 and retries.total + response = urlfetch.fetch( + url, + payload=body, + method=method, + headers=headers or {}, + allow_truncated=False, + follow_redirects=self.urlfetch_retries and follow_redirects, + deadline=self._get_absolute_timeout(timeout), + validate_certificate=self.validate_certificate, + ) + except urlfetch.DeadlineExceededError as e: + raise TimeoutError(self, e) + + except urlfetch.InvalidURLError as e: + if "too large" in str(e): + raise AppEnginePlatformError( + "URLFetch request too large, URLFetch only " + "supports requests up to 10mb in size.", + e, + ) + raise ProtocolError(e) + + except urlfetch.DownloadError as e: + if "Too many redirects" in str(e): + raise MaxRetryError(self, url, reason=e) + raise ProtocolError(e) + + except urlfetch.ResponseTooLargeError as e: + raise AppEnginePlatformError( + "URLFetch response too large, URLFetch only supports" + "responses up to 32mb in size.", + e, + ) + + except urlfetch.SSLCertificateError as e: + raise SSLError(e) + + except urlfetch.InvalidMethodError as e: + raise AppEnginePlatformError( + "URLFetch does not support method: %s" % method, e + ) + + http_response = self._urlfetch_response_to_http_response( + response, retries=retries, **response_kw + ) + + # Handle redirect? + redirect_location = redirect and http_response.get_redirect_location() + if redirect_location: + # Check for redirect response + if self.urlfetch_retries and retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + else: + if http_response.status == 303: + method = "GET" + + try: + retries = retries.increment( + method, url, response=http_response, _pool=self + ) + except MaxRetryError: + if retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + return http_response + + retries.sleep_for_retry(http_response) + log.debug("Redirecting %s -> %s", url, redirect_location) + redirect_url = urljoin(url, redirect_location) + return self.urlopen( + method, + redirect_url, + body, + headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(http_response.headers.get("Retry-After")) + if retries.is_retry(method, http_response.status, has_retry_after): + retries = retries.increment(method, url, response=http_response, _pool=self) + log.debug("Retry: %s", url) + retries.sleep(http_response) + return self.urlopen( + method, + url, + body=body, + headers=headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + return http_response + + def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): + + if is_prod_appengine(): + # Production GAE handles deflate encoding automatically, but does + # not remove the encoding header. + content_encoding = urlfetch_resp.headers.get("content-encoding") + + if content_encoding == "deflate": + del urlfetch_resp.headers["content-encoding"] + + transfer_encoding = urlfetch_resp.headers.get("transfer-encoding") + # We have a full response's content, + # so let's make sure we don't report ourselves as chunked data. + if transfer_encoding == "chunked": + encodings = transfer_encoding.split(",") + encodings.remove("chunked") + urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings) + + original_response = HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=io.BytesIO(urlfetch_resp.content), + msg=urlfetch_resp.header_msg, + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **response_kw + ) + + return HTTPResponse( + body=io.BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + original_response=original_response, + **response_kw + ) + + def _get_absolute_timeout(self, timeout): + if timeout is Timeout.DEFAULT_TIMEOUT: + return None # Defer to URLFetch's default. + if isinstance(timeout, Timeout): + if timeout._read is not None or timeout._connect is not None: + warnings.warn( + "URLFetch does not support granular timeout settings, " + "reverting to total or default URLFetch timeout.", + AppEnginePlatformWarning, + ) + return timeout.total + return timeout + + def _get_retries(self, retries, redirect): + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if retries.connect or retries.read or retries.redirect: + warnings.warn( + "URLFetch only supports total retries and does not " + "recognize connect, read, or redirect retry parameters.", + AppEnginePlatformWarning, + ) + + return retries + + +# Alias methods from _appengine_environ to maintain public API interface. + +is_appengine = _appengine_environ.is_appengine +is_appengine_sandbox = _appengine_environ.is_appengine_sandbox +is_local_appengine = _appengine_environ.is_local_appengine +is_prod_appengine = _appengine_environ.is_prod_appengine +is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py new file mode 100644 index 0000000..4716657 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py @@ -0,0 +1,130 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +import warnings +from logging import getLogger + +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + +warnings.warn( + "The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed " + "in urllib3 v2.0 release, urllib3 is not able to support it properly due " + "to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. " + "If you are a user of this module please comment in the mentioned issue.", + DeprecationWarning, +) + +log = getLogger(__name__) + + +class NTLMConnectionPool(HTTPSConnectionPool): + """ + Implements an NTLM authentication version of an urllib3 connection pool + """ + + scheme = "https" + + def __init__(self, user, pw, authurl, *args, **kwargs): + """ + authurl is a random URL on the server that is protected by NTLM. + user is the Windows user, probably in the DOMAIN\\username format. + pw is the password for the user. + """ + super(NTLMConnectionPool, self).__init__(*args, **kwargs) + self.authurl = authurl + self.rawuser = user + user_parts = user.split("\\", 1) + self.domain = user_parts[0].upper() + self.user = user_parts[1] + self.pw = pw + + def _new_conn(self): + # Performs the NTLM handshake that secures the connection. The socket + # must be kept open while requests are performed. + self.num_connections += 1 + log.debug( + "Starting NTLM HTTPS connection no. %d: https://%s%s", + self.num_connections, + self.host, + self.authurl, + ) + + headers = {"Connection": "Keep-Alive"} + req_header = "Authorization" + resp_header = "www-authenticate" + + conn = HTTPSConnection(host=self.host, port=self.port) + + # Send negotiation message + headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE( + self.rawuser + ) + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + reshdr = dict(res.headers) + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", reshdr) + log.debug("Response data: %s [...]", res.read(100)) + + # Remove the reference to the socket, so that it can not be closed by + # the response object (we want to keep the socket open) + res.fp = None + + # Server should respond with a challenge message + auth_header_values = reshdr[resp_header].split(", ") + auth_header_value = None + for s in auth_header_values: + if s[:5] == "NTLM ": + auth_header_value = s[5:] + if auth_header_value is None: + raise Exception( + "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header]) + ) + + # Send authentication message + ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( + auth_header_value + ) + auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE( + ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags + ) + headers[req_header] = "NTLM %s" % auth_msg + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", dict(res.headers)) + log.debug("Response data: %s [...]", res.read()[:100]) + if res.status != 200: + if res.status == 401: + raise Exception("Server rejected request: wrong username or password") + raise Exception("Wrong server response: %s %s" % (res.status, res.reason)) + + res.fp = None + log.debug("Connection established") + return conn + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=3, + redirect=True, + assert_same_host=True, + ): + if headers is None: + headers = {} + headers["Connection"] = "Keep-Alive" + return super(NTLMConnectionPool, self).urlopen( + method, url, body, headers, retries, redirect, assert_same_host + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py new file mode 100644 index 0000000..19e4aa9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py @@ -0,0 +1,518 @@ +""" +TLS with SNI_-support for Python 2. Follow these instructions if you would +like to verify TLS certificates in Python 2. Note, the default libraries do +*not* do certificate checking; you need to do additional work to validate +certificates yourself. + +This needs the following packages installed: + +* `pyOpenSSL`_ (tested with 16.0.0) +* `cryptography`_ (minimum 1.3.4, from pyopenssl) +* `idna`_ (minimum 2.0, from cryptography) + +However, pyopenssl depends on cryptography, which depends on idna, so while we +use all three directly here we end up having relatively few packages required. + +You can install them with the following command: + +.. code-block:: bash + + $ python -m pip install pyopenssl cryptography idna + +To activate certificate checking, call +:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code +before you begin making HTTP requests. This can be done in a ``sitecustomize`` +module, or at any other time before your application begins using ``urllib3``, +like this: + +.. code-block:: python + + try: + import pip._vendor.urllib3.contrib.pyopenssl as pyopenssl + pyopenssl.inject_into_urllib3() + except ImportError: + pass + +Now you can use :mod:`urllib3` as you normally would, and it will support SNI +when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +compression in Python 2 (see `CRIME attack`_). + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +.. _pyopenssl: https://www.pyopenssl.org +.. _cryptography: https://cryptography.io +.. _idna: https://github.com/kjd/idna +""" +from __future__ import absolute_import + +import OpenSSL.crypto +import OpenSSL.SSL +from cryptography import x509 +from cryptography.hazmat.backends.openssl import backend as openssl_backend + +try: + from cryptography.x509 import UnsupportedExtension +except ImportError: + # UnsupportedExtension is gone in cryptography >= 2.1.0 + class UnsupportedExtension(Exception): + pass + + +from io import BytesIO +from socket import error as SocketError +from socket import timeout + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +import logging +import ssl +import sys +import warnings + +from .. import util +from ..packages import six +from ..util.ssl_ import PROTOCOL_TLS_CLIENT + +warnings.warn( + "'urllib3.contrib.pyopenssl' module is deprecated and will be removed " + "in a future release of urllib3 2.x. Read more in this issue: " + "https://github.com/urllib3/urllib3/issues/2680", + category=DeprecationWarning, + stacklevel=2, +) + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, + PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, +} + +if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"): + _openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD + + +_stdlib_to_openssl_verify = { + ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, + ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, + ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER + + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, +} +_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items()) + +# OpenSSL will only write 16K at a time +SSL_WRITE_BLOCKSIZE = 16384 + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + + +log = logging.getLogger(__name__) + + +def inject_into_urllib3(): + "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support." + + _validate_dependencies_met() + + util.SSLContext = PyOpenSSLContext + util.ssl_.SSLContext = PyOpenSSLContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_PYOPENSSL = True + util.ssl_.IS_PYOPENSSL = True + + +def extract_from_urllib3(): + "Undo monkey-patching by :func:`inject_into_urllib3`." + + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_PYOPENSSL = False + util.ssl_.IS_PYOPENSSL = False + + +def _validate_dependencies_met(): + """ + Verifies that PyOpenSSL's package-level dependencies have been met. + Throws `ImportError` if they are not met. + """ + # Method added in `cryptography==1.1`; not available in older versions + from cryptography.x509.extensions import Extensions + + if getattr(Extensions, "get_extension_for_class", None) is None: + raise ImportError( + "'cryptography' module missing required functionality. " + "Try upgrading to v1.3.4 or newer." + ) + + # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 + # attribute is only present on those versions. + from OpenSSL.crypto import X509 + + x509 = X509() + if getattr(x509, "_x509", None) is None: + raise ImportError( + "'pyOpenSSL' module missing required functionality. " + "Try upgrading to v0.14 or newer." + ) + + +def _dnsname_to_stdlib(name): + """ + Converts a dNSName SubjectAlternativeName field to the form used by the + standard library on the given Python version. + + Cryptography produces a dNSName as a unicode string that was idna-decoded + from ASCII bytes. We need to idna-encode that string to get it back, and + then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib + uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + + If the name cannot be idna-encoded then we return None signalling that + the name given should be skipped. + """ + + def idna_encode(name): + """ + Borrowed wholesale from the Python Cryptography Project. It turns out + that we can't just safely call `idna.encode`: it can explode for + wildcard names. This avoids that problem. + """ + from pip._vendor import idna + + try: + for prefix in [u"*.", u"."]: + if name.startswith(prefix): + name = name[len(prefix) :] + return prefix.encode("ascii") + idna.encode(name) + return idna.encode(name) + except idna.core.IDNAError: + return None + + # Don't send IPv6 addresses through the IDNA encoder. + if ":" in name: + return name + + name = idna_encode(name) + if name is None: + return None + elif sys.version_info >= (3, 0): + name = name.decode("utf-8") + return name + + +def get_subj_alt_name(peer_cert): + """ + Given an PyOpenSSL certificate, provides all the subject alternative names. + """ + # Pass the cert to cryptography, which has much better APIs for this. + if hasattr(peer_cert, "to_cryptography"): + cert = peer_cert.to_cryptography() + else: + der = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, peer_cert) + cert = x509.load_der_x509_certificate(der, openssl_backend) + + # We want to find the SAN extension. Ask Cryptography to locate it (it's + # faster than looping in Python) + try: + ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value + except x509.ExtensionNotFound: + # No such extension, return the empty list. + return [] + except ( + x509.DuplicateExtension, + UnsupportedExtension, + x509.UnsupportedGeneralNameType, + UnicodeError, + ) as e: + # A problem has been found with the quality of the certificate. Assume + # no SAN field is present. + log.warning( + "A problem was encountered with the certificate that prevented " + "urllib3 from finding the SubjectAlternativeName field. This can " + "affect certificate validation. The error was %s", + e, + ) + return [] + + # We want to return dNSName and iPAddress fields. We need to cast the IPs + # back to strings because the match_hostname function wants them as + # strings. + # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 + # decoded. This is pretty frustrating, but that's what the standard library + # does with certificates, and so we need to attempt to do the same. + # We also want to skip over names which cannot be idna encoded. + names = [ + ("DNS", name) + for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName)) + if name is not None + ] + names.extend( + ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress) + ) + + return names + + +class WrappedSocket(object): + """API-compatibility wrapper for Python OpenSSL's Connection-class. + + Note: _makefile_refs, _drop() and _reuse() are needed for the garbage + collector of pypy. + """ + + def __init__(self, connection, socket, suppress_ragged_eofs=True): + self.connection = connection + self.socket = socket + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + self._closed = False + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, *args, **kwargs): + try: + data = self.connection.recv(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return b"" + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b"" + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + else: + return data + + def recv_into(self, *args, **kwargs): + try: + return self.connection.recv_into(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return 0 + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv_into(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + + def settimeout(self, timeout): + return self.socket.settimeout(timeout) + + def _send_until_done(self, data): + while True: + try: + return self.connection.send(data) + except OpenSSL.SSL.WantWriteError: + if not util.wait_for_write(self.socket, self.socket.gettimeout()): + raise timeout() + continue + except OpenSSL.SSL.SysCallError as e: + raise SocketError(str(e)) + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self._send_until_done( + data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE] + ) + total_sent += sent + + def shutdown(self): + # FIXME rethrow compatible exceptions should we ever use this + self.connection.shutdown() + + def close(self): + if self._makefile_refs < 1: + try: + self._closed = True + return self.connection.close() + except OpenSSL.SSL.Error: + return + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + x509 = self.connection.get_peer_certificate() + + if not x509: + return x509 + + if binary_form: + return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) + + return { + "subject": ((("commonName", x509.get_subject().CN),),), + "subjectAltName": get_subj_alt_name(x509), + } + + def version(self): + return self.connection.get_protocol_version_name() + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + +else: # Platform-specific: Python 3 + makefile = backport_makefile + +WrappedSocket.makefile = makefile + + +class PyOpenSSLContext(object): + """ + I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible + for translating the interface of the standard library ``SSLContext`` object + to calls into PyOpenSSL. + """ + + def __init__(self, protocol): + self.protocol = _openssl_versions[protocol] + self._ctx = OpenSSL.SSL.Context(self.protocol) + self._options = 0 + self.check_hostname = False + + @property + def options(self): + return self._options + + @options.setter + def options(self, value): + self._options = value + self._ctx.set_options(value) + + @property + def verify_mode(self): + return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] + + @verify_mode.setter + def verify_mode(self, value): + self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback) + + def set_default_verify_paths(self): + self._ctx.set_default_verify_paths() + + def set_ciphers(self, ciphers): + if isinstance(ciphers, six.text_type): + ciphers = ciphers.encode("utf-8") + self._ctx.set_cipher_list(ciphers) + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile is not None: + cafile = cafile.encode("utf-8") + if capath is not None: + capath = capath.encode("utf-8") + try: + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("unable to load trusted certificates: %r" % e) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_chain_file(certfile) + if password is not None: + if not isinstance(password, six.binary_type): + password = password.encode("utf-8") + self._ctx.set_passwd_cb(lambda *_: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + def set_alpn_protocols(self, protocols): + protocols = [six.ensure_binary(p) for p in protocols] + return self._ctx.set_alpn_protos(protocols) + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + cnx = OpenSSL.SSL.Connection(self._ctx, sock) + + if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 + server_hostname = server_hostname.encode("utf-8") + + if server_hostname is not None: + cnx.set_tlsext_host_name(server_hostname) + + cnx.set_connect_state() + + while True: + try: + cnx.do_handshake() + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(sock, sock.gettimeout()): + raise timeout("select timed out") + continue + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("bad handshake: %r" % e) + break + + return WrappedSocket(cnx, sock) + + +def _verify_callback(cnx, x509, err_no, err_depth, return_code): + return err_no == 0 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py new file mode 100644 index 0000000..722ee4e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py @@ -0,0 +1,920 @@ +""" +SecureTranport support for urllib3 via ctypes. + +This makes platform-native TLS available to urllib3 users on macOS without the +use of a compiler. This is an important feature because the Python Package +Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL +that ships with macOS is not capable of doing TLSv1.2. The only way to resolve +this is to give macOS users an alternative solution to the problem, and that +solution is to use SecureTransport. + +We use ctypes here because this solution must not require a compiler. That's +because pip is not allowed to require a compiler either. + +This is not intended to be a seriously long-term solution to this problem. +The hope is that PEP 543 will eventually solve this issue for us, at which +point we can retire this contrib module. But in the short term, we need to +solve the impending tire fire that is Python on Mac without this kind of +contrib module. So...here we are. + +To use this module, simply import and inject it:: + + import pip._vendor.urllib3.contrib.securetransport as securetransport + securetransport.inject_into_urllib3() + +Happy TLSing! + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + +.. code-block:: + + Copyright (c) 2015-2016 Will Bond + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +""" +from __future__ import absolute_import + +import contextlib +import ctypes +import errno +import os.path +import shutil +import socket +import ssl +import struct +import threading +import weakref + +from .. import util +from ..packages import six +from ..util.ssl_ import PROTOCOL_TLS_CLIENT +from ._securetransport.bindings import CoreFoundation, Security, SecurityConst +from ._securetransport.low_level import ( + _assert_no_error, + _build_tls_unknown_ca_alert, + _cert_array_from_pem, + _create_cfstring_array, + _load_client_cert_chain, + _temporary_keychain, +) + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works +HAS_SNI = True + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + +# This dictionary is used by the read callback to obtain a handle to the +# calling wrapped socket. This is a pretty silly approach, but for now it'll +# do. I feel like I should be able to smuggle a handle to the wrapped socket +# directly in the SSLConnectionRef, but for now this approach will work I +# guess. +# +# We need to lock around this structure for inserts, but we don't do it for +# reads/writes in the callbacks. The reasoning here goes as follows: +# +# 1. It is not possible to call into the callbacks before the dictionary is +# populated, so once in the callback the id must be in the dictionary. +# 2. The callbacks don't mutate the dictionary, they only read from it, and +# so cannot conflict with any of the insertions. +# +# This is good: if we had to lock in the callbacks we'd drastically slow down +# the performance of this code. +_connection_refs = weakref.WeakValueDictionary() +_connection_ref_lock = threading.Lock() + +# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over +# for no better reason than we need *a* limit, and this one is right there. +SSL_WRITE_BLOCKSIZE = 16384 + +# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to +# individual cipher suites. We need to do this because this is how +# SecureTransport wants them. +CIPHER_SUITES = [ + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_AES_256_GCM_SHA384, + SecurityConst.TLS_AES_128_GCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_AES_128_CCM_8_SHA256, + SecurityConst.TLS_AES_128_CCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA, +] + +# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of +# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version. +# TLSv1 to 1.2 are supported on macOS 10.8+ +_protocol_to_min_max = { + util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), + PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), +} + +if hasattr(ssl, "PROTOCOL_SSLv2"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = ( + SecurityConst.kSSLProtocol2, + SecurityConst.kSSLProtocol2, + ) +if hasattr(ssl, "PROTOCOL_SSLv3"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = ( + SecurityConst.kSSLProtocol3, + SecurityConst.kSSLProtocol3, + ) +if hasattr(ssl, "PROTOCOL_TLSv1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = ( + SecurityConst.kTLSProtocol1, + SecurityConst.kTLSProtocol1, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = ( + SecurityConst.kTLSProtocol11, + SecurityConst.kTLSProtocol11, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_2"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = ( + SecurityConst.kTLSProtocol12, + SecurityConst.kTLSProtocol12, + ) + + +def inject_into_urllib3(): + """ + Monkey-patch urllib3 with SecureTransport-backed SSL-support. + """ + util.SSLContext = SecureTransportContext + util.ssl_.SSLContext = SecureTransportContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_SECURETRANSPORT = True + util.ssl_.IS_SECURETRANSPORT = True + + +def extract_from_urllib3(): + """ + Undo monkey-patching by :func:`inject_into_urllib3`. + """ + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_SECURETRANSPORT = False + util.ssl_.IS_SECURETRANSPORT = False + + +def _read_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport read callback. This is called by ST to request that data + be returned from the socket. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + requested_length = data_length_pointer[0] + + timeout = wrapped_socket.gettimeout() + error = None + read_count = 0 + + try: + while read_count < requested_length: + if timeout is None or timeout >= 0: + if not util.wait_for_read(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + + remaining = requested_length - read_count + buffer = (ctypes.c_char * remaining).from_address( + data_buffer + read_count + ) + chunk_size = base_socket.recv_into(buffer, remaining) + read_count += chunk_size + if not chunk_size: + if not read_count: + return SecurityConst.errSSLClosedGraceful + break + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = read_count + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = read_count + + if read_count != requested_length: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +def _write_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport write callback. This is called by ST to request that data + actually be sent on the network. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + bytes_to_write = data_length_pointer[0] + data = ctypes.string_at(data_buffer, bytes_to_write) + + timeout = wrapped_socket.gettimeout() + error = None + sent = 0 + + try: + while sent < bytes_to_write: + if timeout is None or timeout >= 0: + if not util.wait_for_write(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + chunk_sent = base_socket.send(data) + sent += chunk_sent + + # This has some needless copying here, but I'm not sure there's + # much value in optimising this data path. + data = data[chunk_sent:] + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = sent + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = sent + + if sent != bytes_to_write: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +# We need to keep these two objects references alive: if they get GC'd while +# in use then SecureTransport could attempt to call a function that is in freed +# memory. That would be...uh...bad. Yeah, that's the word. Bad. +_read_callback_pointer = Security.SSLReadFunc(_read_callback) +_write_callback_pointer = Security.SSLWriteFunc(_write_callback) + + +class WrappedSocket(object): + """ + API-compatibility wrapper for Python's OpenSSL wrapped socket object. + + Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage + collector of PyPy. + """ + + def __init__(self, socket): + self.socket = socket + self.context = None + self._makefile_refs = 0 + self._closed = False + self._exception = None + self._keychain = None + self._keychain_dir = None + self._client_cert_chain = None + + # We save off the previously-configured timeout and then set it to + # zero. This is done because we use select and friends to handle the + # timeouts, but if we leave the timeout set on the lower socket then + # Python will "kindly" call select on that socket again for us. Avoid + # that by forcing the timeout to zero. + self._timeout = self.socket.gettimeout() + self.socket.settimeout(0) + + @contextlib.contextmanager + def _raise_on_error(self): + """ + A context manager that can be used to wrap calls that do I/O from + SecureTransport. If any of the I/O callbacks hit an exception, this + context manager will correctly propagate the exception after the fact. + This avoids silently swallowing those exceptions. + + It also correctly forces the socket closed. + """ + self._exception = None + + # We explicitly don't catch around this yield because in the unlikely + # event that an exception was hit in the block we don't want to swallow + # it. + yield + if self._exception is not None: + exception, self._exception = self._exception, None + self.close() + raise exception + + def _set_ciphers(self): + """ + Sets up the allowed ciphers. By default this matches the set in + util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done + custom and doesn't allow changing at this time, mostly because parsing + OpenSSL cipher strings is going to be a freaking nightmare. + """ + ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES) + result = Security.SSLSetEnabledCiphers( + self.context, ciphers, len(CIPHER_SUITES) + ) + _assert_no_error(result) + + def _set_alpn_protocols(self, protocols): + """ + Sets up the ALPN protocols on the context. + """ + if not protocols: + return + protocols_arr = _create_cfstring_array(protocols) + try: + result = Security.SSLSetALPNProtocols(self.context, protocols_arr) + _assert_no_error(result) + finally: + CoreFoundation.CFRelease(protocols_arr) + + def _custom_validate(self, verify, trust_bundle): + """ + Called when we have set custom validation. We do this in two cases: + first, when cert validation is entirely disabled; and second, when + using a custom trust DB. + Raises an SSLError if the connection is not trusted. + """ + # If we disabled cert validation, just say: cool. + if not verify: + return + + successes = ( + SecurityConst.kSecTrustResultUnspecified, + SecurityConst.kSecTrustResultProceed, + ) + try: + trust_result = self._evaluate_trust(trust_bundle) + if trust_result in successes: + return + reason = "error code: %d" % (trust_result,) + except Exception as e: + # Do not trust on error + reason = "exception: %r" % (e,) + + # SecureTransport does not send an alert nor shuts down the connection. + rec = _build_tls_unknown_ca_alert(self.version()) + self.socket.sendall(rec) + # close the connection immediately + # l_onoff = 1, activate linger + # l_linger = 0, linger for 0 seoncds + opts = struct.pack("ii", 1, 0) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts) + self.close() + raise ssl.SSLError("certificate verify failed, %s" % reason) + + def _evaluate_trust(self, trust_bundle): + # We want data in memory, so load it up. + if os.path.isfile(trust_bundle): + with open(trust_bundle, "rb") as f: + trust_bundle = f.read() + + cert_array = None + trust = Security.SecTrustRef() + + try: + # Get a CFArray that contains the certs we want. + cert_array = _cert_array_from_pem(trust_bundle) + + # Ok, now the hard part. We want to get the SecTrustRef that ST has + # created for this connection, shove our CAs into it, tell ST to + # ignore everything else it knows, and then ask if it can build a + # chain. This is a buuuunch of code. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + raise ssl.SSLError("Failed to copy trust reference") + + result = Security.SecTrustSetAnchorCertificates(trust, cert_array) + _assert_no_error(result) + + result = Security.SecTrustSetAnchorCertificatesOnly(trust, True) + _assert_no_error(result) + + trust_result = Security.SecTrustResultType() + result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result)) + _assert_no_error(result) + finally: + if trust: + CoreFoundation.CFRelease(trust) + + if cert_array is not None: + CoreFoundation.CFRelease(cert_array) + + return trust_result.value + + def handshake( + self, + server_hostname, + verify, + trust_bundle, + min_version, + max_version, + client_cert, + client_key, + client_key_passphrase, + alpn_protocols, + ): + """ + Actually performs the TLS handshake. This is run automatically by + wrapped socket, and shouldn't be needed in user code. + """ + # First, we do the initial bits of connection setup. We need to create + # a context, set its I/O funcs, and set the connection reference. + self.context = Security.SSLCreateContext( + None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType + ) + result = Security.SSLSetIOFuncs( + self.context, _read_callback_pointer, _write_callback_pointer + ) + _assert_no_error(result) + + # Here we need to compute the handle to use. We do this by taking the + # id of self modulo 2**31 - 1. If this is already in the dictionary, we + # just keep incrementing by one until we find a free space. + with _connection_ref_lock: + handle = id(self) % 2147483647 + while handle in _connection_refs: + handle = (handle + 1) % 2147483647 + _connection_refs[handle] = self + + result = Security.SSLSetConnection(self.context, handle) + _assert_no_error(result) + + # If we have a server hostname, we should set that too. + if server_hostname: + if not isinstance(server_hostname, bytes): + server_hostname = server_hostname.encode("utf-8") + + result = Security.SSLSetPeerDomainName( + self.context, server_hostname, len(server_hostname) + ) + _assert_no_error(result) + + # Setup the ciphers. + self._set_ciphers() + + # Setup the ALPN protocols. + self._set_alpn_protocols(alpn_protocols) + + # Set the minimum and maximum TLS versions. + result = Security.SSLSetProtocolVersionMin(self.context, min_version) + _assert_no_error(result) + + result = Security.SSLSetProtocolVersionMax(self.context, max_version) + _assert_no_error(result) + + # If there's a trust DB, we need to use it. We do that by telling + # SecureTransport to break on server auth. We also do that if we don't + # want to validate the certs at all: we just won't actually do any + # authing in that case. + if not verify or trust_bundle is not None: + result = Security.SSLSetSessionOption( + self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True + ) + _assert_no_error(result) + + # If there's a client cert, we need to use it. + if client_cert: + self._keychain, self._keychain_dir = _temporary_keychain() + self._client_cert_chain = _load_client_cert_chain( + self._keychain, client_cert, client_key + ) + result = Security.SSLSetCertificate(self.context, self._client_cert_chain) + _assert_no_error(result) + + while True: + with self._raise_on_error(): + result = Security.SSLHandshake(self.context) + + if result == SecurityConst.errSSLWouldBlock: + raise socket.timeout("handshake timed out") + elif result == SecurityConst.errSSLServerAuthCompleted: + self._custom_validate(verify, trust_bundle) + continue + else: + _assert_no_error(result) + break + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, bufsiz): + buffer = ctypes.create_string_buffer(bufsiz) + bytes_read = self.recv_into(buffer, bufsiz) + data = buffer[:bytes_read] + return data + + def recv_into(self, buffer, nbytes=None): + # Read short on EOF. + if self._closed: + return 0 + + if nbytes is None: + nbytes = len(buffer) + + buffer = (ctypes.c_char * nbytes).from_buffer(buffer) + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLRead( + self.context, buffer, nbytes, ctypes.byref(processed_bytes) + ) + + # There are some result codes that we want to treat as "not always + # errors". Specifically, those are errSSLWouldBlock, + # errSSLClosedGraceful, and errSSLClosedNoNotify. + if result == SecurityConst.errSSLWouldBlock: + # If we didn't process any bytes, then this was just a time out. + # However, we can get errSSLWouldBlock in situations when we *did* + # read some data, and in those cases we should just read "short" + # and return. + if processed_bytes.value == 0: + # Timed out, no data read. + raise socket.timeout("recv timed out") + elif result in ( + SecurityConst.errSSLClosedGraceful, + SecurityConst.errSSLClosedNoNotify, + ): + # The remote peer has closed this connection. We should do so as + # well. Note that we don't actually return here because in + # principle this could actually be fired along with return data. + # It's unlikely though. + self.close() + else: + _assert_no_error(result) + + # Ok, we read and probably succeeded. We should return whatever data + # was actually read. + return processed_bytes.value + + def settimeout(self, timeout): + self._timeout = timeout + + def gettimeout(self): + return self._timeout + + def send(self, data): + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLWrite( + self.context, data, len(data), ctypes.byref(processed_bytes) + ) + + if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0: + # Timed out + raise socket.timeout("send timed out") + else: + _assert_no_error(result) + + # We sent, and probably succeeded. Tell them how much we sent. + return processed_bytes.value + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]) + total_sent += sent + + def shutdown(self): + with self._raise_on_error(): + Security.SSLClose(self.context) + + def close(self): + # TODO: should I do clean shutdown here? Do I have to? + if self._makefile_refs < 1: + self._closed = True + if self.context: + CoreFoundation.CFRelease(self.context) + self.context = None + if self._client_cert_chain: + CoreFoundation.CFRelease(self._client_cert_chain) + self._client_cert_chain = None + if self._keychain: + Security.SecKeychainDelete(self._keychain) + CoreFoundation.CFRelease(self._keychain) + shutil.rmtree(self._keychain_dir) + self._keychain = self._keychain_dir = None + return self.socket.close() + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + # Urgh, annoying. + # + # Here's how we do this: + # + # 1. Call SSLCopyPeerTrust to get hold of the trust object for this + # connection. + # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf. + # 3. To get the CN, call SecCertificateCopyCommonName and process that + # string so that it's of the appropriate type. + # 4. To get the SAN, we need to do something a bit more complex: + # a. Call SecCertificateCopyValues to get the data, requesting + # kSecOIDSubjectAltName. + # b. Mess about with this dictionary to try to get the SANs out. + # + # This is gross. Really gross. It's going to be a few hundred LoC extra + # just to repeat something that SecureTransport can *already do*. So my + # operating assumption at this time is that what we want to do is + # instead to just flag to urllib3 that it shouldn't do its own hostname + # validation when using SecureTransport. + if not binary_form: + raise ValueError("SecureTransport only supports dumping binary certs") + trust = Security.SecTrustRef() + certdata = None + der_bytes = None + + try: + # Grab the trust store. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + # Probably we haven't done the handshake yet. No biggie. + return None + + cert_count = Security.SecTrustGetCertificateCount(trust) + if not cert_count: + # Also a case that might happen if we haven't handshaked. + # Handshook? Handshaken? + return None + + leaf = Security.SecTrustGetCertificateAtIndex(trust, 0) + assert leaf + + # Ok, now we want the DER bytes. + certdata = Security.SecCertificateCopyData(leaf) + assert certdata + + data_length = CoreFoundation.CFDataGetLength(certdata) + data_buffer = CoreFoundation.CFDataGetBytePtr(certdata) + der_bytes = ctypes.string_at(data_buffer, data_length) + finally: + if certdata: + CoreFoundation.CFRelease(certdata) + if trust: + CoreFoundation.CFRelease(trust) + + return der_bytes + + def version(self): + protocol = Security.SSLProtocol() + result = Security.SSLGetNegotiatedProtocolVersion( + self.context, ctypes.byref(protocol) + ) + _assert_no_error(result) + if protocol.value == SecurityConst.kTLSProtocol13: + raise ssl.SSLError("SecureTransport does not support TLS 1.3") + elif protocol.value == SecurityConst.kTLSProtocol12: + return "TLSv1.2" + elif protocol.value == SecurityConst.kTLSProtocol11: + return "TLSv1.1" + elif protocol.value == SecurityConst.kTLSProtocol1: + return "TLSv1" + elif protocol.value == SecurityConst.kSSLProtocol3: + return "SSLv3" + elif protocol.value == SecurityConst.kSSLProtocol2: + return "SSLv2" + else: + raise ssl.SSLError("Unknown TLS version: %r" % protocol) + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + +else: # Platform-specific: Python 3 + + def makefile(self, mode="r", buffering=None, *args, **kwargs): + # We disable buffering with SecureTransport because it conflicts with + # the buffering that ST does internally (see issue #1153 for more). + buffering = 0 + return backport_makefile(self, mode, buffering, *args, **kwargs) + + +WrappedSocket.makefile = makefile + + +class SecureTransportContext(object): + """ + I am a wrapper class for the SecureTransport library, to translate the + interface of the standard library ``SSLContext`` object to calls into + SecureTransport. + """ + + def __init__(self, protocol): + self._min_version, self._max_version = _protocol_to_min_max[protocol] + self._options = 0 + self._verify = False + self._trust_bundle = None + self._client_cert = None + self._client_key = None + self._client_key_passphrase = None + self._alpn_protocols = None + + @property + def check_hostname(self): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + return True + + @check_hostname.setter + def check_hostname(self, value): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + pass + + @property + def options(self): + # TODO: Well, crap. + # + # So this is the bit of the code that is the most likely to cause us + # trouble. Essentially we need to enumerate all of the SSL options that + # users might want to use and try to see if we can sensibly translate + # them, or whether we should just ignore them. + return self._options + + @options.setter + def options(self, value): + # TODO: Update in line with above. + self._options = value + + @property + def verify_mode(self): + return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE + + @verify_mode.setter + def verify_mode(self, value): + self._verify = True if value == ssl.CERT_REQUIRED else False + + def set_default_verify_paths(self): + # So, this has to do something a bit weird. Specifically, what it does + # is nothing. + # + # This means that, if we had previously had load_verify_locations + # called, this does not undo that. We need to do that because it turns + # out that the rest of the urllib3 code will attempt to load the + # default verify paths if it hasn't been told about any paths, even if + # the context itself was sometime earlier. We resolve that by just + # ignoring it. + pass + + def load_default_certs(self): + return self.set_default_verify_paths() + + def set_ciphers(self, ciphers): + # For now, we just require the default cipher string. + if ciphers != util.ssl_.DEFAULT_CIPHERS: + raise ValueError("SecureTransport doesn't support custom cipher strings") + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + # OK, we only really support cadata and cafile. + if capath is not None: + raise ValueError("SecureTransport does not support cert directories") + + # Raise if cafile does not exist. + if cafile is not None: + with open(cafile): + pass + + self._trust_bundle = cafile or cadata + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._client_cert = certfile + self._client_key = keyfile + self._client_cert_passphrase = password + + def set_alpn_protocols(self, protocols): + """ + Sets the ALPN protocols that will later be set on the context. + + Raises a NotImplementedError if ALPN is not supported. + """ + if not hasattr(Security, "SSLSetALPNProtocols"): + raise NotImplementedError( + "SecureTransport supports ALPN only in macOS 10.12+" + ) + self._alpn_protocols = [six.ensure_binary(p) for p in protocols] + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + # So, what do we do here? Firstly, we assert some properties. This is a + # stripped down shim, so there is some functionality we don't support. + # See PEP 543 for the real deal. + assert not server_side + assert do_handshake_on_connect + assert suppress_ragged_eofs + + # Ok, we're good to go. Now we want to create the wrapped socket object + # and store it in the appropriate place. + wrapped_socket = WrappedSocket(sock) + + # Now we can handshake + wrapped_socket.handshake( + server_hostname, + self._verify, + self._trust_bundle, + self._min_version, + self._max_version, + self._client_cert, + self._client_key, + self._client_key_passphrase, + self._alpn_protocols, + ) + return wrapped_socket diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py new file mode 100644 index 0000000..c326e80 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and +SOCKS5. To enable its functionality, either install PySocks or install this +module with the ``socks`` extra. + +The SOCKS implementation supports the full range of urllib3 features. It also +supports the following SOCKS features: + +- SOCKS4A (``proxy_url='socks4a://...``) +- SOCKS4 (``proxy_url='socks4://...``) +- SOCKS5 with remote DNS (``proxy_url='socks5h://...``) +- SOCKS5 with local DNS (``proxy_url='socks5://...``) +- Usernames and passwords for the SOCKS proxy + +.. note:: + It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in + your ``proxy_url`` to ensure that DNS resolution is done from the remote + server instead of client-side when connecting to a domain name. + +SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5 +supports IPv4, IPv6, and domain names. + +When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url`` +will be sent as the ``userid`` section of the SOCKS request: + +.. code-block:: python + + proxy_url="socks4a://@proxy-host" + +When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion +of the ``proxy_url`` will be sent as the username/password to authenticate +with the proxy: + +.. code-block:: python + + proxy_url="socks5h://:@proxy-host" + +""" +from __future__ import absolute_import + +try: + import socks +except ImportError: + import warnings + + from ..exceptions import DependencyWarning + + warnings.warn( + ( + "SOCKS support in urllib3 requires the installation of optional " + "dependencies: specifically, PySocks. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies" + ), + DependencyWarning, + ) + raise + +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from ..connection import HTTPConnection, HTTPSConnection +from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from ..exceptions import ConnectTimeoutError, NewConnectionError +from ..poolmanager import PoolManager +from ..util.url import parse_url + +try: + import ssl +except ImportError: + ssl = None + + +class SOCKSConnection(HTTPConnection): + """ + A plain-text HTTP connection that connects via a SOCKS proxy. + """ + + def __init__(self, *args, **kwargs): + self._socks_options = kwargs.pop("_socks_options") + super(SOCKSConnection, self).__init__(*args, **kwargs) + + def _new_conn(self): + """ + Establish a new connection via the SOCKS proxy. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = socks.create_connection( + (self.host, self.port), + proxy_type=self._socks_options["socks_version"], + proxy_addr=self._socks_options["proxy_host"], + proxy_port=self._socks_options["proxy_port"], + proxy_username=self._socks_options["username"], + proxy_password=self._socks_options["password"], + proxy_rdns=self._socks_options["rdns"], + timeout=self.timeout, + **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except socks.ProxyError as e: + # This is fragile as hell, but it seems to be the only way to raise + # useful errors here. + if e.socket_err: + error = e.socket_err + if isinstance(error, SocketTimeout): + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % error + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + except SocketError as e: # Defensive: PySocks should catch all these. + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + +# We don't need to duplicate the Verified/Unverified distinction from +# urllib3/connection.py here because the HTTPSConnection will already have been +# correctly set to either the Verified or Unverified form by that module. This +# means the SOCKSHTTPSConnection will automatically be the correct type. +class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): + pass + + +class SOCKSHTTPConnectionPool(HTTPConnectionPool): + ConnectionCls = SOCKSConnection + + +class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): + ConnectionCls = SOCKSHTTPSConnection + + +class SOCKSProxyManager(PoolManager): + """ + A version of the urllib3 ProxyManager that routes connections via the + defined SOCKS proxy. + """ + + pool_classes_by_scheme = { + "http": SOCKSHTTPConnectionPool, + "https": SOCKSHTTPSConnectionPool, + } + + def __init__( + self, + proxy_url, + username=None, + password=None, + num_pools=10, + headers=None, + **connection_pool_kw + ): + parsed = parse_url(proxy_url) + + if username is None and password is None and parsed.auth is not None: + split = parsed.auth.split(":") + if len(split) == 2: + username, password = split + if parsed.scheme == "socks5": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = False + elif parsed.scheme == "socks5h": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = True + elif parsed.scheme == "socks4": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = False + elif parsed.scheme == "socks4a": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = True + else: + raise ValueError("Unable to determine SOCKS version from %s" % proxy_url) + + self.proxy_url = proxy_url + + socks_options = { + "socks_version": socks_version, + "proxy_host": parsed.host, + "proxy_port": parsed.port, + "username": username, + "password": password, + "rdns": rdns, + } + connection_pool_kw["_socks_options"] = socks_options + + super(SOCKSProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw + ) + + self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py new file mode 100644 index 0000000..cba6f3f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py @@ -0,0 +1,323 @@ +from __future__ import absolute_import + +from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead + +# Base Exceptions + + +class HTTPError(Exception): + """Base exception used by this module.""" + + pass + + +class HTTPWarning(Warning): + """Base warning used by this module.""" + + pass + + +class PoolError(HTTPError): + """Base exception for errors caused within a pool.""" + + def __init__(self, pool, message): + self.pool = pool + HTTPError.__init__(self, "%s: %s" % (pool, message)) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, None) + + +class RequestError(PoolError): + """Base exception for PoolErrors that have associated URLs.""" + + def __init__(self, pool, url, message): + self.url = url + PoolError.__init__(self, pool, message) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, self.url, None) + + +class SSLError(HTTPError): + """Raised when SSL certificate fails in an HTTPS connection.""" + + pass + + +class ProxyError(HTTPError): + """Raised when the connection to a proxy fails.""" + + def __init__(self, message, error, *args): + super(ProxyError, self).__init__(message, error, *args) + self.original_error = error + + +class DecodeError(HTTPError): + """Raised when automatic decoding based on Content-Type fails.""" + + pass + + +class ProtocolError(HTTPError): + """Raised when something unexpected happens mid-request/response.""" + + pass + + +#: Renamed to ProtocolError but aliased for backwards compatibility. +ConnectionError = ProtocolError + + +# Leaf Exceptions + + +class MaxRetryError(RequestError): + """Raised when the maximum number of retries is exceeded. + + :param pool: The connection pool + :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` + :param string url: The requested Url + :param exceptions.Exception reason: The underlying error + + """ + + def __init__(self, pool, url, reason=None): + self.reason = reason + + message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason) + + RequestError.__init__(self, pool, url, message) + + +class HostChangedError(RequestError): + """Raised when an existing pool gets a request for a foreign host.""" + + def __init__(self, pool, url, retries=3): + message = "Tried to open a foreign host with url: %s" % url + RequestError.__init__(self, pool, url, message) + self.retries = retries + + +class TimeoutStateError(HTTPError): + """Raised when passing an invalid state to a timeout""" + + pass + + +class TimeoutError(HTTPError): + """Raised when a socket timeout error occurs. + + Catching this error will catch both :exc:`ReadTimeoutErrors + ` and :exc:`ConnectTimeoutErrors `. + """ + + pass + + +class ReadTimeoutError(TimeoutError, RequestError): + """Raised when a socket timeout occurs while receiving data from a server""" + + pass + + +# This timeout error does not have a URL attached and needs to inherit from the +# base HTTPError +class ConnectTimeoutError(TimeoutError): + """Raised when a socket timeout occurs while connecting to a server""" + + pass + + +class NewConnectionError(ConnectTimeoutError, PoolError): + """Raised when we fail to establish a new connection. Usually ECONNREFUSED.""" + + pass + + +class EmptyPoolError(PoolError): + """Raised when a pool runs out of connections and no more are allowed.""" + + pass + + +class ClosedPoolError(PoolError): + """Raised when a request enters a pool after the pool has been closed.""" + + pass + + +class LocationValueError(ValueError, HTTPError): + """Raised when there is something wrong with a given URL input.""" + + pass + + +class LocationParseError(LocationValueError): + """Raised when get_host or similar fails to parse the URL input.""" + + def __init__(self, location): + message = "Failed to parse: %s" % location + HTTPError.__init__(self, message) + + self.location = location + + +class URLSchemeUnknown(LocationValueError): + """Raised when a URL input has an unsupported scheme.""" + + def __init__(self, scheme): + message = "Not supported URL scheme %s" % scheme + super(URLSchemeUnknown, self).__init__(message) + + self.scheme = scheme + + +class ResponseError(HTTPError): + """Used as a container for an error reason supplied in a MaxRetryError.""" + + GENERIC_ERROR = "too many error responses" + SPECIFIC_ERROR = "too many {status_code} error responses" + + +class SecurityWarning(HTTPWarning): + """Warned when performing security reducing actions""" + + pass + + +class SubjectAltNameWarning(SecurityWarning): + """Warned when connecting to a host with a certificate missing a SAN.""" + + pass + + +class InsecureRequestWarning(SecurityWarning): + """Warned when making an unverified HTTPS request.""" + + pass + + +class SystemTimeWarning(SecurityWarning): + """Warned when system time is suspected to be wrong""" + + pass + + +class InsecurePlatformWarning(SecurityWarning): + """Warned when certain TLS/SSL configuration is not available on a platform.""" + + pass + + +class SNIMissingWarning(HTTPWarning): + """Warned when making a HTTPS request without SNI available.""" + + pass + + +class DependencyWarning(HTTPWarning): + """ + Warned when an attempt is made to import a module with missing optional + dependencies. + """ + + pass + + +class ResponseNotChunked(ProtocolError, ValueError): + """Response needs to be chunked in order to read it as chunks.""" + + pass + + +class BodyNotHttplibCompatible(HTTPError): + """ + Body should be :class:`http.client.HTTPResponse` like + (have an fp attribute which returns raw chunks) for read_chunked(). + """ + + pass + + +class IncompleteRead(HTTPError, httplib_IncompleteRead): + """ + Response length doesn't match expected Content-Length + + Subclass of :class:`http.client.IncompleteRead` to allow int value + for ``partial`` to avoid creating large objects on streamed reads. + """ + + def __init__(self, partial, expected): + super(IncompleteRead, self).__init__(partial, expected) + + def __repr__(self): + return "IncompleteRead(%i bytes read, %i more expected)" % ( + self.partial, + self.expected, + ) + + +class InvalidChunkLength(HTTPError, httplib_IncompleteRead): + """Invalid chunk length in a chunked response.""" + + def __init__(self, response, length): + super(InvalidChunkLength, self).__init__( + response.tell(), response.length_remaining + ) + self.response = response + self.length = length + + def __repr__(self): + return "InvalidChunkLength(got length %r, %i bytes read)" % ( + self.length, + self.partial, + ) + + +class InvalidHeader(HTTPError): + """The header provided was somehow invalid.""" + + pass + + +class ProxySchemeUnknown(AssertionError, URLSchemeUnknown): + """ProxyManager does not support the supplied scheme""" + + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + # 'localhost' is here because our URL parser parses + # localhost:8080 -> scheme=localhost, remove if we fix this. + if scheme == "localhost": + scheme = None + if scheme is None: + message = "Proxy URL had no scheme, should start with http:// or https://" + else: + message = ( + "Proxy URL had unsupported scheme %s, should use http:// or https://" + % scheme + ) + super(ProxySchemeUnknown, self).__init__(message) + + +class ProxySchemeUnsupported(ValueError): + """Fetching HTTPS resources through HTTPS proxies is unsupported""" + + pass + + +class HeaderParsingError(HTTPError): + """Raised by assert_header_parsing, but we convert it to a log.warning statement.""" + + def __init__(self, defects, unparsed_data): + message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data) + super(HeaderParsingError, self).__init__(message) + + +class UnrewindableBodyError(HTTPError): + """urllib3 encountered an error when trying to rewind a body""" + + pass diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/fields.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/fields.py new file mode 100644 index 0000000..9d630f4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/fields.py @@ -0,0 +1,274 @@ +from __future__ import absolute_import + +import email.utils +import mimetypes +import re + +from .packages import six + + +def guess_content_type(filename, default="application/octet-stream"): + """ + Guess the "Content-Type" of a file. + + :param filename: + The filename to guess the "Content-Type" of using :mod:`mimetypes`. + :param default: + If no "Content-Type" can be guessed, default to `default`. + """ + if filename: + return mimetypes.guess_type(filename)[0] or default + return default + + +def format_header_param_rfc2231(name, value): + """ + Helper function to format and quote a single header parameter using the + strategy defined in RFC 2231. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows + `RFC 2388 Section 4.4 `_. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + An RFC-2231-formatted unicode string. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + if not any(ch in value for ch in '"\\\r\n'): + result = u'%s="%s"' % (name, value) + try: + result.encode("ascii") + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + + if six.PY2: # Python 2: + value = value.encode("utf-8") + + # encode_rfc2231 accepts an encoded string and returns an ascii-encoded + # string in Python 2 but accepts and returns unicode strings in Python 3 + value = email.utils.encode_rfc2231(value, "utf-8") + value = "%s*=%s" % (name, value) + + if six.PY2: # Python 2: + value = value.decode("utf-8") + + return value + + +_HTML5_REPLACEMENTS = { + u"\u0022": u"%22", + # Replace "\" with "\\". + u"\u005C": u"\u005C\u005C", +} + +# All control characters from 0x00 to 0x1F *except* 0x1B. +_HTML5_REPLACEMENTS.update( + { + six.unichr(cc): u"%{:02X}".format(cc) + for cc in range(0x00, 0x1F + 1) + if cc not in (0x1B,) + } +) + + +def _replace_multiple(value, needles_and_replacements): + def replacer(match): + return needles_and_replacements[match.group(0)] + + pattern = re.compile( + r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()]) + ) + + result = pattern.sub(replacer, value) + + return result + + +def format_header_param_html5(name, value): + """ + Helper function to format and quote a single header parameter using the + HTML5 strategy. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows the `HTML5 Working Draft + Section 4.10.22.7`_ and matches the behavior of curl and modern browsers. + + .. _HTML5 Working Draft Section 4.10.22.7: + https://w3c.github.io/html/sec-forms.html#multipart-form-data + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + A unicode string, stripped of troublesome characters. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + value = _replace_multiple(value, _HTML5_REPLACEMENTS) + + return u'%s="%s"' % (name, value) + + +# For backwards-compatibility. +format_header_param = format_header_param_html5 + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. Must be unicode. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. Must be unicode. + :param headers: + An optional dict-like object of headers to initially use for the field. + :param header_formatter: + An optional callable that is used to encode and format the headers. By + default, this is :func:`format_header_param_html5`. + """ + + def __init__( + self, + name, + data, + filename=None, + headers=None, + header_formatter=format_header_param_html5, + ): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + self.header_formatter = header_formatter + + @classmethod + def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5): + """ + A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. + + Supports constructing :class:`~urllib3.fields.RequestField` from + parameter of key/value strings AND key/filetuple. A filetuple is a + (filename, data, MIME type) tuple where the MIME type is optional. + For example:: + + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + + Field names and filenames must be unicode. + """ + if isinstance(value, tuple): + if len(value) == 3: + filename, data, content_type = value + else: + filename, data = value + content_type = guess_content_type(filename) + else: + filename = None + content_type = None + data = value + + request_param = cls( + fieldname, data, filename=filename, header_formatter=header_formatter + ) + request_param.make_multipart(content_type=content_type) + + return request_param + + def _render_part(self, name, value): + """ + Overridable helper function to format a single header parameter. By + default, this calls ``self.header_formatter``. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + + return self.header_formatter(name, value) + + def _render_parts(self, header_parts): + """ + Helper function to format and quote a single header. + + Useful for single headers that are composed of multiple items. E.g., + 'Content-Disposition' fields. + + :param header_parts: + A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format + as `k1="v1"; k2="v2"; ...`. + """ + parts = [] + iterable = header_parts + if isinstance(header_parts, dict): + iterable = header_parts.items() + + for name, value in iterable: + if value is not None: + parts.append(self._render_part(name, value)) + + return u"; ".join(parts) + + def render_headers(self): + """ + Renders the headers for this request field. + """ + lines = [] + + sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"] + for sort_key in sort_keys: + if self.headers.get(sort_key, False): + lines.append(u"%s: %s" % (sort_key, self.headers[sort_key])) + + for header_name, header_value in self.headers.items(): + if header_name not in sort_keys: + if header_value: + lines.append(u"%s: %s" % (header_name, header_value)) + + lines.append(u"\r\n") + return u"\r\n".join(lines) + + def make_multipart( + self, content_disposition=None, content_type=None, content_location=None + ): + """ + Makes this request field into a multipart request field. + + This method overrides "Content-Disposition", "Content-Type" and + "Content-Location" headers to the request parameter. + + :param content_type: + The 'Content-Type' of the request body. + :param content_location: + The 'Content-Location' of the request body. + + """ + self.headers["Content-Disposition"] = content_disposition or u"form-data" + self.headers["Content-Disposition"] += u"; ".join( + [ + u"", + self._render_parts( + ((u"name", self._name), (u"filename", self._filename)) + ), + ] + ) + self.headers["Content-Type"] = content_type + self.headers["Content-Location"] = content_location diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py new file mode 100644 index 0000000..36c9252 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py @@ -0,0 +1,98 @@ +from __future__ import absolute_import + +import binascii +import codecs +import os +from io import BytesIO + +from .fields import RequestField +from .packages import six +from .packages.six import b + +writer = codecs.lookup("utf-8")[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + boundary = binascii.hexlify(os.urandom(16)) + if not six.PY2: + boundary = boundary.decode("ascii") + return boundary + + +def iter_field_objects(fields): + """ + Iterate over fields. + + Supports list of (k, v) tuples and dicts, and lists of + :class:`~urllib3.fields.RequestField`. + + """ + if isinstance(fields, dict): + i = six.iteritems(fields) + else: + i = iter(fields) + + for field in i: + if isinstance(field, RequestField): + yield field + else: + yield RequestField.from_tuples(*field) + + +def iter_fields(fields): + """ + .. deprecated:: 1.6 + + Iterate over fields. + + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. + + Supports list of (k, v) tuples and dicts. + """ + if isinstance(fields, dict): + return ((k, v) for k, v in six.iteritems(fields)) + + return ((k, v) for k, v in fields) + + +def encode_multipart_formdata(fields, boundary=None): + """ + Encode a dictionary of ``fields`` using the multipart/form-data MIME format. + + :param fields: + Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). + + :param boundary: + If not specified, then a random boundary will be generated using + :func:`urllib3.filepost.choose_boundary`. + """ + body = BytesIO() + if boundary is None: + boundary = choose_boundary() + + for field in iter_field_objects(fields): + body.write(b("--%s\r\n" % (boundary))) + + writer(body).write(field.render_headers()) + data = field.data + + if isinstance(data, int): + data = str(data) # Backwards compatibility + + if isinstance(data, six.text_type): + writer(body).write(data) + else: + body.write(data) + + body.write(b"\r\n") + + body.write(b("--%s--\r\n" % (boundary))) + + content_type = str("multipart/form-data; boundary=%s" % boundary) + + return body.getvalue(), content_type diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1e5a3f90cb93826e152b672b4e40cfc656b991a GIT binary patch literal 205 zcmX@j%ge<81j_4zGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!%5k=eDJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`nFadsK)ICsBK^{$oSe)gV||#Uemu~e%#!$cy@JYH95%W6DWy57c15f}%Nc>V Q7{vI<%*e=C#0+Es0GM<-7XSbN literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27005df4b892fc104151434c81ebd0c5fad2a764 GIT binary patch literal 41261 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c67891927ea665d0df1f78e2f70631368f0fc740 GIT binary patch literal 215 zcmX@j%ge<81j_4zGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!Ds#4qDJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`nFadsK)ICsBK^{$oSe)gV||#UK1gpteo;xWemu~`%#!$cy@JYH95%W6DWy57 Yc15f}XD|YBF^KVznURsPh#ANN07ET482|tP literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6c378b61e99b15a89325249e38d77b37e09eb96 GIT binary patch literal 1831 zcmZux&2JM&6rWwMckNw&6ENkYngj_jqKRl)p`r>kkc6hBfJi86u;i@0<7AWdt~I-k zNwh{5;^3&4a3X4jgwzXFq^f^Iue~@#Rh(5gR6TK{3a4J$H@4StKc3~C_w{@8-kUe` zOEfAYpff+-)z^av{mulR_%3sB7MN#9Lvu*uG~VFmI9LM)Ukc0xI21-&P!pbTbHXa0 z5!ar}d9|=ywy0wdm(*oa)D0p(`VYzSHQx<8iv-_UbrvlXkK*}x+bS#*rw5*&$0Y(r z4HqqnD>lJZ-C4w{2?*U>0JQ4JRn>HC>{z%!iRuun;-MmJK7>2Lu$5mT1!q`(!)m&f z;k?jHdzY!(1+iNuTNodJ|3M0he}){6DH*xkR+nFdCVbB=pFqftJIuFD8t-!7@mk<{ z!1sI1X@bkGpqi)!+4_*Pp;@jNK{d&hY{3<6{tE>NtUJKWFm)GQFz|({i@?$Qw$H135 zYuEEUc*fn3t@Kr^99HSdGYIlN0ofjR!hVFMh|e9at_(kZtD8?vF-HNH?!&|meSNNt z@M~2}*rn68K2*Z@JzW2Zazm7Nl^N8BNgew7oU6D2S8#({LPt}JxSSiw_4?vQW>6-w zc16ZO{_J9__`d^Nq*kdn(!(DQw?S7~y~$9d}4C!-t=tl+P%riiMzR( zsksR+cCEX^-TQY`o%YE@)kvRwpXv_C(OL4)nYw+Ss^v0>0xK~S^#q$3MLNLB2zPRZ z3+#o6S+F$5iG<~5dy+}2hHes1szN+wk)W=QOQ$4Is8tr#3jpJZooJrmz`i!jJz}TS zqd!-!U&)rKwLsNU3BqNomQ}DyB|-}%2gg86$D*rQ_HYqX%YwX;o!0YN8;bd$3|e)8 z*x9mP9?5}Cv*<{L8it-99r2ALy+?1vZ|QJ()l2&7UZd#{B*zl8hv6LS=v@Rw;tl7U zPri-6QqH}O9shZ@`QFW)*mN^A-HIhQW*f`(8(rpA?EH)L=7ai;Jtg&Yp(&hhDyLh~ z#Kw5zL4C3nOMpR&wLgV_6)W%1f=^c5ne!V4xc7^mSA-#ENTR8QrkZwtd zrgXeDaI6sqcH`3H+Wx??-GK|+0~b1)vB!`0;z##Wr<$if+ewWzBV(<2sv*M$PcQE$ zkL)Igwv$6IMqdVAe!Y{tye{sA6aDJ&PV&Qb@wfP~Myyf&x1k~KNzqpPXd}9>M0b^w z+set!$rqo$EdI2xqg<_zw-N*O@h4L)C0@UI0Bu8=VEZ!M0?GtEDVNi%LM}(y+u@0w z*S5^en7iS6g# literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fdb56e22bf07478031d6e3c42fec56249c8b7f2 GIT binary patch literal 7342 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 AssI20 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py new file mode 100644 index 0000000..b8fb215 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +backports.makefile +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``socket.makefile`` method for use with anything that +wants to create a "fake" socket object. +""" +import io +from socket import SocketIO + + +def backport_makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None +): + """ + Backport of ``socket.makefile`` from Python 3.5. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = SocketIO(self, rawmode) + self._makefile_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py new file mode 100644 index 0000000..a2f2966 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +""" +backports.weakref_finalize +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``weakref.finalize`` method. +""" +from __future__ import absolute_import + +import itertools +import sys +from weakref import ref + +__all__ = ["weakref_finalize"] + + +class weakref_finalize(object): + """Class for finalization of weakrefable objects + finalize(obj, func, *args, **kwargs) returns a callable finalizer + object which will be called when obj is garbage collected. The + first time the finalizer is called it evaluates func(*arg, **kwargs) + and returns the result. After this the finalizer is dead, and + calling it just returns None. + When the program exits any remaining finalizers for which the + atexit attribute is true will be run in reverse order of creation. + By default atexit is true. + """ + + # Finalizer objects don't have any state of their own. They are + # just used as keys to lookup _Info objects in the registry. This + # ensures that they cannot be part of a ref-cycle. + + __slots__ = () + _registry = {} + _shutdown = False + _index_iter = itertools.count() + _dirty = False + _registered_with_atexit = False + + class _Info(object): + __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") + + def __init__(self, obj, func, *args, **kwargs): + if not self._registered_with_atexit: + # We may register the exit function more than once because + # of a thread race, but that is harmless + import atexit + + atexit.register(self._exitfunc) + weakref_finalize._registered_with_atexit = True + info = self._Info() + info.weakref = ref(obj, self) + info.func = func + info.args = args + info.kwargs = kwargs or None + info.atexit = True + info.index = next(self._index_iter) + self._registry[self] = info + weakref_finalize._dirty = True + + def __call__(self, _=None): + """If alive then mark as dead and return func(*args, **kwargs); + otherwise return None""" + info = self._registry.pop(self, None) + if info and not self._shutdown: + return info.func(*info.args, **(info.kwargs or {})) + + def detach(self): + """If alive then mark as dead and return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None and self._registry.pop(self, None): + return (obj, info.func, info.args, info.kwargs or {}) + + def peek(self): + """If alive then return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None: + return (obj, info.func, info.args, info.kwargs or {}) + + @property + def alive(self): + """Whether finalizer is alive""" + return self in self._registry + + @property + def atexit(self): + """Whether finalizer should be called at exit""" + info = self._registry.get(self) + return bool(info) and info.atexit + + @atexit.setter + def atexit(self, value): + info = self._registry.get(self) + if info: + info.atexit = bool(value) + + def __repr__(self): + info = self._registry.get(self) + obj = info and info.weakref() + if obj is None: + return "<%s object at %#x; dead>" % (type(self).__name__, id(self)) + else: + return "<%s object at %#x; for %r at %#x>" % ( + type(self).__name__, + id(self), + type(obj).__name__, + id(obj), + ) + + @classmethod + def _select_for_exit(cls): + # Return live finalizers marked for exit, oldest first + L = [(f, i) for (f, i) in cls._registry.items() if i.atexit] + L.sort(key=lambda item: item[1].index) + return [f for (f, i) in L] + + @classmethod + def _exitfunc(cls): + # At shutdown invoke finalizers for which atexit is true. + # This is called once all other non-daemonic threads have been + # joined. + reenable_gc = False + try: + if cls._registry: + import gc + + if gc.isenabled(): + reenable_gc = True + gc.disable() + pending = None + while True: + if pending is None or weakref_finalize._dirty: + pending = cls._select_for_exit() + weakref_finalize._dirty = False + if not pending: + break + f = pending.pop() + try: + # gc is disabled, so (assuming no daemonic + # threads) the following is the only line in + # this function which might trigger creation + # of a new finalizer + f() + except Exception: + sys.excepthook(*sys.exc_info()) + assert f not in cls._registry + finally: + # prevent any more finalizers from executing during shutdown + weakref_finalize._shutdown = True + if reenable_gc: + gc.enable() diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py new file mode 100644 index 0000000..f099a3d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py @@ -0,0 +1,1076 @@ +# Copyright (c) 2010-2020 Benjamin Peterson +# +# 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. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.16.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = (str,) + integer_types = (int,) + class_types = (type,) + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = (basestring,) + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + + get_source = get_code # same as get_code + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute( + "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse" + ), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute( + "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload" + ), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute( + "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest" + ), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule( + "collections_abc", + "collections", + "collections.abc" if sys.version_info >= (3, 3) else "collections", + ), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule( + "_dummy_thread", + "dummy_thread", + "_dummy_thread" if sys.version_info < (3, 9) else "_thread", + ), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule( + "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart" + ), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute( + "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes" + ), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", + "moves.urllib.parse", +) + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", + "moves.urllib.error", +) + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", + "moves.urllib.request", +) + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", + "moves.urllib.response", +) + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = ( + _urllib_robotparser_moved_attributes +) + +_importer._add_module( + Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", + "moves.urllib.robotparser", +) + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ["parse", "error", "request", "response", "robotparser"] + + +_importer._add_module( + Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib" +) + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + + def advance_iterator(it): + return it.next() + + +next = advance_iterator + + +try: + callable = callable +except NameError: + + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc( + get_unbound_function, """Get the function out of a possibly unbound function""" +) + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc( + iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary." +) + + +if PY3: + + def b(s): + return s.encode("latin-1") + + def u(s): + return s + + unichr = chr + import struct + + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + + def b(s): + return s + + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") + + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec ("""exec _code_ in _globs_, _locs_""") + + exec_( + """def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""" + ) + + +if sys.version_info[:2] > (3,): + exec_( + """def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""" + ) +else: + + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if ( + isinstance(fp, file) + and isinstance(data, unicode) + and fp.encoding is not None + ): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) + + +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper( + wrapper, + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps( + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + return functools.partial( + _update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated + ) + + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d["__orig_bases__"] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + + return type.__new__(metaclass, "temporary_class", (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get("__slots__") + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop("__dict__", None) + orig_vars.pop("__weakref__", None) + if hasattr(cls, "__qualname__"): + orig_vars["__qualname__"] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + + return wrapper + + +def ensure_binary(s, encoding="utf-8", errors="strict"): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, binary_type): + return s + if isinstance(s, text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding="utf-8", errors="strict"): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + # Optimization: Fast return for the common case. + if type(s) is str: + return s + if PY2 and isinstance(s, text_type): + return s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + return s + + +def ensure_text(s, encoding="utf-8", errors="strict"): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if "__str__" not in klass.__dict__: + raise ValueError( + "@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % klass.__name__ + ) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode("utf-8") + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if ( + type(importer).__name__ == "_SixMetaPathImporter" + and importer.name == __name__ + ): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py new file mode 100644 index 0000000..fb51bf7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py @@ -0,0 +1,540 @@ +from __future__ import absolute_import + +import collections +import functools +import logging + +from ._collections import HTTPHeaderDict, RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme +from .exceptions import ( + LocationValueError, + MaxRetryError, + ProxySchemeUnknown, + ProxySchemeUnsupported, + URLSchemeUnknown, +) +from .packages import six +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.proxy import connection_requires_http_tunnel +from .util.retry import Retry +from .util.url import parse_url + +__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"] + + +log = logging.getLogger(__name__) + +SSL_KEYWORDS = ( + "key_file", + "cert_file", + "cert_reqs", + "ca_certs", + "ssl_version", + "ca_cert_dir", + "ssl_context", + "key_password", + "server_hostname", +) + +# All known keyword arguments that could be provided to the pool manager, its +# pools, or the underlying connections. This is used to construct a pool key. +_key_fields = ( + "key_scheme", # str + "key_host", # str + "key_port", # int + "key_timeout", # int or float or Timeout + "key_retries", # int or Retry + "key_strict", # bool + "key_block", # bool + "key_source_address", # str + "key_key_file", # str + "key_key_password", # str + "key_cert_file", # str + "key_cert_reqs", # str + "key_ca_certs", # str + "key_ssl_version", # str + "key_ca_cert_dir", # str + "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext + "key_maxsize", # int + "key_headers", # dict + "key__proxy", # parsed proxy url + "key__proxy_headers", # dict + "key__proxy_config", # class + "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples + "key__socks_options", # dict + "key_assert_hostname", # bool or string + "key_assert_fingerprint", # str + "key_server_hostname", # str +) + +#: The namedtuple class used to construct keys for the connection pool. +#: All custom key schemes should include the fields in this key at a minimum. +PoolKey = collections.namedtuple("PoolKey", _key_fields) + +_proxy_config_fields = ("ssl_context", "use_forwarding_for_https") +ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields) + + +def _default_key_normalizer(key_class, request_context): + """ + Create a pool key out of a request context dictionary. + + According to RFC 3986, both the scheme and host are case-insensitive. + Therefore, this function normalizes both before constructing the pool + key for an HTTPS request. If you wish to change this behaviour, provide + alternate callables to ``key_fn_by_scheme``. + + :param key_class: + The class to use when constructing the key. This should be a namedtuple + with the ``scheme`` and ``host`` keys at a minimum. + :type key_class: namedtuple + :param request_context: + A dictionary-like object that contain the context for a request. + :type request_context: dict + + :return: A namedtuple that can be used as a connection pool key. + :rtype: PoolKey + """ + # Since we mutate the dictionary, make a copy first + context = request_context.copy() + context["scheme"] = context["scheme"].lower() + context["host"] = context["host"].lower() + + # These are both dictionaries and need to be transformed into frozensets + for key in ("headers", "_proxy_headers", "_socks_options"): + if key in context and context[key] is not None: + context[key] = frozenset(context[key].items()) + + # The socket_options key may be a list and needs to be transformed into a + # tuple. + socket_opts = context.get("socket_options") + if socket_opts is not None: + context["socket_options"] = tuple(socket_opts) + + # Map the kwargs to the names in the namedtuple - this is necessary since + # namedtuples can't have fields starting with '_'. + for key in list(context.keys()): + context["key_" + key] = context.pop(key) + + # Default to ``None`` for keys missing from the context + for field in key_class._fields: + if field not in context: + context[field] = None + + return key_class(**context) + + +#: A dictionary that maps a scheme to a callable that creates a pool key. +#: This can be used to alter the way pool keys are constructed, if desired. +#: Each PoolManager makes a copy of this dictionary so they can be configured +#: globally here, or individually on the instance. +key_fn_by_scheme = { + "http": functools.partial(_default_key_normalizer, PoolKey), + "https": functools.partial(_default_key_normalizer, PoolKey), +} + +pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool} + + +class PoolManager(RequestMethods): + """ + Allows for arbitrary requests while transparently keeping track of + necessary connection pools for you. + + :param num_pools: + Number of connection pools to cache before discarding the least + recently used pool. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param \\**connection_pool_kw: + Additional parameters are used to create fresh + :class:`urllib3.connectionpool.ConnectionPool` instances. + + Example:: + + >>> manager = PoolManager(num_pools=2) + >>> r = manager.request('GET', 'http://google.com/') + >>> r = manager.request('GET', 'http://google.com/mail') + >>> r = manager.request('GET', 'http://yahoo.com/') + >>> len(manager.pools) + 2 + + """ + + proxy = None + proxy_config = None + + def __init__(self, num_pools=10, headers=None, **connection_pool_kw): + RequestMethods.__init__(self, headers) + self.connection_pool_kw = connection_pool_kw + self.pools = RecentlyUsedContainer(num_pools) + + # Locally set the pool classes and keys so other PoolManagers can + # override them. + self.pool_classes_by_scheme = pool_classes_by_scheme + self.key_fn_by_scheme = key_fn_by_scheme.copy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.clear() + # Return False to re-raise any potential exceptions + return False + + def _new_pool(self, scheme, host, port, request_context=None): + """ + Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and + any additional pool keyword arguments. + + If ``request_context`` is provided, it is provided as keyword arguments + to the pool class used. This method is used to actually create the + connection pools handed out by :meth:`connection_from_url` and + companion methods. It is intended to be overridden for customization. + """ + pool_cls = self.pool_classes_by_scheme[scheme] + if request_context is None: + request_context = self.connection_pool_kw.copy() + + # Although the context has everything necessary to create the pool, + # this function has historically only used the scheme, host, and port + # in the positional args. When an API change is acceptable these can + # be removed. + for key in ("scheme", "host", "port"): + request_context.pop(key, None) + + if scheme == "http": + for kw in SSL_KEYWORDS: + request_context.pop(kw, None) + + return pool_cls(host, port, **request_context) + + def clear(self): + """ + Empty our store of pools and direct them all to close. + + This will not affect in-flight connections, but they will not be + re-used after completion. + """ + self.pools.clear() + + def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme. + + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is + provided, it is merged with the instance's ``connection_pool_kw`` + variable and used to create the new connection pool, if one is + needed. + """ + + if not host: + raise LocationValueError("No host specified.") + + request_context = self._merge_pool_kwargs(pool_kwargs) + request_context["scheme"] = scheme or "http" + if not port: + port = port_by_scheme.get(request_context["scheme"].lower(), 80) + request_context["port"] = port + request_context["host"] = host + + return self.connection_from_context(request_context) + + def connection_from_context(self, request_context): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context. + + ``request_context`` must at least contain the ``scheme`` key and its + value must be a key in ``key_fn_by_scheme`` instance variable. + """ + scheme = request_context["scheme"].lower() + pool_key_constructor = self.key_fn_by_scheme.get(scheme) + if not pool_key_constructor: + raise URLSchemeUnknown(scheme) + pool_key = pool_key_constructor(request_context) + + return self.connection_from_pool_key(pool_key, request_context=request_context) + + def connection_from_pool_key(self, pool_key, request_context=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key. + + ``pool_key`` should be a namedtuple that only contains immutable + objects. At a minimum it must have the ``scheme``, ``host``, and + ``port`` fields. + """ + with self.pools.lock: + # If the scheme, host, or port doesn't match existing open + # connections, open a new ConnectionPool. + pool = self.pools.get(pool_key) + if pool: + return pool + + # Make a fresh ConnectionPool of the desired type + scheme = request_context["scheme"] + host = request_context["host"] + port = request_context["port"] + pool = self._new_pool(scheme, host, port, request_context=request_context) + self.pools[pool_key] = pool + + return pool + + def connection_from_url(self, url, pool_kwargs=None): + """ + Similar to :func:`urllib3.connectionpool.connection_from_url`. + + If ``pool_kwargs`` is not provided and a new pool needs to be + constructed, ``self.connection_pool_kw`` is used to initialize + the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs`` + is provided, it is used instead. Note that if a new pool does not + need to be created for the request, the provided ``pool_kwargs`` are + not used. + """ + u = parse_url(url) + return self.connection_from_host( + u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs + ) + + def _merge_pool_kwargs(self, override): + """ + Merge a dictionary of override values for self.connection_pool_kw. + + This does not modify self.connection_pool_kw and returns a new dict. + Any keys in the override dictionary with a value of ``None`` are + removed from the merged dictionary. + """ + base_pool_kwargs = self.connection_pool_kw.copy() + if override: + for key, value in override.items(): + if value is None: + try: + del base_pool_kwargs[key] + except KeyError: + pass + else: + base_pool_kwargs[key] = value + return base_pool_kwargs + + def _proxy_requires_url_absolute_form(self, parsed_url): + """ + Indicates if the proxy requires the complete destination URL in the + request. Normally this is only needed when not using an HTTP CONNECT + tunnel. + """ + if self.proxy is None: + return False + + return not connection_requires_http_tunnel( + self.proxy, self.proxy_config, parsed_url.scheme + ) + + def _validate_proxy_scheme_url_selection(self, url_scheme): + """ + Validates that were not attempting to do TLS in TLS connections on + Python2 or with unsupported SSL implementations. + """ + if self.proxy is None or url_scheme != "https": + return + + if self.proxy.scheme != "https": + return + + if six.PY2 and not self.proxy_config.use_forwarding_for_https: + raise ProxySchemeUnsupported( + "Contacting HTTPS destinations through HTTPS proxies " + "'via CONNECT tunnels' is not supported in Python 2" + ) + + def urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. + + The given ``url`` parameter must be absolute, such that an appropriate + :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. + """ + u = parse_url(url) + self._validate_proxy_scheme_url_selection(u.scheme) + + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + kw["assert_same_host"] = False + kw["redirect"] = False + + if "headers" not in kw: + kw["headers"] = self.headers.copy() + + if self._proxy_requires_url_absolute_form(u): + response = conn.urlopen(method, url, **kw) + else: + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + + if response.status == 303: + # Change the method according to RFC 9110, Section 15.4.4. + method = "GET" + # And lose the body not to transfer anything sensitive. + kw["body"] = None + kw["headers"] = HTTPHeaderDict(kw["headers"])._prepare_for_method_change() + + retries = kw.get("retries") + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect) + + # Strip headers marked as unsafe to forward to the redirected location. + # Check remove_headers_on_redirect to avoid a potential network call within + # conn.is_same_host() which may use socket.gethostbyname() in the future. + if retries.remove_headers_on_redirect and not conn.is_same_host( + redirect_location + ): + headers = list(six.iterkeys(kw["headers"])) + for header in headers: + if header.lower() in retries.remove_headers_on_redirect: + kw["headers"].pop(header, None) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + kw["retries"] = retries + kw["redirect"] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + + response.drain_conn() + return self.urlopen(method, redirect_location, **kw) + + +class ProxyManager(PoolManager): + """ + Behaves just like :class:`PoolManager`, but sends all requests through + the defined proxy, using the CONNECT method for HTTPS URLs. + + :param proxy_url: + The URL of the proxy to be used. + + :param proxy_headers: + A dictionary containing headers that will be sent to the proxy. In case + of HTTP they are being sent with each request, while in the + HTTPS/CONNECT case they are sent only once. Could be used for proxy + authentication. + + :param proxy_ssl_context: + The proxy SSL context is used to establish the TLS connection to the + proxy when using HTTPS proxies. + + :param use_forwarding_for_https: + (Defaults to False) If set to True will forward requests to the HTTPS + proxy to be made on behalf of the client instead of creating a TLS + tunnel via the CONNECT method. **Enabling this flag means that request + and response headers and content will be visible from the HTTPS proxy** + whereas tunneling keeps request and response headers and content + private. IP address, target hostname, SNI, and port are always visible + to an HTTPS proxy even when this flag is disabled. + + Example: + >>> proxy = urllib3.ProxyManager('http://localhost:3128/') + >>> r1 = proxy.request('GET', 'http://google.com/') + >>> r2 = proxy.request('GET', 'http://httpbin.org/') + >>> len(proxy.pools) + 1 + >>> r3 = proxy.request('GET', 'https://httpbin.org/') + >>> r4 = proxy.request('GET', 'https://twitter.com/') + >>> len(proxy.pools) + 3 + + """ + + def __init__( + self, + proxy_url, + num_pools=10, + headers=None, + proxy_headers=None, + proxy_ssl_context=None, + use_forwarding_for_https=False, + **connection_pool_kw + ): + + if isinstance(proxy_url, HTTPConnectionPool): + proxy_url = "%s://%s:%i" % ( + proxy_url.scheme, + proxy_url.host, + proxy_url.port, + ) + proxy = parse_url(proxy_url) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + if not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + self.proxy_ssl_context = proxy_ssl_context + self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https) + + connection_pool_kw["_proxy"] = self.proxy + connection_pool_kw["_proxy_headers"] = self.proxy_headers + connection_pool_kw["_proxy_config"] = self.proxy_config + + super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw) + + def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): + if scheme == "https": + return super(ProxyManager, self).connection_from_host( + host, port, scheme, pool_kwargs=pool_kwargs + ) + + return super(ProxyManager, self).connection_from_host( + self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs + ) + + def _set_proxy_headers(self, url, headers=None): + """ + Sets headers needed by proxies: specifically, the Accept and Host + headers. Only sets headers not provided by the user. + """ + headers_ = {"Accept": "*/*"} + + netloc = parse_url(url).netloc + if netloc: + headers_["Host"] = netloc + + if headers: + headers_.update(headers) + return headers_ + + def urlopen(self, method, url, redirect=True, **kw): + "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." + u = parse_url(url) + if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme): + # For connections using HTTP CONNECT, httplib sets the necessary + # headers on the CONNECT to the proxy. If we're not using CONNECT, + # we'll definitely need to set 'Host' at the very least. + headers = kw.get("headers", self.headers) + kw["headers"] = self._set_proxy_headers(url, headers) + + return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) + + +def proxy_from_url(url, **kw): + return ProxyManager(proxy_url=url, **kw) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/request.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/request.py new file mode 100644 index 0000000..3b4cf99 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/request.py @@ -0,0 +1,191 @@ +from __future__ import absolute_import + +import sys + +from .filepost import encode_multipart_formdata +from .packages import six +from .packages.six.moves.urllib.parse import urlencode + +__all__ = ["RequestMethods"] + + +class RequestMethods(object): + """ + Convenience mixin for classes who implement a :meth:`urlopen` method, such + as :class:`urllib3.HTTPConnectionPool` and + :class:`urllib3.PoolManager`. + + Provides behavior for making common types of HTTP request methods and + decides which type of request field encoding to use. + + Specifically, + + :meth:`.request_encode_url` is for sending requests whose fields are + encoded in the URL (such as GET, HEAD, DELETE). + + :meth:`.request_encode_body` is for sending requests whose fields are + encoded in the *body* of the request using multipart or www-form-urlencoded + (such as for POST, PUT, PATCH). + + :meth:`.request` is for making any kind of request, it will look up the + appropriate encoding format and use one of the above two methods to make + the request. + + Initializer parameters: + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + """ + + _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"} + + def __init__(self, headers=None): + self.headers = headers or {} + + def urlopen( + self, + method, + url, + body=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **kw + ): # Abstract + raise NotImplementedError( + "Classes extending RequestMethods must implement " + "their own ``urlopen`` method." + ) + + def request(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the appropriate encoding of + ``fields`` based on the ``method`` used. + + This is a convenience method that requires the least amount of manual + effort. It can be used in most situations, while still having the + option to drop down to more specific methods when necessary, such as + :meth:`request_encode_url`, :meth:`request_encode_body`, + or even the lowest level :meth:`urlopen`. + """ + method = method.upper() + + urlopen_kw["request_url"] = url + + if method in self._encode_url_methods: + return self.request_encode_url( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + else: + return self.request_encode_body( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + + def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the url. This is useful for request methods like GET, HEAD, DELETE, etc. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": headers} + extra_kw.update(urlopen_kw) + + if fields: + url += "?" + urlencode(fields) + + return self.urlopen(method, url, **extra_kw) + + def request_encode_body( + self, + method, + url, + fields=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **urlopen_kw + ): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the body. This is useful for request methods like POST, PUT, PATCH, etc. + + When ``encode_multipart=True`` (default), then + :func:`urllib3.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :func:`urllib.parse.urlencode` is used with the + 'application/x-www-form-urlencoded' content type. + + Multipart encoding must be used when posting files, and it's reasonably + safe to use it in other times too. However, it may break request + signing, such as with OAuth. + + Supports an optional ``fields`` parameter of key/value strings AND + key/filetuple. A filetuple is a (filename, data, MIME type) tuple where + the MIME type is optional. For example:: + + fields = { + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), + 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + } + + When uploading a file, providing a filename (the first parameter of the + tuple) is optional but recommended to best mimic behavior of browsers. + + Note that if ``headers`` are supplied, the 'Content-Type' header will + be overwritten because it depends on the dynamic random boundary string + which is used to compose the body of the request. The random boundary + string can be explicitly set with the ``multipart_boundary`` parameter. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": {}} + + if fields: + if "body" in urlopen_kw: + raise TypeError( + "request got values for both 'fields' and 'body', can only specify one." + ) + + if encode_multipart: + body, content_type = encode_multipart_formdata( + fields, boundary=multipart_boundary + ) + else: + body, content_type = ( + urlencode(fields), + "application/x-www-form-urlencoded", + ) + + extra_kw["body"] = body + extra_kw["headers"] = {"Content-Type": content_type} + + extra_kw["headers"].update(headers) + extra_kw.update(urlopen_kw) + + return self.urlopen(method, url, **extra_kw) + + +if not six.PY2: + + class RequestModule(sys.modules[__name__].__class__): + def __call__(self, *args, **kwargs): + """ + If user tries to call this module directly urllib3 v2.x style raise an error to the user + suggesting they may need urllib3 v2 + """ + raise TypeError( + "'module' object is not callable\n" + "urllib3.request() method is not supported in this release, " + "upgrade to urllib3 v2 to use it\n" + "see https://urllib3.readthedocs.io/en/stable/v2-migration-guide.html" + ) + + sys.modules[__name__].__class__ = RequestModule diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/response.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/response.py new file mode 100644 index 0000000..8909f84 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/response.py @@ -0,0 +1,879 @@ +from __future__ import absolute_import + +import io +import logging +import sys +import warnings +import zlib +from contextlib import contextmanager +from socket import error as SocketError +from socket import timeout as SocketTimeout + +brotli = None + +from . import util +from ._collections import HTTPHeaderDict +from .connection import BaseSSLError, HTTPException +from .exceptions import ( + BodyNotHttplibCompatible, + DecodeError, + HTTPError, + IncompleteRead, + InvalidChunkLength, + InvalidHeader, + ProtocolError, + ReadTimeoutError, + ResponseNotChunked, + SSLError, +) +from .packages import six +from .util.response import is_fp_closed, is_response_to_head + +log = logging.getLogger(__name__) + + +class DeflateDecoder(object): + def __init__(self): + self._first_try = True + self._data = b"" + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + + if not self._first_try: + return self._obj.decompress(data) + + self._data += data + try: + decompressed = self._obj.decompress(data) + if decompressed: + self._first_try = False + self._data = None + return decompressed + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: + return self.decompress(self._data) + finally: + self._data = None + + +class GzipDecoderState(object): + + FIRST_MEMBER = 0 + OTHER_MEMBERS = 1 + SWALLOW_DATA = 2 + + +class GzipDecoder(object): + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + self._state = GzipDecoderState.FIRST_MEMBER + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + ret = bytearray() + if self._state == GzipDecoderState.SWALLOW_DATA or not data: + return bytes(ret) + while True: + try: + ret += self._obj.decompress(data) + except zlib.error: + previous_state = self._state + # Ignore data after the first error + self._state = GzipDecoderState.SWALLOW_DATA + if previous_state == GzipDecoderState.OTHER_MEMBERS: + # Allow trailing garbage acceptable in other gzip clients + return bytes(ret) + raise + data = self._obj.unused_data + if not data: + return bytes(ret) + self._state = GzipDecoderState.OTHER_MEMBERS + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + +if brotli is not None: + + class BrotliDecoder(object): + # Supports both 'brotlipy' and 'Brotli' packages + # since they share an import name. The top branches + # are for 'brotlipy' and bottom branches for 'Brotli' + def __init__(self): + self._obj = brotli.Decompressor() + if hasattr(self._obj, "decompress"): + self.decompress = self._obj.decompress + else: + self.decompress = self._obj.process + + def flush(self): + if hasattr(self._obj, "flush"): + return self._obj.flush() + return b"" + + +class MultiDecoder(object): + """ + From RFC7231: + If one or more encodings have been applied to a representation, the + sender that applied the encodings MUST generate a Content-Encoding + header field that lists the content codings in the order in which + they were applied. + """ + + def __init__(self, modes): + self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] + + def flush(self): + return self._decoders[0].flush() + + def decompress(self, data): + for d in reversed(self._decoders): + data = d.decompress(data) + return data + + +def _get_decoder(mode): + if "," in mode: + return MultiDecoder(mode) + + if mode == "gzip": + return GzipDecoder() + + if brotli is not None and mode == "br": + return BrotliDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is + loaded and decoded on-demand when the ``data`` property is accessed. This + class is also compatible with the Python standard library's :mod:`io` + module, and can hence be treated as a readable object in the context of that + framework. + + Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param original_response: + When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse` + object, it's convenient to include the original for debug purposes. It's + otherwise unused. + + :param retries: + The retries contains the last :class:`~urllib3.util.retry.Retry` that + was used during the request. + + :param enforce_content_length: + Enforce content length checking. Body returned by server must match + value of Content-Length header, if present. Otherwise, raise error. + """ + + CONTENT_DECODERS = ["gzip", "deflate"] + if brotli is not None: + CONTENT_DECODERS += ["br"] + REDIRECT_STATUSES = [301, 302, 303, 307, 308] + + def __init__( + self, + body="", + headers=None, + status=0, + version=0, + reason=None, + strict=0, + preload_content=True, + decode_content=True, + original_response=None, + pool=None, + connection=None, + msg=None, + retries=None, + enforce_content_length=False, + request_method=None, + request_url=None, + auto_close=True, + ): + + if isinstance(headers, HTTPHeaderDict): + self.headers = headers + else: + self.headers = HTTPHeaderDict(headers) + self.status = status + self.version = version + self.reason = reason + self.strict = strict + self.decode_content = decode_content + self.retries = retries + self.enforce_content_length = enforce_content_length + self.auto_close = auto_close + + self._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + self.msg = msg + self._request_url = request_url + + if body and isinstance(body, (six.string_types, bytes)): + self._body = body + + self._pool = pool + self._connection = connection + + if hasattr(body, "read"): + self._fp = body + + # Are we using the chunked-style of transfer encoding? + self.chunked = False + self.chunk_left = None + tr_enc = self.headers.get("transfer-encoding", "").lower() + # Don't incur the penalty of creating a list and then discarding it + encodings = (enc.strip() for enc in tr_enc.split(",")) + if "chunked" in encodings: + self.chunked = True + + # Determine length of response + self.length_remaining = self._init_length(request_method) + + # If requested, preload the body. + if preload_content and not self._body: + self._body = self.read(decode_content=decode_content) + + def get_redirect_location(self): + """ + Should we redirect and where to? + + :returns: Truthy redirect location string if we got a redirect status + code and valid location. ``None`` if redirect status and no + location. ``False`` if not a redirect status code. + """ + if self.status in self.REDIRECT_STATUSES: + return self.headers.get("location") + + return False + + def release_conn(self): + if not self._pool or not self._connection: + return + + self._pool._put_conn(self._connection) + self._connection = None + + def drain_conn(self): + """ + Read and discard any remaining HTTP response data in the response connection. + + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: + self.read() + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + + @property + def data(self): + # For backwards-compat with earlier urllib3 0.4 and earlier. + if self._body: + return self._body + + if self._fp: + return self.read(cache_content=True) + + @property + def connection(self): + return self._connection + + def isclosed(self): + return is_fp_closed(self._fp) + + def tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``urllib3.response.HTTPResponse.read`` + if bytes are encoded on the wire (e.g, compressed). + """ + return self._fp_bytes_read + + def _init_length(self, request_method): + """ + Set initial length value for Response content if available. + """ + length = self.headers.get("content-length") + + if length is not None: + if self.chunked: + # This Response will fail with an IncompleteRead if it can't be + # received as chunked. This method falls back to attempt reading + # the response before raising an exception. + log.warning( + "Received response with both Content-Length and " + "Transfer-Encoding set. This is expressly forbidden " + "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " + "attempting to process response as Transfer-Encoding: " + "chunked." + ) + return None + + try: + # RFC 7230 section 3.3.2 specifies multiple content lengths can + # be sent in a single Content-Length header + # (e.g. Content-Length: 42, 42). This line ensures the values + # are all valid ints and that as long as the `set` length is 1, + # all values are the same. Otherwise, the header is invalid. + lengths = set([int(val) for val in length.split(",")]) + if len(lengths) > 1: + raise InvalidHeader( + "Content-Length contained multiple " + "unmatching values (%s)" % length + ) + length = lengths.pop() + except ValueError: + length = None + else: + if length < 0: + length = None + + # Convert status to int for comparison + # In some cases, httplib returns a status of "_UNKNOWN" + try: + status = int(self.status) + except ValueError: + status = 0 + + # Check for responses that shouldn't include a body + if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD": + length = 0 + + return length + + def _init_decoder(self): + """ + Set-up the _decoder attribute if necessary. + """ + # Note: content-encoding value should be case-insensitive, per RFC 7230 + # Section 3.2 + content_encoding = self.headers.get("content-encoding", "").lower() + if self._decoder is None: + if content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + elif "," in content_encoding: + encodings = [ + e.strip() + for e in content_encoding.split(",") + if e.strip() in self.CONTENT_DECODERS + ] + if len(encodings): + self._decoder = _get_decoder(content_encoding) + + DECODER_ERROR_CLASSES = (IOError, zlib.error) + if brotli is not None: + DECODER_ERROR_CLASSES += (brotli.error,) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + if not decode_content: + return data + + try: + if self._decoder: + data = self._decoder.decompress(data) + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( + "Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding, + e, + ) + if flush_decoder: + data += self._flush_decoder() + + return data + + def _flush_decoder(self): + """ + Flushes the decoder. Should only be called if the decoder is actually + being used. + """ + if self._decoder: + buf = self._decoder.decompress(b"") + return buf + self._decoder.flush() + + return b"" + + @contextmanager + def _error_catcher(self): + """ + Catch low-level python exceptions, instead re-raising urllib3 + variants, so that low-level exceptions are not leaked in the + high-level api. + + On exit, release the connection back to the pool. + """ + clean_exit = False + + try: + try: + yield + + except SocketTimeout: + # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but + # there is yet no clean way to get at it from this context. + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except BaseSSLError as e: + # FIXME: Is there a better way to differentiate between SSLErrors? + if "read operation timed out" not in str(e): + # SSL errors related to framing/MAC get wrapped and reraised here + raise SSLError(e) + + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except (HTTPException, SocketError) as e: + # This includes IncompleteRead. + raise ProtocolError("Connection broken: %r" % e, e) + + # If no exception is thrown, we should avoid cleaning up + # unnecessarily. + clean_exit = True + finally: + # If we didn't terminate cleanly, we need to throw away our + # connection. + if not clean_exit: + # The response may not be closed but we're not going to use it + # anymore so close it now to ensure that the connection is + # released back to the pool. + if self._original_response: + self._original_response.close() + + # Closing the response may not actually be sufficient to close + # everything, so if we have a hold of the connection close that + # too. + if self._connection: + self._connection.close() + + # If we hold the original response but it's closed now, we should + # return the connection back to the pool. + if self._original_response and self._original_response.isclosed(): + self.release_conn() + + def _fp_read(self, amt): + """ + Read a response with the thought that reading the number of bytes + larger than can fit in a 32-bit int at a time via SSL in some + known cases leads to an overflow error that has to be prevented + if `amt` or `self.length_remaining` indicate that a problem may + happen. + + The known cases: + * 3.8 <= CPython < 3.9.7 because of a bug + https://github.com/urllib3/urllib3/issues/2513#issuecomment-1152559900. + * urllib3 injected with pyOpenSSL-backed SSL-support. + * CPython < 3.10 only when `amt` does not fit 32-bit int. + """ + assert self._fp + c_int_max = 2 ** 31 - 1 + if ( + ( + (amt and amt > c_int_max) + or (self.length_remaining and self.length_remaining > c_int_max) + ) + and not util.IS_SECURETRANSPORT + and (util.IS_PYOPENSSL or sys.version_info < (3, 10)) + ): + buffer = io.BytesIO() + # Besides `max_chunk_amt` being a maximum chunk size, it + # affects memory overhead of reading a response by this + # method in CPython. + # `c_int_max` equal to 2 GiB - 1 byte is the actual maximum + # chunk size that does not lead to an overflow error, but + # 256 MiB is a compromise. + max_chunk_amt = 2 ** 28 + while amt is None or amt != 0: + if amt is not None: + chunk_amt = min(amt, max_chunk_amt) + amt -= chunk_amt + else: + chunk_amt = max_chunk_amt + data = self._fp.read(chunk_amt) + if not data: + break + buffer.write(data) + del data # to reduce peak memory usage by `max_chunk_amt`. + return buffer.getvalue() + else: + # StringIO doesn't like amt=None + return self._fp.read(amt) if amt is not None else self._fp.read() + + def read(self, amt=None, decode_content=None, cache_content=False): + """ + Similar to :meth:`http.client.HTTPResponse.read`, but with two additional + parameters: ``decode_content`` and ``cache_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param cache_content: + If True, will save the returned data such that the same result is + returned despite of the state of the underlying file object. This + is useful if you want the ``.data`` property to continue working + after having ``.read()`` the file object. (Overridden if ``amt`` is + set.) + """ + self._init_decoder() + if decode_content is None: + decode_content = self.decode_content + + if self._fp is None: + return + + flush_decoder = False + fp_closed = getattr(self._fp, "closed", False) + + with self._error_catcher(): + data = self._fp_read(amt) if not fp_closed else b"" + if amt is None: + flush_decoder = True + else: + cache_content = False + if ( + amt != 0 and not data + ): # Platform-specific: Buggy versions of Python. + # Close the connection when no data is returned + # + # This is redundant to what httplib/http.client _should_ + # already do. However, versions of python released before + # December 15, 2012 (http://bugs.python.org/issue16298) do + # not properly close the connection in all cases. There is + # no harm in redundantly calling close. + self._fp.close() + flush_decoder = True + if self.enforce_content_length and self.length_remaining not in ( + 0, + None, + ): + # This is an edge case that httplib failed to cover due + # to concerns of backward compatibility. We're + # addressing it here to make sure IncompleteRead is + # raised during streaming, so all calls with incorrect + # Content-Length are caught. + raise IncompleteRead(self._fp_bytes_read, self.length_remaining) + + if data: + self._fp_bytes_read += len(data) + if self.length_remaining is not None: + self.length_remaining -= len(data) + + data = self._decode(data, decode_content, flush_decoder) + + if cache_content: + self._body = data + + return data + + def stream(self, amt=2 ** 16, decode_content=None): + """ + A generator wrapper for the read() method. A call will block until + ``amt`` bytes have been read from the connection or until the + connection is closed. + + :param amt: + How much of the content to read. The generator will return up to + much data per iteration, but may return less. This is particularly + likely when using compressed data. However, the empty string will + never be returned. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + if self.chunked and self.supports_chunked_reads(): + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: + while not is_fp_closed(self._fp): + data = self.read(amt=amt, decode_content=decode_content) + + if data: + yield data + + @classmethod + def from_httplib(ResponseCls, r, **response_kw): + """ + Given an :class:`http.client.HTTPResponse` instance ``r``, return a + corresponding :class:`urllib3.response.HTTPResponse` object. + + Remaining parameters are passed to the HTTPResponse constructor, along + with ``original_response=r``. + """ + headers = r.msg + + if not isinstance(headers, HTTPHeaderDict): + if six.PY2: + # Python 2.7 + headers = HTTPHeaderDict.from_httplib(headers) + else: + headers = HTTPHeaderDict(headers.items()) + + # HTTPResponse objects in Python 3 don't have a .strict attribute + strict = getattr(r, "strict", 0) + resp = ResponseCls( + body=r, + headers=headers, + status=r.status, + version=r.version, + reason=r.reason, + strict=strict, + original_response=r, + **response_kw + ) + return resp + + # Backwards-compatibility methods for http.client.HTTPResponse + def getheaders(self): + warnings.warn( + "HTTPResponse.getheaders() is deprecated and will be removed " + "in urllib3 v2.1.0. Instead access HTTPResponse.headers directly.", + category=DeprecationWarning, + stacklevel=2, + ) + return self.headers + + def getheader(self, name, default=None): + warnings.warn( + "HTTPResponse.getheader() is deprecated and will be removed " + "in urllib3 v2.1.0. Instead use HTTPResponse.headers.get(name, default).", + category=DeprecationWarning, + stacklevel=2, + ) + return self.headers.get(name, default) + + # Backwards compatibility for http.cookiejar + def info(self): + return self.headers + + # Overrides from io.IOBase + def close(self): + if not self.closed: + self._fp.close() + + if self._connection: + self._connection.close() + + if not self.auto_close: + io.IOBase.close(self) + + @property + def closed(self): + if not self.auto_close: + return io.IOBase.closed.__get__(self) + elif self._fp is None: + return True + elif hasattr(self._fp, "isclosed"): + return self._fp.isclosed() + elif hasattr(self._fp, "closed"): + return self._fp.closed + else: + return True + + def fileno(self): + if self._fp is None: + raise IOError("HTTPResponse has no file to get a fileno from") + elif hasattr(self._fp, "fileno"): + return self._fp.fileno() + else: + raise IOError( + "The file-like object this HTTPResponse is wrapped " + "around has no file descriptor" + ) + + def flush(self): + if ( + self._fp is not None + and hasattr(self._fp, "flush") + and not getattr(self._fp, "closed", False) + ): + return self._fp.flush() + + def readable(self): + # This method is required for `io` module compatibility. + return True + + def readinto(self, b): + # This method is required for `io` module compatibility. + temp = self.read(len(b)) + if len(temp) == 0: + return 0 + else: + b[: len(temp)] = temp + return len(temp) + + def supports_chunked_reads(self): + """ + Checks if the underlying file-like object looks like a + :class:`http.client.HTTPResponse` object. We do this by testing for + the fp attribute. If it is present we assume it returns raw chunks as + processed by read_chunked(). + """ + return hasattr(self._fp, "fp") + + def _update_chunk_length(self): + # First, we'll figure out length of a chunk and then + # we'll try to read it from socket. + if self.chunk_left is not None: + return + line = self._fp.fp.readline() + line = line.split(b";", 1)[0] + try: + self.chunk_left = int(line, 16) + except ValueError: + # Invalid chunked protocol response, abort. + self.close() + raise InvalidChunkLength(self, line) + + def _handle_chunk(self, amt): + returned_chunk = None + if amt is None: + chunk = self._fp._safe_read(self.chunk_left) + returned_chunk = chunk + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + elif amt < self.chunk_left: + value = self._fp._safe_read(amt) + self.chunk_left = self.chunk_left - amt + returned_chunk = value + elif amt == self.chunk_left: + value = self._fp._safe_read(amt) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + returned_chunk = value + else: # amt > self.chunk_left + returned_chunk = self._fp._safe_read(self.chunk_left) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + return returned_chunk + + def read_chunked(self, amt=None, decode_content=None): + """ + Similar to :meth:`HTTPResponse.read`, but with an additional + parameter: ``decode_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + self._init_decoder() + # FIXME: Rewrite this method and make it a class with a better structured logic. + if not self.chunked: + raise ResponseNotChunked( + "Response is not chunked. " + "Header 'transfer-encoding: chunked' is missing." + ) + if not self.supports_chunked_reads(): + raise BodyNotHttplibCompatible( + "Body should be http.client.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks." + ) + + with self._error_catcher(): + # Don't bother reading the body of a HEAD request. + if self._original_response and is_response_to_head(self._original_response): + self._original_response.close() + return + + # If a response is already read and closed + # then return immediately. + if self._fp.fp is None: + return + + while True: + self._update_chunk_length() + if self.chunk_left == 0: + break + chunk = self._handle_chunk(amt) + decoded = self._decode( + chunk, decode_content=decode_content, flush_decoder=False + ) + if decoded: + yield decoded + + if decode_content: + # On CPython and PyPy, we should never need to flush the + # decoder. However, on Jython we *might* need to, so + # lets defensively do it anyway. + decoded = self._flush_decoder() + if decoded: # Platform-specific: Jython. + yield decoded + + # Chunk content ends with \r\n: discard it. + while True: + line = self._fp.fp.readline() + if not line: + # Some sites may not end with '\r\n'. + break + if line == b"\r\n": + break + + # We read everything; close the "file". + if self._original_response: + self._original_response.close() + + def geturl(self): + """ + Returns the URL that was the source of this response. + If the request that generated this response redirected, this method + will return the final redirect location. + """ + if self.retries is not None and len(self.retries.history): + return self.retries.history[-1].redirect_location + else: + return self._request_url + + def __iter__(self): + buffer = [] + for chunk in self.stream(decode_content=True): + if b"\n" in chunk: + chunk = chunk.split(b"\n") + yield b"".join(buffer) + chunk[0] + b"\n" + for x in chunk[1:-1]: + yield x + b"\n" + if chunk[-1]: + buffer = [chunk[-1]] + else: + buffer = [] + else: + buffer.append(chunk) + if buffer: + yield b"".join(buffer) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py new file mode 100644 index 0000000..4547fc5 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import + +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers +from .response import is_fp_closed +from .retry import Retry +from .ssl_ import ( + ALPN_PROTOCOLS, + HAS_SNI, + IS_PYOPENSSL, + IS_SECURETRANSPORT, + PROTOCOL_TLS, + SSLContext, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import Timeout, current_time +from .url import Url, get_host, parse_url, split_first +from .wait import wait_for_read, wait_for_write + +__all__ = ( + "HAS_SNI", + "IS_PYOPENSSL", + "IS_SECURETRANSPORT", + "SSLContext", + "PROTOCOL_TLS", + "ALPN_PROTOCOLS", + "Retry", + "Timeout", + "Url", + "assert_fingerprint", + "current_time", + "is_connection_dropped", + "is_fp_closed", + "get_host", + "parse_url", + "make_headers", + "resolve_cert_reqs", + "resolve_ssl_version", + "split_first", + "ssl_wrap_socket", + "wait_for_read", + "wait_for_write", + "SKIP_HEADER", + "SKIPPABLE_HEADERS", +) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d26ecad906cdb8c15dd2ef8fc41f2b99eb8cde3c GIT binary patch literal 1152 zcmZ9LOK%%D5XZTCt=_WaN95Rf13{Fc(IG$%MO#311;nTz30mb4LIAPW()J?cazj#f zeJuJR`WbrZso$cfqBjDD4?X1;ASeR#)R}c00p;O`nce13#WtJ^;T)A70dZjdv)a=ebsRWRzH0&SIG=ZQps< z@$J~KrAiXMw6RK9q*a>osF!!O;D^I0dpR6@Kb*NXI@7^-qv5AW;Oa7b!`UehBd!f3 zsKZ6aDO(C<;JoLGGj8=ouj-nE(R9qFv&npNFc}5Te>n(PFg|qk!+=d+Po~3h5R6<0 zykL0nYBrqD2IF8lnay4O<`kR5!76-qpc2b}w5}5x!?k6{adN_Ss^i4Ew&o!5jI$-~ zX#Uo?&6|)hf}KI3pwYF^IoDyzj9R|owwH7MJeFLotgA0qTJyv*3xQt2>|pD4q_8=8?lAhL+m3;2p=%+J#tmXj#qZ2Ib%8xF;`trJWJqw z=+=rGyFQmCab@UVsuE~5mf(sSXPOo33fRT#;{PWtQV=Y#Cvu{27i*lC3$#Bx*u~jFZYprMwfVBT#*-l Tkr!8_|GuzW%l+i*Cvd}m&RIN9 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d9408e7979e6e4da4e0bab1355490db64fe3b8c GIT binary patch literal 4753 zcmaJ_T}&L;6~6Pc|I5xUiy@AGxHLHSVggQ`kd)Ysh=D*tuxoHz6Ov`vnT1);?yT<2 z8ZX+l*H)w~l~u4*)jafpN|EY{s(ont-c*THsV^p=dNZ=sNJ$^^Mlh8u_n|#^es-~C z^@_ds&iy&(+;h+U&N=+OsVRt{yzu+;%8@uiU(*k_a8BppFQIcANl0Q;lx3zEhW1&N zonj?U;#DroPw_CuNgmac^-g)MzE|~S{ZoGE`y{^_$Ofl^+0ax7z5^ejsj$puo_85F zT8Wj|G$#c=Vx}Te2-XQw80x6h1a*u>a!iV>Gxqwa<|3OAzNH@t#uUU^T~iB&oK&)T zjTqzKvi3xCQq1S&+?NHb0X2@Awo0)qnxf>`IeGTu;%`8 z?I&V!5-P>g{0~s@uq@&y_%X61(o` zw9J&?tAGeoWJ^qiDRKd1xcWvg$N$c=P7eTO0=<9?-tHsRi3rD_i>Syhpex)(w7?|1 zVkfW(VkqZjqd;;xo+JesD`{-Z%Q&Uwa&n5E6)QTHhz9DAu$YsuKCcy23D3eBRnuju zCukAr&x=INTKoE~0ZO?)rHZ=VKQnI_`JR-j$T_2DWODM{nL70utj%VCkwax%Gvs~@ zn!|ZjG(cHd9jnSE84u+1L)LY4gLoj(f}*NeR2Rgej)^5do|zdIRb8H$!G>l@pvs1I z7MB#B2l>?}&PL=^5#-9vVS|V{9nJtEsznT(aY65~$e6qi*El>m=V}w~+-E3RSt}R` z&h*X6hG-as&^JK>P=OurRDUE4A3D7dj2~yt^iSuBHU~<|0>9}6O-pIntV~j1e7VcO zRwKpfSrH5-Cr!im<>@hHc3M{q`K3IJigU6)omcX`Ntlx~(pw;^s?473Ef|X0+qkZt ze9_#e=*h-N(z!hn14%+uq!FkpXtxE0<14SMwyy2l3>~cu)_kFA;d;3yv_P*?stNIJ zmiO%YMmV@SdFSMo(0kY4`{;hCa|bb=eP0SK+Z?oyb$ZC#;ZF2P-~{&v<^-3jTOCaJ z;AdI(7odjQsD!4WE%RkhiOAc(u7%u8I^YtXl2m35~r z`vM5|QqE5miFfxh$e_xwN~YQEHQEwi@|1i=)E&vRxV=WZ?woTFeXs~;@|XP6AWJz= z4wggZaJdPji@^JA@TpU4&?p5;!BVLHz9UAPJ6DR7IQK0x@V58J@|?S-(H0ocS0r?JQoolqEx>jLTB-7rQaeJkvhVDv{6w3g@@Tlay&X&A4m_4V&?v6$) zdELD?7(gYzI|Hb61a5+wq*XH1l%6Vv;0{P&GmBn?Tv}3HKPmPiNaG?KaHwlKgWcVY z7P#WFP!h`CQsjCwoc4vroZEA4iTb2+V(* ztm|DCRyxQ;0hMA1;L#Ik2m9bL11hFuoG#=nxb4CCndFX%`1>yzg*@Qb%*?TQO*guO z6k@5{O3ch8{y#sA&jAoyI0v$5c?#^JY7yvipsWj92re5kvC&m`;M1AM;0pE}M9Jxf z2!dNQW@P|O83PQ;S)fhfRC8Sj9B4F+bD)|!BfxLHkk5lZkSLtnH0D%oR#dShr^SK_ zz-M{dTAba6ZMr z*@A9RZzf_}yILCC>a|sC(W35P&)MN{vkJIEQHNbNW$aJ}N|q|J;w4wx4J5Yx$v_U% z>%+k4=uu2v9b6$kfel$zb&Ji}393Jk-uiM5=Qtzg{YCcu55`Sik#geVp`%Ciqup2) zXJr*r-4`iAL({OT<>nSUsBZ#;RB~y}ag!i&&RMA{x{+u$gK&|=&=(YA-t_1OQSxT9 zsH)n6EG6eeC7Bkpidry*V`twQ7)uTg4G&xxn@moQzBhFC!X$`D zt-$iQCQnsw`W&sA9+`$=rpF3K5>eCVTm)&Nf<&IYclu4AVVxsSZ^Gp14VWBIGQG}e zIe5e-E2d39-C-2-vgrZ$ZD?j7CFa1ni&@!ZbLAV<`yuAjE9g z0XYfdN8qPVfxD}q?M~FZ|N1+X!D=VC-jAUT}9n~eny-jDCUefrkvwdS>--YIOxU#$-AdQlTz{0XOO(U#l7En&^K6+QN)aEN{eZUt6*wxWqzIJ!KxG`8Bj6+T#t zxBcwh?L#Q~4zt~j{GrOVS|nBtd=rc=cQ19{ZR_6*zHyg-SZ3kffvEBtb{&Q@QMW6N$93MQ%e#RajJi&d|%h38{eCS2b z=ib(#4$tQu9_XiNsOA>x-D&*sun#JTTxh%vHF$gQ=w+6LSSI7H-P4xXpCbm{jPs}n z3C1{tiqv+g4S|s-INMx&uEBHA(J2?O8p~M7Vfe5r2|D`spsJvnF9I6$N4^$X;UfKQ zReo7m5?141_z!)@p=jGfScOuwatjTjEaA^X2NDW*9A)+%(HSl8NfbzQ&szGFpDJZI z_5>Vk@sE=<3U{5Bl_SWyGM58@2IyMQ$R(`U{sPS2kgrg{p3#D zPqSxWIC)`w;@r>~N|b`G>k%M$wxGwNR|`9(f%WJ(1$o%_$6oAuVRgkjjJ-d-m4@u*Q;gdR!w>GiRjJtdI;rNeC1gQs9w||n7{zGj<3x*w`#{% zJ>$cK+VW(=Pw2VL7RY%TIlB(VGOJy&@7q5w>PaPkxzF@FH{VA(=$^pPm6UA7LZlPE z;dvf|#(JaVP3S%GG|fQLr9<9=$pyNARu%MBNPzT7XsL_<2>YME=j++<^=$c0z|c3o zrjM`PxV9bk1Y!=-e$x7z_FuPe#$T=uQqUY-8eK6~f3%`(g)yL4b>urg@`ow12bY33 z!?jSna`w?~2u1fp;uVN}8ID5Y6^K37X=bth`oL@G)7JuTaok^72I@twzyIY#+zcj@ z=>nwnaxzIM5;&GmA0ts_ZIuOO_xQT)w*79RX}fiv{>Q?~XzkpVG9)xNu>6+|Ro2^} z>L71G^;=|FzU}w?r?Q$0jvB19bcWdj6lNf5#hV z_HDn8n&S7uT^r#p@FDQ`FmQ@FwR4s6Fo$=dex`Y+^#IfI-6<5_w{l@Kbl|$*;`cw~ C;-5qS literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fed01e16437cc249cc6c6466b3589c6db5ada911 GIT binary patch literal 1558 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b09e3320d5ddf1033190f27aa872bef0f7a335d7 GIT binary patch literal 2998 zcma)8OKcm*8J>OdDUy0W96wg36PIX21yRrdf@)Nel{ihU7?$HSf?8t99g-_AcQ-Rb zNtCHVFnWlP0#=fPbx47r=pliEpr-=86iw1Y(O#%XfaQe(q^OI+H$_T;HmClx%atfO zhYql_^Y~vg`+wiRe@i4{2wM7+>&EXB2>pXkf+jWx2S0|vJ)|RDFi}OA5d=OKO|c@) zNELZThPkB6rcw#bguJn0hAWYoD2zkDL^Clx41HXWK;Kr2W@3-H;f&y>v^=%VD#JOW z;@E^`M0fCN)ntaF5%#h*uMtDD*iFMWHD=h>Wn9Ds<~}jaVEYBTYUvuOP1)>4KJ+&q z@tDDK=M}8!m|W8cHLTJkAvS^4c$qOLS1=81v4X&ZXf_$%52sSW+W(~&I-vwpU8thRbQ9bsiw4rVxY3OG zju6C=k(O9Yg*H*fgdHrcJS)jd^;b z@FBDc-yQYl+}4dUeq52+YJvO6dSX*cnb#~WZ($7F*iFr>`s?s1C5Vag1FPSbCq`!-VwWINa8sIHurV(*wbw?TqUMy#Oy*f6<7X`Oj{AU>^xe z;z6WsPlETidm&j#e3k0FyR^F0hzxv}z@e4-)%o@Aw~pD_iL^b8bvJr`v=tj~$m4rq zZj)xf|D9APdN+Dj`n7OY`b|8GK8cP>e-K8cKPJZ8(5G$D@$=HBg97x&@;(BZUf#b8 zS9uSy!LM8itfqYF);_>0Jtv~N7|fRCmNUw%Jrywe&#frkZ16|e|jE<~Ov97!${_3<0XIWP20?Z|nU;}|F4+*J`W`uaVE!aMP+AZ#k|Ty-{-l z5-ZxIqA^!yu;hlpz6LDkkx3;ecCM1IF-%>FGC~yaNjT^T$5ti;F8mMeMMHSHksj#W za5GLf)C`~34*s=OmGIPddo(X=a=tzs%PWT@4SU~%hkgOw3i{?OYU^Dqy}xk(+_RhK zp52a*>?Zpf{bTq0CpP;h{(Si_eVc75~oNh#>A0~U&O6#=`FKi`;S6a~co0s0eHuM+{y+(J#r}S3a4odkb!Ml%cYENu?H|0}=>O?AlGvTxS5TsB=hWby zf}-tv2t>bbN0HP!L%T`!!@fTywv$th$kd*My43&fcfdB~*YH`#xd~Z5#&-NlJ+_;J z!98B%;eE0J<21Pkp}N2hxi3H{0SxQHEx5jE*q=LOzau*V*XW`z1y%Up9)wR+VIOgC zRx$M;r*Zgsr3Ua!eK>3CmC5nTLj-$Lem-B(EZqd0aP>E zq0d1F)wdfZd+#UCY$ndEyto_gSbOUI^mh2{PO4|UWA%0;a%v~uad&KW?CneIH#g(y zhMYbCJv7C^oXZuftV(b$N4$vJa78oBtWPIC5IH2>*byap$aFh{--j$U7PA$59#g_g zD(T}L|3C1c=EeFEB13$^!)0WwV(V2CUm_#0#;YPtLkIr|g777J>R;&ff1>YyiJspN WofcjY_AiYHuL=jIkPt3-M*atZ$O?P_ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da580ea3f531c3574c58b55f96eb395f270092d1 GIT binary patch literal 21728 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

        2oJ*JnkCJ5YCdhK&4}fQ2 zJ&?xeK2E13k@2V0bPAWEDd+V-Kumzi;gt8VK3Ts=8P$Y@A~0Fc;GMeIX0$5%Ua9e5 z*&xsu!Xj}_a5ZQKATOmLRMuwQkctHoL&Iu+(sr{3TE9bc9(rh z0jLofNMVHR5(ci%f}3NU&G=$-r*IiKr}>A+mzukx0nIH-v*|=q(wylWc)3gqsRbZ< zof~{{q%VHHcZ?w!&80JL&3;)@Wy0l}OUfn*9=mi=Qmffj!jv7T8+B<8S|`n4Mt3b} z$e{W}G|vnuL4?pM%WB2h5^8?N%=HEe9aLIu6F5~R6fj;jUe-*WL7o4IKSe`O;J_~< z`|npBTCF;CJ9+2CT2v3(s#>*RA;1st*>2`1}+*LTY;SLwwb*Q`%7{4F5uo}3qQL*ol z-4+ZzvOB`QEzaTfL6Y9ve7oa*^QqP5Q)|uLYkN)?9W`H7)vug-6N6}5t!i7ViWZ*# z+ArL0D0V%w?thkb*ndCp{A%F&jf#eMUb_8H*7hCW(J$~@pjT&^$#Q;3Ys0wZzd!`s zk}J4W#PnxkoA&27agy9#((b4hGRgx}naVY&Y578Aw^}5lE#fogxu=>F_&!jLJ@LOW zM0QBWB?b)i(~WC!jyAgiCJ>iXNlU5IDa_BLk~8L!o26A2QI+*W%%SYUv`)~`j0CtY z>Hvsw5G4)lL3fybI{T&R1hg>>+4K+!@0kKR=-Q@=n9{2bncOL1@`4mYU>FF7N<$&t z5`Ba&MW$pzoatFeCj~TxGB(;CjDUS-${34)!wh~RBraV7bORy-*wR1RK9Lg^46FqP zlY|&5Oqn{8DRinpza-MfrhdzqQ)(MfqLjkNWnpS0mzAc#4rIVJgQLw$;Egl|41o}3 zB2BPsL7$1f2yE2WOiJsZ%S%9yn7FkdyYXEv+$LZLN(XYXngxWLKfzKw9z zvhRVvy6C9ZrJ;ZHhiOq@tCLP$m4x3Q4J#Vayq5Y4OV9=)$yX^zQ;?y6=q_gwY$J8V z?5_+k%fvoNg=Z4mV-mZe=xO)^i2cJm7gn3P*Q!qMLTtJn%*WzfWDxjM7x6CHo99a0 zi*&@YOSNRaC9Vw1S-R?EKNax7WT%BkL7=Z5P#f2G#UE4}kJYLT?XE##T!fA{!^ zHcCX@WA<^S-i(#rqW$VcP_RZNB+i~2E*SSL-tOgo>=vCjTyYC!F1sMLx?c4_Z~q5; zUk>Maw6^E~?CCJkCC_C;+tb_Ys>CPEF}ck<1ozQFGyh7f87sZ7L`!iqCVI?uU2^7~ zvO7;RvXJc!7w#i(q7s{}H=P#D8%Pmm5=>kLe8- z3xcTMCY|7&V5Am|6LY|?2_X%n1xC%TA?kHLCtpP>p|a+zh~`9W!*tNm=@i*}r)=iMbwQCvtI{SfTZM!jGuKu9Euxq&|F8Qz7O` zlrK%Aj5b2MGIvQ)Qz{0DwVs+PGYd>ju`d(oo|+;GpTv^rH@c8cz^ar^WpRyO%3YJ9 z#&$47i!#<(5-lbH3`9wRwo!z#M%O}HdJ_x|Di}kRGoQk?Gf?+olqSmx4aXu}DYV7{_w$u=a@f-o%*mK11&?&ma2o!B(AF-B*lEGdl) zji`RFm&sgAvr?MiOEbV-z#EtgZs<8olnsVpyD5(`y(LL-gmrYil`&5OW7gpGW3e6E z7=X<9ys-sJAD>`23DD6Tv{8e;B0;%TBBy?u%l6EPsj1E#pDx=_DBRX!+Xm6knm*ie zvk>tIS}~JYx?P|&+Lv@x%d$aUQkoLkK>XaizGL;JK^_bV5Z#RKWZha>>ZlJQC-j8u zIAf`hB-UZ73g-a;1sy?>0Bw*&ADK+n&>lL{MkAIzq8m!=-`K%Rzo9Gi8@ivh$Smw6 z@fjdA*qN_N@x+`uGnq8`ExqaLCe^~DV+j77FIUmtfbbx4rugtnYNsrc5gR=u9X&a z|EmJ`bs%!{Y;oU_JL+2CR59@EmWONYSU&rUK=YQD3mT%97KXhiox2QK6JjfPx)uZx zpC7m|JbHF;Xm}u6tD`Ntmzd^@X~wj0|G;4Hi^G%gzM-*m1LG4q{Gt!b9Tap@aF~K4 z6#Nka;N%5G3m95U7>h^%r@{paNEr#|g@i&NTC?R~n}T6DCFip8Kc(^|1W~tqp5nt4 zP?t<+Dd!Q>g5Xm6OlTtV50R(Pg44bggl7$6?@m;iBujXga7qUPQ1075=D9%KO2-F{ z_v)Y6tc@=FzYgtLX;=##Dx7`b@ZWdTtvc#f-1qjJc<-5Y$H^@h*Lt*gsQZ@ve#L=% z6$d^VDhxevhYBxmR7IBE4?N*pXJADxkD-OPVm)$j)pKy!z2!sV)>EsVCRB0w|8(?~ z(VO$Dj{X09bgP2%R^6JoU(>o;(|XU-`a#S6!#%5qdp=6tJAC%Py|m#87b{!uI3P%m z@U92J$}J}%Rp`8}W7)m#X?g5$IXkxM0dH^h-LF2hT7BrA`_RVzHY#lR%(MR&9^os` z{&kOF<~;@!4lmCa_e9s-hd1}szw3M3_ipIz(CwEY&a*dbE2X|9; z=20W>H_sfP*Z#bx(5RNcWKgtQ5UT=xl#j_6TM4-3d3jIXSEyAjSXfei%KkFtpyMu` zR6MY~+2nS#iJv1%Wa#1)9gX6!B>d;?08fQY@6c((05+v z9n@EJk_yp+^Nvp&kTD()#2>=1gDVMSdytqtHBWdP$)VOAN7m$KEnaqn<LJ9UZxCH7idd5k|DcTPZID@ z=^@N$+^til0$KpD&O#kSqW}oJ1_PAXDNqK%IQ9{uFjOl#;}y5heRppBd%#Aosq_J) zGeEuo{g00ANm~W&x~_oR73h^#tbDSj)tvO+P*uZ`0V~wkTdt&sZa*tzplC}$p$!~E z%6b4)x^19EPbk)Gt>qv!x`E%Izk+d|Oy$CKIsp|ta3zhEScP7L}Oh6*Ey1Y-n2$lp(eaw4c{1+XHHSBV5K z0xhE#%h`&0rSoPSl@z2UEVXX#)G06`p9A~Ssu3T%*MY8Ml$J zvy9M+DK>~&6?q3F(zDsPDJdz50&bSxtZ;5}a%_UtBnb!b2ZseGn+{&5aA^*TWNZ^U z=j{_Zh8`i#G6dD4E_Ot5+*K({f-%huu3EJ3=gMdo#QnZitN3a<|PH2&l zoH}Hh!6Z@dK7d|Qvk6fowT4XBp;k2n_rQU^7sm%C$9qR6#zw~{`)7o^APyJm_<00ny+-U z7_`=SNvnW}A6K%elGB+7`$nWJ%|pYaAt|IWBtEtM(cyS_$7JNcMCCLNhH@PNwBW-$ z7p^ay-5@LtXc~#$Y4|YpcXjJkFD$#ia);kI^H-f)HoJHKMj&!O5M2#K@3epT{LdSI z5g382-!cafr`yY`$nMRX4^{7hc7?2 z+p2xb9!L*?>cZ$_J69dOQ+;RtBi~x2Z`rfqj}%6K_4qQ+RqlDG4$e~#Io`W}6IQz8 zZ*~*|`@Y+8|BU^U4u5~Q z{gZAd#h>;L`0Ss0d4#*0>i#>rfXs|ge|B?gQVx_WyGuCF#FBC)oQr7J?|4ccaZs0A z5`bzU{$1UdEM+>-FMcOca%1}4weMmd(!(6N|7Sn0r6kmjKyhH1`W0@0EZyu6<_o?# zGn+^A^V1B7bIA?fy633UW zC*Wjlm;!rrjY`ip|8KJ$T?}k&=7>6X_XF3Q2_>0I!7-MItJ%jcoM5&V&8b_iU82Oy z?ZTv{fpf#zg}d6|{~Y7US2MW*M_eF5d0C}Y7rI^SoJVm{e{@aw04a{AWd?e-4_ z*6U6@h%~(Q%p1?#KD`#{SoUoC!?)aT1>Xp+%&b+k-K!X1?|ANh$GO#xbAPvItz&%6 zKT&i{{HBe|l0jvBrCf8v%)XFI>3M>FpTonIAIkkD8%({nYn;Nr=D}|>?DWsvg*><5 zaL{jVcIG-;xZ`Ls583Gg$K&6EQ~zB`)U|ln+$pJPA;C}rT^8G*0&Ndm(_I=bYu2#XM?0YsS#8JfLG&2CY!LIJ@Jg@{4dqV8JuFDajb z|3!$2< zycT|@=y~QVckM>F{(iW1HQahz{U}}xx2}cH7d>#IwQ|?OokdS4J38>tBuBXbg~l@| zKa0;tpCE6!={fwO1m1EoEjv@t&EU5fnqwxDNXq{Vd2)dQ!YP{PQYy=M2lJ89ooal# zKn;AV=uU`4I|gQSHyn@oiw}d_K;Oyu2xBa|!jX}jA*28h(%6O3v4Igldif3N>CY(0 zP;ij~fdV34nL_d)lA0d~3?>@`d||;<^XC`3ezTq0(9Nf7EjuX2l$b}Twc|=Im6czn zs7rTTW&SwKY|qTeI)WtpqH{WSG-);AJ?}F7fxLx#9 z`o5hDR&L;bsEWesJsTC(KtvSce`O8*4_7~GNb-F3!(qFRpX49bd-%%7wITk<|9un> zVRFCPI>vb-06o0-Glz%h?EMZX>JQ1PV6|L)2fSCE9bb4(Kd5iL5&qSNzm_mm$42yU z(Q|k?{IgDiQXT(q%a5wx!BtD|yKSSs^`4`SzS#C1m@nnpcwwXIwUHvZZW1p+P5_rx-sIJ~Mz;PcR@C^jHk2_rhP2AtQTmzll-=1;y z+wGs&cnV$4{*e8XAWvbXvwyGslRZ3zjn4k>**|Ia^mo`kIm}bM!`pw_`N=68#k+Zm tpSDx{DJuPxb6ZI9(_mnr(f(-zPhpdLAZq`#ou{y~V&ED3r%&?;|39`NZp{Dy literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5674b540e402123a135843395fdd04ea06d733c6 GIT binary patch literal 5057 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 Q727^^(|L&bj5@^p8(e>*p#T5? literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d3b1a30af3d5460d24fb4039e81dc4748913ee2 GIT binary patch literal 10759 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 make_headers(keep_alive=True, user_agent="Batman/1.0") + {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} + >>> make_headers(accept_encoding=True) + {'accept-encoding': 'gzip,deflate'} + """ + headers = {} + if accept_encoding: + if isinstance(accept_encoding, str): + pass + elif isinstance(accept_encoding, list): + accept_encoding = ",".join(accept_encoding) + else: + accept_encoding = ACCEPT_ENCODING + headers["accept-encoding"] = accept_encoding + + if user_agent: + headers["user-agent"] = user_agent + + if keep_alive: + headers["connection"] = "keep-alive" + + if basic_auth: + headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8") + + if proxy_basic_auth: + headers["proxy-authorization"] = "Basic " + b64encode( + b(proxy_basic_auth) + ).decode("utf-8") + + if disable_cache: + headers["cache-control"] = "no-cache" + + return headers + + +def set_file_position(body, pos): + """ + If a position is provided, move file to that point. + Otherwise, we'll attempt to record a position for future use. + """ + if pos is not None: + rewind_body(body, pos) + elif getattr(body, "tell", None) is not None: + try: + pos = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body. + pos = _FAILEDTELL + + return pos + + +def rewind_body(body, body_pos): + """ + Attempt to rewind body to a certain position. + Primarily used for request redirects and retries. + + :param body: + File-like object that supports seek. + + :param int pos: + Position to seek to in file. + """ + body_seek = getattr(body, "seek", None) + if body_seek is not None and isinstance(body_pos, integer_types): + try: + body_seek(body_pos) + except (IOError, OSError): + raise UnrewindableBodyError( + "An error occurred when rewinding request body for redirect/retry." + ) + elif body_pos is _FAILEDTELL: + raise UnrewindableBodyError( + "Unable to record file position for rewinding " + "request body during a redirect/retry." + ) + else: + raise ValueError( + "body_pos must be of type integer, instead it was %s." % type(body_pos) + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py new file mode 100644 index 0000000..5ea609c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py @@ -0,0 +1,107 @@ +from __future__ import absolute_import + +from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect + +from ..exceptions import HeaderParsingError +from ..packages.six.moves import http_client as httplib + + +def is_fp_closed(obj): + """ + Checks whether a given file-like object is closed. + + :param obj: + The file-like object to check. + """ + + try: + # Check `isclosed()` first, in case Python3 doesn't set `closed`. + # GH Issue #928 + return obj.isclosed() + except AttributeError: + pass + + try: + # Check via the official file-like-object way. + return obj.closed + except AttributeError: + pass + + try: + # Check if the object is a container for another file-like object that + # gets released on exhaustion (e.g. HTTPResponse). + return obj.fp is None + except AttributeError: + pass + + raise ValueError("Unable to determine whether fp is closed.") + + +def assert_header_parsing(headers): + """ + Asserts whether all headers have been successfully parsed. + Extracts encountered errors from the result of parsing headers. + + Only works on Python 3. + + :param http.client.HTTPMessage headers: Headers to verify. + + :raises urllib3.exceptions.HeaderParsingError: + If parsing errors are found. + """ + + # This will fail silently if we pass in the wrong kind of parameter. + # To make debugging easier add an explicit check. + if not isinstance(headers, httplib.HTTPMessage): + raise TypeError("expected httplib.Message, got {0}.".format(type(headers))) + + defects = getattr(headers, "defects", None) + get_payload = getattr(headers, "get_payload", None) + + unparsed_data = None + if get_payload: + # get_payload is actually email.message.Message.get_payload; + # we're only interested in the result if it's not a multipart message + if not headers.is_multipart(): + payload = get_payload() + + if isinstance(payload, (bytes, str)): + unparsed_data = payload + if defects: + # httplib is assuming a response body is available + # when parsing headers even when httplib only sends + # header data to parse_headers() This results in + # defects on multipart responses in particular. + # See: https://github.com/urllib3/urllib3/issues/800 + + # So we ignore the following defects: + # - StartBoundaryNotFoundDefect: + # The claimed start boundary was never found. + # - MultipartInvariantViolationDefect: + # A message claimed to be a multipart but no subparts were found. + defects = [ + defect + for defect in defects + if not isinstance( + defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect) + ) + ] + + if defects or unparsed_data: + raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) + + +def is_response_to_head(response): + """ + Checks whether the request of a response has been a HEAD-request. + Handles the quirks of AppEngine. + + :param http.client.HTTPResponse response: + Response to check if the originating request + used 'HEAD' as a method. + """ + # FIXME: Can we do this somehow without accessing private httplib _method? + method = response._method + if isinstance(method, int): # Platform-specific: Appengine + return method == 3 + return method.upper() == "HEAD" diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py new file mode 100644 index 0000000..9a1e90d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py @@ -0,0 +1,622 @@ +from __future__ import absolute_import + +import email +import logging +import re +import time +import warnings +from collections import namedtuple +from itertools import takewhile + +from ..exceptions import ( + ConnectTimeoutError, + InvalidHeader, + MaxRetryError, + ProtocolError, + ProxyError, + ReadTimeoutError, + ResponseError, +) +from ..packages import six + +log = logging.getLogger(__name__) + + +# Data structure for representing the metadata of requests that result in a retry. +RequestHistory = namedtuple( + "RequestHistory", ["method", "url", "error", "status", "redirect_location"] +) + + +# TODO: In v2 we can remove this sentinel and metaclass with deprecated options. +_Default = object() + + +class _RetryMeta(type): + @property + def DEFAULT_METHOD_WHITELIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + return cls.DEFAULT_ALLOWED_METHODS + + @DEFAULT_METHOD_WHITELIST.setter + def DEFAULT_METHOD_WHITELIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + cls.DEFAULT_ALLOWED_METHODS = value + + @property + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + @DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value + + @property + def BACKOFF_MAX(cls): + warnings.warn( + "Using 'Retry.BACKOFF_MAX' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_BACKOFF_MAX' instead", + DeprecationWarning, + ) + return cls.DEFAULT_BACKOFF_MAX + + @BACKOFF_MAX.setter + def BACKOFF_MAX(cls, value): + warnings.warn( + "Using 'Retry.BACKOFF_MAX' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_BACKOFF_MAX' instead", + DeprecationWarning, + ) + cls.DEFAULT_BACKOFF_MAX = value + + +@six.add_metaclass(_RetryMeta) +class Retry(object): + """Retry configuration. + + Each retry attempt will create a new Retry object with updated values, so + they can be safely reused. + + Retries can be defined as a default for a pool:: + + retries = Retry(connect=5, read=2, redirect=5) + http = PoolManager(retries=retries) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', retries=Retry(10)) + + Retries can be disabled by passing ``False``:: + + response = http.request('GET', 'http://example.com/', retries=False) + + Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless + retries are disabled, in which case the causing exception will be raised. + + :param int total: + Total number of retries to allow. Takes precedence over other counts. + + Set to ``None`` to remove this constraint and fall back on other + counts. + + Set to ``0`` to fail on the first retry. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int connect: + How many connection-related errors to retry on. + + These are errors raised before the request is sent to the remote server, + which we assume has not triggered the server to process the request. + + Set to ``0`` to fail on the first retry of this type. + + :param int read: + How many times to retry on read errors. + + These errors are raised after the request was sent to the server, so the + request may have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + :param int redirect: + How many redirects to perform. Limit this to avoid infinite redirect + loops. + + A redirect is a HTTP response with a status code 301, 302, 303, 307 or + 308. + + Set to ``0`` to fail on the first retry of this type. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int status: + How many times to retry on bad status codes. + + These are retries made on responses, where status code matches + ``status_forcelist``. + + Set to ``0`` to fail on the first retry of this type. + + :param int other: + How many times to retry on other errors. + + Other errors are errors that are not connect, read, redirect or status errors. + These errors might be raised after the request was sent to the server, so the + request might have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + If ``total`` is not set, it's a good idea to set this to 0 to account + for unexpected edge cases and avoid infinite retry loops. + + :param iterable allowed_methods: + Set of uppercased HTTP method verbs that we should retry on. + + By default, we only retry on methods which are considered to be + idempotent (multiple requests with the same parameters end with the + same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`. + + Set to a ``False`` value to retry on any verb. + + .. warning:: + + Previously this parameter was named ``method_whitelist``, that + usage is deprecated in v1.26.0 and will be removed in v2.0. + + :param iterable status_forcelist: + A set of integer HTTP status codes that we should force a retry on. + A retry is initiated if the request method is in ``allowed_methods`` + and the response status code is in ``status_forcelist``. + + By default, this is disabled with ``None``. + + :param float backoff_factor: + A backoff factor to apply between attempts after the second try + (most errors are resolved immediately by a second try without a + delay). urllib3 will sleep for:: + + {backoff factor} * (2 ** ({number of total retries} - 1)) + + seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep + for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer + than :attr:`Retry.DEFAULT_BACKOFF_MAX`. + + By default, backoff is disabled (set to 0). + + :param bool raise_on_redirect: Whether, if the number of redirects is + exhausted, to raise a MaxRetryError, or to return a response with a + response code in the 3xx range. + + :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: + whether we should raise an exception, or return a response, + if status falls in ``status_forcelist`` range and retries have + been exhausted. + + :param tuple history: The history of the request encountered during + each call to :meth:`~Retry.increment`. The list is in the order + the requests occurred. Each list item is of class :class:`RequestHistory`. + + :param bool respect_retry_after_header: + Whether to respect Retry-After header on status codes defined as + :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. + + :param iterable remove_headers_on_redirect: + Sequence of headers to remove from the request when a response + indicating a redirect is returned before firing off the redirected + request. + """ + + #: Default methods to be used for ``allowed_methods`` + DEFAULT_ALLOWED_METHODS = frozenset( + ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"] + ) + + #: Default status codes to be used for ``status_forcelist`` + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Default headers to be used for ``remove_headers_on_redirect`` + DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset( + ["Cookie", "Authorization", "Proxy-Authorization"] + ) + + #: Maximum backoff time. + DEFAULT_BACKOFF_MAX = 120 + + def __init__( + self, + total=10, + connect=None, + read=None, + redirect=None, + status=None, + other=None, + allowed_methods=_Default, + status_forcelist=None, + backoff_factor=0, + raise_on_redirect=True, + raise_on_status=True, + history=None, + respect_retry_after_header=True, + remove_headers_on_redirect=_Default, + # TODO: Deprecated, remove in v2.0 + method_whitelist=_Default, + ): + + if method_whitelist is not _Default: + if allowed_methods is not _Default: + raise ValueError( + "Using both 'allowed_methods' and " + "'method_whitelist' together is not allowed. " + "Instead only use 'allowed_methods'" + ) + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + stacklevel=2, + ) + allowed_methods = method_whitelist + if allowed_methods is _Default: + allowed_methods = self.DEFAULT_ALLOWED_METHODS + if remove_headers_on_redirect is _Default: + remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + self.total = total + self.connect = connect + self.read = read + self.status = status + self.other = other + + if redirect is False or total is False: + redirect = 0 + raise_on_redirect = False + + self.redirect = redirect + self.status_forcelist = status_forcelist or set() + self.allowed_methods = allowed_methods + self.backoff_factor = backoff_factor + self.raise_on_redirect = raise_on_redirect + self.raise_on_status = raise_on_status + self.history = history or tuple() + self.respect_retry_after_header = respect_retry_after_header + self.remove_headers_on_redirect = frozenset( + [h.lower() for h in remove_headers_on_redirect] + ) + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, + read=self.read, + redirect=self.redirect, + status=self.status, + other=self.other, + status_forcelist=self.status_forcelist, + backoff_factor=self.backoff_factor, + raise_on_redirect=self.raise_on_redirect, + raise_on_status=self.raise_on_status, + history=self.history, + remove_headers_on_redirect=self.remove_headers_on_redirect, + respect_retry_after_header=self.respect_retry_after_header, + ) + + # TODO: If already given in **kw we use what's given to us + # If not given we need to figure out what to pass. We decide + # based on whether our class has the 'method_whitelist' property + # and if so we pass the deprecated 'method_whitelist' otherwise + # we use 'allowed_methods'. Remove in v2.0 + if "method_whitelist" not in kw and "allowed_methods" not in kw: + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + params["method_whitelist"] = self.allowed_methods + else: + params["allowed_methods"] = self.allowed_methods + + params.update(kw) + return type(self)(**params) + + @classmethod + def from_int(cls, retries, redirect=True, default=None): + """Backwards-compatibility for the old retries format.""" + if retries is None: + retries = default if default is not None else cls.DEFAULT + + if isinstance(retries, Retry): + return retries + + redirect = bool(redirect) and None + new_retries = cls(retries, redirect=redirect) + log.debug("Converted retries value: %r -> %r", retries, new_retries) + return new_retries + + def get_backoff_time(self): + """Formula for computing the current backoff + + :rtype: float + """ + # We want to consider only the last consecutive errors sequence (Ignore redirects). + consecutive_errors_len = len( + list( + takewhile(lambda x: x.redirect_location is None, reversed(self.history)) + ) + ) + if consecutive_errors_len <= 1: + return 0 + + backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) + return min(self.DEFAULT_BACKOFF_MAX, backoff_value) + + def parse_retry_after(self, retry_after): + # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = int(retry_after) + else: + retry_date_tuple = email.utils.parsedate_tz(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + if retry_date_tuple[9] is None: # Python 2 + # Assume UTC if no timezone was specified + # On Python2.7, parsedate_tz returns None for a timezone offset + # instead of 0 if no timezone is given, where mktime_tz treats + # a None timezone offset as local time. + retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:] + + retry_date = email.utils.mktime_tz(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + def get_retry_after(self, response): + """Get the value of Retry-After in seconds.""" + + retry_after = response.headers.get("Retry-After") + + if retry_after is None: + return None + + return self.parse_retry_after(retry_after) + + def sleep_for_retry(self, response=None): + retry_after = self.get_retry_after(response) + if retry_after: + time.sleep(retry_after) + return True + + return False + + def _sleep_backoff(self): + backoff = self.get_backoff_time() + if backoff <= 0: + return + time.sleep(backoff) + + def sleep(self, response=None): + """Sleep between retry attempts. + + This method will respect a server's ``Retry-After`` response header + and sleep the duration of the time requested. If that is not present, it + will use an exponential backoff. By default, the backoff factor is 0 and + this method will return immediately. + """ + + if self.respect_retry_after_header and response: + slept = self.sleep_for_retry(response) + if slept: + return + + self._sleep_backoff() + + def _is_connection_error(self, err): + """Errors when we're fairly sure that the server did not receive the + request, so it should be safe to retry. + """ + if isinstance(err, ProxyError): + err = err.original_error + return isinstance(err, ConnectTimeoutError) + + def _is_read_error(self, err): + """Errors that occur after the request has been started, so we should + assume that the server began processing it. + """ + return isinstance(err, (ReadTimeoutError, ProtocolError)) + + def _is_method_retryable(self, method): + """Checks if a given HTTP method should be retried upon, depending if + it is included in the allowed_methods + """ + # TODO: For now favor if the Retry implementation sets its own method_whitelist + # property outside of our constructor to avoid breaking custom implementations. + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + allowed_methods = self.method_whitelist + else: + allowed_methods = self.allowed_methods + + if allowed_methods and method.upper() not in allowed_methods: + return False + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """Is this method/status code retryable? (Based on allowlists and control + variables such as the number of total retries to allow, whether to + respect the Retry-After header, whether this header is present, and + whether the returned status code is on the list of status codes to + be retried upon on the presence of the aforementioned header) + """ + if not self._is_method_retryable(method): + return False + + if self.status_forcelist and status_code in self.status_forcelist: + return True + + return ( + self.total + and self.respect_retry_after_header + and has_retry_after + and (status_code in self.RETRY_AFTER_STATUS_CODES) + ) + + def is_exhausted(self): + """Are we out of retries?""" + retry_counts = ( + self.total, + self.connect, + self.read, + self.redirect, + self.status, + self.other, + ) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + + return min(retry_counts) < 0 + + def increment( + self, + method=None, + url=None, + response=None, + error=None, + _pool=None, + _stacktrace=None, + ): + """Return a new Retry object with incremented retry counters. + + :param response: A response object, or None, if the server did not + return a response. + :type response: :class:`~urllib3.response.HTTPResponse` + :param Exception error: An error encountered during the request, or + None if the response was received successfully. + + :return: A new ``Retry`` object. + """ + if self.total is False and error: + # Disabled, indicate to re-raise the error. + raise six.reraise(type(error), error, _stacktrace) + + total = self.total + if total is not None: + total -= 1 + + connect = self.connect + read = self.read + redirect = self.redirect + status_count = self.status + other = self.other + cause = "unknown" + status = None + redirect_location = None + + if error and self._is_connection_error(error): + # Connect retry? + if connect is False: + raise six.reraise(type(error), error, _stacktrace) + elif connect is not None: + connect -= 1 + + elif error and self._is_read_error(error): + # Read retry? + if read is False or not self._is_method_retryable(method): + raise six.reraise(type(error), error, _stacktrace) + elif read is not None: + read -= 1 + + elif error: + # Other retry? + if other is not None: + other -= 1 + + elif response and response.get_redirect_location(): + # Redirect retry? + if redirect is not None: + redirect -= 1 + cause = "too many redirects" + redirect_location = response.get_redirect_location() + status = response.status + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and the given method is in the allowed_methods + cause = ResponseError.GENERIC_ERROR + if response and response.status: + if status_count is not None: + status_count -= 1 + cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) + status = response.status + + history = self.history + ( + RequestHistory(method, url, error, status, redirect_location), + ) + + new_retry = self.new( + total=total, + connect=connect, + read=read, + redirect=redirect, + status=status_count, + other=other, + history=history, + ) + + if new_retry.is_exhausted(): + raise MaxRetryError(_pool, url, error or ResponseError(cause)) + + log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) + + return new_retry + + def __repr__(self): + return ( + "{cls.__name__}(total={self.total}, connect={self.connect}, " + "read={self.read}, redirect={self.redirect}, status={self.status})" + ).format(cls=type(self), self=self) + + def __getattr__(self, item): + if item == "method_whitelist": + # TODO: Remove this deprecated alias in v2.0 + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + return self.allowed_methods + try: + return getattr(super(Retry, self), item) + except AttributeError: + return getattr(Retry, item) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py new file mode 100644 index 0000000..0a6a0e0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py @@ -0,0 +1,504 @@ +from __future__ import absolute_import + +import hashlib +import hmac +import os +import sys +import warnings +from binascii import hexlify, unhexlify + +from ..exceptions import ( + InsecurePlatformWarning, + ProxySchemeUnsupported, + SNIMissingWarning, + SSLError, +) +from ..packages import six +from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE + +SSLContext = None +SSLTransport = None +HAS_SNI = False +IS_PYOPENSSL = False +IS_SECURETRANSPORT = False +ALPN_PROTOCOLS = ["http/1.1"] + +# Maps the length of a digest to a possible hash function producing this digest +HASHFUNC_MAP = { + length: getattr(hashlib, algorithm, None) + for length, algorithm in ((32, "md5"), (40, "sha1"), (64, "sha256")) +} + + +def _const_compare_digest_backport(a, b): + """ + Compare two digests of equal length in constant time. + + The digests must be of type str/bytes. + Returns True if the digests match, and False otherwise. + """ + result = abs(len(a) - len(b)) + for left, right in zip(bytearray(a), bytearray(b)): + result |= left ^ right + return result == 0 + + +_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport) + +try: # Test for SSL features + import ssl + from ssl import CERT_REQUIRED, wrap_socket +except ImportError: + pass + +try: + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + +try: + from .ssltransport import SSLTransport +except ImportError: + pass + + +try: # Platform-specific: Python 3.6 + from ssl import PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS +except ImportError: + try: + from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS + except ImportError: + PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 + +try: + from ssl import PROTOCOL_TLS_CLIENT +except ImportError: + PROTOCOL_TLS_CLIENT = PROTOCOL_TLS + + +try: + from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3 +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + + +try: # OP_NO_TICKET was added in Python 3.6 + from ssl import OP_NO_TICKET +except ImportError: + OP_NO_TICKET = 0x4000 + + +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs, DSS, and other +# insecure ciphers for security reasons. +# - NOTE: TLS 1.3 cipher suites are managed through a different interface +# not exposed by CPython (yet!) and are enabled by default if they're available. +DEFAULT_CIPHERS = ":".join( + [ + "ECDHE+AESGCM", + "ECDHE+CHACHA20", + "DHE+AESGCM", + "DHE+CHACHA20", + "ECDH+AESGCM", + "DH+AESGCM", + "ECDH+AES", + "DH+AES", + "RSA+AESGCM", + "RSA+AES", + "!aNULL", + "!eNULL", + "!MD5", + "!DSS", + ] +) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + + class SSLContext(object): # Platform-specific: Python 2 + def __init__(self, protocol_version): + self.protocol = protocol_version + # Use default values from a real SSLContext + self.check_hostname = False + self.verify_mode = ssl.CERT_NONE + self.ca_certs = None + self.options = 0 + self.certfile = None + self.keyfile = None + self.ciphers = None + + def load_cert_chain(self, certfile, keyfile): + self.certfile = certfile + self.keyfile = keyfile + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + if cadata is not None: + raise SSLError("CA data not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + self.ciphers = cipher_suite + + def wrap_socket(self, socket, server_hostname=None, server_side=False): + warnings.warn( + "A true SSLContext object is not available. This prevents " + "urllib3 from configuring SSL appropriately and may cause " + "certain SSL connections to fail. You can upgrade to a newer " + "version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + InsecurePlatformWarning, + ) + kwargs = { + "keyfile": self.keyfile, + "certfile": self.certfile, + "ca_certs": self.ca_certs, + "cert_reqs": self.verify_mode, + "ssl_version": self.protocol, + "server_side": server_side, + } + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + + +def assert_fingerprint(cert, fingerprint): + """ + Checks if given fingerprint matches the supplied certificate. + + :param cert: + Certificate as bytes object. + :param fingerprint: + Fingerprint as string of hexdigits, can be interspersed by colons. + """ + + fingerprint = fingerprint.replace(":", "").lower() + digest_length = len(fingerprint) + if digest_length not in HASHFUNC_MAP: + raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint)) + hashfunc = HASHFUNC_MAP.get(digest_length) + if hashfunc is None: + raise SSLError( + "Hash function implementation unavailable for fingerprint length: {0}".format( + digest_length + ) + ) + + # We need encode() here for py32; works on py2 and p33. + fingerprint_bytes = unhexlify(fingerprint.encode()) + + cert_digest = hashfunc(cert).digest() + + if not _const_compare_digest(cert_digest, fingerprint_bytes): + raise SSLError( + 'Fingerprints did not match. Expected "{0}", got "{1}".'.format( + fingerprint, hexlify(cert_digest) + ) + ) + + +def resolve_cert_reqs(candidate): + """ + Resolves the argument to a numeric constant, which can be passed to + the wrap_socket function/method from the ssl module. + Defaults to :data:`ssl.CERT_REQUIRED`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbreviation. + (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. + If it's neither `None` nor a string we assume it is already the numeric + constant which can directly be passed to wrap_socket. + """ + if candidate is None: + return CERT_REQUIRED + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "CERT_" + candidate) + return res + + return candidate + + +def resolve_ssl_version(candidate): + """ + like resolve_cert_reqs + """ + if candidate is None: + return PROTOCOL_TLS + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "PROTOCOL_" + candidate) + return res + + return candidate + + +def create_urllib3_context( + ssl_version=None, cert_reqs=None, options=None, ciphers=None +): + """All arguments have the same meaning as ``ssl_wrap_socket``. + + By default, this function does a lot of the same work that + ``ssl.create_default_context`` does on Python 3.4+. It: + + - Disables SSLv2, SSLv3, and compression + - Sets a restricted set of server ciphers + + If you wish to enable SSLv3, you can do:: + + from pip._vendor.urllib3.util import ssl_ + context = ssl_.create_urllib3_context() + context.options &= ~ssl_.OP_NO_SSLv3 + + You can do the same to enable compression (substituting ``COMPRESSION`` + for ``SSLv3`` in the last line above). + + :param ssl_version: + The desired protocol version to use. This will default to + PROTOCOL_SSLv23 which will negotiate the highest protocol that both + the server and your installation of OpenSSL support. + :param cert_reqs: + Whether to require the certificate verification. This defaults to + ``ssl.CERT_REQUIRED``. + :param options: + Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, + ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + # PROTOCOL_TLS is deprecated in Python 3.10 + if not ssl_version or ssl_version == PROTOCOL_TLS: + ssl_version = PROTOCOL_TLS_CLIENT + + context = SSLContext(ssl_version) + + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + # Setting the default here, as we may have no ssl module on import + cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs + + if options is None: + options = 0 + # SSLv2 is easily broken and is considered harmful and dangerous + options |= OP_NO_SSLv2 + # SSLv3 has several problems and is now dangerous + options |= OP_NO_SSLv3 + # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ + # (issue #309) + options |= OP_NO_COMPRESSION + # TLSv1.2 only. Unless set explicitly, do not request tickets. + # This may save some bandwidth on wire, and although the ticket is encrypted, + # there is a risk associated with it being on wire, + # if the server is not rotating its ticketing keys properly. + options |= OP_NO_TICKET + + context.options |= options + + # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is + # necessary for conditional client cert authentication with TLS 1.3. + # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older + # versions of Python. We only enable on Python 3.7.4+ or if certificate + # verification is enabled to work around Python issue #37428 + # See: https://bugs.python.org/issue37428 + if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( + context, "post_handshake_auth", None + ) is not None: + context.post_handshake_auth = True + + def disable_check_hostname(): + if ( + getattr(context, "check_hostname", None) is not None + ): # Platform-specific: Python 3.2 + # We do our own verification, including fingerprints and alternative + # hostnames. So disable it here + context.check_hostname = False + + # The order of the below lines setting verify_mode and check_hostname + # matter due to safe-guards SSLContext has to prevent an SSLContext with + # check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more + # complex because we don't know whether PROTOCOL_TLS_CLIENT will be used + # or not so we don't know the initial state of the freshly created SSLContext. + if cert_reqs == ssl.CERT_REQUIRED: + context.verify_mode = cert_reqs + disable_check_hostname() + else: + disable_check_hostname() + context.verify_mode = cert_reqs + + # Enable logging of TLS session keys via defacto standard environment variable + # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. + if hasattr(context, "keylog_filename"): + sslkeylogfile = os.environ.get("SSLKEYLOGFILE") + if sslkeylogfile: + context.keylog_filename = sslkeylogfile + + return context + + +def ssl_wrap_socket( + sock, + keyfile=None, + certfile=None, + cert_reqs=None, + ca_certs=None, + server_hostname=None, + ssl_version=None, + ciphers=None, + ssl_context=None, + ca_cert_dir=None, + key_password=None, + ca_cert_data=None, + tls_in_tls=False, +): + """ + All arguments except for server_hostname, ssl_context, and ca_cert_dir have + the same meaning as they do when using :func:`ssl.wrap_socket`. + + :param server_hostname: + When SNI is supported, the expected hostname of the certificate + :param ssl_context: + A pre-made :class:`SSLContext` object. If none is provided, one will + be created using :func:`create_urllib3_context`. + :param ciphers: + A string of ciphers we wish the client to support. + :param ca_cert_dir: + A directory containing CA certificates in multiple separate files, as + supported by OpenSSL's -CApath flag or the capath argument to + SSLContext.load_verify_locations(). + :param key_password: + Optional password if the keyfile is encrypted. + :param ca_cert_data: + Optional string containing CA certificates in PEM format suitable for + passing as the cadata parameter to SSLContext.load_verify_locations() + :param tls_in_tls: + Use SSLTransport to wrap the existing socket. + """ + context = ssl_context + if context is None: + # Note: This branch of code and all the variables in it are no longer + # used by urllib3 itself. We should consider deprecating and removing + # this code. + context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) + + if ca_certs or ca_cert_dir or ca_cert_data: + try: + context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) + except (IOError, OSError) as e: + raise SSLError(e) + + elif ssl_context is None and hasattr(context, "load_default_certs"): + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + # Attempt to detect if we get the goofy behavior of the + # keyfile being encrypted and OpenSSL asking for the + # passphrase via the terminal and instead error out. + if keyfile and key_password is None and _is_key_file_encrypted(keyfile): + raise SSLError("Client private key is encrypted, password is required") + + if certfile: + if key_password is None: + context.load_cert_chain(certfile, keyfile) + else: + context.load_cert_chain(certfile, keyfile, key_password) + + try: + if hasattr(context, "set_alpn_protocols"): + context.set_alpn_protocols(ALPN_PROTOCOLS) + except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols + pass + + # If we detect server_hostname is an IP address then the SNI + # extension should not be used according to RFC3546 Section 3.1 + use_sni_hostname = server_hostname and not is_ipaddress(server_hostname) + # SecureTransport uses server_hostname in certificate verification. + send_sni = (use_sni_hostname and HAS_SNI) or ( + IS_SECURETRANSPORT and server_hostname + ) + # Do not warn the user if server_hostname is an invalid SNI hostname. + if not HAS_SNI and use_sni_hostname: + warnings.warn( + "An HTTPS request has been made, but the SNI (Server Name " + "Indication) extension to TLS is not available on this platform. " + "This may cause the server to present an incorrect TLS " + "certificate, which can cause validation failures. You can upgrade to " + "a newer version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + SNIMissingWarning, + ) + + if send_sni: + ssl_sock = _ssl_wrap_socket_impl( + sock, context, tls_in_tls, server_hostname=server_hostname + ) + else: + ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls) + return ssl_sock + + +def is_ipaddress(hostname): + """Detects whether the hostname given is an IPv4 or IPv6 address. + Also detects IPv6 addresses with Zone IDs. + + :param str hostname: Hostname to examine. + :return: True if the hostname is an IP address, False otherwise. + """ + if not six.PY2 and isinstance(hostname, bytes): + # IDN A-label bytes are ASCII compatible. + hostname = hostname.decode("ascii") + return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname)) + + +def _is_key_file_encrypted(key_file): + """Detects if a key file is encrypted or not.""" + with open(key_file, "r") as f: + for line in f: + # Look for Proc-Type: 4,ENCRYPTED + if "ENCRYPTED" in line: + return True + + return False + + +def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None): + if tls_in_tls: + if not SSLTransport: + # Import error, ssl is not available. + raise ProxySchemeUnsupported( + "TLS in TLS requires support for the 'ssl' module" + ) + + SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context) + return SSLTransport(sock, ssl_context, server_hostname) + + if server_hostname: + return ssl_context.wrap_socket(sock, server_hostname=server_hostname) + else: + return ssl_context.wrap_socket(sock) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py new file mode 100644 index 0000000..1dd950c --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py @@ -0,0 +1,159 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# util.ssl_match_hostname to continue to be used in Python 2.7. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = "3.5.0.1" + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r".") + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count("*") + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn) + ) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == "*": + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append("[^.]+") + elif leftmost.startswith("xn--") or hostname.startswith("xn--"): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r"\*", "[^.]*")) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + # ignored flake8 # F821 to support python 2.7 function + obj = unicode(obj, encoding="ascii", errors="strict") # noqa: F821 + return obj + + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError( + "empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED" + ) + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except (UnicodeError, ValueError): + # ValueError: Not an IP address (common case) + # UnicodeError: Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: # Defensive + raise + dnsnames = [] + san = cert.get("subjectAltName", ()) + for key, value in san: + if key == "DNS": + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == "IP Address": + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get("subject", ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == "commonName": + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError( + "hostname %r " + "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames))) + ) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) + else: + raise CertificateError( + "no appropriate commonName or subjectAltName fields were found" + ) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py new file mode 100644 index 0000000..4a7105d --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py @@ -0,0 +1,221 @@ +import io +import socket +import ssl + +from ..exceptions import ProxySchemeUnsupported +from ..packages import six + +SSL_BLOCKSIZE = 16384 + + +class SSLTransport: + """ + The SSLTransport wraps an existing socket and establishes an SSL connection. + + Contrary to Python's implementation of SSLSocket, it allows you to chain + multiple TLS connections together. It's particularly useful if you need to + implement TLS within TLS. + + The class supports most of the socket API operations. + """ + + @staticmethod + def _validate_ssl_context_for_tls_in_tls(ssl_context): + """ + Raises a ProxySchemeUnsupported if the provided ssl_context can't be used + for TLS in TLS. + + The only requirement is that the ssl_context provides the 'wrap_bio' + methods. + """ + + if not hasattr(ssl_context, "wrap_bio"): + if six.PY2: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "supported on Python 2" + ) + else: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "available on non-native SSLContext" + ) + + def __init__( + self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True + ): + """ + Create an SSLTransport around socket using the provided ssl_context. + """ + self.incoming = ssl.MemoryBIO() + self.outgoing = ssl.MemoryBIO() + + self.suppress_ragged_eofs = suppress_ragged_eofs + self.socket = socket + + self.sslobj = ssl_context.wrap_bio( + self.incoming, self.outgoing, server_hostname=server_hostname + ) + + # Perform initial handshake. + self._ssl_io_loop(self.sslobj.do_handshake) + + def __enter__(self): + return self + + def __exit__(self, *_): + self.close() + + def fileno(self): + return self.socket.fileno() + + def read(self, len=1024, buffer=None): + return self._wrap_ssl_read(len, buffer) + + def recv(self, len=1024, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv") + return self._wrap_ssl_read(len) + + def recv_into(self, buffer, nbytes=None, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv_into") + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + return self.read(nbytes, buffer) + + def sendall(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to sendall") + count = 0 + with memoryview(data) as view, view.cast("B") as byte_view: + amount = len(byte_view) + while count < amount: + v = self.send(byte_view[count:]) + count += v + + def send(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to send") + response = self._ssl_io_loop(self.sslobj.write, data) + return response + + def makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None + ): + """ + Python's httpclient uses makefile and buffered io when reading HTTP + messages and we need to support it. + + This is unfortunately a copy and paste of socket.py makefile with small + changes to point to the socket directly. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = socket.SocketIO(self, rawmode) + self.socket._io_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text + + def unwrap(self): + self._ssl_io_loop(self.sslobj.unwrap) + + def close(self): + self.socket.close() + + def getpeercert(self, binary_form=False): + return self.sslobj.getpeercert(binary_form) + + def version(self): + return self.sslobj.version() + + def cipher(self): + return self.sslobj.cipher() + + def selected_alpn_protocol(self): + return self.sslobj.selected_alpn_protocol() + + def selected_npn_protocol(self): + return self.sslobj.selected_npn_protocol() + + def shared_ciphers(self): + return self.sslobj.shared_ciphers() + + def compression(self): + return self.sslobj.compression() + + def settimeout(self, value): + self.socket.settimeout(value) + + def gettimeout(self): + return self.socket.gettimeout() + + def _decref_socketios(self): + self.socket._decref_socketios() + + def _wrap_ssl_read(self, len, buffer=None): + try: + return self._ssl_io_loop(self.sslobj.read, len, buffer) + except ssl.SSLError as e: + if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs: + return 0 # eof, return 0. + else: + raise + + def _ssl_io_loop(self, func, *args): + """Performs an I/O loop between incoming/outgoing and the socket.""" + should_loop = True + ret = None + + while should_loop: + errno = None + try: + ret = func(*args) + except ssl.SSLError as e: + if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE): + # WANT_READ, and WANT_WRITE are expected, others are not. + raise e + errno = e.errno + + buf = self.outgoing.read() + self.socket.sendall(buf) + + if errno is None: + should_loop = False + elif errno == ssl.SSL_ERROR_WANT_READ: + buf = self.socket.recv(SSL_BLOCKSIZE) + if buf: + self.incoming.write(buf) + else: + self.incoming.write_eof() + return ret diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py new file mode 100644 index 0000000..78e18a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py @@ -0,0 +1,271 @@ +from __future__ import absolute_import + +import time + +# The default socket timeout, used by httplib to indicate that no timeout was; specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT, getdefaulttimeout + +from ..exceptions import TimeoutStateError + +# A sentinel value to indicate that no timeout was specified by the user in +# urllib3 +_Default = object() + + +# Use time.monotonic if available. +current_time = getattr(time, "monotonic", time.time) + + +class Timeout(object): + """Timeout configuration. + + Timeouts can be defined as a default for a pool: + + .. code-block:: python + + timeout = Timeout(connect=2.0, read=7.0) + http = PoolManager(timeout=timeout) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool): + + .. code-block:: python + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``: + + .. code-block:: python + + no_timeout = Timeout(connect=None, read=None) + response = http.request('GET', 'http://example.com/, timeout=no_timeout) + + + :param total: + This combines the connect and read timeouts into one; the read timeout + will be set to the time leftover from the connect attempt. In the + event that both a connect timeout and a total are specified, or a read + timeout and a total are specified, the shorter timeout will be applied. + + Defaults to None. + + :type total: int, float, or None + + :param connect: + The maximum amount of time (in seconds) to wait for a connection + attempt to a server to succeed. Omitting the parameter will default the + connect timeout to the system default, probably `the global default + timeout in socket.py + `_. + None will set an infinite timeout for connection attempts. + + :type connect: int, float, or None + + :param read: + The maximum amount of time (in seconds) to wait between consecutive + read operations for a response from the server. Omitting the parameter + will default the read timeout to the system default, probably `the + global default timeout in socket.py + `_. + None will set an infinite timeout. + + :type read: int, float, or None + + .. note:: + + Many factors can affect the total amount of time for urllib3 to return + an HTTP response. + + For example, Python's DNS resolver does not obey the timeout specified + on the socket. Other factors that can affect total request time include + high CPU load, high swap, the program running at a low priority level, + or other behaviors. + + In addition, the read and total timeouts only measure the time between + read operations on the socket connecting the client and the server, + not the total amount of time for the request to return a complete + response. For most requests, the timeout is raised because the server + has not sent the first byte in the specified time. This is not always + the case; if a server streams one byte every fifteen seconds, a timeout + of 20 seconds will not trigger, even though the request will take + several minutes to complete. + + If your goal is to cut off any request after a set amount of wall clock + time, consider having a second "watcher" thread to cut off a slow + request. + """ + + #: A sentinel object representing the default timeout value + DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT + + def __init__(self, total=None, connect=_Default, read=_Default): + self._connect = self._validate_timeout(connect, "connect") + self._read = self._validate_timeout(read, "read") + self.total = self._validate_timeout(total, "total") + self._start_connect = None + + def __repr__(self): + return "%s(connect=%r, read=%r, total=%r)" % ( + type(self).__name__, + self._connect, + self._read, + self.total, + ) + + # __str__ provided for backwards compatibility + __str__ = __repr__ + + @classmethod + def resolve_default_timeout(cls, timeout): + return getdefaulttimeout() if timeout is cls.DEFAULT_TIMEOUT else timeout + + @classmethod + def _validate_timeout(cls, value, name): + """Check that a timeout attribute is valid. + + :param value: The timeout value to validate + :param name: The name of the timeout attribute to validate. This is + used to specify in error messages. + :return: The validated and casted version of the given value. + :raises ValueError: If it is a numeric value less than or equal to + zero, or the type is not an integer, float, or None. + """ + if value is _Default: + return cls.DEFAULT_TIMEOUT + + if value is None or value is cls.DEFAULT_TIMEOUT: + return value + + if isinstance(value, bool): + raise ValueError( + "Timeout cannot be a boolean value. It must " + "be an int, float or None." + ) + try: + float(value) + except (TypeError, ValueError): + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + try: + if value <= 0: + raise ValueError( + "Attempted to set %s timeout to %s, but the " + "timeout cannot be set to a value less " + "than or equal to 0." % (name, value) + ) + except TypeError: + # Python 3 + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + return value + + @classmethod + def from_float(cls, timeout): + """Create a new Timeout from a legacy timeout value. + + The timeout value used by httplib.py sets the same timeout on the + connect(), and recv() socket requests. This creates a :class:`Timeout` + object that sets the individual timeouts to the ``timeout`` value + passed to this function. + + :param timeout: The legacy timeout value. + :type timeout: integer, float, sentinel default object, or None + :return: Timeout object + :rtype: :class:`Timeout` + """ + return Timeout(read=timeout, connect=timeout) + + def clone(self): + """Create a copy of the timeout object + + Timeout properties are stored per-pool but each request needs a fresh + Timeout object to ensure each one has its own start/stop configured. + + :return: a copy of the timeout object + :rtype: :class:`Timeout` + """ + # We can't use copy.deepcopy because that will also create a new object + # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to + # detect the user default. + return Timeout(connect=self._connect, read=self._read, total=self.total) + + def start_connect(self): + """Start the timeout clock, used during a connect() attempt + + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to start a timer that has been started already. + """ + if self._start_connect is not None: + raise TimeoutStateError("Timeout timer has already been started.") + self._start_connect = current_time() + return self._start_connect + + def get_connect_duration(self): + """Gets the time elapsed since the call to :meth:`start_connect`. + + :return: Elapsed time in seconds. + :rtype: float + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to get duration for a timer that hasn't been started. + """ + if self._start_connect is None: + raise TimeoutStateError( + "Can't get connect duration for timer that has not started." + ) + return current_time() - self._start_connect + + @property + def connect_timeout(self): + """Get the value to use when setting a connection timeout. + + This will be a positive float or integer, the value None + (never timeout), or the default system timeout. + + :return: Connect timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + """ + if self.total is None: + return self._connect + + if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: + return self.total + + return min(self._connect, self.total) + + @property + def read_timeout(self): + """Get the value for the read timeout. + + This assumes some time has elapsed in the connection timeout and + computes the read timeout appropriately. + + If self.total is set, the read timeout is dependent on the amount of + time taken by the connect timeout. If the connection time has not been + established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be + raised. + + :return: Value to use for the read timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` + has not yet been called on this object. + """ + if ( + self.total is not None + and self.total is not self.DEFAULT_TIMEOUT + and self._read is not None + and self._read is not self.DEFAULT_TIMEOUT + ): + # In case the connect timeout has not yet been established. + if self._start_connect is None: + return self._read + return max(0, min(self.total - self.get_connect_duration(), self._read)) + elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: + return max(0, self.total - self.get_connect_duration()) + else: + return self._read diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py new file mode 100644 index 0000000..a960b2f --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py @@ -0,0 +1,435 @@ +from __future__ import absolute_import + +import re +from collections import namedtuple + +from ..exceptions import LocationParseError +from ..packages import six + +url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"] + +# We only want to normalize urls with an HTTP(S) scheme. +# urllib3 infers URLs without a scheme (None) to be http. +NORMALIZABLE_SCHEMES = ("http", "https", None) + +# Almost all of these patterns were derived from the +# 'rfc3986' module: https://github.com/python-hyper/rfc3986 +PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}") +SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)") +URI_RE = re.compile( + r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?" + r"(?://([^\\/?#]*))?" + r"([^?#]*)" + r"(?:\?([^#]*))?" + r"(?:#(.*))?$", + re.UNICODE | re.DOTALL, +) + +IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}" +HEX_PAT = "[0-9A-Fa-f]{1,4}" +LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT) +_subs = {"hex": HEX_PAT, "ls32": LS32_PAT} +_variations = [ + # 6( h16 ":" ) ls32 + "(?:%(hex)s:){6}%(ls32)s", + # "::" 5( h16 ":" ) ls32 + "::(?:%(hex)s:){5}%(ls32)s", + # [ h16 ] "::" 4( h16 ":" ) ls32 + "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s", + # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s", + # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s", + # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s", + # [ *4( h16 ":" ) h16 ] "::" ls32 + "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s", + # [ *5( h16 ":" ) h16 ] "::" h16 + "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s", + # [ *6( h16 ":" ) h16 ] "::" + "(?:(?:%(hex)s:){0,6}%(hex)s)?::", +] + +UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._\-~" +IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")" +ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+" +IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]" +REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*" +TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$") + +IPV4_RE = re.compile("^" + IPV4_PAT + "$") +IPV6_RE = re.compile("^" + IPV6_PAT + "$") +IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$") +BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$") +ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$") + +_HOST_PORT_PAT = ("^(%s|%s|%s)(?::0*?(|0|[1-9][0-9]{0,4}))?$") % ( + REG_NAME_PAT, + IPV4_PAT, + IPV6_ADDRZ_PAT, +) +_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL) + +UNRESERVED_CHARS = set( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~" +) +SUB_DELIM_CHARS = set("!$&'()*+,;=") +USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"} +PATH_CHARS = USERINFO_CHARS | {"@", "/"} +QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"} + + +class Url(namedtuple("Url", url_attrs)): + """ + Data structure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. Both the scheme and host are normalized as they are + both case-insensitive according to RFC 3986. + """ + + __slots__ = () + + def __new__( + cls, + scheme=None, + auth=None, + host=None, + port=None, + path=None, + query=None, + fragment=None, + ): + if path and not path.startswith("/"): + path = "/" + path + if scheme is not None: + scheme = scheme.lower() + return super(Url, cls).__new__( + cls, scheme, auth, host, port, path, query, fragment + ) + + @property + def hostname(self): + """For backwards-compatibility with urlparse. We're nice like that.""" + return self.host + + @property + def request_uri(self): + """Absolute path including the query string.""" + uri = self.path or "/" + + if self.query is not None: + uri += "?" + self.query + + return uri + + @property + def netloc(self): + """Network location including host and port""" + if self.port: + return "%s:%d" % (self.host, self.port) + return self.host + + @property + def url(self): + """ + Convert self into a url + + This function should more or less round-trip with :func:`.parse_url`. The + returned url may not be exactly the same as the url inputted to + :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls + with a blank port will have : removed). + + Example: :: + + >>> U = parse_url('http://google.com/mail/') + >>> U.url + 'http://google.com/mail/' + >>> Url('http', 'username:password', 'host.com', 80, + ... '/path', 'query', 'fragment').url + 'http://username:password@host.com:80/path?query#fragment' + """ + scheme, auth, host, port, path, query, fragment = self + url = u"" + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + u"://" + if auth is not None: + url += auth + u"@" + if host is not None: + url += host + if port is not None: + url += u":" + str(port) + if path is not None: + url += path + if query is not None: + url += u"?" + query + if fragment is not None: + url += u"#" + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + .. deprecated:: 1.25 + + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, "", None + + return s[:min_idx], s[min_idx + 1 :], min_delim + + +def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"): + """Percent-encodes a URI component without reapplying + onto an already percent-encoded component. + """ + if component is None: + return component + + component = six.ensure_text(component) + + # Normalize existing percent-encoded bytes. + # Try to see if the component we're encoding is already percent-encoded + # so we can skip all '%' characters but still encode all others. + component, percent_encodings = PERCENT_RE.subn( + lambda match: match.group(0).upper(), component + ) + + uri_bytes = component.encode("utf-8", "surrogatepass") + is_percent_encoded = percent_encodings == uri_bytes.count(b"%") + encoded_component = bytearray() + + for i in range(0, len(uri_bytes)): + # Will return a single character bytestring on both Python 2 & 3 + byte = uri_bytes[i : i + 1] + byte_ord = ord(byte) + if (is_percent_encoded and byte == b"%") or ( + byte_ord < 128 and byte.decode() in allowed_chars + ): + encoded_component += byte + continue + encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper())) + + return encoded_component.decode(encoding) + + +def _remove_path_dot_segments(path): + # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code + segments = path.split("/") # Turn the path into a list of segments + output = [] # Initialize the variable to use to store output + + for segment in segments: + # '.' is the current directory, so ignore it, it is superfluous + if segment == ".": + continue + # Anything other than '..', should be appended to the output + elif segment != "..": + output.append(segment) + # In this case segment == '..', if we can, we should pop the last + # element + elif output: + output.pop() + + # If the path starts with '/' and the output is empty or the first string + # is non-empty + if path.startswith("/") and (not output or output[0]): + output.insert(0, "") + + # If the path starts with '/.' or '/..' ensure we add one more empty + # string to add a trailing '/' + if path.endswith(("/.", "/..")): + output.append("") + + return "/".join(output) + + +def _normalize_host(host, scheme): + if host: + if isinstance(host, six.binary_type): + host = six.ensure_str(host) + + if scheme in NORMALIZABLE_SCHEMES: + is_ipv6 = IPV6_ADDRZ_RE.match(host) + if is_ipv6: + # IPv6 hosts of the form 'a::b%zone' are encoded in a URL as + # such per RFC 6874: 'a::b%25zone'. Unquote the ZoneID + # separator as necessary to return a valid RFC 4007 scoped IP. + match = ZONE_ID_RE.search(host) + if match: + start, end = match.span(1) + zone_id = host[start:end] + + if zone_id.startswith("%25") and zone_id != "%25": + zone_id = zone_id[3:] + else: + zone_id = zone_id[1:] + zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS) + return host[:start].lower() + zone_id + host[end:] + else: + return host.lower() + elif not IPV4_RE.match(host): + return six.ensure_str( + b".".join([_idna_encode(label) for label in host.split(".")]) + ) + return host + + +def _idna_encode(name): + if name and any(ord(x) >= 128 for x in name): + try: + from pip._vendor import idna + except ImportError: + six.raise_from( + LocationParseError("Unable to parse URL without the 'idna' module"), + None, + ) + try: + return idna.encode(name.lower(), strict=True, std3_rules=True) + except idna.IDNAError: + six.raise_from( + LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None + ) + return name.lower().encode("ascii") + + +def _encode_target(target): + """Percent-encodes a request target so that there are no invalid characters""" + path, query = TARGET_RE.match(target).groups() + target = _encode_invalid_chars(path, PATH_CHARS) + query = _encode_invalid_chars(query, QUERY_CHARS) + if query is not None: + target += "?" + query + return target + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + This parser is RFC 3986 and RFC 6874 compliant. + + The parser logic and helper functions are based heavily on + work done in the ``rfc3986`` module. + + :param str url: URL to parse into a :class:`.Url` namedtuple. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/mail/', ...) + >>> parse_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> parse_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + if not url: + # Empty + return Url() + + source_url = url + if not SCHEME_RE.search(url): + url = "//" + url + + try: + scheme, authority, path, query, fragment = URI_RE.match(url).groups() + normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES + + if scheme: + scheme = scheme.lower() + + if authority: + auth, _, host_port = authority.rpartition("@") + auth = auth or None + host, port = _HOST_PORT_RE.match(host_port).groups() + if auth and normalize_uri: + auth = _encode_invalid_chars(auth, USERINFO_CHARS) + if port == "": + port = None + else: + auth, host, port = None, None, None + + if port is not None: + port = int(port) + if not (0 <= port <= 65535): + raise LocationParseError(url) + + host = _normalize_host(host, scheme) + + if normalize_uri and path: + path = _remove_path_dot_segments(path) + path = _encode_invalid_chars(path, PATH_CHARS) + if normalize_uri and query: + query = _encode_invalid_chars(query, QUERY_CHARS) + if normalize_uri and fragment: + fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS) + + except (ValueError, AttributeError): + return six.raise_from(LocationParseError(source_url), None) + + # For the sake of backwards compatibility we put empty + # string values for path if there are any defined values + # beyond the path in the URL. + # TODO: Remove this when we break backwards compatibility. + if not path: + if query is not None or fragment is not None: + path = "" + else: + path = None + + # Ensure that each part of the URL is a `str` for + # backwards compatibility. + if isinstance(url, six.text_type): + ensure_func = six.ensure_text + else: + ensure_func = six.ensure_str + + def ensure_type(x): + return x if x is None else ensure_func(x) + + return Url( + scheme=ensure_type(scheme), + auth=ensure_type(auth), + host=ensure_type(host), + port=port, + path=ensure_type(path), + query=ensure_type(query), + fragment=ensure_type(fragment), + ) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or "http", p.hostname, p.port diff --git a/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py new file mode 100644 index 0000000..21b4590 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py @@ -0,0 +1,152 @@ +import errno +import select +import sys +from functools import partial + +try: + from time import monotonic +except ImportError: + from time import time as monotonic + +__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"] + + +class NoWayToWaitForSocketError(Exception): + pass + + +# How should we wait on sockets? +# +# There are two types of APIs you can use for waiting on sockets: the fancy +# modern stateful APIs like epoll/kqueue, and the older stateless APIs like +# select/poll. The stateful APIs are more efficient when you have a lots of +# sockets to keep track of, because you can set them up once and then use them +# lots of times. But we only ever want to wait on a single socket at a time +# and don't want to keep track of state, so the stateless APIs are actually +# more efficient. So we want to use select() or poll(). +# +# Now, how do we choose between select() and poll()? On traditional Unixes, +# select() has a strange calling convention that makes it slow, or fail +# altogether, for high-numbered file descriptors. The point of poll() is to fix +# that, so on Unixes, we prefer poll(). +# +# On Windows, there is no poll() (or at least Python doesn't provide a wrapper +# for it), but that's OK, because on Windows, select() doesn't have this +# strange calling convention; plain select() works fine. +# +# So: on Windows we use select(), and everywhere else we use poll(). We also +# fall back to select() in case poll() is somehow broken or missing. + +if sys.version_info >= (3, 5): + # Modern Python, that retries syscalls by default + def _retry_on_intr(fn, timeout): + return fn(timeout) + +else: + # Old and broken Pythons. + def _retry_on_intr(fn, timeout): + if timeout is None: + deadline = float("inf") + else: + deadline = monotonic() + timeout + + while True: + try: + return fn(timeout) + # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7 + except (OSError, select.error) as e: + # 'e.args[0]' incantation works for both OSError and select.error + if e.args[0] != errno.EINTR: + raise + else: + timeout = deadline - monotonic() + if timeout < 0: + timeout = 0 + if timeout == float("inf"): + timeout = None + continue + + +def select_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + rcheck = [] + wcheck = [] + if read: + rcheck.append(sock) + if write: + wcheck.append(sock) + # When doing a non-blocking connect, most systems signal success by + # marking the socket writable. Windows, though, signals success by marked + # it as "exceptional". We paper over the difference by checking the write + # sockets for both conditions. (The stdlib selectors module does the same + # thing.) + fn = partial(select.select, rcheck, wcheck, wcheck) + rready, wready, xready = _retry_on_intr(fn, timeout) + return bool(rready or wready or xready) + + +def poll_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + mask = 0 + if read: + mask |= select.POLLIN + if write: + mask |= select.POLLOUT + poll_obj = select.poll() + poll_obj.register(sock, mask) + + # For some reason, poll() takes timeout in milliseconds + def do_poll(t): + if t is not None: + t *= 1000 + return poll_obj.poll(t) + + return bool(_retry_on_intr(do_poll, timeout)) + + +def null_wait_for_socket(*args, **kwargs): + raise NoWayToWaitForSocketError("no select-equivalent available") + + +def _have_working_poll(): + # Apparently some systems have a select.poll that fails as soon as you try + # to use it, either due to strange configuration or broken monkeypatching + # from libraries like eventlet/greenlet. + try: + poll_obj = select.poll() + _retry_on_intr(poll_obj.poll, 0) + except (AttributeError, OSError): + return False + else: + return True + + +def wait_for_socket(*args, **kwargs): + # We delay choosing which implementation to use until the first time we're + # called. We could do it at import time, but then we might make the wrong + # decision if someone goes wild with monkeypatching select.poll after + # we're imported. + global wait_for_socket + if _have_working_poll(): + wait_for_socket = poll_wait_for_socket + elif hasattr(select, "select"): + wait_for_socket = select_wait_for_socket + else: # Platform-specific: Appengine. + wait_for_socket = null_wait_for_socket + return wait_for_socket(*args, **kwargs) + + +def wait_for_read(sock, timeout=None): + """Waits for reading to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, read=True, timeout=timeout) + + +def wait_for_write(sock, timeout=None): + """Waits for writing to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, write=True, timeout=timeout) diff --git a/backend/venv/Lib/site-packages/pip/_vendor/vendor.txt b/backend/venv/Lib/site-packages/pip/_vendor/vendor.txt new file mode 100644 index 0000000..f04a9c1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/_vendor/vendor.txt @@ -0,0 +1,18 @@ +CacheControl==0.14.1 +distlib==0.3.9 +distro==1.9.0 +msgpack==1.1.0 +packaging==24.2 +platformdirs==4.3.6 +pyproject-hooks==1.2.0 +requests==2.32.3 + certifi==2024.8.30 + idna==3.10 + urllib3==1.26.20 +rich==13.9.4 + pygments==2.18.0 + typing_extensions==4.12.2 +resolvelib==1.0.1 +setuptools==70.3.0 +tomli==2.2.1 +truststore==0.10.0 diff --git a/backend/venv/Lib/site-packages/pip/py.typed b/backend/venv/Lib/site-packages/pip/py.typed new file mode 100644 index 0000000..493b53e --- /dev/null +++ b/backend/venv/Lib/site-packages/pip/py.typed @@ -0,0 +1,4 @@ +pip is a command line program. While it is implemented in Python, and so is +available for import, you must not use pip's internal APIs in this way. Typing +information is provided as a convenience only and is not a guarantee. Expect +unannounced changes to the API and types in releases. diff --git a/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/INSTALLER b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/METADATA b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/METADATA new file mode 100644 index 0000000..fe0df08 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/METADATA @@ -0,0 +1,1029 @@ +Metadata-Version: 2.4 +Name: pydantic +Version: 2.12.5 +Summary: Data validation using Python type hints +Project-URL: Homepage, https://github.com/pydantic/pydantic +Project-URL: Documentation, https://docs.pydantic.dev +Project-URL: Funding, https://github.com/sponsors/samuelcolvin +Project-URL: Source, https://github.com/pydantic/pydantic +Project-URL: Changelog, https://docs.pydantic.dev/latest/changelog/ +Author-email: Samuel Colvin , Eric Jolibois , Hasan Ramezani , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Terrence Dorsey , David Montague , Serge Matveenko , Marcelo Trylesinski , Sydney Runkle , David Hewitt , Alex Hall , Victorien Plot , Douwe Maan +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Hypothesis +Classifier: Framework :: Pydantic +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +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 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.9 +Requires-Dist: annotated-types>=0.6.0 +Requires-Dist: pydantic-core==2.41.5 +Requires-Dist: typing-extensions>=4.14.1 +Requires-Dist: typing-inspection>=0.4.2 +Provides-Extra: email +Requires-Dist: email-validator>=2.0.0; extra == 'email' +Provides-Extra: timezone +Requires-Dist: tzdata; (python_version >= '3.9' and platform_system == 'Windows') and extra == 'timezone' +Description-Content-Type: text/markdown + +# Pydantic Validation + +[![CI](https://img.shields.io/github/actions/workflow/status/pydantic/pydantic/ci.yml?branch=main&logo=github&label=CI)](https://github.com/pydantic/pydantic/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) +[![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/pydantic.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/pydantic) +[![pypi](https://img.shields.io/pypi/v/pydantic.svg)](https://pypi.python.org/pypi/pydantic) +[![CondaForge](https://img.shields.io/conda/v/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) +[![downloads](https://static.pepy.tech/badge/pydantic/month)](https://pepy.tech/project/pydantic) +[![versions](https://img.shields.io/pypi/pyversions/pydantic.svg)](https://github.com/pydantic/pydantic) +[![license](https://img.shields.io/github/license/pydantic/pydantic.svg)](https://github.com/pydantic/pydantic/blob/main/LICENSE) +[![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://docs.pydantic.dev/latest/contributing/#badges) +[![llms.txt](https://img.shields.io/badge/llms.txt-green)](https://docs.pydantic.dev/latest/llms.txt) + +Data validation using Python type hints. + +Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. +Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic. + +## Pydantic Logfire :fire: + +We've recently launched Pydantic Logfire to help you monitor your applications. +[Learn more](https://pydantic.dev/articles/logfire-announcement) + +## Pydantic V1.10 vs. V2 + +Pydantic V2 is a ground-up rewrite that offers many new features, performance improvements, and some breaking changes compared to Pydantic V1. + +If you're using Pydantic V1 you may want to look at the +[pydantic V1.10 Documentation](https://docs.pydantic.dev/) or, +[`1.10.X-fixes` git branch](https://github.com/pydantic/pydantic/tree/1.10.X-fixes). Pydantic V2 also ships with the latest version of Pydantic V1 built in so that you can incrementally upgrade your code base and projects: `from pydantic import v1 as pydantic_v1`. + +## Help + +See [documentation](https://docs.pydantic.dev/) for more details. + +## Installation + +Install using `pip install -U pydantic` or `conda install pydantic -c conda-forge`. +For more installation options to make Pydantic even faster, +see the [Install](https://docs.pydantic.dev/install/) section in the documentation. + +## A Simple Example + +```python +from datetime import datetime +from typing import Optional +from pydantic import BaseModel + +class User(BaseModel): + id: int + name: str = 'John Doe' + signup_ts: Optional[datetime] = None + friends: list[int] = [] + +external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']} +user = User(**external_data) +print(user) +#> User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] +print(user.id) +#> 123 +``` + +## Contributing + +For guidance on setting up a development environment and how to make a +contribution to Pydantic, see +[Contributing to Pydantic](https://docs.pydantic.dev/contributing/). + +## Reporting a Security Vulnerability + +See our [security policy](https://github.com/pydantic/pydantic/security/policy). + +## Changelog + + + + + +## v2.12.5 (2025-11-26) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.5) + +This is the fifth 2.12 patch release, addressing an issue with the `MISSING` sentinel and providing several documentation improvements. + +The next 2.13 minor release will be published in a couple weeks, and will include a new *polymorphic serialization* feature addressing +the remaining unexpected changes to the *serialize as any* behavior. + +* Fix pickle error when using `model_construct()` on a model with `MISSING` as a default value by [@ornariece](https://github.com/ornariece) in [#12522](https://github.com/pydantic/pydantic/pull/12522). +* Several updates to the documentation by [@Viicos](https://github.com/Viicos). + +## v2.12.4 (2025-11-05) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.4) + +This is the fourth 2.12 patch release, fixing more regressions, and reverting a change in the `build()` method +of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/). + +This patch release also fixes an issue with the serialization of IP address types, when `serialize_as_any` is used. The next patch release +will try to address the remaining issues with *serialize as any* behavior by introducing a new *polymorphic serialization* feature, that +should be used in most cases in place of *serialize as any*. + +* Fix issue with forward references in parent `TypedDict` classes by [@Viicos](https://github.com/Viicos) in [#12427](https://github.com/pydantic/pydantic/pull/12427). + + This issue is only relevant on Python 3.14 and greater. +* Exclude fields with `exclude_if` from JSON Schema required fields by [@Viicos](https://github.com/Viicos) in [#12430](https://github.com/pydantic/pydantic/pull/12430) +* Revert URL percent-encoding of credentials in the `build()` method + of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/) by [@davidhewitt](https://github.com/davidhewitt) in + [pydantic-core#1833](https://github.com/pydantic/pydantic-core/pull/1833). + + This was initially considered as a bugfix, but caused regressions and as such was fully reverted. The next release will include + an opt-in option to percent-encode components of the URL. +* Add type inference for IP address types by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1868](https://github.com/pydantic/pydantic-core/pull/1868). + + The 2.12 changes to the `serialize_as_any` behavior made it so that IP address types could not properly serialize to JSON. +* Avoid getting default values from defaultdict by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1853](https://github.com/pydantic/pydantic-core/pull/1853). + + This fixes a subtle regression in the validation behavior of the [`collections.defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict) + type. +* Fix issue with field serializers on nested typed dictionaries by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1879](https://github.com/pydantic/pydantic-core/pull/1879). +* Add more `pydantic-core` builds for the three-threaded version of Python 3.14 by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1864](https://github.com/pydantic/pydantic-core/pull/1864). + +## v2.12.3 (2025-10-17) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.3) + +### What's Changed + +This is the third 2.12 patch release, fixing issues related to the `FieldInfo` class, and reverting a change to the supported +[*after* model validator](https://docs.pydantic.dev/latest/concepts/validators/#model-validators) function signatures. + +* Raise a warning when an invalid after model validator function signature is raised by [@Viicos](https://github.com/Viicos) in [#12414](https://github.com/pydantic/pydantic/pull/12414). + Starting in 2.12.0, using class methods for *after* model validators raised an error, but the error wasn't raised concistently. We decided + to emit a deprecation warning instead. +* Add [`FieldInfo.asdict()`](https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.FieldInfo.asdict) method, improve documentation around `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#12411](https://github.com/pydantic/pydantic/pull/12411). + This also add back support for mutations on `FieldInfo` classes, that are reused as `Annotated` metadata. **However**, note that this is still + *not* a supported pattern. Instead, please refer to the [added example](https://docs.pydantic.dev/latest/examples/dynamic_models/) in the documentation. + +The [blog post](https://pydantic.dev/articles/pydantic-v2-12-release#changes) section on changes was also updated to document the changes related to `serialize_as_any`. + +## v2.12.2 (2025-10-14) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.2) + +### What's Changed + +#### Fixes + +* Release a new `pydantic-core` version, as a corrupted CPython 3.10 `manylinux2014_aarch64` wheel got uploaded ([pydantic-core#1843](https://github.com/pydantic/pydantic-core/pull/1843)). +* Fix issue with recursive generic models with a parent model class by [@Viicos](https://github.com/Viicos) in [#12398](https://github.com/pydantic/pydantic/pull/12398) + +## v2.12.1 (2025-10-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.1) + +### What's Changed + +This is the first 2.12 patch release, addressing most (but not all yet) regressions from the initial 2.12.0 release. + +#### Fixes + +* Do not evaluate annotations when inspecting validators and serializers by [@Viicos](https://github.com/Viicos) in [#12355](https://github.com/pydantic/pydantic/pull/12355) +* Make sure `None` is converted as `NoneType` in Python 3.14 by [@Viicos](https://github.com/Viicos) in [#12370](https://github.com/pydantic/pydantic/pull/12370) +* Backport V1 runtime warning when using Python 3.14 by [@Viicos](https://github.com/Viicos) in [#12367](https://github.com/pydantic/pydantic/pull/12367) +* Fix error message for invalid validator signatures by [@Viicos](https://github.com/Viicos) in [#12366](https://github.com/pydantic/pydantic/pull/12366) +* Populate field name in `ValidationInfo` for validation of default value by [@Viicos](https://github.com/Viicos) in [pydantic-core#1826](https://github.com/pydantic/pydantic-core/pull/1826) +* Encode credentials in `MultiHostUrl` builder by [@willswire](https://github.com/willswire) in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) +* Respect field serializers when using `serialize_as_any` serialization flag by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) +* Fix various `RootModel` serialization issues by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1836](https://github.com/pydantic/pydantic-core/pull/1836) + +### New Contributors + +* [@willswire](https://github.com/willswire) made their first contribution in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) + +## v2.12.0 (2025-10-07) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0) + +### What's Changed + +This is the final 2.12 release. It features the work of 20 external contributors and provides useful new features, along with initial Python 3.14 support. +Several minor changes (considered non-breaking changes according to our [versioning policy](https://docs.pydantic.dev/2.12/version-policy/#pydantic-v2)) +are also included in this release. Make sure to look into them before upgrading. + +**Note that Pydantic V1 is not compatible with Python 3.14 and greater**. + +Changes (see the alpha and beta releases for additional changes since 2.11): + +#### Packaging + +* Update V1 copy to v1.10.24 by [@Viicos](https://github.com/Viicos) in [#12338](https://github.com/pydantic/pydantic/pull/12338) + +#### New Features + +* Add `extra` parameter to the validate functions by [@anvilpete](https://github.com/anvilpete) in [#12233](https://github.com/pydantic/pydantic/pull/12233) +* Add `exclude_computed_fields` serialization option by [@Viicos](https://github.com/Viicos) in [#12334](https://github.com/pydantic/pydantic/pull/12334) +* Add `preverse_empty_path` URL options by [@Viicos](https://github.com/Viicos) in [#12336](https://github.com/pydantic/pydantic/pull/12336) +* Add `union_format` parameter to JSON Schema generation by [@Viicos](https://github.com/Viicos) in [#12147](https://github.com/pydantic/pydantic/pull/12147) +* Add `__qualname__` parameter for `create_model` by [@Atry](https://github.com/Atry) in [#12001](https://github.com/pydantic/pydantic/pull/12001) + +#### Fixes + +* Do not try to infer name from lambda definitions in pipelines API by [@Viicos](https://github.com/Viicos) in [#12289](https://github.com/pydantic/pydantic/pull/12289) +* Use proper namespace for functions in `TypeAdapter` by [@Viicos](https://github.com/Viicos) in [#12324](https://github.com/pydantic/pydantic/pull/12324) +* Use `Any` for context type annotation in `TypeAdapter` by [@inducer](https://github.com/inducer) in [#12279](https://github.com/pydantic/pydantic/pull/12279) +* Expose `FieldInfo` in `pydantic.fields.__all__` by [@Viicos](https://github.com/Viicos) in [#12339](https://github.com/pydantic/pydantic/pull/12339) +* Respect `validation_alias` in `@validate_call` by [@Viicos](https://github.com/Viicos) in [#12340](https://github.com/pydantic/pydantic/pull/12340) +* Use `Any` as context annotation in plugin API by [@Viicos](https://github.com/Viicos) in [#12341](https://github.com/pydantic/pydantic/pull/12341) +* Use proper `stacklevel` in warnings when possible by [@Viicos](https://github.com/Viicos) in [#12342](https://github.com/pydantic/pydantic/pull/12342) + +### New Contributors + +* [@anvilpete](https://github.com/anvilpete) made their first contribution in [#12233](https://github.com/pydantic/pydantic/pull/12233) +* [@JonathanWindell](https://github.com/JonathanWindell) made their first contribution in [#12327](https://github.com/pydantic/pydantic/pull/12327) +* [@inducer](https://github.com/inducer) made their first contribution in [#12279](https://github.com/pydantic/pydantic/pull/12279) +* [@Atry](https://github.com/Atry) made their first contribution in [#12001](https://github.com/pydantic/pydantic/pull/12001) + +## v2.12.0b1 (2025-10-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0b1) + +This is the first beta release of the upcoming 2.12 release. + +### What's Changed + +#### Packaging + +* Bump `pydantic-core` to v2.40.1 by [@Viicos](https://github.com/Viicos) in [#12314](https://github.com/pydantic/pydantic/pull/12314) + +#### New Features + +* Add support for `exclude_if` at the field level by [@andresliszt](https://github.com/andresliszt) in [#12141](https://github.com/pydantic/pydantic/pull/12141) +* Add `ValidateAs` annotation helper by [@Viicos](https://github.com/Viicos) in [#11942](https://github.com/pydantic/pydantic/pull/11942) +* Add configuration options for validation and JSON serialization of temporal types by [@ollz272](https://github.com/ollz272) in [#12068](https://github.com/pydantic/pydantic/pull/12068) +* Add support for PEP 728 by [@Viicos](https://github.com/Viicos) in [#12179](https://github.com/pydantic/pydantic/pull/12179) +* Add field name in serialization error by [@NicolasPllr1](https://github.com/NicolasPllr1) in [pydantic-core#1799](https://github.com/pydantic/pydantic-core/pull/1799) +* Add option to preserve empty URL paths by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1789](https://github.com/pydantic/pydantic-core/pull/1789) + +#### Changes + +* Raise error if an incompatible `pydantic-core` version is installed by [@Viicos](https://github.com/Viicos) in [#12196](https://github.com/pydantic/pydantic/pull/12196) +* Remove runtime warning for experimental features by [@Viicos](https://github.com/Viicos) in [#12265](https://github.com/pydantic/pydantic/pull/12265) +* Warn if registering virtual subclasses on Pydantic models by [@Viicos](https://github.com/Viicos) in [#11669](https://github.com/pydantic/pydantic/pull/11669) + +#### Fixes + +* Fix `__getattr__()` behavior on Pydantic models when a property raised an `AttributeError` and extra values are present by [@raspuchin](https://github.com/raspuchin) in [#12106](https://github.com/pydantic/pydantic/pull/12106) +* Add test to prevent regression with Pydantic models used as annotated metadata by [@Viicos](https://github.com/Viicos) in [#12133](https://github.com/pydantic/pydantic/pull/12133) +* Allow to use property setters on Pydantic dataclasses with `validate_assignment` set by [@Viicos](https://github.com/Viicos) in [#12173](https://github.com/pydantic/pydantic/pull/12173) +* Fix mypy v2 plugin for upcoming mypy release by [@cdce8p](https://github.com/cdce8p) in [#12209](https://github.com/pydantic/pydantic/pull/12209) +* Respect custom title in functions JSON Schema by [@Viicos](https://github.com/Viicos) in [#11892](https://github.com/pydantic/pydantic/pull/11892) +* Fix `ImportString` JSON serialization for objects with a `name` attribute by [@chr1sj0nes](https://github.com/chr1sj0nes) in [#12219](https://github.com/pydantic/pydantic/pull/12219) +* Do not error on fields overridden by methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#12290](https://github.com/pydantic/pydantic/pull/12290) + +### New Contributors + +* [@raspuchin](https://github.com/raspuchin) made their first contribution in [#12106](https://github.com/pydantic/pydantic/pull/12106) +* [@chr1sj0nes](https://github.com/chr1sj0nes) made their first contribution in [#12219](https://github.com/pydantic/pydantic/pull/12219) + +## v2.12.0a1 (2025-07-26) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0a1) + +This is the first alpha release of the upcoming 2.12 release, which adds initial support for Python 3.14. + +### What's Changed + +#### New Features + +* Add `__pydantic_on_complete__()` hook that is called once model is fully ready to be used by [@DouweM](https://github.com/DouweM) in [#11762](https://github.com/pydantic/pydantic/pull/11762) +* Add initial support for Python 3.14 by [@Viicos](https://github.com/Viicos) in [#11991](https://github.com/pydantic/pydantic/pull/11991) +* Add regex patterns to JSON schema for `Decimal` type by [@Dima-Bulavenko](https://github.com/Dima-Bulavenko) in [#11987](https://github.com/pydantic/pydantic/pull/11987) +* Add support for `doc` attribute on dataclass fields by [@Viicos](https://github.com/Viicos) in [#12077](https://github.com/pydantic/pydantic/pull/12077) +* Add experimental `MISSING` sentinel by [@Viicos](https://github.com/Viicos) in [#11883](https://github.com/pydantic/pydantic/pull/11883) + +#### Changes + +* Allow config and bases to be specified together in `create_model()` by [@Viicos](https://github.com/Viicos) in [#11714](https://github.com/pydantic/pydantic/pull/11714) +* Move some field logic out of the `GenerateSchema` class by [@Viicos](https://github.com/Viicos) in [#11733](https://github.com/pydantic/pydantic/pull/11733) +* Always make use of `inspect.getsourcelines()` for docstring extraction on Python 3.13 and greater by [@Viicos](https://github.com/Viicos) in [#11829](https://github.com/pydantic/pydantic/pull/11829) +* Only support the latest Mypy version by [@Viicos](https://github.com/Viicos) in [#11832](https://github.com/pydantic/pydantic/pull/11832) +* Do not implicitly convert after model validators to class methods by [@Viicos](https://github.com/Viicos) in [#11957](https://github.com/pydantic/pydantic/pull/11957) +* Refactor `FieldInfo` creation implementation by [@Viicos](https://github.com/Viicos) in [#11898](https://github.com/pydantic/pydantic/pull/11898) +* Make `Secret` covariant by [@bluenote10](https://github.com/bluenote10) in [#12008](https://github.com/pydantic/pydantic/pull/12008) +* Emit warning when field-specific metadata is used in invalid contexts by [@Viicos](https://github.com/Viicos) in [#12028](https://github.com/pydantic/pydantic/pull/12028) + +#### Fixes + +* Properly fetch plain serializer function when serializing default value in JSON Schema by [@Viicos](https://github.com/Viicos) in [#11721](https://github.com/pydantic/pydantic/pull/11721) +* Remove generics cache workaround by [@Viicos](https://github.com/Viicos) in [#11755](https://github.com/pydantic/pydantic/pull/11755) +* Remove coercion of decimal constraints by [@Viicos](https://github.com/Viicos) in [#11772](https://github.com/pydantic/pydantic/pull/11772) +* Fix crash when expanding root type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11735](https://github.com/pydantic/pydantic/pull/11735) +* Only mark model as complete once all fields are complete by [@DouweM](https://github.com/DouweM) in [#11759](https://github.com/pydantic/pydantic/pull/11759) +* Do not provide `field_name` in validator core schemas by [@DouweM](https://github.com/DouweM) in [#11761](https://github.com/pydantic/pydantic/pull/11761) +* Fix issue with recursive generic models by [@Viicos](https://github.com/Viicos) in [#11775](https://github.com/pydantic/pydantic/pull/11775) +* Fix qualified name comparison of private attributes during namespace inspection by [@karta9821](https://github.com/karta9821) in [#11803](https://github.com/pydantic/pydantic/pull/11803) +* Make sure Pydantic dataclasses with slots and `validate_assignment` can be unpickled by [@Viicos](https://github.com/Viicos) in [#11769](https://github.com/pydantic/pydantic/pull/11769) +* Traverse `function-before` schemas during schema gathering by [@Viicos](https://github.com/Viicos) in [#11801](https://github.com/pydantic/pydantic/pull/11801) +* Fix check for stdlib dataclasses by [@Viicos](https://github.com/Viicos) in [#11822](https://github.com/pydantic/pydantic/pull/11822) +* Check if `FieldInfo` is complete after applying type variable map by [@Viicos](https://github.com/Viicos) in [#11855](https://github.com/pydantic/pydantic/pull/11855) +* Do not delete mock validator/serializer in `model_rebuild()` by [@Viicos](https://github.com/Viicos) in [#11890](https://github.com/pydantic/pydantic/pull/11890) +* Rebuild dataclass fields before schema generation by [@Viicos](https://github.com/Viicos) in [#11949](https://github.com/pydantic/pydantic/pull/11949) +* Always store the original field assignment on `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11946](https://github.com/pydantic/pydantic/pull/11946) +* Do not use deprecated methods as default field values by [@Viicos](https://github.com/Viicos) in [#11914](https://github.com/pydantic/pydantic/pull/11914) +* Allow callable discriminator to be applied on PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in [#11941](https://github.com/pydantic/pydantic/pull/11941) +* Suppress core schema generation warning when using `SkipValidation` by [@ygsh0816](https://github.com/ygsh0816) in [#12002](https://github.com/pydantic/pydantic/pull/12002) +* Do not emit typechecking error for invalid `Field()` default with `validate_default` set to `True` by [@Viicos](https://github.com/Viicos) in [#11988](https://github.com/pydantic/pydantic/pull/11988) +* Refactor logic to support Pydantic's `Field()` function in dataclasses by [@Viicos](https://github.com/Viicos) in [#12051](https://github.com/pydantic/pydantic/pull/12051) + +#### Packaging + +* Update project metadata to use PEP 639 by [@Viicos](https://github.com/Viicos) in [#11694](https://github.com/pydantic/pydantic/pull/11694) +* Bump `mkdocs-llmstxt` to v0.2.0 by [@Viicos](https://github.com/Viicos) in [#11725](https://github.com/pydantic/pydantic/pull/11725) +* Bump `pydantic-core` to v2.35.1 by [@Viicos](https://github.com/Viicos) in [#11963](https://github.com/pydantic/pydantic/pull/11963) +* Bump dawidd6/action-download-artifact from 10 to 11 by [@dependabot](https://github.com/dependabot)[bot] in [#12033](https://github.com/pydantic/pydantic/pull/12033) +* Bump astral-sh/setup-uv from 5 to 6 by [@dependabot](https://github.com/dependabot)[bot] in [#11826](https://github.com/pydantic/pydantic/pull/11826) +* Update mypy to 1.17.0 by [@Viicos](https://github.com/Viicos) in [#12076](https://github.com/pydantic/pydantic/pull/12076) + +### New Contributors + +* [@parth-paradkar](https://github.com/parth-paradkar) made their first contribution in [#11695](https://github.com/pydantic/pydantic/pull/11695) +* [@dqkqd](https://github.com/dqkqd) made their first contribution in [#11739](https://github.com/pydantic/pydantic/pull/11739) +* [@fhightower](https://github.com/fhightower) made their first contribution in [#11722](https://github.com/pydantic/pydantic/pull/11722) +* [@gbaian10](https://github.com/gbaian10) made their first contribution in [#11766](https://github.com/pydantic/pydantic/pull/11766) +* [@DouweM](https://github.com/DouweM) made their first contribution in [#11759](https://github.com/pydantic/pydantic/pull/11759) +* [@bowenliang123](https://github.com/bowenliang123) made their first contribution in [#11719](https://github.com/pydantic/pydantic/pull/11719) +* [@rawwar](https://github.com/rawwar) made their first contribution in [#11799](https://github.com/pydantic/pydantic/pull/11799) +* [@karta9821](https://github.com/karta9821) made their first contribution in [#11803](https://github.com/pydantic/pydantic/pull/11803) +* [@jinnovation](https://github.com/jinnovation) made their first contribution in [#11834](https://github.com/pydantic/pydantic/pull/11834) +* [@zmievsa](https://github.com/zmievsa) made their first contribution in [#11861](https://github.com/pydantic/pydantic/pull/11861) +* [@Otto-AA](https://github.com/Otto-AA) made their first contribution in [#11860](https://github.com/pydantic/pydantic/pull/11860) +* [@ygsh0816](https://github.com/ygsh0816) made their first contribution in [#12002](https://github.com/pydantic/pydantic/pull/12002) +* [@lukland](https://github.com/lukland) made their first contribution in [#12015](https://github.com/pydantic/pydantic/pull/12015) +* [@Dima-Bulavenko](https://github.com/Dima-Bulavenko) made their first contribution in [#11987](https://github.com/pydantic/pydantic/pull/11987) +* [@GSemikozov](https://github.com/GSemikozov) made their first contribution in [#12050](https://github.com/pydantic/pydantic/pull/12050) +* [@hannah-heywa](https://github.com/hannah-heywa) made their first contribution in [#12082](https://github.com/pydantic/pydantic/pull/12082) + +## v2.11.7 (2025-06-14) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.7) + +### What's Changed + +#### Fixes + +* Copy `FieldInfo` instance if necessary during `FieldInfo` build by [@Viicos](https://github.com/Viicos) in [#11898](https://github.com/pydantic/pydantic/pull/11898) + +## v2.11.6 (2025-06-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.6) + +### What's Changed + +#### Fixes + +* Rebuild dataclass fields before schema generation by [@Viicos](https://github.com/Viicos) in [#11949](https://github.com/pydantic/pydantic/pull/11949) +* Always store the original field assignment on `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11946](https://github.com/pydantic/pydantic/pull/11946) + +## v2.11.5 (2025-05-22) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.5) + +### What's Changed + +#### Fixes + +* Check if `FieldInfo` is complete after applying type variable map by [@Viicos](https://github.com/Viicos) in [#11855](https://github.com/pydantic/pydantic/pull/11855) +* Do not delete mock validator/serializer in `model_rebuild()` by [@Viicos](https://github.com/Viicos) in [#11890](https://github.com/pydantic/pydantic/pull/11890) +* Do not duplicate metadata on model rebuild by [@Viicos](https://github.com/Viicos) in [#11902](https://github.com/pydantic/pydantic/pull/11902) + +## v2.11.4 (2025-04-29) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.4) + +### What's Changed + +#### Packaging + +* Bump `mkdocs-llmstxt` to v0.2.0 by [@Viicos](https://github.com/Viicos) in [#11725](https://github.com/pydantic/pydantic/pull/11725) + +#### Changes + +* Allow config and bases to be specified together in `create_model()` by [@Viicos](https://github.com/Viicos) in [#11714](https://github.com/pydantic/pydantic/pull/11714). + This change was backported as it was previously possible (although not meant to be supported) + to provide `model_config` as a field, which would make it possible to provide both configuration + and bases. + +#### Fixes + +* Remove generics cache workaround by [@Viicos](https://github.com/Viicos) in [#11755](https://github.com/pydantic/pydantic/pull/11755) +* Remove coercion of decimal constraints by [@Viicos](https://github.com/Viicos) in [#11772](https://github.com/pydantic/pydantic/pull/11772) +* Fix crash when expanding root type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11735](https://github.com/pydantic/pydantic/pull/11735) +* Fix issue with recursive generic models by [@Viicos](https://github.com/Viicos) in [#11775](https://github.com/pydantic/pydantic/pull/11775) +* Traverse `function-before` schemas during schema gathering by [@Viicos](https://github.com/Viicos) in [#11801](https://github.com/pydantic/pydantic/pull/11801) + +## v2.11.3 (2025-04-08) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.3) + +### What's Changed + +#### Packaging + +* Update V1 copy to v1.10.21 by [@Viicos](https://github.com/Viicos) in [#11706](https://github.com/pydantic/pydantic/pull/11706) + +#### Fixes + +* Preserve field description when rebuilding model fields by [@Viicos](https://github.com/Viicos) in [#11698](https://github.com/pydantic/pydantic/pull/11698) + +## v2.11.2 (2025-04-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.2) + +### What's Changed + +#### Fixes + +* Bump `pydantic-core` to v2.33.1 by [@Viicos](https://github.com/Viicos) in [#11678](https://github.com/pydantic/pydantic/pull/11678) +* Make sure `__pydantic_private__` exists before setting private attributes by [@Viicos](https://github.com/Viicos) in [#11666](https://github.com/pydantic/pydantic/pull/11666) +* Do not override `FieldInfo._complete` when using field from parent class by [@Viicos](https://github.com/Viicos) in [#11668](https://github.com/pydantic/pydantic/pull/11668) +* Provide the available definitions when applying discriminated unions by [@Viicos](https://github.com/Viicos) in [#11670](https://github.com/pydantic/pydantic/pull/11670) +* Do not expand root type in the mypy plugin for variables by [@Viicos](https://github.com/Viicos) in [#11676](https://github.com/pydantic/pydantic/pull/11676) +* Mention the attribute name in model fields deprecation message by [@Viicos](https://github.com/Viicos) in [#11674](https://github.com/pydantic/pydantic/pull/11674) +* Properly validate parameterized mappings by [@Viicos](https://github.com/Viicos) in [#11658](https://github.com/pydantic/pydantic/pull/11658) + +## v2.11.1 (2025-03-28) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.1) + +### What's Changed + +#### Fixes + +* Do not override `'definitions-ref'` schemas containing serialization schemas or metadata by [@Viicos](https://github.com/Viicos) in [#11644](https://github.com/pydantic/pydantic/pull/11644) + +## v2.11.0 (2025-03-27) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +See the [blog post](https://pydantic.dev/articles/pydantic-v2-11-release) for more details. + +#### Packaging + +* Bump `pydantic-core` to v2.33.0 by [@Viicos](https://github.com/Viicos) in [#11631](https://github.com/pydantic/pydantic/pull/11631) + +#### New Features + +* Add `encoded_string()` method to the URL types by [@YassinNouh21](https://github.com/YassinNouh21) in [#11580](https://github.com/pydantic/pydantic/pull/11580) +* Add support for `defer_build` with `@validate_call` decorator by [@Viicos](https://github.com/Viicos) in [#11584](https://github.com/pydantic/pydantic/pull/11584) +* Allow `@with_config` decorator to be used with keyword arguments by [@Viicos](https://github.com/Viicos) in [#11608](https://github.com/pydantic/pydantic/pull/11608) +* Simplify customization of default value inclusion in JSON Schema generation by [@Viicos](https://github.com/Viicos) in [#11634](https://github.com/pydantic/pydantic/pull/11634) +* Add `generate_arguments_schema()` function by [@Viicos](https://github.com/Viicos) in [#11572](https://github.com/pydantic/pydantic/pull/11572) + +#### Fixes + +* Allow generic typed dictionaries to be used for unpacked variadic keyword parameters by [@Viicos](https://github.com/Viicos) in [#11571](https://github.com/pydantic/pydantic/pull/11571) +* Fix runtime error when computing model string representation involving cached properties and self-referenced models by [@Viicos](https://github.com/Viicos) in [#11579](https://github.com/pydantic/pydantic/pull/11579) +* Preserve other steps when using the ellipsis in the pipeline API by [@Viicos](https://github.com/Viicos) in [#11626](https://github.com/pydantic/pydantic/pull/11626) +* Fix deferred discriminator application logic by [@Viicos](https://github.com/Viicos) in [#11591](https://github.com/pydantic/pydantic/pull/11591) + +### New Contributors + +* [@cmenon12](https://github.com/cmenon12) made their first contribution in [#11562](https://github.com/pydantic/pydantic/pull/11562) +* [@Jeukoh](https://github.com/Jeukoh) made their first contribution in [#11611](https://github.com/pydantic/pydantic/pull/11611) + +## v2.11.0b2 (2025-03-17) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b2) + +### What's Changed + +#### Packaging + +* Bump `pydantic-core` to v2.32.0 by [@Viicos](https://github.com/Viicos) in [#11567](https://github.com/pydantic/pydantic/pull/11567) + +#### New Features + +* Add experimental support for free threading by [@Viicos](https://github.com/Viicos) in [#11516](https://github.com/pydantic/pydantic/pull/11516) + +#### Fixes + +* Fix `NotRequired` qualifier not taken into account in stringified annotation by [@Viicos](https://github.com/Viicos) in [#11559](https://github.com/pydantic/pydantic/pull/11559) + +### New Contributors + +* [@joren485](https://github.com/joren485) made their first contribution in [#11547](https://github.com/pydantic/pydantic/pull/11547) + +## v2.11.0b1 (2025-03-06) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b1) + +### What's Changed + +#### Packaging + +* Add a `check_pydantic_core_version()` function by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11324 +* Remove `greenlet` development dependency by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11351 +* Use the `typing-inspection` library by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11479 +* Bump `pydantic-core` to `v2.31.1` by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11526 + +#### New Features + +* Support unsubstituted type variables with both a default and a bound or constraints by [@FyZzyss](https://github.com/FyZzyss) in https://github.com/pydantic/pydantic/pull/10789 +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11034 +* Raise a better error when a generic alias is used inside `type[]` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11088 +* Properly support PEP 695 generics syntax by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11189 +* Properly support type variable defaults by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11332 +* Add support for validating v6, v7, v8 UUIDs by [@astei](https://github.com/astei) in https://github.com/pydantic/pydantic/pull/11436 +* Improve alias configuration APIs by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11468 + +#### Changes + +* Rework `create_model` field definitions format by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11032 +* Raise a deprecation warning when a field is annotated as final with a default value by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11168 +* Deprecate accessing `model_fields` and `model_computed_fields` on instances by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11169 +* **Breaking Change:** Move core schema generation logic for path types inside the `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/10846 +* Remove Python 3.8 Support by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11258 +* Optimize calls to `get_type_ref` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10863 +* Disable `pydantic-core` core schema validation by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11271 + +#### Performance + +* Only evaluate `FieldInfo` annotations if required during schema building by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10769 +* Improve `__setattr__` performance of Pydantic models by caching setter functions by [@MarkusSintonen](https://github.com/MarkusSintonen) in https://github.com/pydantic/pydantic/pull/10868 +* Improve annotation application performance by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11186 +* Improve performance of `_typing_extra` module by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11255 +* Refactor and optimize schema cleaning logic by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11244 +* Create a single dictionary when creating a `CoreConfig` instance by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11384 +* Bump `pydantic-core` and thus use `SchemaValidator` and `SchemaSerializer` caching by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11402 +* Reuse cached core schemas for parametrized generic Pydantic models by [@MarkusSintonen](https://github.com/MarkusSintonen) in https://github.com/pydantic/pydantic/pull/11434 + +#### Fixes + +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/10872 +* Use the correct frame when instantiating a parametrized `TypeAdapter` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10893 +* Infer final fields with a default value as class variables in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11121 +* Recursively unpack `Literal` values if using PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11114 +* Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11116 +* Remove unused `_extract_get_pydantic_json_schema()` parameter by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11155 +* Improve discriminated union error message for invalid union variants by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11161 +* Unpack PEP 695 type aliases if using the `Annotated` form by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11109 +* Add missing stacklevel in `deprecated_instance_property` warning by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11200 +* Copy `WithJsonSchema` schema to avoid sharing mutated data by [@thejcannon](https://github.com/thejcannon) in https://github.com/pydantic/pydantic/pull/11014 +* Do not cache parametrized models when in the process of parametrizing another model by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10704 +* Add discriminated union related metadata entries to the `CoreMetadata` definition by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11216 +* Consolidate schema definitions logic in the `_Definitions` class by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11208 +* Support initializing root model fields with values of the `root` type in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11212 +* Fix various issues with dataclasses and `use_attribute_docstrings` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11246 +* Only compute normalized decimal places if necessary in `decimal_places_validator` by [@misrasaurabh1](https://github.com/misrasaurabh1) in https://github.com/pydantic/pydantic/pull/11281 +* Add support for `validation_alias` in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11295 +* Fix JSON Schema reference collection with `"examples"` keys by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11305 +* Do not transform model serializer functions as class methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11298 +* Simplify `GenerateJsonSchema.literal_schema()` implementation by [@misrasaurabh1](https://github.com/misrasaurabh1) in https://github.com/pydantic/pydantic/pull/11321 +* Add additional allowed schemes for `ClickHouseDsn` by [@Maze21127](https://github.com/Maze21127) in https://github.com/pydantic/pydantic/pull/11319 +* Coerce decimal constraints to `Decimal` instances by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11350 +* Use the correct JSON Schema mode when handling function schemas by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11367 +* Improve exception message when encountering recursion errors during type evaluation by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11356 +* Always include `additionalProperties: True` for arbitrary dictionary schemas by [@austinyu](https://github.com/austinyu) in https://github.com/pydantic/pydantic/pull/11392 +* Expose `fallback` parameter in serialization methods by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11398 +* Fix path serialization behavior by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11416 +* Do not reuse validators and serializers during model rebuild by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11429 +* Collect model fields when rebuilding a model by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11388 +* Allow cached properties to be altered on frozen models by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11432 +* Fix tuple serialization for `Sequence` types by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11435 +* Fix: do not check for `__get_validators__` on classes where `__get_pydantic_core_schema__` is also defined by [@tlambert03](https://github.com/tlambert03) in https://github.com/pydantic/pydantic/pull/11444 +* Allow callable instances to be used as serializers by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11451 +* Improve error thrown when overriding field with a property by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11459 +* Fix JSON Schema generation with referenceable core schemas holding JSON metadata by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11475 +* Support strict specification on union member types by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11481 +* Implicitly set `validate_by_name` to `True` when `validate_by_alias` is `False` by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11503 +* Change type of `Any` when synthesizing `BaseSettings.__init__` signature in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11497 +* Support type variable defaults referencing other type variables by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11520 +* Fix `ValueError` on year zero by [@davidhewitt](https://github.com/davidhewitt) in https://github.com/pydantic/pydantic-core/pull/1583 +* `dataclass` `InitVar` shouldn't be required on serialization by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic-core/pull/1602 + +## New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in https://github.com/pydantic/pydantic/pull/10789 +* [@tamird](https://github.com/tamird) made their first contribution in https://github.com/pydantic/pydantic/pull/10948 +* [@felixxm](https://github.com/felixxm) made their first contribution in https://github.com/pydantic/pydantic/pull/11077 +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in https://github.com/pydantic/pydantic/pull/11082 +* [@Kharianne](https://github.com/Kharianne) made their first contribution in https://github.com/pydantic/pydantic/pull/11111 +* [@mdaffad](https://github.com/mdaffad) made their first contribution in https://github.com/pydantic/pydantic/pull/11177 +* [@thejcannon](https://github.com/thejcannon) made their first contribution in https://github.com/pydantic/pydantic/pull/11014 +* [@thomasfrimannkoren](https://github.com/thomasfrimannkoren) made their first contribution in https://github.com/pydantic/pydantic/pull/11251 +* [@usernameMAI](https://github.com/usernameMAI) made their first contribution in https://github.com/pydantic/pydantic/pull/11275 +* [@ananiavito](https://github.com/ananiavito) made their first contribution in https://github.com/pydantic/pydantic/pull/11302 +* [@pawamoy](https://github.com/pawamoy) made their first contribution in https://github.com/pydantic/pydantic/pull/11311 +* [@Maze21127](https://github.com/Maze21127) made their first contribution in https://github.com/pydantic/pydantic/pull/11319 +* [@kauabh](https://github.com/kauabh) made their first contribution in https://github.com/pydantic/pydantic/pull/11369 +* [@jaceklaskowski](https://github.com/jaceklaskowski) made their first contribution in https://github.com/pydantic/pydantic/pull/11353 +* [@tmpbeing](https://github.com/tmpbeing) made their first contribution in https://github.com/pydantic/pydantic/pull/11375 +* [@petyosi](https://github.com/petyosi) made their first contribution in https://github.com/pydantic/pydantic/pull/11405 +* [@austinyu](https://github.com/austinyu) made their first contribution in https://github.com/pydantic/pydantic/pull/11392 +* [@mikeedjones](https://github.com/mikeedjones) made their first contribution in https://github.com/pydantic/pydantic/pull/11402 +* [@astei](https://github.com/astei) made their first contribution in https://github.com/pydantic/pydantic/pull/11436 +* [@dsayling](https://github.com/dsayling) made their first contribution in https://github.com/pydantic/pydantic/pull/11522 +* [@sobolevn](https://github.com/sobolevn) made their first contribution in https://github.com/pydantic/pydantic-core/pull/1645 + +## v2.11.0a2 (2025-02-10) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a2) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +This is another early alpha release, meant to collect early feedback from users having issues with core schema builds. + +#### Packaging + +* Bump `ruff` from 0.9.2 to 0.9.5 by [@Viicos](https://github.com/Viicos) in [#11407](https://github.com/pydantic/pydantic/pull/11407) +* Bump `pydantic-core` to v2.29.0 by [@mikeedjones](https://github.com/mikeedjones) in [#11402](https://github.com/pydantic/pydantic/pull/11402) +* Use locally-built rust with symbols & pgo by [@davidhewitt](https://github.com/davidhewitt) in [#11403](https://github.com/pydantic/pydantic/pull/11403) + +#### Performance + +* Create a single dictionary when creating a `CoreConfig` instance by [@sydney-runkle](https://github.com/sydney-runkle) in [#11384](https://github.com/pydantic/pydantic/pull/11384) + +#### Fixes + +* Use the correct JSON Schema mode when handling function schemas by [@Viicos](https://github.com/Viicos) in [#11367](https://github.com/pydantic/pydantic/pull/11367) +* Fix JSON Schema reference logic with `examples` keys by [@Viicos](https://github.com/Viicos) in [#11366](https://github.com/pydantic/pydantic/pull/11366) +* Improve exception message when encountering recursion errors during type evaluation by [@Viicos](https://github.com/Viicos) in [#11356](https://github.com/pydantic/pydantic/pull/11356) +* Always include `additionalProperties: True` for arbitrary dictionary schemas by [@austinyu](https://github.com/austinyu) in [#11392](https://github.com/pydantic/pydantic/pull/11392) +* Expose `fallback` parameter in serialization methods by [@Viicos](https://github.com/Viicos) in [#11398](https://github.com/pydantic/pydantic/pull/11398) +* Fix path serialization behavior by [@sydney-runkle](https://github.com/sydney-runkle) in [#11416](https://github.com/pydantic/pydantic/pull/11416) + +### New Contributors + +* [@kauabh](https://github.com/kauabh) made their first contribution in [#11369](https://github.com/pydantic/pydantic/pull/11369) +* [@jaceklaskowski](https://github.com/jaceklaskowski) made their first contribution in [#11353](https://github.com/pydantic/pydantic/pull/11353) +* [@tmpbeing](https://github.com/tmpbeing) made their first contribution in [#11375](https://github.com/pydantic/pydantic/pull/11375) +* [@petyosi](https://github.com/petyosi) made their first contribution in [#11405](https://github.com/pydantic/pydantic/pull/11405) +* [@austinyu](https://github.com/austinyu) made their first contribution in [#11392](https://github.com/pydantic/pydantic/pull/11392) +* [@mikeedjones](https://github.com/mikeedjones) made their first contribution in [#11402](https://github.com/pydantic/pydantic/pull/11402) + +## v2.11.0a1 (2025-01-30) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a1) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +This is an early alpha release, meant to collect early feedback from users having issues with core schema builds. + +#### Packaging + +* Bump dawidd6/action-download-artifact from 6 to 7 by [@dependabot](https://github.com/dependabot) in [#11018](https://github.com/pydantic/pydantic/pull/11018) +* Re-enable memray related tests on Python 3.12+ by [@Viicos](https://github.com/Viicos) in [#11191](https://github.com/pydantic/pydantic/pull/11191) +* Bump astral-sh/setup-uv to 5 by [@dependabot](https://github.com/dependabot) in [#11205](https://github.com/pydantic/pydantic/pull/11205) +* Bump `ruff` to v0.9.0 by [@sydney-runkle](https://github.com/sydney-runkle) in [#11254](https://github.com/pydantic/pydantic/pull/11254) +* Regular `uv.lock` deps update by [@sydney-runkle](https://github.com/sydney-runkle) in [#11333](https://github.com/pydantic/pydantic/pull/11333) +* Add a `check_pydantic_core_version()` function by [@Viicos](https://github.com/Viicos) in [#11324](https://github.com/pydantic/pydantic/pull/11324) +* Remove `greenlet` development dependency by [@Viicos](https://github.com/Viicos) in [#11351](https://github.com/pydantic/pydantic/pull/11351) +* Bump `pydantic-core` to v2.28.0 by [@Viicos](https://github.com/Viicos) in [#11364](https://github.com/pydantic/pydantic/pull/11364) + +#### New Features + +* Support unsubstituted type variables with both a default and a bound or constraints by [@FyZzyss](https://github.com/FyZzyss) in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11034](https://github.com/pydantic/pydantic/pull/11034) +* Raise a better error when a generic alias is used inside `type[]` by [@Viicos](https://github.com/Viicos) in [#11088](https://github.com/pydantic/pydantic/pull/11088) +* Properly support PEP 695 generics syntax by [@Viicos](https://github.com/Viicos) in [#11189](https://github.com/pydantic/pydantic/pull/11189) +* Properly support type variable defaults by [@Viicos](https://github.com/Viicos) in [#11332](https://github.com/pydantic/pydantic/pull/11332) + +#### Changes + +* Rework `create_model` field definitions format by [@Viicos](https://github.com/Viicos) in [#11032](https://github.com/pydantic/pydantic/pull/11032) +* Raise a deprecation warning when a field is annotated as final with a default value by [@Viicos](https://github.com/Viicos) in [#11168](https://github.com/pydantic/pydantic/pull/11168) +* Deprecate accessing `model_fields` and `model_computed_fields` on instances by [@Viicos](https://github.com/Viicos) in [#11169](https://github.com/pydantic/pydantic/pull/11169) +* Move core schema generation logic for path types inside the `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in [#10846](https://github.com/pydantic/pydantic/pull/10846) +* Move `deque` schema gen to `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in [#11239](https://github.com/pydantic/pydantic/pull/11239) +* Move `Mapping` schema gen to `GenerateSchema` to complete removal of `prepare_annotations_for_known_type` workaround by [@sydney-runkle](https://github.com/sydney-runkle) in [#11247](https://github.com/pydantic/pydantic/pull/11247) +* Remove Python 3.8 Support by [@sydney-runkle](https://github.com/sydney-runkle) in [#11258](https://github.com/pydantic/pydantic/pull/11258) +* Disable `pydantic-core` core schema validation by [@sydney-runkle](https://github.com/sydney-runkle) in [#11271](https://github.com/pydantic/pydantic/pull/11271) + +#### Performance + +* Only evaluate `FieldInfo` annotations if required during schema building by [@Viicos](https://github.com/Viicos) in [#10769](https://github.com/pydantic/pydantic/pull/10769) +* Optimize calls to `get_type_ref` by [@Viicos](https://github.com/Viicos) in [#10863](https://github.com/pydantic/pydantic/pull/10863) +* Improve `__setattr__` performance of Pydantic models by caching setter functions by [@MarkusSintonen](https://github.com/MarkusSintonen) in [#10868](https://github.com/pydantic/pydantic/pull/10868) +* Improve annotation application performance by [@Viicos](https://github.com/Viicos) in [#11186](https://github.com/pydantic/pydantic/pull/11186) +* Improve performance of `_typing_extra` module by [@Viicos](https://github.com/Viicos) in [#11255](https://github.com/pydantic/pydantic/pull/11255) +* Refactor and optimize schema cleaning logic by [@Viicos](https://github.com/Viicos) and [@MarkusSintonen](https://github.com/MarkusSintonen) in [#11244](https://github.com/pydantic/pydantic/pull/11244) + +#### Fixes + +* Add validation tests for `_internal/_validators.py` by [@tkasuz](https://github.com/tkasuz) in [#10763](https://github.com/pydantic/pydantic/pull/10763) +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in [#10872](https://github.com/pydantic/pydantic/pull/10872) +* Revert "ci: use locally built pydantic-core with debug symbols by [@sydney-runkle](https://github.com/sydney-runkle) in [#10942](https://github.com/pydantic/pydantic/pull/10942) +* Re-enable all FastAPI tests by [@tamird](https://github.com/tamird) in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* Fix typo in HISTORY.md. by [@felixxm](https://github.com/felixxm) in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* Infer final fields with a default value as class variables in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11121](https://github.com/pydantic/pydantic/pull/11121) +* Recursively unpack `Literal` values if using PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in [#11114](https://github.com/pydantic/pydantic/pull/11114) +* Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by [@Viicos](https://github.com/Viicos) in [#11116](https://github.com/pydantic/pydantic/pull/11116) +* Remove unused `_extract_get_pydantic_json_schema()` parameter by [@Viicos](https://github.com/Viicos) in [#11155](https://github.com/pydantic/pydantic/pull/11155) +* Add FastAPI and SQLModel to third-party tests by [@sydney-runkle](https://github.com/sydney-runkle) in [#11044](https://github.com/pydantic/pydantic/pull/11044) +* Fix conditional expressions syntax for third-party tests by [@Viicos](https://github.com/Viicos) in [#11162](https://github.com/pydantic/pydantic/pull/11162) +* Move FastAPI tests to third-party workflow by [@Viicos](https://github.com/Viicos) in [#11164](https://github.com/pydantic/pydantic/pull/11164) +* Improve discriminated union error message for invalid union variants by [@Viicos](https://github.com/Viicos) in [#11161](https://github.com/pydantic/pydantic/pull/11161) +* Unpack PEP 695 type aliases if using the `Annotated` form by [@Viicos](https://github.com/Viicos) in [#11109](https://github.com/pydantic/pydantic/pull/11109) +* Include `openapi-python-client` check in issue creation for third-party failures, use `main` branch by [@sydney-runkle](https://github.com/sydney-runkle) in [#11182](https://github.com/pydantic/pydantic/pull/11182) +* Add pandera third-party tests by [@Viicos](https://github.com/Viicos) in [#11193](https://github.com/pydantic/pydantic/pull/11193) +* Add ODMantic third-party tests by [@sydney-runkle](https://github.com/sydney-runkle) in [#11197](https://github.com/pydantic/pydantic/pull/11197) +* Add missing stacklevel in `deprecated_instance_property` warning by [@Viicos](https://github.com/Viicos) in [#11200](https://github.com/pydantic/pydantic/pull/11200) +* Copy `WithJsonSchema` schema to avoid sharing mutated data by [@thejcannon](https://github.com/thejcannon) in [#11014](https://github.com/pydantic/pydantic/pull/11014) +* Do not cache parametrized models when in the process of parametrizing another model by [@Viicos](https://github.com/Viicos) in [#10704](https://github.com/pydantic/pydantic/pull/10704) +* Re-enable Beanie third-party tests by [@Viicos](https://github.com/Viicos) in [#11214](https://github.com/pydantic/pydantic/pull/11214) +* Add discriminated union related metadata entries to the `CoreMetadata` definition by [@Viicos](https://github.com/Viicos) in [#11216](https://github.com/pydantic/pydantic/pull/11216) +* Consolidate schema definitions logic in the `_Definitions` class by [@Viicos](https://github.com/Viicos) in [#11208](https://github.com/pydantic/pydantic/pull/11208) +* Support initializing root model fields with values of the `root` type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11212](https://github.com/pydantic/pydantic/pull/11212) +* Fix various issues with dataclasses and `use_attribute_docstrings` by [@Viicos](https://github.com/Viicos) in [#11246](https://github.com/pydantic/pydantic/pull/11246) +* Only compute normalized decimal places if necessary in `decimal_places_validator` by [@misrasaurabh1](https://github.com/misrasaurabh1) in [#11281](https://github.com/pydantic/pydantic/pull/11281) +* Fix two misplaced sentences in validation errors documentation by [@ananiavito](https://github.com/ananiavito) in [#11302](https://github.com/pydantic/pydantic/pull/11302) +* Fix mkdocstrings inventory example in documentation by [@pawamoy](https://github.com/pawamoy) in [#11311](https://github.com/pydantic/pydantic/pull/11311) +* Add support for `validation_alias` in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11295](https://github.com/pydantic/pydantic/pull/11295) +* Do not transform model serializer functions as class methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11298](https://github.com/pydantic/pydantic/pull/11298) +* Simplify `GenerateJsonSchema.literal_schema()` implementation by [@misrasaurabh1](https://github.com/misrasaurabh1) in [#11321](https://github.com/pydantic/pydantic/pull/11321) +* Add additional allowed schemes for `ClickHouseDsn` by [@Maze21127](https://github.com/Maze21127) in [#11319](https://github.com/pydantic/pydantic/pull/11319) +* Coerce decimal constraints to `Decimal` instances by [@Viicos](https://github.com/Viicos) in [#11350](https://github.com/pydantic/pydantic/pull/11350) +* Fix `ValueError` on year zero by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1583](https://github.com/pydantic/pydantic-core/pull/1583) + +### New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* [@tamird](https://github.com/tamird) made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* [@felixxm](https://github.com/felixxm) made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* [@Kharianne](https://github.com/Kharianne) made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) +* [@mdaffad](https://github.com/mdaffad) made their first contribution in [#11177](https://github.com/pydantic/pydantic/pull/11177) +* [@thejcannon](https://github.com/thejcannon) made their first contribution in [#11014](https://github.com/pydantic/pydantic/pull/11014) +* [@thomasfrimannkoren](https://github.com/thomasfrimannkoren) made their first contribution in [#11251](https://github.com/pydantic/pydantic/pull/11251) +* [@usernameMAI](https://github.com/usernameMAI) made their first contribution in [#11275](https://github.com/pydantic/pydantic/pull/11275) +* [@ananiavito](https://github.com/ananiavito) made their first contribution in [#11302](https://github.com/pydantic/pydantic/pull/11302) +* [@pawamoy](https://github.com/pawamoy) made their first contribution in [#11311](https://github.com/pydantic/pydantic/pull/11311) +* [@Maze21127](https://github.com/Maze21127) made their first contribution in [#11319](https://github.com/pydantic/pydantic/pull/11319) + +## v2.10.6 (2025-01-23) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.6) + +### What's Changed + +#### Fixes + +* Fix JSON Schema reference collection with `'examples'` keys by [@Viicos](https://github.com/Viicos) in [#11325](https://github.com/pydantic/pydantic/pull/11325) +* Fix url python serialization by [@sydney-runkle](https://github.com/sydney-runkle) in [#11331](https://github.com/pydantic/pydantic/pull/11331) + +## v2.10.5 (2025-01-08) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.5) + +### What's Changed + +#### Fixes + +* Remove custom MRO implementation of Pydantic models by [@Viicos](https://github.com/Viicos) in [#11184](https://github.com/pydantic/pydantic/pull/11184) +* Fix URL serialization for unions by [@sydney-runkle](https://github.com/sydney-runkle) in [#11233](https://github.com/pydantic/pydantic/pull/11233) + +## v2.10.4 (2024-12-18) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.4) + +### What's Changed + +#### Packaging + +* Bump `pydantic-core` to v2.27.2 by [@davidhewitt](https://github.com/davidhewitt) in [#11138](https://github.com/pydantic/pydantic/pull/11138) + +#### Fixes + +* Fix for comparison of `AnyUrl` objects by [@alexprabhat99](https://github.com/alexprabhat99) in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* Properly fetch PEP 695 type params for functions, do not fetch annotations from signature by [@Viicos](https://github.com/Viicos) in [#11093](https://github.com/pydantic/pydantic/pull/11093) +* Include JSON Schema input core schema in function schemas by [@Viicos](https://github.com/Viicos) in [#11085](https://github.com/pydantic/pydantic/pull/11085) +* Add `len` to `_BaseUrl` to avoid TypeError by [@Kharianne](https://github.com/Kharianne) in [#11111](https://github.com/pydantic/pydantic/pull/11111) +* Make sure the type reference is removed from the seen references by [@Viicos](https://github.com/Viicos) in [#11143](https://github.com/pydantic/pydantic/pull/11143) + +### New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* [@tamird](https://github.com/tamird) made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* [@felixxm](https://github.com/felixxm) made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* [@Kharianne](https://github.com/Kharianne) made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) + +## v2.10.3 (2024-12-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.3) + +### What's Changed + +#### Fixes + +* Set fields when `defer_build` is set on Pydantic dataclasses by [@Viicos](https://github.com/Viicos) in [#10984](https://github.com/pydantic/pydantic/pull/10984) +* Do not resolve the JSON Schema reference for `dict` core schema keys by [@Viicos](https://github.com/Viicos) in [#10989](https://github.com/pydantic/pydantic/pull/10989) +* Use the globals of the function when evaluating the return type for `PlainSerializer` and `WrapSerializer` functions by [@Viicos](https://github.com/Viicos) in [#11008](https://github.com/pydantic/pydantic/pull/11008) +* Fix host required enforcement for urls to be compatible with v2.9 behavior by [@sydney-runkle](https://github.com/sydney-runkle) in [#11027](https://github.com/pydantic/pydantic/pull/11027) +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11034](https://github.com/pydantic/pydantic/pull/11034) +* Fix url json schema in `serialization` mode by [@sydney-runkle](https://github.com/sydney-runkle) in [#11035](https://github.com/pydantic/pydantic/pull/11035) + +## v2.10.2 (2024-11-25) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.2) + +### What's Changed + +#### Fixes + +* Only evaluate FieldInfo annotations if required during schema building by [@Viicos](https://github.com/Viicos) in [#10769](https://github.com/pydantic/pydantic/pull/10769) +* Do not evaluate annotations for private fields by [@Viicos](https://github.com/Viicos) in [#10962](https://github.com/pydantic/pydantic/pull/10962) +* Support serialization as any for `Secret` types and `Url` types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10947](https://github.com/pydantic/pydantic/pull/10947) +* Fix type hint of `Field.default` to be compatible with Python 3.8 and 3.9 by [@Viicos](https://github.com/Viicos) in [#10972](https://github.com/pydantic/pydantic/pull/10972) +* Add hashing support for URL types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10975](https://github.com/pydantic/pydantic/pull/10975) +* Hide `BaseModel.__replace__` definition from type checkers by [@Viicos](https://github.com/Viicos) in [#10979](https://github.com/pydantic/pydantic/pull/10979) + +## v2.10.1 (2024-11-21) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.1) + +### What's Changed + +#### Packaging + +* Bump `pydantic-core` version to `v2.27.1` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10938](https://github.com/pydantic/pydantic/pull/10938) + +#### Fixes + +* Use the correct frame when instantiating a parametrized `TypeAdapter` by [@Viicos](https://github.com/Viicos) in [#10893](https://github.com/pydantic/pydantic/pull/10893) +* Relax check for validated data in `default_factory` utils by [@sydney-runkle](https://github.com/sydney-runkle) in [#10909](https://github.com/pydantic/pydantic/pull/10909) +* Fix type checking issue with `model_fields` and `model_computed_fields` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10911](https://github.com/pydantic/pydantic/pull/10911) +* Use the parent configuration during schema generation for stdlib `dataclass`es by [@sydney-runkle](https://github.com/sydney-runkle) in [#10928](https://github.com/pydantic/pydantic/pull/10928) +* Use the `globals` of the function when evaluating the return type of serializers and `computed_field`s by [@Viicos](https://github.com/Viicos) in [#10929](https://github.com/pydantic/pydantic/pull/10929) +* Fix URL constraint application by [@sydney-runkle](https://github.com/sydney-runkle) in [#10922](https://github.com/pydantic/pydantic/pull/10922) +* Fix URL equality with different validation methods by [@sydney-runkle](https://github.com/sydney-runkle) in [#10934](https://github.com/pydantic/pydantic/pull/10934) +* Fix JSON schema title when specified as `''` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10936](https://github.com/pydantic/pydantic/pull/10936) +* Fix `python` mode serialization for `complex` inference by [@sydney-runkle](https://github.com/sydney-runkle) in [pydantic-core#1549](https://github.com/pydantic/pydantic-core/pull/1549) + +### New Contributors + +## v2.10.0 (2024-11-20) + +The code released in v2.10.0 is practically identical to that of v2.10.0b2. + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0) + +See the [v2.10 release blog post](https://pydantic.dev/articles/pydantic-v2-10-release) for the highlights! + +### What's Changed + +#### Packaging + +* Bump `pydantic-core` to `v2.27.0` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10825](https://github.com/pydantic/pydantic/pull/10825) +* Replaced pdm with uv by [@frfahim](https://github.com/frfahim) in [#10727](https://github.com/pydantic/pydantic/pull/10727) + +#### New Features + +* Support `fractions.Fraction` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10318](https://github.com/pydantic/pydantic/pull/10318) +* Support `Hashable` for json validation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10324](https://github.com/pydantic/pydantic/pull/10324) +* Add a `SocketPath` type for `linux` systems by [@theunkn0wn1](https://github.com/theunkn0wn1) in [#10378](https://github.com/pydantic/pydantic/pull/10378) +* Allow arbitrary refs in JSON schema `examples` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10417](https://github.com/pydantic/pydantic/pull/10417) +* Support `defer_build` for Pydantic dataclasses by [@Viicos](https://github.com/Viicos) in [#10313](https://github.com/pydantic/pydantic/pull/10313) +* Adding v1 / v2 incompatibility warning for nested v1 model by [@sydney-runkle](https://github.com/sydney-runkle) in [#10431](https://github.com/pydantic/pydantic/pull/10431) +* Add support for unpacked `TypedDict` to type hint variadic keyword arguments with `@validate_call` by [@Viicos](https://github.com/Viicos) in [#10416](https://github.com/pydantic/pydantic/pull/10416) +* Support compiled patterns in `protected_namespaces` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10522](https://github.com/pydantic/pydantic/pull/10522) +* Add support for `propertyNames` in JSON schema by [@FlorianSW](https://github.com/FlorianSW) in [#10478](https://github.com/pydantic/pydantic/pull/10478) +* Adding `__replace__` protocol for Python 3.13+ support by [@sydney-runkle](https://github.com/sydney-runkle) in [#10596](https://github.com/pydantic/pydantic/pull/10596) +* Expose public `sort` method for JSON schema generation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10595](https://github.com/pydantic/pydantic/pull/10595) +* Add runtime validation of `@validate_call` callable argument by [@kc0506](https://github.com/kc0506) in [#10627](https://github.com/pydantic/pydantic/pull/10627) +* Add `experimental_allow_partial` support by [@samuelcolvin](https://github.com/samuelcolvin) in [#10748](https://github.com/pydantic/pydantic/pull/10748) +* Support default factories taking validated data as an argument by [@Viicos](https://github.com/Viicos) in [#10678](https://github.com/pydantic/pydantic/pull/10678) +* Allow subclassing `ValidationError` and `PydanticCustomError` by [@Youssefares](https://github.com/Youssefares) in [pydantic/pydantic-core#1413](https://github.com/pydantic/pydantic-core/pull/1413) +* Add `trailing-strings` support to `experimental_allow_partial` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10825](https://github.com/pydantic/pydantic/pull/10825) +* Add `rebuild()` method for `TypeAdapter` and simplify `defer_build` patterns by [@sydney-runkle](https://github.com/sydney-runkle) in [#10537](https://github.com/pydantic/pydantic/pull/10537) +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in [#10872](https://github.com/pydantic/pydantic/pull/10872) + +#### Changes + +* Don't allow customization of `SchemaGenerator` until interface is more stable by [@sydney-runkle](https://github.com/sydney-runkle) in [#10303](https://github.com/pydantic/pydantic/pull/10303) +* Cleanly `defer_build` on `TypeAdapters`, removing experimental flag by [@sydney-runkle](https://github.com/sydney-runkle) in [#10329](https://github.com/pydantic/pydantic/pull/10329) +* Fix `mro` of generic subclass by [@kc0506](https://github.com/kc0506) in [#10100](https://github.com/pydantic/pydantic/pull/10100) +* Strip whitespaces on JSON Schema title generation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10404](https://github.com/pydantic/pydantic/pull/10404) +* Use `b64decode` and `b64encode` for `Base64Bytes` type by [@sydney-runkle](https://github.com/sydney-runkle) in [#10486](https://github.com/pydantic/pydantic/pull/10486) +* Relax protected namespace config default by [@sydney-runkle](https://github.com/sydney-runkle) in [#10441](https://github.com/pydantic/pydantic/pull/10441) +* Revalidate parametrized generics if instance's origin is subclass of OG class by [@sydney-runkle](https://github.com/sydney-runkle) in [#10666](https://github.com/pydantic/pydantic/pull/10666) +* Warn if configuration is specified on the `@dataclass` decorator and with the `__pydantic_config__` attribute by [@sydney-runkle](https://github.com/sydney-runkle) in [#10406](https://github.com/pydantic/pydantic/pull/10406) +* Recommend against using `Ellipsis` (...) with `Field` by [@Viicos](https://github.com/Viicos) in [#10661](https://github.com/pydantic/pydantic/pull/10661) +* Migrate to subclassing instead of annotated approach for pydantic url types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10662](https://github.com/pydantic/pydantic/pull/10662) +* Change JSON schema generation of `Literal`s and `Enums` by [@Viicos](https://github.com/Viicos) in [#10692](https://github.com/pydantic/pydantic/pull/10692) +* Simplify unions involving `Any` or `Never` when replacing type variables by [@Viicos](https://github.com/Viicos) in [#10338](https://github.com/pydantic/pydantic/pull/10338) +* Do not require padding when decoding `base64` bytes by [@bschoenmaeckers](https://github.com/bschoenmaeckers) in [pydantic/pydantic-core#1448](https://github.com/pydantic/pydantic-core/pull/1448) +* Support dates all the way to 1BC by [@changhc](https://github.com/changhc) in [pydantic/speedate#77](https://github.com/pydantic/speedate/pull/77) + +#### Performance + +* Schema cleaning: skip unnecessary copies during schema walking by [@Viicos](https://github.com/Viicos) in [#10286](https://github.com/pydantic/pydantic/pull/10286) +* Refactor namespace logic for annotations evaluation by [@Viicos](https://github.com/Viicos) in [#10530](https://github.com/pydantic/pydantic/pull/10530) +* Improve email regexp on edge cases by [@AlekseyLobanov](https://github.com/AlekseyLobanov) in [#10601](https://github.com/pydantic/pydantic/pull/10601) +* `CoreMetadata` refactor with an emphasis on documentation, schema build time performance, and reducing complexity by [@sydney-runkle](https://github.com/sydney-runkle) in [#10675](https://github.com/pydantic/pydantic/pull/10675) + +#### Fixes + +* Remove guarding check on `computed_field` with `field_serializer` by [@nix010](https://github.com/nix010) in [#10390](https://github.com/pydantic/pydantic/pull/10390) +* Fix `Predicate` issue in `v2.9.0` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10321](https://github.com/pydantic/pydantic/pull/10321) +* Fixing `annotated-types` bound by [@sydney-runkle](https://github.com/sydney-runkle) in [#10327](https://github.com/pydantic/pydantic/pull/10327) +* Turn `tzdata` install requirement into optional `timezone` dependency by [@jakob-keller](https://github.com/jakob-keller) in [#10331](https://github.com/pydantic/pydantic/pull/10331) +* Use correct types namespace when building `namedtuple` core schemas by [@Viicos](https://github.com/Viicos) in [#10337](https://github.com/pydantic/pydantic/pull/10337) +* Fix evaluation of stringified annotations during namespace inspection by [@Viicos](https://github.com/Viicos) in [#10347](https://github.com/pydantic/pydantic/pull/10347) +* Fix `IncEx` type alias definition by [@Viicos](https://github.com/Viicos) in [#10339](https://github.com/pydantic/pydantic/pull/10339) +* Do not error when trying to evaluate annotations of private attributes by [@Viicos](https://github.com/Viicos) in [#10358](https://github.com/pydantic/pydantic/pull/10358) +* Fix nested type statement by [@kc0506](https://github.com/kc0506) in [#10369](https://github.com/pydantic/pydantic/pull/10369) +* Improve typing of `ModelMetaclass.mro` by [@Viicos](https://github.com/Viicos) in [#10372](https://github.com/pydantic/pydantic/pull/10372) +* Fix class access of deprecated `computed_field`s by [@Viicos](https://github.com/Viicos) in [#10391](https://github.com/pydantic/pydantic/pull/10391) +* Make sure `inspect.iscoroutinefunction` works on coroutines decorated with `@validate_call` by [@MovisLi](https://github.com/MovisLi) in [#10374](https://github.com/pydantic/pydantic/pull/10374) +* Fix `NameError` when using `validate_call` with PEP 695 on a class by [@kc0506](https://github.com/kc0506) in [#10380](https://github.com/pydantic/pydantic/pull/10380) +* Fix `ZoneInfo` with various invalid types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10408](https://github.com/pydantic/pydantic/pull/10408) +* Fix `PydanticUserError` on empty `model_config` with annotations by [@cdwilson](https://github.com/cdwilson) in [#10412](https://github.com/pydantic/pydantic/pull/10412) +* Fix variance issue in `_IncEx` type alias, only allow `True` by [@Viicos](https://github.com/Viicos) in [#10414](https://github.com/pydantic/pydantic/pull/10414) +* Fix serialization schema generation when using `PlainValidator` by [@Viicos](https://github.com/Viicos) in [#10427](https://github.com/pydantic/pydantic/pull/10427) +* Fix schema generation error when serialization schema holds references by [@Viicos](https://github.com/Viicos) in [#10444](https://github.com/pydantic/pydantic/pull/10444) +* Inline references if possible when generating schema for `json_schema_input_type` by [@Viicos](https://github.com/Viicos) in [#10439](https://github.com/pydantic/pydantic/pull/10439) +* Fix recursive arguments in `Representation` by [@Viicos](https://github.com/Viicos) in [#10480](https://github.com/pydantic/pydantic/pull/10480) +* Fix representation for builtin function types by [@kschwab](https://github.com/kschwab) in [#10479](https://github.com/pydantic/pydantic/pull/10479) +* Add python validators for decimal constraints (`max_digits` and `decimal_places`) by [@sydney-runkle](https://github.com/sydney-runkle) in [#10506](https://github.com/pydantic/pydantic/pull/10506) +* Only fetch `__pydantic_core_schema__` from the current class during schema generation by [@Viicos](https://github.com/Viicos) in [#10518](https://github.com/pydantic/pydantic/pull/10518) +* Fix `stacklevel` on deprecation warnings for `BaseModel` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10520](https://github.com/pydantic/pydantic/pull/10520) +* Fix warning `stacklevel` in `BaseModel.__init__` by [@Viicos](https://github.com/Viicos) in [#10526](https://github.com/pydantic/pydantic/pull/10526) +* Improve error handling for in-evaluable refs for discriminator application by [@sydney-runkle](https://github.com/sydney-runkle) in [#10440](https://github.com/pydantic/pydantic/pull/10440) +* Change the signature of `ConfigWrapper.core_config` to take the title directly by [@Viicos](https://github.com/Viicos) in [#10562](https://github.com/pydantic/pydantic/pull/10562) +* Do not use the previous config from the stack for dataclasses without config by [@Viicos](https://github.com/Viicos) in [#10576](https://github.com/pydantic/pydantic/pull/10576) +* Fix serialization for IP types with `mode='python'` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10594](https://github.com/pydantic/pydantic/pull/10594) +* Support constraint application for `Base64Etc` types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10584](https://github.com/pydantic/pydantic/pull/10584) +* Fix `validate_call` ignoring `Field` in `Annotated` by [@kc0506](https://github.com/kc0506) in [#10610](https://github.com/pydantic/pydantic/pull/10610) +* Raise an error when `Self` is invalid by [@kc0506](https://github.com/kc0506) in [#10609](https://github.com/pydantic/pydantic/pull/10609) +* Using `core_schema.InvalidSchema` instead of metadata injection + checks by [@sydney-runkle](https://github.com/sydney-runkle) in [#10523](https://github.com/pydantic/pydantic/pull/10523) +* Tweak type alias logic by [@kc0506](https://github.com/kc0506) in [#10643](https://github.com/pydantic/pydantic/pull/10643) +* Support usage of `type` with `typing.Self` and type aliases by [@kc0506](https://github.com/kc0506) in [#10621](https://github.com/pydantic/pydantic/pull/10621) +* Use overloads for `Field` and `PrivateAttr` functions by [@Viicos](https://github.com/Viicos) in [#10651](https://github.com/pydantic/pydantic/pull/10651) +* Clean up the `mypy` plugin implementation by [@Viicos](https://github.com/Viicos) in [#10669](https://github.com/pydantic/pydantic/pull/10669) +* Properly check for `typing_extensions` variant of `TypeAliasType` by [@Daraan](https://github.com/Daraan) in [#10713](https://github.com/pydantic/pydantic/pull/10713) +* Allow any mapping in `BaseModel.model_copy()` by [@Viicos](https://github.com/Viicos) in [#10751](https://github.com/pydantic/pydantic/pull/10751) +* Fix `isinstance` behavior for urls by [@sydney-runkle](https://github.com/sydney-runkle) in [#10766](https://github.com/pydantic/pydantic/pull/10766) +* Ensure `cached_property` can be set on Pydantic models by [@Viicos](https://github.com/Viicos) in [#10774](https://github.com/pydantic/pydantic/pull/10774) +* Fix equality checks for primitives in literals by [@sydney-runkle](https://github.com/sydney-runkle) in [pydantic/pydantic-core#1459](https://github.com/pydantic/pydantic-core/pull/1459) +* Properly enforce `host_required` for URLs by [@Viicos](https://github.com/Viicos) in [pydantic/pydantic-core#1488](https://github.com/pydantic/pydantic-core/pull/1488) +* Fix when `coerce_numbers_to_str` enabled and string has invalid Unicode character by [@andrey-berenda](https://github.com/andrey-berenda) in [pydantic/pydantic-core#1515](https://github.com/pydantic/pydantic-core/pull/1515) +* Fix serializing `complex` values in `Enum`s by [@changhc](https://github.com/changhc) in [pydantic/pydantic-core#1524](https://github.com/pydantic/pydantic-core/pull/1524) +* Refactor `_typing_extra` module by [@Viicos](https://github.com/Viicos) in [#10725](https://github.com/pydantic/pydantic/pull/10725) +* Support intuitive equality for urls by [@sydney-runkle](https://github.com/sydney-runkle) in [#10798](https://github.com/pydantic/pydantic/pull/10798) +* Add `bytearray` to `TypeAdapter.validate_json` signature by [@samuelcolvin](https://github.com/samuelcolvin) in [#10802](https://github.com/pydantic/pydantic/pull/10802) +* Ensure class access of method descriptors is performed when used as a default with `Field` by [@Viicos](https://github.com/Viicos) in [#10816](https://github.com/pydantic/pydantic/pull/10816) +* Fix circular import with `validate_call` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10807](https://github.com/pydantic/pydantic/pull/10807) +* Fix error when using type aliases referencing other type aliases by [@Viicos](https://github.com/Viicos) in [#10809](https://github.com/pydantic/pydantic/pull/10809) +* Fix `IncEx` type alias to be compatible with mypy by [@Viicos](https://github.com/Viicos) in [#10813](https://github.com/pydantic/pydantic/pull/10813) +* Make `__signature__` a lazy property, do not deepcopy defaults by [@Viicos](https://github.com/Viicos) in [#10818](https://github.com/pydantic/pydantic/pull/10818) +* Make `__signature__` lazy for dataclasses, too by [@sydney-runkle](https://github.com/sydney-runkle) in [#10832](https://github.com/pydantic/pydantic/pull/10832) +* Subclass all single host url classes from `AnyUrl` to preserve behavior from v2.9 by [@sydney-runkle](https://github.com/sydney-runkle) in [#10856](https://github.com/pydantic/pydantic/pull/10856) + +### New Contributors + +* [@jakob-keller](https://github.com/jakob-keller) made their first contribution in [#10331](https://github.com/pydantic/pydantic/pull/10331) +* [@MovisLi](https://github.com/MovisLi) made their first contribution in [#10374](https://github.com/pydantic/pydantic/pull/10374) +* [@joaopalmeiro](https://github.com/joaopalmeiro) made their first contribution in [#10405](https://github.com/pydantic/pydantic/pull/10405) +* [@theunkn0wn1](https://github.com/theunkn0wn1) made their first contribution in [#10378](https://github.com/pydantic/pydantic/pull/10378) +* [@cdwilson](https://github.com/cdwilson) made their first contribution in [#10412](https://github.com/pydantic/pydantic/pull/10412) +* [@dlax](https://github.com/dlax) made their first contribution in [#10421](https://github.com/pydantic/pydantic/pull/10421) +* [@kschwab](https://github.com/kschwab) made their first contribution in [#10479](https://github.com/pydantic/pydantic/pull/10479) +* [@santibreo](https://github.com/santibreo) made their first contribution in [#10453](https://github.com/pydantic/pydantic/pull/10453) +* [@FlorianSW](https://github.com/FlorianSW) made their first contribution in [#10478](https://github.com/pydantic/pydantic/pull/10478) +* [@tkasuz](https://github.com/tkasuz) made their first contribution in [#10555](https://github.com/pydantic/pydantic/pull/10555) +* [@AlekseyLobanov](https://github.com/AlekseyLobanov) made their first contribution in [#10601](https://github.com/pydantic/pydantic/pull/10601) +* [@NiclasvanEyk](https://github.com/NiclasvanEyk) made their first contribution in [#10667](https://github.com/pydantic/pydantic/pull/10667) +* [@mschoettle](https://github.com/mschoettle) made their first contribution in [#10677](https://github.com/pydantic/pydantic/pull/10677) +* [@Daraan](https://github.com/Daraan) made their first contribution in [#10713](https://github.com/pydantic/pydantic/pull/10713) +* [@k4nar](https://github.com/k4nar) made their first contribution in [#10736](https://github.com/pydantic/pydantic/pull/10736) +* [@UriyaHarpeness](https://github.com/UriyaHarpeness) made their first contribution in [#10740](https://github.com/pydantic/pydantic/pull/10740) +* [@frfahim](https://github.com/frfahim) made their first contribution in [#10727](https://github.com/pydantic/pydantic/pull/10727) + +## v2.10.0b2 (2024-11-13) + +Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b2) for details. + +## v2.10.0b1 (2024-11-06) + +Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b1) for details. + + +... see [here](https://docs.pydantic.dev/changelog/#v0322-2019-08-17) for earlier changes. diff --git a/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/RECORD b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/RECORD new file mode 100644 index 0000000..2baa547 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/RECORD @@ -0,0 +1,217 @@ +pydantic-2.12.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pydantic-2.12.5.dist-info/METADATA,sha256=o7oj6JUZH-1puDI8vLzcgphMoLajzcYsSKI0GIapwI0,90587 +pydantic-2.12.5.dist-info/RECORD,, +pydantic-2.12.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 +pydantic-2.12.5.dist-info/licenses/LICENSE,sha256=qeGG88oWte74QxjnpwFyE1GgDLe4rjpDlLZ7SeNSnvM,1129 +pydantic/__init__.py,sha256=5iEnJ4wHv1OEzdKQPzaKaZKfO4pSQAC65ODrYI6_S8Y,15812 +pydantic/__pycache__/__init__.cpython-312.pyc,, +pydantic/__pycache__/_migration.cpython-312.pyc,, +pydantic/__pycache__/alias_generators.cpython-312.pyc,, +pydantic/__pycache__/aliases.cpython-312.pyc,, +pydantic/__pycache__/annotated_handlers.cpython-312.pyc,, +pydantic/__pycache__/class_validators.cpython-312.pyc,, +pydantic/__pycache__/color.cpython-312.pyc,, +pydantic/__pycache__/config.cpython-312.pyc,, +pydantic/__pycache__/dataclasses.cpython-312.pyc,, +pydantic/__pycache__/datetime_parse.cpython-312.pyc,, +pydantic/__pycache__/decorator.cpython-312.pyc,, +pydantic/__pycache__/env_settings.cpython-312.pyc,, +pydantic/__pycache__/error_wrappers.cpython-312.pyc,, +pydantic/__pycache__/errors.cpython-312.pyc,, +pydantic/__pycache__/fields.cpython-312.pyc,, +pydantic/__pycache__/functional_serializers.cpython-312.pyc,, +pydantic/__pycache__/functional_validators.cpython-312.pyc,, +pydantic/__pycache__/generics.cpython-312.pyc,, +pydantic/__pycache__/json.cpython-312.pyc,, +pydantic/__pycache__/json_schema.cpython-312.pyc,, +pydantic/__pycache__/main.cpython-312.pyc,, +pydantic/__pycache__/mypy.cpython-312.pyc,, +pydantic/__pycache__/networks.cpython-312.pyc,, +pydantic/__pycache__/parse.cpython-312.pyc,, +pydantic/__pycache__/root_model.cpython-312.pyc,, +pydantic/__pycache__/schema.cpython-312.pyc,, +pydantic/__pycache__/tools.cpython-312.pyc,, +pydantic/__pycache__/type_adapter.cpython-312.pyc,, +pydantic/__pycache__/types.cpython-312.pyc,, +pydantic/__pycache__/typing.cpython-312.pyc,, +pydantic/__pycache__/utils.cpython-312.pyc,, +pydantic/__pycache__/validate_call_decorator.cpython-312.pyc,, +pydantic/__pycache__/validators.cpython-312.pyc,, +pydantic/__pycache__/version.cpython-312.pyc,, +pydantic/__pycache__/warnings.cpython-312.pyc,, +pydantic/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/_internal/__pycache__/__init__.cpython-312.pyc,, +pydantic/_internal/__pycache__/_config.cpython-312.pyc,, +pydantic/_internal/__pycache__/_core_metadata.cpython-312.pyc,, +pydantic/_internal/__pycache__/_core_utils.cpython-312.pyc,, +pydantic/_internal/__pycache__/_dataclasses.cpython-312.pyc,, +pydantic/_internal/__pycache__/_decorators.cpython-312.pyc,, +pydantic/_internal/__pycache__/_decorators_v1.cpython-312.pyc,, +pydantic/_internal/__pycache__/_discriminated_union.cpython-312.pyc,, +pydantic/_internal/__pycache__/_docs_extraction.cpython-312.pyc,, +pydantic/_internal/__pycache__/_fields.cpython-312.pyc,, +pydantic/_internal/__pycache__/_forward_ref.cpython-312.pyc,, +pydantic/_internal/__pycache__/_generate_schema.cpython-312.pyc,, +pydantic/_internal/__pycache__/_generics.cpython-312.pyc,, +pydantic/_internal/__pycache__/_git.cpython-312.pyc,, +pydantic/_internal/__pycache__/_import_utils.cpython-312.pyc,, +pydantic/_internal/__pycache__/_internal_dataclass.cpython-312.pyc,, +pydantic/_internal/__pycache__/_known_annotated_metadata.cpython-312.pyc,, +pydantic/_internal/__pycache__/_mock_val_ser.cpython-312.pyc,, +pydantic/_internal/__pycache__/_model_construction.cpython-312.pyc,, +pydantic/_internal/__pycache__/_namespace_utils.cpython-312.pyc,, +pydantic/_internal/__pycache__/_repr.cpython-312.pyc,, +pydantic/_internal/__pycache__/_schema_gather.cpython-312.pyc,, +pydantic/_internal/__pycache__/_schema_generation_shared.cpython-312.pyc,, +pydantic/_internal/__pycache__/_serializers.cpython-312.pyc,, +pydantic/_internal/__pycache__/_signature.cpython-312.pyc,, +pydantic/_internal/__pycache__/_typing_extra.cpython-312.pyc,, +pydantic/_internal/__pycache__/_utils.cpython-312.pyc,, +pydantic/_internal/__pycache__/_validate_call.cpython-312.pyc,, +pydantic/_internal/__pycache__/_validators.cpython-312.pyc,, +pydantic/_internal/_config.py,sha256=TWZwg3c0bZHiT3boR5-YYqkouHcwjRdenmyGHofV7E0,14674 +pydantic/_internal/_core_metadata.py,sha256=Y_g2t3i7uluK-wXCZvzJfRFMPUM23aBYLfae4FzBPy0,5162 +pydantic/_internal/_core_utils.py,sha256=1jru4VbJ0x63R6dtVcuOI-dKQTC_d_lSnJWEBQzGNEQ,6487 +pydantic/_internal/_dataclasses.py,sha256=Tk1mEafhad1kV7K5tPX5BwxWSXY7C-MKwf0OLFgIlEA,13158 +pydantic/_internal/_decorators.py,sha256=PnyAoKSg3BNbCVSZnwqw9naEg1UDtYvDT9LluigPiO8,33529 +pydantic/_internal/_decorators_v1.py,sha256=tfdfdpQKY4R2XCOwqHbZeoQMur6VNigRrfhudXBHx38,6185 +pydantic/_internal/_discriminated_union.py,sha256=aMl0SRSyQyHfW4-klnMTHNvwSRoqE3H3PRV_05vRsTg,25478 +pydantic/_internal/_docs_extraction.py,sha256=fyznSAHh5AzohnXZStV0HvH-nRbavNHPyg-knx-S_EE,4127 +pydantic/_internal/_fields.py,sha256=YSfEKq21FgjLJ6YqYXKh0eEEs5nxMPvQ6hp9pA8Nzfw,28093 +pydantic/_internal/_forward_ref.py,sha256=5n3Y7-3AKLn8_FS3Yc7KutLiPUhyXmAtkEZOaFnonwM,611 +pydantic/_internal/_generate_schema.py,sha256=TT49vzYzqH90rWrv5ptNoZgjzOsR0KPlSkqPVFrnrBw,132665 +pydantic/_internal/_generics.py,sha256=ELqjT6LMzQzWAK0EB5_9qke_iAazz0OQ4gunp_uKuYY,23822 +pydantic/_internal/_git.py,sha256=IwPh3DPfa2Xq3rBuB9Nx8luR2A1i69QdeTfWWXIuCVg,809 +pydantic/_internal/_import_utils.py,sha256=TRhxD5OuY6CUosioBdBcJUs0om7IIONiZdYAV7zQ8jM,402 +pydantic/_internal/_internal_dataclass.py,sha256=_bedc1XbuuygRGiLZqkUkwwFpQaoR1hKLlR501nyySY,144 +pydantic/_internal/_known_annotated_metadata.py,sha256=Jc7KTNFZoB3f-0ibP_NgJINOeVvYE3q3OTBQDjVMk3U,16765 +pydantic/_internal/_mock_val_ser.py,sha256=wmRRFSBvqfcLbI41PsFliB4u2AZ3mJpZeiERbD3xKTo,8885 +pydantic/_internal/_model_construction.py,sha256=wk-bNGDAJvduaGvn0U0_8zEl0GERu0shJvN8_ZfkYaw,37783 +pydantic/_internal/_namespace_utils.py,sha256=hl3-TRAr82U2jTyPP3t-QqsvKLirxtkLfNfrN-fp0x8,12878 +pydantic/_internal/_repr.py,sha256=jQfnJuyDxQpSRNhG29II9PX8e4Nv2qWZrEw2lqih3UE,5172 +pydantic/_internal/_schema_gather.py,sha256=VLEv51TYEeeND2czsyrmJq1MVnJqTOmnLan7VG44c8A,9114 +pydantic/_internal/_schema_generation_shared.py,sha256=F_rbQbrkoomgxsskdHpP0jUJ7TCfe0BADAEkq6CJ4nM,4842 +pydantic/_internal/_serializers.py,sha256=YIWvSmAR5fnbGSWCOQduWt1yB4ZQY42eAruc-enrb6c,1491 +pydantic/_internal/_signature.py,sha256=8EljPJe4pSnapuirG5DkBAgD1hggHxEAyzFPH-9H0zE,6779 +pydantic/_internal/_typing_extra.py,sha256=_GRYopNi4a9USi5UQ285ObrlsYmvqKEWTNbBoJFSK2c,30309 +pydantic/_internal/_utils.py,sha256=c6Naqf3bds4jBctepiW5jV0xISQQQk5EBUhMNmVQ3Nk,15912 +pydantic/_internal/_validate_call.py,sha256=PfdVnSzhXOrENtaDoDw3PFWPVYD5W_gNYPe8p3Ug6Lg,5321 +pydantic/_internal/_validators.py,sha256=dv0a2Nkc4zcYqv31Gh_QId2lcf-W0kQpV0oSNzgEdfg,20588 +pydantic/_migration.py,sha256=VF73LRCUz3Irb5xVt13jb3NAcXVnEF6T1-J0OLfeZ5A,12160 +pydantic/alias_generators.py,sha256=KM1n3u4JfLSBl1UuYg3hoYHzXJD-yvgrnq8u1ccwh_A,2124 +pydantic/aliases.py,sha256=vhCHyoSWnX-EJ-wWb5qj4xyRssgGWnTQfzQp4GSZ9ug,4937 +pydantic/annotated_handlers.py,sha256=WfyFSqwoEIFXBh7T73PycKloI1DiX45GWi0-JOsCR4Y,4407 +pydantic/class_validators.py,sha256=i_V3j-PYdGLSLmj_IJZekTRjunO8SIVz8LMlquPyP7E,148 +pydantic/color.py,sha256=AzqGfVQHF92_ZctDcue0DM4yTp2P6tekkwRINTWrLIo,21481 +pydantic/config.py,sha256=5MjjzlAR0_xq7C1yAEPf7qWp5qraQwStRvma9nzbqVI,44267 +pydantic/dataclasses.py,sha256=VlknbEulg08xdmPg_60hBsCVIw-W603OJWY2n5gyXA0,18936 +pydantic/datetime_parse.py,sha256=QC-WgMxMr_wQ_mNXUS7AVf-2hLEhvvsPY1PQyhSGOdk,150 +pydantic/decorator.py,sha256=YX-jUApu5AKaVWKPoaV-n-4l7UbS69GEt9Ra3hszmKI,145 +pydantic/deprecated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/deprecated/__pycache__/__init__.cpython-312.pyc,, +pydantic/deprecated/__pycache__/class_validators.cpython-312.pyc,, +pydantic/deprecated/__pycache__/config.cpython-312.pyc,, +pydantic/deprecated/__pycache__/copy_internals.cpython-312.pyc,, +pydantic/deprecated/__pycache__/decorator.cpython-312.pyc,, +pydantic/deprecated/__pycache__/json.cpython-312.pyc,, +pydantic/deprecated/__pycache__/parse.cpython-312.pyc,, +pydantic/deprecated/__pycache__/tools.cpython-312.pyc,, +pydantic/deprecated/class_validators.py,sha256=EAcaVQM5zp2wBml0ybN62CfQfyJvDLx5Qd9Pk4_tb4U,10273 +pydantic/deprecated/config.py,sha256=k_lsVk57paxLJOcBueH07cu1OgEgWdVBxm6lfaC3CCU,2663 +pydantic/deprecated/copy_internals.py,sha256=Ghd-vkMd5EYCCgyCGtPKO58np9cEKBQC6qkBeIEFI2g,7618 +pydantic/deprecated/decorator.py,sha256=TBm6bJ7wJsNih_8Wq5IzDcwP32m9_vfxs96desLuk00,10845 +pydantic/deprecated/json.py,sha256=HlWCG35RRrxyzuTS6LTQiZBwRhmDZWmeqQH8rLW6wA8,4657 +pydantic/deprecated/parse.py,sha256=Gzd6b_g8zJXcuE7QRq5adhx_EMJahXfcpXCF0RgrqqI,2511 +pydantic/deprecated/tools.py,sha256=Nrm9oFRZWp8-jlfvPgJILEsywp4YzZD52XIGPDLxHcI,3330 +pydantic/env_settings.py,sha256=6IHeeWEqlUPRUv3V-AXiF_W91fg2Jw_M3O0l34J_eyA,148 +pydantic/error_wrappers.py,sha256=RK6mqATc9yMD-KBD9IJS9HpKCprWHd8wo84Bnm-3fR8,150 +pydantic/errors.py,sha256=7ctBNCtt57kZFx71Ls2H86IufQARv4wPKf8DhdsVn5w,6002 +pydantic/experimental/__init__.py,sha256=QT7rKYdDsCiTJ9GEjmsQdWHScwpKrrNkGq6vqONP6RQ,104 +pydantic/experimental/__pycache__/__init__.cpython-312.pyc,, +pydantic/experimental/__pycache__/arguments_schema.cpython-312.pyc,, +pydantic/experimental/__pycache__/missing_sentinel.cpython-312.pyc,, +pydantic/experimental/__pycache__/pipeline.cpython-312.pyc,, +pydantic/experimental/arguments_schema.py,sha256=EFnjX_ulp-tPyUjQX5pmQtug1OFL_Acc8bcMbLd-fVY,1866 +pydantic/experimental/missing_sentinel.py,sha256=hQejgtF00wUuQMni9429evg-eXyIwpKvjsD8ofqfj-w,127 +pydantic/experimental/pipeline.py,sha256=Kv_dvcexKumazfRL0y69AayeA6H37SrmsZ3SUl_n0qY,23582 +pydantic/fields.py,sha256=WuDGOvB22KWuuW3fXnS4Wvg4qX_tdp8X7BrAlza4sw8,79194 +pydantic/functional_serializers.py,sha256=rEzH391zqy3o_bWk2QEuvySmcQNZmwXmJQLC3ZGF7QA,17151 +pydantic/functional_validators.py,sha256=c_-7weWpGNcOYfRfVUFu11jrxMVMdfY_c-4istwk95Y,31839 +pydantic/generics.py,sha256=0ZqZ9O9annIj_3mGBRqps4htey3b5lV1-d2tUxPMMnA,144 +pydantic/json.py,sha256=ZH8RkI7h4Bz-zp8OdTAxbJUoVvcoU-jhMdRZ0B-k0xc,140 +pydantic/json_schema.py,sha256=-h8c7vsNGAJCIxR-n52-69Q54w38EM-j0AGC_4VGt30,123653 +pydantic/main.py,sha256=WZTxwW81igl75Y00zHJJmoU3qCNSy-1KCEmEsBPftiQ,84205 +pydantic/mypy.py,sha256=p6KU1GwPHazF7E5vJq1uLd4tHd6DE6bre4-m5Ln23ms,58986 +pydantic/networks.py,sha256=Smf_RyImQ-F5FZLCgFwHPfROYxW_e-Hz68R_8LW0sZ0,42099 +pydantic/parse.py,sha256=wkd82dgtvWtD895U_I6E1htqMlGhBSYEV39cuBSeo3A,141 +pydantic/plugin/__init__.py,sha256=a7Tw366U6K3kltCCNZY76nc9ss-7uGGQ40TXad9OypQ,7333 +pydantic/plugin/__pycache__/__init__.cpython-312.pyc,, +pydantic/plugin/__pycache__/_loader.cpython-312.pyc,, +pydantic/plugin/__pycache__/_schema_validator.cpython-312.pyc,, +pydantic/plugin/_loader.py,sha256=9QLXneLEmvyhXka_9j4Lrkbme4qPv6qYphlsjF2MGsA,2210 +pydantic/plugin/_schema_validator.py,sha256=QbmqsG33MBmftNQ2nNiuN22LhbrexUA7ipDVv3J02BU,5267 +pydantic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/root_model.py,sha256=BvmLtW4i11dJk-dLOM3rl-jnJdQGeeQTFBcmEOq6pMg,6311 +pydantic/schema.py,sha256=Vqqjvq_LnapVknebUd3Bp_J1p2gXZZnZRgL48bVEG7o,142 +pydantic/tools.py,sha256=iHQpd8SJ5DCTtPV5atAV06T89bjSaMFeZZ2LX9lasZY,141 +pydantic/type_adapter.py,sha256=VT--yg4a27shSBzWHBPKz493f3iQ9obdkEkhjZKlE7Q,35653 +pydantic/types.py,sha256=nqdS-J2ZXqTh2qeyJOzBTBtHWyZ5YRFe8gaMV59d9HE,105431 +pydantic/typing.py,sha256=P7feA35MwTcLsR1uL7db0S-oydBxobmXa55YDoBgajQ,138 +pydantic/utils.py,sha256=15nR2QpqTBFlQV4TNtTItMyTJx_fbyV-gPmIEY1Gooc,141 +pydantic/v1/__init__.py,sha256=FLQ8ISp6MVZRfjnS7fQ4m1FxQxFCF2QVikE4DK-4PhE,3164 +pydantic/v1/__pycache__/__init__.cpython-312.pyc,, +pydantic/v1/__pycache__/_hypothesis_plugin.cpython-312.pyc,, +pydantic/v1/__pycache__/annotated_types.cpython-312.pyc,, +pydantic/v1/__pycache__/class_validators.cpython-312.pyc,, +pydantic/v1/__pycache__/color.cpython-312.pyc,, +pydantic/v1/__pycache__/config.cpython-312.pyc,, +pydantic/v1/__pycache__/dataclasses.cpython-312.pyc,, +pydantic/v1/__pycache__/datetime_parse.cpython-312.pyc,, +pydantic/v1/__pycache__/decorator.cpython-312.pyc,, +pydantic/v1/__pycache__/env_settings.cpython-312.pyc,, +pydantic/v1/__pycache__/error_wrappers.cpython-312.pyc,, +pydantic/v1/__pycache__/errors.cpython-312.pyc,, +pydantic/v1/__pycache__/fields.cpython-312.pyc,, +pydantic/v1/__pycache__/generics.cpython-312.pyc,, +pydantic/v1/__pycache__/json.cpython-312.pyc,, +pydantic/v1/__pycache__/main.cpython-312.pyc,, +pydantic/v1/__pycache__/mypy.cpython-312.pyc,, +pydantic/v1/__pycache__/networks.cpython-312.pyc,, +pydantic/v1/__pycache__/parse.cpython-312.pyc,, +pydantic/v1/__pycache__/schema.cpython-312.pyc,, +pydantic/v1/__pycache__/tools.cpython-312.pyc,, +pydantic/v1/__pycache__/types.cpython-312.pyc,, +pydantic/v1/__pycache__/typing.cpython-312.pyc,, +pydantic/v1/__pycache__/utils.cpython-312.pyc,, +pydantic/v1/__pycache__/validators.cpython-312.pyc,, +pydantic/v1/__pycache__/version.cpython-312.pyc,, +pydantic/v1/_hypothesis_plugin.py,sha256=5ES5xWuw1FQAsymLezy8QgnVz0ZpVfU3jkmT74H27VQ,14847 +pydantic/v1/annotated_types.py,sha256=uk2NAAxqiNELKjiHhyhxKaIOh8F1lYW_LzrW3X7oZBc,3157 +pydantic/v1/class_validators.py,sha256=ULOaIUgYUDBsHL7EEVEarcM-UubKUggoN8hSbDonsFE,14672 +pydantic/v1/color.py,sha256=iZABLYp6OVoo2AFkP9Ipri_wSc6-Kklu8YuhSartd5g,16844 +pydantic/v1/config.py,sha256=a6P0Wer9x4cbwKW7Xv8poSUqM4WP-RLWwX6YMpYq9AA,6532 +pydantic/v1/dataclasses.py,sha256=784cqvInbwIPWr9usfpX3ch7z4t3J2tTK6N067_wk1o,18172 +pydantic/v1/datetime_parse.py,sha256=4Qy1kQpq3rNVZJeIHeSPDpuS2Bvhp1KPtzJG1xu-H00,7724 +pydantic/v1/decorator.py,sha256=zaaxxxoWPCm818D1bs0yhapRjXm32V8G0ZHWCdM1uXA,10339 +pydantic/v1/env_settings.py,sha256=A9VXwtRl02AY-jH0C0ouy5VNw3fi6F_pkzuHDjgAAOM,14105 +pydantic/v1/error_wrappers.py,sha256=6625Mfw9qkC2NwitB_JFAWe8B-Xv6zBU7rL9k28tfyo,5196 +pydantic/v1/errors.py,sha256=mIwPED5vGM5Q5v4C4Z1JPldTRH-omvEylH6ksMhOmPw,17726 +pydantic/v1/fields.py,sha256=VqWJCriUNiEyptXroDVJ501JpVA0en2VANcksqXL2b8,50649 +pydantic/v1/generics.py,sha256=VzC9YUV-EbPpQ3aAfk1cNFej79_IzznkQ7WrmTTZS9E,17871 +pydantic/v1/json.py,sha256=WQ5Hy_hIpfdR3YS8k6N2E6KMJzsdbBi_ldWOPJaV81M,3390 +pydantic/v1/main.py,sha256=zuNpdN5Q0V0wG2UUTKt0HUy3XJ4OAvPSZDdiXY-FIzs,44824 +pydantic/v1/mypy.py,sha256=Cl8XRfCmIcVE3j5AEU52C8iDh8lcX__D3hz2jIWxMAs,38860 +pydantic/v1/networks.py,sha256=HYNtKAfOmOnKJpsDg1g6SIkj9WPhU_-i8l5e2JKBpG4,22124 +pydantic/v1/parse.py,sha256=BJtdqiZRtav9VRFCmOxoY-KImQmjPy-A_NoojiFUZxY,1821 +pydantic/v1/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/v1/schema.py,sha256=aqBuA--cq8gAVkim5BJPFASHzOZ8dFtmFX_fNGr6ip4,47801 +pydantic/v1/tools.py,sha256=1lDdXHk0jL5uP3u5RCYAvUAlGClgAO-45lkq9j7fyBA,2881 +pydantic/v1/types.py,sha256=Bzl-RcnitPBHnqwwj9iv7JjHuN1GpnWH24dKkF3l9e8,35455 +pydantic/v1/typing.py,sha256=7GdBg1YTHULU81thB_9cjRNDfZfn4khoX7nGtw_keCE,19677 +pydantic/v1/utils.py,sha256=M5FRyfNUb1A2mk9laGgCVdfHHb3AtQgrjO5qfyBf4xA,25989 +pydantic/v1/validators.py,sha256=lyUkn1MWhHxlCX5ZfEgFj_CAHojoiPcaQeMdEM9XviU,22187 +pydantic/v1/version.py,sha256=HXnXW-1bMW5qKhlr5RgOEPohrZDCDSuyy8-gi8GCgZo,1039 +pydantic/validate_call_decorator.py,sha256=8jqLlgXTjWEj4dXDg0wI3EGQKkb0JnCsL_JSUjbU5Sg,4389 +pydantic/validators.py,sha256=pwbIJXVb1CV2mAE4w_EGfNj7DwzsKaWw_tTL6cviTus,146 +pydantic/version.py,sha256=XNmGSyOP87Mqa_A9HFzfDcNippfnqfRK3ZUiGyBb4-A,3985 +pydantic/warnings.py,sha256=Wu1VGzrvFZw4T6yCIKHjH7LSY66HjbtyCFbn5uWoMJ4,4802 diff --git a/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/WHEEL b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/WHEEL new file mode 100644 index 0000000..12228d4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.27.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/licenses/LICENSE new file mode 100644 index 0000000..488c626 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic-2.12.5.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 to present Pydantic Services Inc. and individual 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/backend/venv/Lib/site-packages/pydantic/__init__.py b/backend/venv/Lib/site-packages/pydantic/__init__.py new file mode 100644 index 0000000..0121284 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/__init__.py @@ -0,0 +1,456 @@ +from importlib import import_module +from typing import TYPE_CHECKING +from warnings import warn + +from ._migration import getattr_migration +from .version import VERSION, _ensure_pydantic_core_version + +_ensure_pydantic_core_version() +del _ensure_pydantic_core_version + +if TYPE_CHECKING: + # import of virtually everything is supported via `__getattr__` below, + # but we need them here for type checking and IDE support + import pydantic_core + from pydantic_core.core_schema import ( + FieldSerializationInfo, + SerializationInfo, + SerializerFunctionWrapHandler, + ValidationInfo, + ValidatorFunctionWrapHandler, + ) + + from . import dataclasses + from .aliases import AliasChoices, AliasGenerator, AliasPath + from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler + from .config import ConfigDict, with_config + from .errors import * + from .fields import Field, PrivateAttr, computed_field + from .functional_serializers import ( + PlainSerializer, + SerializeAsAny, + WrapSerializer, + field_serializer, + model_serializer, + ) + from .functional_validators import ( + AfterValidator, + BeforeValidator, + InstanceOf, + ModelWrapValidatorHandler, + PlainValidator, + SkipValidation, + ValidateAs, + WrapValidator, + field_validator, + model_validator, + ) + from .json_schema import WithJsonSchema + from .main import * + from .networks import * + from .type_adapter import TypeAdapter + from .types import * + from .validate_call_decorator import validate_call + from .warnings import ( + PydanticDeprecatedSince20, + PydanticDeprecatedSince26, + PydanticDeprecatedSince29, + PydanticDeprecatedSince210, + PydanticDeprecatedSince211, + PydanticDeprecatedSince212, + PydanticDeprecationWarning, + PydanticExperimentalWarning, + ) + + # this encourages pycharm to import `ValidationError` from here, not pydantic_core + ValidationError = pydantic_core.ValidationError + from .deprecated.class_validators import root_validator, validator + from .deprecated.config import BaseConfig, Extra + from .deprecated.tools import * + from .root_model import RootModel + +__version__ = VERSION +__all__ = ( + # dataclasses + 'dataclasses', + # functional validators + 'field_validator', + 'model_validator', + 'AfterValidator', + 'BeforeValidator', + 'PlainValidator', + 'WrapValidator', + 'SkipValidation', + 'ValidateAs', + 'InstanceOf', + 'ModelWrapValidatorHandler', + # JSON Schema + 'WithJsonSchema', + # deprecated V1 functional validators, these are imported via `__getattr__` below + 'root_validator', + 'validator', + # functional serializers + 'field_serializer', + 'model_serializer', + 'PlainSerializer', + 'SerializeAsAny', + 'WrapSerializer', + # config + 'ConfigDict', + 'with_config', + # deprecated V1 config, these are imported via `__getattr__` below + 'BaseConfig', + 'Extra', + # validate_call + 'validate_call', + # errors + 'PydanticErrorCodes', + 'PydanticUserError', + 'PydanticSchemaGenerationError', + 'PydanticImportError', + 'PydanticUndefinedAnnotation', + 'PydanticInvalidForJsonSchema', + 'PydanticForbiddenQualifier', + # fields + 'Field', + 'computed_field', + 'PrivateAttr', + # alias + 'AliasChoices', + 'AliasGenerator', + 'AliasPath', + # main + 'BaseModel', + 'create_model', + # network + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'FtpUrl', + 'WebsocketUrl', + 'AnyWebsocketUrl', + 'UrlConstraints', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'NatsDsn', + 'MySQLDsn', + 'MariaDBDsn', + 'ClickHouseDsn', + 'SnowflakeDsn', + 'validate_email', + # root_model + 'RootModel', + # deprecated tools, these are imported via `__getattr__` below + 'parse_obj_as', + 'schema_of', + 'schema_json_of', + # types + 'Strict', + 'StrictStr', + 'conbytes', + 'conlist', + 'conset', + 'confrozenset', + 'constr', + 'StringConstraints', + 'ImportString', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'condecimal', + 'condate', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'UUID6', + 'UUID7', + 'UUID8', + 'FilePath', + 'DirectoryPath', + 'NewPath', + 'Json', + 'Secret', + 'SecretStr', + 'SecretBytes', + 'SocketPath', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'PastDatetime', + 'FutureDatetime', + 'AwareDatetime', + 'NaiveDatetime', + 'AllowInfNan', + 'EncoderProtocol', + 'EncodedBytes', + 'EncodedStr', + 'Base64Encoder', + 'Base64Bytes', + 'Base64Str', + 'Base64UrlBytes', + 'Base64UrlStr', + 'GetPydanticSchema', + 'Tag', + 'Discriminator', + 'JsonValue', + 'FailFast', + # type_adapter + 'TypeAdapter', + # version + '__version__', + 'VERSION', + # warnings + 'PydanticDeprecatedSince20', + 'PydanticDeprecatedSince26', + 'PydanticDeprecatedSince29', + 'PydanticDeprecatedSince210', + 'PydanticDeprecatedSince211', + 'PydanticDeprecatedSince212', + 'PydanticDeprecationWarning', + 'PydanticExperimentalWarning', + # annotated handlers + 'GetCoreSchemaHandler', + 'GetJsonSchemaHandler', + # pydantic_core + 'ValidationError', + 'ValidationInfo', + 'SerializationInfo', + 'ValidatorFunctionWrapHandler', + 'FieldSerializationInfo', + 'SerializerFunctionWrapHandler', + 'OnErrorOmit', +) + +# A mapping of {: (package, )} defining dynamic imports +_dynamic_imports: 'dict[str, tuple[str, str]]' = { + 'dataclasses': (__spec__.parent, '__module__'), + # functional validators + 'field_validator': (__spec__.parent, '.functional_validators'), + 'model_validator': (__spec__.parent, '.functional_validators'), + 'AfterValidator': (__spec__.parent, '.functional_validators'), + 'BeforeValidator': (__spec__.parent, '.functional_validators'), + 'PlainValidator': (__spec__.parent, '.functional_validators'), + 'WrapValidator': (__spec__.parent, '.functional_validators'), + 'SkipValidation': (__spec__.parent, '.functional_validators'), + 'InstanceOf': (__spec__.parent, '.functional_validators'), + 'ValidateAs': (__spec__.parent, '.functional_validators'), + 'ModelWrapValidatorHandler': (__spec__.parent, '.functional_validators'), + # JSON Schema + 'WithJsonSchema': (__spec__.parent, '.json_schema'), + # functional serializers + 'field_serializer': (__spec__.parent, '.functional_serializers'), + 'model_serializer': (__spec__.parent, '.functional_serializers'), + 'PlainSerializer': (__spec__.parent, '.functional_serializers'), + 'SerializeAsAny': (__spec__.parent, '.functional_serializers'), + 'WrapSerializer': (__spec__.parent, '.functional_serializers'), + # config + 'ConfigDict': (__spec__.parent, '.config'), + 'with_config': (__spec__.parent, '.config'), + # validate call + 'validate_call': (__spec__.parent, '.validate_call_decorator'), + # errors + 'PydanticErrorCodes': (__spec__.parent, '.errors'), + 'PydanticUserError': (__spec__.parent, '.errors'), + 'PydanticSchemaGenerationError': (__spec__.parent, '.errors'), + 'PydanticImportError': (__spec__.parent, '.errors'), + 'PydanticUndefinedAnnotation': (__spec__.parent, '.errors'), + 'PydanticInvalidForJsonSchema': (__spec__.parent, '.errors'), + 'PydanticForbiddenQualifier': (__spec__.parent, '.errors'), + # fields + 'Field': (__spec__.parent, '.fields'), + 'computed_field': (__spec__.parent, '.fields'), + 'PrivateAttr': (__spec__.parent, '.fields'), + # alias + 'AliasChoices': (__spec__.parent, '.aliases'), + 'AliasGenerator': (__spec__.parent, '.aliases'), + 'AliasPath': (__spec__.parent, '.aliases'), + # main + 'BaseModel': (__spec__.parent, '.main'), + 'create_model': (__spec__.parent, '.main'), + # network + 'AnyUrl': (__spec__.parent, '.networks'), + 'AnyHttpUrl': (__spec__.parent, '.networks'), + 'FileUrl': (__spec__.parent, '.networks'), + 'HttpUrl': (__spec__.parent, '.networks'), + 'FtpUrl': (__spec__.parent, '.networks'), + 'WebsocketUrl': (__spec__.parent, '.networks'), + 'AnyWebsocketUrl': (__spec__.parent, '.networks'), + 'UrlConstraints': (__spec__.parent, '.networks'), + 'EmailStr': (__spec__.parent, '.networks'), + 'NameEmail': (__spec__.parent, '.networks'), + 'IPvAnyAddress': (__spec__.parent, '.networks'), + 'IPvAnyInterface': (__spec__.parent, '.networks'), + 'IPvAnyNetwork': (__spec__.parent, '.networks'), + 'PostgresDsn': (__spec__.parent, '.networks'), + 'CockroachDsn': (__spec__.parent, '.networks'), + 'AmqpDsn': (__spec__.parent, '.networks'), + 'RedisDsn': (__spec__.parent, '.networks'), + 'MongoDsn': (__spec__.parent, '.networks'), + 'KafkaDsn': (__spec__.parent, '.networks'), + 'NatsDsn': (__spec__.parent, '.networks'), + 'MySQLDsn': (__spec__.parent, '.networks'), + 'MariaDBDsn': (__spec__.parent, '.networks'), + 'ClickHouseDsn': (__spec__.parent, '.networks'), + 'SnowflakeDsn': (__spec__.parent, '.networks'), + 'validate_email': (__spec__.parent, '.networks'), + # root_model + 'RootModel': (__spec__.parent, '.root_model'), + # types + 'Strict': (__spec__.parent, '.types'), + 'StrictStr': (__spec__.parent, '.types'), + 'conbytes': (__spec__.parent, '.types'), + 'conlist': (__spec__.parent, '.types'), + 'conset': (__spec__.parent, '.types'), + 'confrozenset': (__spec__.parent, '.types'), + 'constr': (__spec__.parent, '.types'), + 'StringConstraints': (__spec__.parent, '.types'), + 'ImportString': (__spec__.parent, '.types'), + 'conint': (__spec__.parent, '.types'), + 'PositiveInt': (__spec__.parent, '.types'), + 'NegativeInt': (__spec__.parent, '.types'), + 'NonNegativeInt': (__spec__.parent, '.types'), + 'NonPositiveInt': (__spec__.parent, '.types'), + 'confloat': (__spec__.parent, '.types'), + 'PositiveFloat': (__spec__.parent, '.types'), + 'NegativeFloat': (__spec__.parent, '.types'), + 'NonNegativeFloat': (__spec__.parent, '.types'), + 'NonPositiveFloat': (__spec__.parent, '.types'), + 'FiniteFloat': (__spec__.parent, '.types'), + 'condecimal': (__spec__.parent, '.types'), + 'condate': (__spec__.parent, '.types'), + 'UUID1': (__spec__.parent, '.types'), + 'UUID3': (__spec__.parent, '.types'), + 'UUID4': (__spec__.parent, '.types'), + 'UUID5': (__spec__.parent, '.types'), + 'UUID6': (__spec__.parent, '.types'), + 'UUID7': (__spec__.parent, '.types'), + 'UUID8': (__spec__.parent, '.types'), + 'FilePath': (__spec__.parent, '.types'), + 'DirectoryPath': (__spec__.parent, '.types'), + 'NewPath': (__spec__.parent, '.types'), + 'Json': (__spec__.parent, '.types'), + 'Secret': (__spec__.parent, '.types'), + 'SecretStr': (__spec__.parent, '.types'), + 'SecretBytes': (__spec__.parent, '.types'), + 'StrictBool': (__spec__.parent, '.types'), + 'StrictBytes': (__spec__.parent, '.types'), + 'StrictInt': (__spec__.parent, '.types'), + 'StrictFloat': (__spec__.parent, '.types'), + 'PaymentCardNumber': (__spec__.parent, '.types'), + 'ByteSize': (__spec__.parent, '.types'), + 'PastDate': (__spec__.parent, '.types'), + 'SocketPath': (__spec__.parent, '.types'), + 'FutureDate': (__spec__.parent, '.types'), + 'PastDatetime': (__spec__.parent, '.types'), + 'FutureDatetime': (__spec__.parent, '.types'), + 'AwareDatetime': (__spec__.parent, '.types'), + 'NaiveDatetime': (__spec__.parent, '.types'), + 'AllowInfNan': (__spec__.parent, '.types'), + 'EncoderProtocol': (__spec__.parent, '.types'), + 'EncodedBytes': (__spec__.parent, '.types'), + 'EncodedStr': (__spec__.parent, '.types'), + 'Base64Encoder': (__spec__.parent, '.types'), + 'Base64Bytes': (__spec__.parent, '.types'), + 'Base64Str': (__spec__.parent, '.types'), + 'Base64UrlBytes': (__spec__.parent, '.types'), + 'Base64UrlStr': (__spec__.parent, '.types'), + 'GetPydanticSchema': (__spec__.parent, '.types'), + 'Tag': (__spec__.parent, '.types'), + 'Discriminator': (__spec__.parent, '.types'), + 'JsonValue': (__spec__.parent, '.types'), + 'OnErrorOmit': (__spec__.parent, '.types'), + 'FailFast': (__spec__.parent, '.types'), + # type_adapter + 'TypeAdapter': (__spec__.parent, '.type_adapter'), + # warnings + 'PydanticDeprecatedSince20': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince26': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince29': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince210': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince211': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince212': (__spec__.parent, '.warnings'), + 'PydanticDeprecationWarning': (__spec__.parent, '.warnings'), + 'PydanticExperimentalWarning': (__spec__.parent, '.warnings'), + # annotated handlers + 'GetCoreSchemaHandler': (__spec__.parent, '.annotated_handlers'), + 'GetJsonSchemaHandler': (__spec__.parent, '.annotated_handlers'), + # pydantic_core stuff + 'ValidationError': ('pydantic_core', '.'), + 'ValidationInfo': ('pydantic_core', '.core_schema'), + 'SerializationInfo': ('pydantic_core', '.core_schema'), + 'ValidatorFunctionWrapHandler': ('pydantic_core', '.core_schema'), + 'FieldSerializationInfo': ('pydantic_core', '.core_schema'), + 'SerializerFunctionWrapHandler': ('pydantic_core', '.core_schema'), + # deprecated, mostly not included in __all__ + 'root_validator': (__spec__.parent, '.deprecated.class_validators'), + 'validator': (__spec__.parent, '.deprecated.class_validators'), + 'BaseConfig': (__spec__.parent, '.deprecated.config'), + 'Extra': (__spec__.parent, '.deprecated.config'), + 'parse_obj_as': (__spec__.parent, '.deprecated.tools'), + 'schema_of': (__spec__.parent, '.deprecated.tools'), + 'schema_json_of': (__spec__.parent, '.deprecated.tools'), + # deprecated dynamic imports + 'FieldValidationInfo': ('pydantic_core', '.core_schema'), + 'GenerateSchema': (__spec__.parent, '._internal._generate_schema'), +} +_deprecated_dynamic_imports = {'FieldValidationInfo', 'GenerateSchema'} + +_getattr_migration = getattr_migration(__name__) + + +def __getattr__(attr_name: str) -> object: + if attr_name in _deprecated_dynamic_imports: + from pydantic.warnings import PydanticDeprecatedSince20 + + warn( + f'Importing {attr_name} from `pydantic` is deprecated. This feature is either no longer supported, or is not public.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + dynamic_attr = _dynamic_imports.get(attr_name) + if dynamic_attr is None: + return _getattr_migration(attr_name) + + package, module_name = dynamic_attr + + if module_name == '__module__': + result = import_module(f'.{attr_name}', package=package) + globals()[attr_name] = result + return result + else: + module = import_module(module_name, package=package) + result = getattr(module, attr_name) + g = globals() + for k, (_, v_module_name) in _dynamic_imports.items(): + if v_module_name == module_name and k not in _deprecated_dynamic_imports: + g[k] = getattr(module, k) + return result + + +def __dir__() -> list[str]: + return list(__all__) diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90e821aa6faa000289bf1963d5a1460b62d1065b GIT binary patch literal 14425 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 NNnlICSDcAM{t3Gnx77du literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/aliases.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/aliases.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..441c09954b73a2a01f77bcf8ad83f61960a26e9b GIT binary patch literal 6562 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 a0)@K(n^TXPpWvqI1PV6)8y;%xM*jsdeWP0d literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/annotated_handlers.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/annotated_handlers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48e0a7c3f200fbe83bd320e5b8ea584f42525647 GIT binary patch literal 5496 zcmd5=TW=gm74Dw<#WT*5%O+uyl!q+V2z$5)2`~}JI9ad5uCvNINQ^A?w7Y6N9rtCn zy4%hSAVnzrhP?0x!bv^Z(7Q02a z)GfK?ZdtSyoQhlRR&|XP`CVG1C8y@ryLEV1q-AH$ZFC!Mv)hFCWmbK7JzXsOhgOn3 zr8Q`6rS4HxoO+$ zqei8}FCd{$qJWVDI~=mvg|=l_K4(T?4VY^hMh}M3 z6I~t#zL$0Be2Nyd^|-Dq(ay(>t)IVl$5?y&&e~5mHrM0)syB*@4?Hjc`zp(Ps>|{7 zo2JWxp=q&TD;heior{}yVX60pG4J}6#q-(o&rB!6E*I8Wn66)4Dn!B=-Pt(aqBwE71Hcctgvy@TAZ!(h4oYe`!=|SNR;g82>hz z6}@Shjzeq@YT-S_Wp66r^>%RI(~?@2%MEIfoxtw!Lt8iw57i9!~vh-Ykb zVW%qu_mqyumL*ukBRh=r_D#p8VzwUfIq3zA+t4(YO&u{0$FPVCIM70bBq-6))v$AY z(uB%WEre43eyz84^9FQV!>!;hY!8ek1L;tK1Hg%Rlet?Q0exYKsWGj`FsX;kT#Ecwc%tg9}cYnJZ3Y1>Db6i>3xsvNKXnR|Tm&jp>eX z+7ztHxjxh5^P7IS;X;7A%nKR4gFb{nECkHy^D@9GK(rC^#m?Hw_K^F#+;m+y*CA0(SWdXMykROV7x2952oU-N}yMh6(s3EMA9Vvt1B@ z62F$k_&xrX%^Vt+NNepfqTU0tG>o`r7!bITgY`MX_#iT!GEJSjAbt(OD} zu?f-Ff^O4aUe@%jKDfJXCzPOE}eORP+5NUR?wlXNSzPD{|EIx4s4 zcmtZpw_i=PnG4f^oJF^1i1P`=`6*aXS@$dis0=$h|D{B=2+06)FZZ%6q-@$Xt$_{X zJ^KGxP->=xR6(kUAnl!!29@n$UPRvC6}c|(Bgp$C1TCt>^~vNT`x)3z(wOZHBS^YO z$IWEHY;8Gm%B{;5B*Gra-e-JxEFC;c(m`D@LrnrAb_CUAlO^z+Qq3IzZAvv)CDn+4 zIRga$BdA7*Mog>;X+$1pjtP{DIUYT0MVteRf~Ej4JPNbDJOI6OB;TWaVV&KMAPW;% zL2xM2LP|)AL=}7%un!{US&GDgo4^6w5peMYY>I7o*mel844JFY)IBhhA3*wF5-THB z0N10;qrO<(cNrK8b~yGPOg9`lLJ$I(fMhTn=Iw@q9&RuQLB@IERG)~Yq?$8; z?su=&Hg4EKm0ZgzRc3;!eaaM$eRr1(=xrunrtQ z`|>#cZmNw@e-K~FUCZ%7`h}#A+D4`=P@%~U*5@6ui)XsfU;)lgq}Hm50Yc=AZ_Gq} z)**mlK_cx-YQ8-@t-kA+%!~YbYS&3f%98 zjE5uM!M1N<(ZT|AkJOc@;e?PwRT!Xeo@gHzHYbHfu{F6a3XqhCL@PBv%jKXg54A(A zy{teXXTnJ~+n0q6sCoMld~X2F%TaTJ@Kp{WE`g`v+;{hG&? z50x^ilbwtK$Ls_goeBD8p1%OWYRy$c^%94X$Lx6RPB95V=#=PfvNdfT=_ z`P^9ZT~ITOibwucTmp2uxWGyQF1&TrgK_1Sl=wg5KZXGatY9CC!@RERA8YIr?K}V0 zmY!=%pJ;FXBY*C%g&+Q{aO>}vul=QR{?C=`&nwrDR$9+1EzvTqEIh9)999d}uf52Z lu9QA1Ts%Cd)qn7~{CR0nZ@ti<_9g{{T(-2Fw5e literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/class_validators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/class_validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0ca4df48beaaabb6046327b609cb8ffd2bc27b6 GIT binary patch literal 370 zcmZ8cJxjze7*5&~>y2Tz;?Q5RQn5OgSkG?&B@Y?6}1O5OYqf~%_t{t-tf zyNNis3AZ_!a2|s1@P0h+*YiA&MnmB3^yx(0`uHA-g~h+gY{MsafPn%q$f6p`sE8nl z0FQY52`>su6+^ym(UF)UD;(c!JW48VQPVM^oS<9(l}(ziPxj{O i4ovDF1`&46yRR5R_zLzvK>jvfzfWGq`Auq8eCG!j{&A52 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/color.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/color.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..306b214fbc645554580559f88f66206ca59b40a7 GIT binary patch literal 30176 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/dataclasses.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/dataclasses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..528ce7eb49213157e1100a7c1c5118cb4a232531 GIT binary patch literal 17329 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 istIx-1z2(u| literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/datetime_parse.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/datetime_parse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..280ab76d9b39bd597c7ed21072c09071eb10dfab GIT binary patch literal 370 zcmY*UJx{|h5VeycN~2a{U?u}g28tL#2nJTffPkU0xVrHXENVM)Oi|eSCtzhoNc<5- zCbA*Kz=qU~2}dPD+;AW7zTSK8c00t|$8 zeJG*Ta)ypOXFX*DgtPB;epI*Uf*Z?+bp-n zUs6iyj9nX(8l}*t2vSc_J7Y^$b3!ecuP5w4j#wcbuIC=*85S%r1=mid8~=6n^RjC1 k%(d;>$iJ&46f53+g_P1)viCufx8CY~`=ysmBfI1~KcVGu2mk;8 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/decorator.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/decorator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86b8575e72984677b04e02dad13679676980bc9a GIT binary patch literal 360 zcmYL^ze~h06vvbH#Cqip9GuPI(!mqK=@1uJaS#Ir`iA%8`|@5s@446OB5x;8M{?%ldsDO){wDJcpWGpVQY5elCRhb& zfKh-TfbbD7UZtHXOgc9^#}`0G0y1N{Gj>Fj5myr+vLu|0d3ISC>ss;L8bwaG2cON3 z1lOxMIPRQfO6GoC8hw~7)ys?tlQC9z|8?82)e&QwEAXwDv38a{pm~GzeYQWOg*ASY zQc~yi+L+8J1vUdF^%S({t7yXnT2Nn4>46;6QaacyyvlPZX;BHToy@lWP8t+d9qlg8 i+Ox6$si7~|y!#3<#;<7jfs(iW`hE1$Pi|wo;yXXa!))vT literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/env_settings.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/env_settings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5c6355b06738659e53948da98c7694d10c38cad GIT binary patch literal 366 zcmYjMJxjze7*5&~>y`uN@!orS;2Y|STkNT3u6EP^RkK^kBb zAP69Q#Pg}NSBFXOdh7Tc$QX3RN^nlFa(Pw)m z!Oe0Gjyq?WlDXwh8hw~7G>eQ0lQGux|8U#VYa+%pSKwPQW8E%$K(m(BH{IW+g*EK*`&1^*(wTCO5HN@|_>n18<}N literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/error_wrappers.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/error_wrappers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f862b7d8a20b909b6f45635e11d3f7cc8c41806 GIT binary patch literal 370 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/fields.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba51b7098c109a44d5bb29bb9fab9ae4d49cdf66 GIT binary patch literal 72927 zcmd?Sd3ak_b|(lB0Ko;^_x*8^NKhoSZ?qQE+GUB7Ey)Wc8HD&i3N%2l9zaQCpo;8r zy6GAxmQ$6MoKnVe;%ZA{r_1T_B+kUsaaCthuAWQ>5ayOmTd_A<~e4Wzt zd_BK&?%P0ulB>$;uhRV_Ufg%z-IsIEcF+CaN=k|>cuxJZCxhP2R?EMq7wuUkJl1>p zE{o-w<&;IXcrCJ3&I?(?d0v~9{I-zYYv*5w*TKK}-hBRbdY$;ShYG@l-okK^w}|6A zLdD@?Z!!DxL-w%CTf%;4s5D&WEn|N{s61TZtq50oE5lXZs&KWpI$Yze3Dc zc80sWUEx*URs78rS{?58cC)`E)Dw1l-QiwuZ+MM&O}Nk77w-4=<6Eg*7V?DGde^eQ zJhU#n-n%}$!Mh>6(YrCc$-61M*}FNs#k(cE)w`ABRD`yLw|lpT2fPFPUKx5Myu-UA zywkfgyvw_b!>U5N!;g9&Wq);OF#MSJvG5-69)7P0?G5kq?qh!~+PdGn-)ad|C@$2c zE_5J#(0h=-)rSs+4|@;8-{5^bAbF3-je(Hj= z1C8T{jjx(7uxiF>v3QTkEy%5va+`1lR+-=PEC(!d+e;Q%3Utct?{>Un7iqo6`Aa9h zbOnxQeR+bvtiqSoNYnjpkDlhqKs|qR<6CcF^Y}m2>S6r8V-x;&)FAIkPO%0l`U0KW zSMRByMedh9-?GYUWgFae?5<~b1G^j9-Nf!@cDJy*mECRZZfAFZ-ACBn!R}6Wcd^?o z+xXw^8}{#7y-x)#fv3KUb@70IkKQOn%%}4#fm(U+9jj=F_nAOL;K(ojPk!u1N1^4H z?Vo&B-uqI%K4z}3qOJ128|}Yr?JTs&&&m70d`o4|mmBe4(oyxv2fln;zhp~)IY)I^ zKKNC)G;rjXbX5KFq5l@zDxZ@NXSGurwSKud`mk8?<2O2g`5+V3NFI@oyyWz{u=hNR zKgam{#?Gqw0xoS&8vjEr%=p#5dCvsSjQ@!duKDCWS`4d&cjlwmnTH;{mwTTJG|27p zu^U#S*JN2fZWqw(qpEk8PfYA;u%hmR?=E^-3md~Jv0@F74#7yJfz-VwH zI58%T1_L2EDn%xwa6}G-qMn~n2e_@7V*kWMB<7C=BNNdfcV4Dok3SUhp9=*t&ZGXx zNu)(2`$%MR8o!SHlnp#(BmR-|0ogaHL?#1DY}#FzDLMJ<@qNBM2lwrH{Ls*WOyQu& zHy~$hgA>!pH{_2-pYkgi=aFD6p!h=>=gH~G0EO5`{Lxs(fvO_3AaWs~gd%<_#(vSS zOrTQEqlZqMpj<1CPs{#^Sa9UjgiK8f$Zki*ej*SW%@k5@gQ1{5D!lUE;7BZ!e`;dV zKk|I0NDfRYff0WUDXf{&*fh1w7dbZ`7>PxZhx63X<3q=u9?F!f^+tc3h)gLXflTH8 zh;l9{%Ylg}ru?BGdQ!<08s5s_M066l_>7MH3E_#f0DD+8Hwb;$G(w=Lu1KG}0V5*!IcGo}1?fXb!XV3?@Kj{9ThQQv~Y z(Z~dK8!~UydOAnzjZugOlzoa4QINPnOF)^N!0ZV7pT_8k38a7As}IA8;KWE^!#boa z*%O%<4URpnV7>(?tAZyHYfu@By6p-`8cU{-=iQ-+(MYEFxDvd8VH}LbluYSJBs@8V zF%?~^6jS7U->Hdc0B!gQksm)Pfuq#Yha#i!5xnbq6KnJ>F{lYq##}VV@iE zdfB%IzCQN#!{=e&TKLwnk4jsw`!=v|Bf>W6VViZ|7Tvd1_ifXC+sQXQ;C>`i?c1+J z!untzn!w;jXHK6yAB;-8CZxcnU^Et$qLEM_G%dvLQ91J0FmS zdwZV;{1}T4OTh_gSkKiniZaB68TQ;Sr^KfLq0UNiX(%!g$P^h1`Tl?g4Nspw+b5~9 zj4&B%<#aTrh)+fg&Zi6z%0Cr~`9}RCSZdSvix5*Q!~sa+kKQlBve$x2IS3#%7*T?; z>HDihbbWy$9{bg$tR*YIfOG&F09ZcGAyb7_8H9Jn9O#GzW1+zP)kfvH-g>W~@(9p7 zp=OjIy^j+KFvZ}aSPn!-l;9+lcE3D?vB>JWg1{wzcrp}--Y-5EiG;K&Is=zRLQ`_! zezQ?J^<|$#vGg*F)M&oo=>2we5U{ivhRKzp$}c7*q-!+#bJzb5RLXlMl<>7L)vzV!odk&C@?V=I}gAAlIp+TEXGs` zcmQ$<;M45UJHR<90y8DpgCiHQCye?g{1YMvIXD)K0f1vC35KyxOojmQqcc6~ZhE>q z8ulx(?mnqI6c~;9ViBJb96KND)^jhKnxHvC`~Q6!Yjlw4+Py&y0xc4P{C=+kh(=gSoNs57Q8a=whq=ldFVclC?Y=aVBN2rl!Pw)LpbciVE0wvGEw z?HM=&+-FSjhtY3iXD&t}*owkjdT`=GV1gF>nRCEA0u%BXyk9tTBzW#j6qrvx;UoUB zK=jO{ip#9!wHEbEPAfZ+IXfHRiT+zSzh?Q=9$3t`RJ5n;Qo80?%6=?eT$8fbq^ny~ z_SSUmBPshM>4wgfy;BWu8cf*-(-loAdsDiU(b?oDSM;pmT>$k&PRlca?7`+?Ay{+8&md;>2goX?n&3}N!jBn5vYb!ot{HVjM_0n4!0;yzF*axGw?)-cTa;kvQSd~(h(7j zV&raaAHHNaHvm+GHcHtBpPhXU`0~j&?Q|EIn?D#OERO4_?8f)|g*vFt6odmYKOvd- zOS88xY<$3}g6DuwffBGQQ%I;>Am<`E)8s5^;foYT&N=)=tKj^aWud(48^_Y6Vj{K9 z*;_?ZDb`7hasEgs5)H^%tuDtmJl1>P1S*!@>Yob%a{&zzXcr+urQBEK69`y2d=+}w zFOGl_%GSpDkx!sv?eGZ%jKTy0M!qgRo_B`Ul0$CcNdx<@KhN4S`1ah`hl>&^HCDK=e0{ z59BC$qwIcnlg2ENkII{kbb7s816A^nyv6w9Z9~X0d8;Wz3bf0|r4um`*Z#RW> z2D;Fn16hofC*?;>bzg-TJLH|{jT7=NbGW=4DIdL&C!drDU&{Bcl26Hxp`TaFPsw}m z+s%xDr@;=0I%U&?U?cQGbG#JHp@0w}1`;4*~ed2!?WR(e!o{tbG z0k}y-2{VQ%`OihBVv=7l89YTr5*`EJ2KpV9rm*HEq>%g*(;}Y41bmP%Nl6Ke`4t&> zBRCYJ(#7)u;O_#7KP~d=XX2$}PdsgOL;9h1&cF%%pN5|=`fgWy-75q;7GG7L|FM-!0M#!%%CjY`vz zDQO~rxTvWNoc}@qm6-@!RO>->4*EO7oe9hfep&J>0qJ5e6e3EA$fppn(5z0->(-}N zT?vfRa6~{>p>s~l(?FAgBWfus%73=U<5{br|7+DKjBJA06qem;&53LmTg-r-y+Lmc z@Q^S$X9UueAbO5R-RMts>lI1V7YVe`RN%o0G;(Y}8k9y^0zolD{m%!ab?DQvsW5Q9sNN(RpdQSPi|2zQ=TQvJp%|?L$^`@F#{!DFX{Pw4 zD25`0!BI1jMj{h2zu?+Yv;83@;FqVVX+-AH%)sVt^aIm;q8HdJ5e~aT7jOif!W4-# zdNV6YcNFDDdhp_ zX$=Sx5aKXn5lFnUX>u?#SIX)|qrL_?y}SeD0M+z#!3&2Vl=x`WL4!LQ zDQ-#@(Sg!(pt-{QCIUVy2XKLjHDt7&wp5B0hytPt{6gITc(NN6BT~$imEH!irHcKO z^Oh+~8f-vT@B^lZ8>dw-$40I36&{c`vm1OrYY{XvW$flL@J}KNZRRwY=usIM4=54S z#xFe|n7$ZM1|Mx$>cJRdBP9$5BMB)HEh0>Qy%o$NCZtNsWhoQ!Kx`O@h*lH&?IotJBv2$j z#5`C&3f@^RB#_pN*y_>6r-uhMffi6v0W~~&&{@3_S-ArV2zbUk(&>>Y40%}a+obcD z1|jgL7-d3BMgo(u=vo4Ngei6Uqy7E~{MW>C0!^S=idxYG0%{l;n+VRJ1I|tB_@~-7 zWf!n^ruzj4;0nDyO3olTkCC&7oW11iBWFK32go@{&LMJ0#Y}meoFn8MC1;47W8@qs z=LvG2BxjVIF>=n6L+n5$NX|Gp&yy1(Crr)+IT3Ou$@v;N-yr8DIPMlv^(z#>73R8f zHJ8-Ts2taetHib8if|p46rZbPDin-9WA6GOJ%Y%N_<=0#gFw+of~FAmOo%AJogX7f zr4KT?;MfEqep#XVz(EqlBF!OpnR1p|bCR5=$a#hwFF9w(d5#<(Iev1^kuyS$Oiq9t zg`6mynRS{Z^|Zmi*`p$|r#L?jd9cBuyz8=Jw>%{8`mEUc+*~1V=qZ`%-S&{Y z8?$0d4~gBB6kG7gH#{tpBBiG<l$LT>;76Wx|mpDOnn-%`q+7$ zz9mXVrFAuin!qV_6fFzMphbs;Xua13&*K&=AsUvm*q|?CqmV6A)_-EXX0=*gDY9Fp zEx&KOXuWM6Vqp_Bk@7t2IO`~37?PyK@slasL8An6WY^3p<}#3SkVlixd3J;%AdjQF zJbEp(Tr^@5aYqf z*d`;B3PI*f!9H+oC!@ira)r_jQWz_|vG&!Hp3m68WEXfnEin@gpQ8a8CyFE7SK#c_ zk_R^=QvqZcOiXCJX=o+m?HL=;X62id{=XyV*U5Q>oZo=s&d=DRq^6fIbaFD*=QGv| z+?tGwS&hD6lo0PIVLuW-Vx%Fj7ed#W%H;$7V?>Vr9~i4Emc>fThHZb;{0GhNx6ZXq z{Xy&P>RT1J20vQ=7yEy(JMr{0iD7wuIF=la-FZ58(|U9LoA&ow@3c+L+UE+I(??JI z<(VIy`HSb~D$e}qx$mF+=!uW5SKDv--`{fk`ENfrU(=ne>Aq#1tLgpVYstz-KYngD zKUr}m-6*}$`+D!qGpWW6v-VfYAfvBpxYqkx@AYTrdbX!32WFk=;>vHIPZqb{ZR(rd z`^u5Dt9;%iC0)|It1Id1y7}yT_D@`!7n(Zg<3ii2H)dX+N%TJQ!O2wHV_dI=;<8tF zyu4$sZC$c>-FqkJHy=uFK9tye>TYFIqWNg5awy>%TBvEd=6%h3(|M~pRpUWLiqg{R zw~O8^O03!WK`bThrJP#Qo$j{>-W*7H_Iz|Q)p?l0q`P&E$;L|`Z2HrIKOXofHhw3HSC7HlSO~E6zj->H2p0(cb*;mcn`80q6TQy+_yO zXF*yAVigmlC2{68s4&K@7c5F~4B$^ZvQGHCXpQMamkh!nZV4hbDN3KPxE=nlV_EHi z>;WPXAyqOr9*1AXM-SVGpfrb>q;O=z?PkJ|jdo#1*EUirJAK zNrjBy$VVhy<=5D=C^JpV53EsHW^tlFWbAL)uURk%u8yfnPx^z=z>-Q4SBjzO0C9A? z4gO0vaYZLV?9;wULIafzrx#+*SO^fZn>)xdIURUud>p;+#vr(xKnYMLBCfo79X@oEkHOXbZmoqH5ewg zx1^yM1}Z`yg(~LJ>7%4d-lN6wJO;r42f4HBOG!o}kpW;#F=?lsr-yr_XOlatU{ptc z=Us4SdxtR=9W)k%lz^wLa?yE6IICp?BR0z!%zJm9asxjs&xZdB`F|Hq7EVz_Vilnn zI#aC=mq}f;gK&s7NQT{JoyApueM_>qoq_Swsmf;(u4nF+)hEj~-mFWMZM?M~zC^)B z)_#HBi_;fnb#i^N(t@PLiX~{hH;lJyIP+mF(>ORWvi03Oja~tdByU{jXds>X#B|O9 zcnbM3mli%zoICzyyKKjoQZ1hGd%*%KHg8<#To_+2=gW?`J!rk`1eNQM^W#pT{T$P2 z%v{`qc>bt0Xo))spjx+&Sp#JhS zIw2H=n!w0NWD2WS1J5kchWrYhM9|vkC`hFyh-6wSgB#SD=PU%_qVo3BkhG0G(bxqwQ*!t8LR1k(Yhfz@PEq z=NS^c{L`38Bq%~Zkg#9Xem)TE*|fnebX^FX(t|0AJx_}$(rJ}ZVe43IXI8STv0c6| ztEEB;N*QaFAla(e?oF%U$($Qqw%}FY$93U|v2%kOcs@9JJ18!LpaIe1b2x-91Vq7CdyhknL?dmpRtoLMIla&(9ZDZI$()@ge+ozFSXx@AU1{AM~aw_a$8W{@+C# zh2M`7Tkplv#|kY!C@g%e-}Zyb+Q)iqKj?A5k281Tp)HZfKi(3n?JSP4#MF-#a0!$O z+7_|Vm6$MB7`b>?XLP-YV~M6s!V=Gu?e9ADO%#HPaea%?Gq%L^?T|N7eG9}Unlt`o zhwQ``ogr)FgiSObUvze=@#V5p&c9qB7sMUdNDJfn*hmZGg>umjM2S12(U^(x8PnOC z+IFUl#7xZccc`cE81c|IPl64oGbhD&a^F$Cmy6;>xtQGJI%CjC6EDneOXH<0)~GbAMx|Pf zWSUhu=Z-oj_!wD?5KVr72)g8atuHTGFPFXGh?imR@FBCTcqLi!%3mmsmm?nQLQgp2 zR`^*P+7Q`{_i3dVzwrX(Ul4av|3NtBWHhdj(YT`AHIEnh^x2D9UF6f}FO50SI9k>G zFdAo%5me+SZXeeXSS<|eK_3aAaru|+U$>jkxHA8n24%V&!OGgVm<}?ua+ne_?P3}w zrJ``Gs2A06A|giV7*4hd!#@aYLJ(S;q!p1o+Kh7H59-d7g?G5mf@st8V){Iot?7uv zr{OPyiaa={p8+{J37nHQ;w%&;rE3BS*))ls}+XMv{tx&~g)M&jS5&0R6&|rcpm9xkYL<-ey={y90!e`Y+cLf~;%DD*Zt|06l?lk-23!}uiE ztQ<;BlQ^ek@U#DrBK#3Kzemnna564+8i`upqHw)yq9n+rsh0H!Y_Hyo?O|c*13lBB zPlhbCFDnk=e~$p%0sq@(an;^yN%yY1m7R-u){4{Cg_;e(1glCHE%uVq zMb}DLV*SsBB`y|OJR1^V*XG6+KP$47*WWmN^Wyu3bIk)E#y&dmCzt0=o=xsPn{JTa zXnDQmJ8iRv)2`Zi*XpEe^}MS;>FU2VG3VNuu3tT0-T4-Yxb+wtLyIqRV}(X zc=KzYl)D#gmWH(pRV@iu%a4m|u8!T9o-1~zn>yau`TEZ9?4CW6Zd)_owkg@RDdB2P zcded1GUsYf*R|c;anqBmTlez8yCrqkoo_YGw{J+cZ@`{QRmv*pzmrJo(+-`OIh=~(*!%sXuT zlBoB0N)L2ee%M)f&}sW&U+uv>+sAnh_;u79^OxAhswNO7+%?OX#K>7<90UH-6q(Gxk)LuDr ziR*eo3OI^L$Hy6wZWCrt4r0TIZ>8K1fRxDD6NXL~*|UjTWCupst|6{KOF>wQhtN{i z1wbEMgmBXTuP|x%XzIbL1OhsKIeCOQwmuD(h5{`>p|y=OLebzku>ROO0fm~;Qf=2` z)oSQ~0(a2_rzTYNX-$%%Bb~^N57XyjWl6t+Lz=Oj9mGWG0Kz(<`7ak~Tae0yVix^M zocYmZSQ{8k>)m|-VXa-mP*BB@Ar{-1+bab^0X`_B z={}gbdf+XF>8K63ds;rk>0@Itq_aT$6@fL;0e6xJ@d0;J_w~rPEu(pH!~O=LAfzE$3W1cQje-&toJpJyP5iGm{^y<;DEBRelpmhz-Z{i zgvf2Bd1Y|NB>j-l6trMPe@EoC_lGfeINNpo_VP%PTmq zl!3M?j7IlM`$Af#rU4`#9k^=Hmlx7E^|+K?pg_lkZawlP8#1sB#2s&Rw;r1n-3?al zavrD_QwS%yH6RkSP;F-M%q9>3IwS%G3UI>tAPALcbT=6u5g0GcR!jq(--!C5u9)$r z&KC<;J9;B1R}izTWQ_PCTOK$b0sUQ#LhDLBPRI;+7%bu*qbh+=fbzard+O3#RO)~IUw!hvnDz^i!Pyq0>lpoG0)#nfuamqC#Y97= zuat=f`-WJBW#&)zKx;d~hiisO4m=DB3Q4ttGsA*n8eVqFhEJ@r>XR@!f}8qb z9fxI?70QR$wFJ?WFV>adVvi#@W2cs73baNkggIo2PvOj#YJQ3JZEt8B3Cs2Lk zQPreJ`N))_U}_p671}Oo1leg8Wh&I%7~YcclSq_MQf*N2%M=w8dS(Hw!N&hq)8JM^K5;s>5h$yHvBGhY*=*Q_w^%R6j)kUBhFmQ*1OHpVqRW**b4oR_P)O@ zbhNa7;j%P#AhWrKO&>NU_MV)3$~(9H^xgVqL~IFC#Fm~f3LOoNi@lcW`fHE;<|FCq z_WA0bWOdIc$Dc~MpH3cs>SOz@uJ@fE*gud{>-Hpj_au%#m2^M-N%b=eTGU(B^X{EV z_s+TMT?(h$dEL!^IFJIQS8akzsy<~>qCooT=Pj1r zXRNHv^)Fkh_pL9QxlN0>o5xs??P7>~+}#9npz%l`(U^w3R_UZNK{F)~#`ez#xd0%i zSOpU303Fz4xJ!%@B@hZC3U9N>N#wc0N`pX=;No%B0*ku-aQFuXTNDq(^;l1_z!;3U zj9>=pj}ty%*4BH!0Zj5*mbCsI%sP5x>+{e=Rc3*GGNm%EbKn#}K3_ z?J-@@B0FM|Rx_;}P?O~b)nrO%swrBgkB*ie%yOOb#LUPW?=rq`O68u8+o zF8no0IT)!>MZHqMuK?(*f=$x6U{8CmZ@x4QrS4VS{t7Z3}HZZ(M%;@~vm*wjD~f9VUKgS=(FNl4Wb|c5Wg} zsH|*Km*cMHM0eO-M9*6w{*|9 zY)!Uoop0HZY}rA|yF-iix{{i7*M|A7Ey=DeiLHlIU5_Wq+tdB~=KBvN`wt}!pH1~Y zmncV;{fVm0>Aj~C)qRQnN0ZfqcflKO-S%PET-9z9Mg}zOkhL-0x(#?3JPWOBfr!DA zs9%>@zc*RG4+vSkl#tfX)osYav$g;sYiI;QR@<6rT{~B^ZoyO*Sl}hA=3Q%&t~IxY z=3I{~)U?gl^vu=tT(zR?o9%Bs`$^r}bdUS$!5b%Uwtwg8JJqW`b69HKi@PmNs~2$x zL}B}UL3gsC`&Qvx!3OA8Bx?o|(59#vm@T^7+HrH++q>V~o$7>Y^=4A5XwuXwnk?1L zP^&1Z`Lw(mY7`|k_u0hO4;~rZwSQaQpKmKXV0Zk`W`(OO6=FtNXp6x1YrXf+Fe~Vs z1p$tw51qR(7`V9(YBI8*%WV}s2#&2hoPM^SBYJ6N7oIN<5PVN<)o${p7?7$bimaAyELnoy%0 zS{yHwl@Gz{vT#!wwi~v%gSJJL4T)M^wt*4p@Snw?iS0vLu63=m z6PS+zrj;%T!_jdD5;;lg3*X4*L_G4m(t^8$cMn(G;yeL|kKAh5GMyjKoh! z<%f^;xNTy?8Ki&-a(JgI5uqPZ0E;~N*bYbHJ%&Yq$)J+M$*HDBDBEbe^kSLVA1lK5Xd zaJRMVs@!N68 z_pXPNuD-iv)rqpm^{3y9e0=aPkN)UrvMiD~J3($io?-Y&ntzI;zb{txmT zaB~B_KCB;>T|xKwa-K;NV|frIrs15xly@1R1gd0q^dCRD+5+TB+JEsHI1NU*{=ZxlgLUh?4aij}GH!Gf!AsoT1)s|0@w)B?+6A@)V0uDyzNlbdX zs%iv42(3*`Y1#|{a;lLECbF6BDww=csUJXbBoaPHwrW`~6}ESl>a4J^1B@twjm+`W ztFAR+Sfl%oYS9evAQpdtlEGjJ9F&pCSLyXra{hvxPB@tcjajD}NDk=>)}7C%3j}Id zuAV2=zh-PWL6UJWPMXPw)n4!%mM!r&P=XopTgH$7ZCc*nMJz1uT1#8|Y(cuI1%mp! zjjh)&yb*sr{++M?Rio$S!?Sy?)&MUmX9Xo% z8Bn!`tGm*D>l4*oH&5KDb}v*nUpw~Nu{ZbM+WdP*KdIiZSZ8Tk`&qpO2%@X{)nhLo zyK!K?d1sRTKaqI!INUkclj*X$*|NX;qE5wJ8a^$rC(NbcK5IyPx9Txx-VdCGk5xH- zP-%smwS;M@*$8j>8+ca2Tdr8AO{bQy7bEV{$5^yFXv=}=|j?aID33u-) zWPu5nZ*i5sy8GqbiQ ze$RK?_ulR-=fFFY$vh!@(7 zq05EF<{l&sLY}ZpTitmxuRN_;TfxlF`$e^$49V!O$Pal^IOZo zTh_Q~>S%hl;8lWRG$7Cr5RyT(SOA$8HdO~Z*J@#WKZMV(p5IpfBO;o|wM!#m)k^zv zC7%(v5g(cUGVwnmP}7H!F!C;p{Csg+vbZf#yyk9I<9yY&WYxA0s^_;KO>RG$s-iQg z(B5(NX$PN5v#YL;F!JPwmprZgYdHF?d-_ zsu)r@E!s?tF_BHdKcZ$3b;J|6tdeU8X0P&}5vJFR770Bo)hmzd#c9l^#}o?^u2As5 zrh-W;=87f##7Qo8KhRJrR-u;YWmBI}S8&<+$Z(}uf92t`UMJmb$1aTS&1P3|qO0j{Jz$S#+doSXy9pWZy?*OnyuCP;+3ve2_Qd*77 z;}z=g52I@ifK^9$gtjhu12wI-r`f;(*=vPFEy8ycu;>kkjgSoIND3(?uHUfGA|%5Ap*NN=t#!Q5=L%R~QLTGp} zaxnl>fCc5y2q3M1SP;-wD22izC{AsXoe3c{)e9j>F~T9t=pjW7tF4h?8yT$RArU{`@vNOEnVdOr=#wCzE+leX+>lWi>+ zh&!uZ?J+YU_G)orSu29_hp}Fo1rTs$_eQsl4bvEsG1!ZkTtu_#+YAq_Hr={S@T%K0 zQ(;s{t%BPrHisT8*-R0mMMCQ&QvpB6!zTTq;MVPWNfHD z+q|G56oSev(zAIJN3#Q+XDWT^*`~14S$#r{EwfnBxKCNr~*3?zkLRH;zY=K}W!_EEhtOPd= zcGZ;Sl2s{%#3ZMcG8u=Aa0otc=AAustqfsYG`OR5u8YK!>X2iB20Z~!AC$CJPK40Y z&IVD0xv6u-yexChZedAu#q#ncjkQRK!xc1MaMB0Kw-h}nhNNGs zyLq!R1^+)Z(p^Z*n|*optMQlPut1S0TX(1I3C#$_$0rk;pGXuuv3wXX1Y#Is@T@cp zQNo>Rz?MANCTRQPCwGi7;zMdtOuxTt{r!9*#xZDCe-E;TqC+4IyNU#IlmP4B^AKv* z`>;o7lrC=)WW)zhU87L}-c?gOX1UHGlO_;mfx2P9)+J;}G8si@wKSS3xr&)0O%xs4 zm{i|9(lMk_Xf!!5MKeRZLPoF<88laGD8go|p?z}>SDaBxs0yTvK{POI(`C8sS?Ya`w?U?vXVYSUMXpy$db6wdp}sISR_ zr7;q)0E)Fj5K<@VwZjbrAZaXNtU%lVr}Fo{%yuEhA7i8sxv^-lW?sU)5r+ke$hUOO zRI1a*bQ8=>vw>hP|N0+k1#Li9SV4^ztf0%^ybLPo+V0nOCtMv+>!@zIF250ZJ(6hI z^`8BYO8%fE*|IBHg^#<%deYYb@*uR4!5YzaW|f0n>nArbgX(~~*1-EF{Fk3x$e&Sp;VKZ#Ob{0Jh#n%gVyEbB+VXanC8L-KW^y> z`zN7^C0In}5z=RkrV^^Ei11-8-ZcGC2%DZETu3#Zp|FWA=C{DIER~?Hf4(e<1E@${ zCou>s%CNtR^(M{}nHQD0R47D2%quqdhgF=Q2p4CXnaeRSbL&YSY?vtly2;lra&3WI z;VLg6B-{=x+8i~e{abs+_(s5qs6fKR8_*3Pk$gcQbu)nn)vh-$N2ALnaaf2LYsUJZ zoY|O`mZ`9;^>gK^k0{wQ8-!hfY&#+P$_CpUvUd!wN53J_gCjb0;gvWKPg^ig1F}aT zzR)Znpr&;!kFj2$);|yK!Tm$PuDUR%GbLHY3EgZIKwirC%T&@_o95iL)nSG<%fA)@Iz$Cq=8IlSEku)j$r_d6 z@e52YKsV1TIX)3W+>3z?xBO84}A zuk3c&?A}jYs}>!W@`mL*JON3DNF*j%X@}3fdmFnuq<2=+Q3aAl>X3=fcxw<#KdJy@ zC^u}n(msrOxbw1QWu_H`!4ssM&LpOpVHO~1f;7__J&7n{;|1NtgayqqoE_B-2x(wL z!R%#AZYI_9UY!q()iW%X-_qrkeb`W&l1QoT)M`5ImD%9NN~9v7CMlE*5EV)!Dx^>| zhLW6mZ-lw2Mj92!0)%k$pvTU}sfXG88uY=3`Pu`sg=}n&yD`XOhx|wIfs8N${uO8-k3)i4j%zA4$X>7&|YF4>Drb95NicH?9-d3RV zQ1EUT5x9gG^QMV|#a4;{Z757ANPD2`1St_}BOVgjYE$n)c963y(U6!|w<`)6&Kk&Y z$b?qjOs~N4F^h;i%O%OwC!&Ujuu{x7Q5ysh3rFbc{wW0r5)Lm?@-@<-6>Z zMSNaD%aMl7OqtQ|;0;VpZ#KI9iy}*9?N#|(jkEcG-Ed&`(2uK|uJ6BjC{^v5uiluf z-k7T1JiG6%tLp0h>xXVmed6k0bXpn@TA>S3UOQW|94gT2?IiB~0ycSJ;Ze34;mm7 z`IXzq&&B!eLCogmwRvHy>@v*&%$lW->1*!!kt0`aUTD91eLgePFU|W4so?SfHY{Ru z3!`+Xt(d@pmIL0aH0z}9k|D8?7ih#Z5C;Z~`tlX1!7FH!u!Koxk_8+k6$4?zX1~eg z{uTO8G`qW8S&g4e;qefl`IFenGG(|Y1=!CtEY1tGgNt$klEE^)FB*!(a5bfoxiGhX zfHK@e&OvgnkVBJ4u#XsQt1NbFQ~(eF2Mcy3!A~zijwqWX4aj_^&IC!!A08u!@&sza zW>wRrjW_naaqRVD@9vxL8%*{Me$@5DwclTx>U%QPd?HbL;!eSdbZPzduKC8^WMglt zu`f~Dcc-9lp`zwm>u59s$`JiR#sN%2wanG{5H2h3&5-udeW%QQOP=@aPkQ!$-1V2eKkB{XIjLrM=$l`^+4Xkcn|*Uz4kSAc zq-)!dd-I#kiQ4{Dc|U5AsO`Q}(S2+0eBYzVzDE;%N7A+3@78>;?RMLTHS^ntlG}$q zj?Et%Ngf+XZI@H-K%zE~Di8b^Cy4Dg{i*t%t1!k>f2XSJRt-u>xeufpo35X_-t+CD z&vsfWrJqJ={lB=ccAv-kzcv<-+f@V?yTI?_!%V%n*!=X;J1@^>@&y)?v6HY6chquRbH7we%X~St z137}oT-C z<293iLfm~^rc#ue5s^&Zff)V*nY<(TJ%S6ikE%B&AA>pIqrr(IxbZjtsQ(iE7VL+~ z>isybCJZG1Q_9$dGjy@w2+(4100a!XMdi~3%h(2oo>e}e*FU4zVxAgm)PGJP6+pv5 z9GY%;60-7tPiekS&Knf104yxJC}~>xI|}h4qP?{u|H>iK zPOYlH*7sUpy0m4!R7#dg5AxKlp08V!W5vb<%NqIl zpBL>$HpTFXyj*x)e2mh3j%rU@)e^|dP53;o(NV7k!UxkG`K6!d~G zCxYR>wKSs&JMtY*TJM!tI3Bew_F4MZr`N1qENpaaTd2hmHT+`3t?FHLlCQv0>E>@h z@rz3D6(j84wh~9tz1Ct!?H7$5j!rSfX=0DyPk*oi=s_`XjoW)=tJg+cKU}T74~+Qf z$8inYSain6d^K@6oz>%^{eX+qz!L;-3Rkd^*&9Ac%G5J12OoK!SUYrw8>n%%WKZHl z3LEb2<@?S^=T)WdhdnuNE@oi0WQ}g2bxY2e4QrHGnJ?k6Ku|Q1KVCtYM<7dk;1%}N z8L47?>JWuJPRhR8Wi&XeSfkwfwbJ_umke}r9w(7z?N;oYU;4kSN)I!n$;a-JgR z8FEMgM%)y1j(pVpicHRPDxzvzi4%HRaRV4#I>X{e~zjKC|Q*1 z>)`RzN%szf(SvQ!dXG^4Y?YAPT>{1U>W1U*xqZquOfZ(EY0RDn{ff=QiDt91@OLmV z?-k$;ERrFsrMQ&mrn~(s8r~e!@GBhIFFT~lz%S54{}Mf_}VwC5J?|{2A-uW#)xaZ#Ge-Q`6+S}Vfmw;gby%?$E6kS0r?Tw7^h43tY>?qPe z^=W2VExGq~lyu7I;#arO*cA5@NSYlWl5lIMUzjdZ4eUd2VKg`fY6;f}a{;I5eiG17 zswxf{U{d^`jL58(kb?^9NzE9VIm8}^6DWECv&utlrv42IE> z!)l92t;x_3=!Z%AX=&JZY69Bw(0}90a7mRzvk=1i0el}WH7ENZqLAl8Z4@`2vlS7F zGMs(!*04#`%SJ``rWd_`mXu7wVN&B9#k~k$CP!B6;>v2utLQFqo641ZqbLFGjt!Ho~p|#~qN4&_yD;F#p^XS)3zPD>ZW?K_5?Cty>s282M%e zf61(~(umxR(u}NGySQ1)E+TNk6d1Va` z%zo2Gfn#PtD92)$rc9j=Ipc^DM81CR^!=>v%$el76vV3=Gp-!z#6rG zj109+O=PK)Y3IrUGBrwjLlo`Q8yWJ$uBDpIgJ#PxvHoZwdbHR9neT>Y5WbALpB3vI z>^adrR(<*wOv@c@!8JS)a2@@^dX!MQM#;L~wpNs>V){;_9>^1*1{dSt@SN8AC9`3f zVL5IytfbyX+$uNCp0=S~(Y3*DK`khNAC?P%yV}y`q zp;0D9=n+_wB$I_mz#~u7z}(%uKPhx7pMr6nNklPGd8V!_5E1DJ@#54E-@E9RYEq@eel!YR*wxgxexPlDmFP~0y%Vb zWv-Dj%p|J0>No^;8sI=vBUpjjUO`&i%rVdIo}Ob2-!9D`UZGW8LbPqc=B z-#8(F3xbWxjA5=G;6+I^feIagU-qfsB8-(pvt-N^2N7`?0S0Rc*D#uldaB)N%07^t zJ%K@-or0b(8P0rIIa*}V1z)zz5SnxZAo_vrfqu1!@G~?fgvRI@KeQ!A2|r&m!m7yJ z7Xdc#6knC84F=8usviZs__95NZQci4Tw}5G0}`b0!SGaA67MSF6i{gLnx;qCf5}MU zzw{+iOw#V7V6QqZJe)I4MMA85`~c%)Qz1WQ0WQ>{eKay*S{k4tA{WVo3X~k_MlyPp zhVf1$Wxx81Ps2H9AJd#zq_T8+SR*^no|Xjx>QO_^E}x{-NI5tL>fQVp~DJb zVSW|mlJ;N=$66icGlDP$O<+UaDRIOVg$|M;lZ(K@sg?XmW~>w;aHPYehVZ zPWJT^Q~{+&El@8VH!>Rqhygho#X7_y*YE{(6Q=AL>4?T6lZ1^3*oN!>RP2M(h$C-6 zWkBki5;A^bZ~)X>sm(+ZHHL{h^)#@`JJDb%Z!Q2-Y+{@#WIi#{LpI}pSxkZd0khi# z{%9Hr%nGljDauTi0jXy%X`GYEP(apw%y?k{%|IolV~$HVR}-RVQbeap6H`gWd%*$F z^3EC{(Kd`P*I`(*434crLte>jF}OlfP6Nk4GC+Z;#R@fL(}lR=%G%Q=J@T`s_2U_$ zX@(7fv%)&EpuNyl*!-B3p=}GN+@^=Y=+Wf!Kzn&s5;2SM&T0|S4%!Vhv>pT#i40)_ zt3pCPKZp6vG=>Q|%{Uk#7@Bbpvxm($s}^JXm`^aQDrpJpSZMc5srtQN7_U+OXE1^@ zg#;2=vw!BmuF8-@W==7MCOD!?Z*KjdR@CZHmxaBN_0i=7LOL(P;D1@H-E0C&A zTYewc+Onw(vQ(@QAJE?WHu7YfmF80z%5NcbrhY#yC(jOXd~26y2eAUN>+V_yj8lb+GbgaQGl`XJdT2+ii75ws(SWMi zGh5|>=!5@N3OD`Ky(@~{SsUiT+B=52&N<3zgdCY1T_pypK)+1^>&U4jX9GFg;AHIM zk>EteP7_O5Lj7C%w1%91a&C}A>RHMyI8fTWLjFN=_K@=rK_!Sa4wStl!rw>E0dfwK zbBLV7=<3+@SjyFPWnbFqN;vE9 zmbN9N#}iMUn=2hj6pSpC*IX-nt?>Gqo3T`R-<3mYXL-Wee7C@rcAdKGT9vM=|63;x zCP979RSQe=`PW;M#og(Kj@iS%KuRcQZhvk2_2+J#OjT{TawP4nN;un4u|>PJV$=%t zy~>U+iu22GCMq9Ams@I^u08wOvx&B~xT30N%ax(DvnJte=Sn`cq>_!-PbFc#sit9e z|AMRH;qCu-P8afl)?rD@LQDG_&%XX_a`oX4PW`F(kG&tBNv%GdYB`)}e*EM0i;ldK zA+layvYPs&7!~`h)KcD_=-T{YZL({3T3Q9Oe=zk>*pPNLzqLQ<>b+YIQx9w29eIDp zpEV@6K=j#_rt6mMh9K2q5b5p9c=gNV!vozssej^u@->&dsl;woL- zNWM+v+f2SK(LwbGt>k~qO2K>Bk9CU< z+sA%r79;!s`>}wlnimg|f6=nakuMas0F(3w%aI=Iy~A*`l}P10uRY)x#eMFw{RWOW z$&Qzt-u!?wYL|=U{Fm(B0$h*k#4j#7l?(7&B$vvC_${8cxyv%;#0v>Q{Bi;4`5=zW z`4fO2#Cs-Q_aw2|n7Jq-m~4R)*GA~65_v;x62?|dsJV{4K8x!IR4aerf(YIo-P#E9 zi?4zw{_yb9dWbEGxS517 zf7ESjupCFp;N|B$kQ{9M7z;oWWs_U;DpqF-)@@y2~%>Z#?Y;DMr$ zHHKgDK#ilyFbo6B1{9Ycvfpc58a9no5Be%FGP|&0PU;;-m2jBz&8&bZ;elwD*p}#+ z!%V}{38LTD^p6Qe>q8va4=b+x_W5LS>)ob49M?XA4M18uYyYI6dC_KR?xdh}n}-9$ z8q=GC)W}5~+$QvZxJyy6#s$f1B$V z=67I@F>d`%-tU;~h`DVuf6DV)pFP1aO*6!{=Z2|<#F^K}iXLIWFXnTVLOhP_}X3=Y!#7xRgZ?qy2#70l+H z#I>ta_=1H%GYz`zuzzDF12V;20m=vEHRqUYsGj)x8qGISW(RUq00Sn8x<`^_kHFa9 z^-XW=czwsM>bWWp-F3O??HzCK0HV>fC4swSDy6sf-m3n+!}DERlU-XAodb!16N!`0 zBu<=8w4X^;o=v#UiaAN$p*{MXBZtJHIY6+PmK;N-CGh!vo5qZ2$}5(I%33nZM`}4 z-riKz_Su5F#Z^}i&K0+O>Z-na;(FI7t~S6AS8KK+H8LZ3Az%g_qF8Bseqn2bmIo2O zY|`lzdH`H1B?u16iW`QyhD^LP;yBU;e~=2Z%{EOhh6zleeIrDO;>4KX)M<zs?kVpu;QVk7#25vA2?kU4Ug{jbG%sZMlEAHV!Z^{5r zn4yChTBU~^8+utx*d<1ggmug1K*MCM?)PW{g0n$DquR3dk@+o$lUoiawmkXDh553s zWLekElW(7S^GvD?w+T-qo;frBOepzGDD@0s_{;YyJ2JxDv)&_?MwSH!G61H-0(?{- zZC%5v+xnHPx*=r_lLDjIb8=dawdRgZhuTkAw9WoQluxIy8B+u+<_g}qM>Rm~U`uUT zkT~Dx3w(_ZRp(gI^x=EdmHUy=6${;3wh9N2TiE&spzPIvvuz$|6U^`bE9nA^M2(0`eF^PCC;L+4IA*k)~z# zp(G9Qq%`J1R<z8VO9m(vs#}Q z%^NpR%Xf9fe1LhI|8sN$5m;YVp;je?SVR?)bew33ifvfXZxC0hm>UbMLj8p82r5V= ziw+6B53;sJT2>HM=uwC@OlGP0Zc#JA2tth+#RT5zqE^y;R28pqDI}C#O(LtcS*lnn z4A!AL$R8xOcXhkf!w&f|^ z$}Ed`f0mvT-LAX_7^0j2hyb0;+W@n&39=*L3Vj?Thk+mW-CsCt#EY`!;zdyjc&zu{gKO}j zPT`^eFK7*~UA6@r;_g7%0bf3$-LezD0`?WcSH!+z_*{Be3HwSBR;GuQv#$bSmF%m6 zubO=|@YS-f4!(Nw1@h$Gl9`Nn1?Z@iF`;k5 zDWIyis6hoCz?#`ikQS1DDVvcYtvkVFgN7PgI)qLL>4MxT@GfgpK>eh%L-z@{b$?14qdkUE#H?vk8L+T@faU^DBMYq@f1B#H-|)0Dn7?L`_x zu7S#R1N=iQD%dDPRnI=js?)h!jQXk|iuMN@{HzU4%2H?`KuQnuEdNVrbnjI;x};R{ z71rMn{j>V6Djudn)O#}+{Qp;?vb>_k`&ZbZe@|-Bzn~JYCPvRv;hia40%>MS_TV!0 zC~WbNZJ@K6QXM!kI8!!Z&&rf91wu>(Wr|I}MR^SHT!>}&l5Zb5WK-h4M?-Q>3+qG6 zfH{aYDq17f9;cLSgW^2-*yzMj^07$@GC?D3P!RdWCv$Z)9svd#|2KG9k-zg_*`+(m zJ?e`u$XUwg_&Ws7tXkIR;2#MkEG&ENx|}lb5|p1(CQNv#SOeZoz4`;ZtkkQQaHSbI z71nW1lI;-3^93>jn3o++Z&ymi-5RiEseXk}0@F@Bxp^5cv>-1c>XtmYV;eRwRW51X z%;{5;z!wDTO$T+*%?a}^06disBMR0!Fk+2F5L-K=+DkUibAeEVlt5z`$iF$BK?Z&BO=?gW*kzUn&asi8ZG%Ln2eQFT~!I^VND*|Yy+`zNlW#E0GTfEg9SNUt=b zUZ6`Wmy9sI%6ZQ>qSh-I-M{kdvh56JFI|m^o4kQ3iU%Sxv{gLXOjBwxV~9Po;!yGVXjaZZB5~Fnh_$sybsa({t9DFWOvE3cZT9C{8l?NrrF4lRFQ@1+PwNHg2fN zWuy}~@#!b9%`1uI1CS8d{bcfMkk7Z|K%;;X@q`7>076mBRN$RJWMep0r4y#v#4+JS zOXfIZ!CADecD_yMN;88&>>ea&5`nBog&GM}ssm8xVzk;2D;uaC6-jahfs2xF1q6v# zv^dX+hG`;NUgKP4Bg-L0Lf5-(Lu{>%x34`25Q<48tIVkP-VyhJP|rY=WgpCF&QucP zcr*w-Umy4!_+v|jw4N1M`BJ%xlwZc`Qx4*Hshw=)BBIUoEC_?_L2O<@$Zi(_CJ&E+mUp+XZKxQpQv^J7%bSe@9vr_ z8%VF)J-_aFa^3O76Q@$^o=TSYUv*slTC%bKZUv&uRrG#Z-+jxTsz)%{$*rC*>qwS$ zB+7cp#^hkqGx*UHcRc&ktGln-=gK=xQEvM0ly%>2>6~xbl5C-ikU!p+YI*Xi{kMt$ z4$6BLJ1qyS&srHO3@PnsIk>r(sGo@6o{I&G@6?ZgX*!RWa0VT77^D%=r%cWqigI#l zC#lqFDwQxDVJmNjd^8?Q`LhuUBj-N=s6>fDNQUsr!JqB2tb%gV)uSo<=5%dq%HEo; zs7~3d)5SF@dri8ULxjKSP|AKNUD1@XH>JxxDZ3|K%3tgDr0jdrMWx?3yx=HVW?SuE zdA%IQ~&o$8Ymrdr1!OqloULE$CEL{NJ=&%vV)hA01 zX@vp^nl2vXSD^Xz{OU}wHm6zQ?ECb5lDF{TB{nsZki^+87OvWN+$Jfz9SRM1h{4K36F)3I;Z6C!F zSN{L@t}HmN z6{8qM_MGYI_g=s5dvD*qefu_FI^*Zky?8*IH#S{R?mM}Shmsi!*AX#?D!zwbo=Jte)q4wd*{}V zhqvQL*P|bVDmKpi@OyVd1NpzDqPvm!PNWs?aBq)nN0RSGF1!=n89co;c>1UQ?ZFG1 zy%#q97li!~me+2dDWN8}hfxQiCO<&l3V~t%0L8M6?FUiFWby**PfCPm$Nod|gdc_V zv_M2EHKMF2bE4dfUe94(w0YCSz1aft7q&m2P!;nnR)mExAlQG}kmlCt>#UJ&{;yM= zJz5pvYw|xY<%*8npOcO?W36D#x8`39tOeH!*NWCcYhf@`LCQ!Kq=KnHsxakG6{SL{ zaLRWzJZJoI^gDsw^N|w6=&i0+c zDgX=@Fji$-y!za0?3I8MuFWaS<}vLMt!)pUok4s;k2t5b+1W9P(0rv=9_a9#y*E>9 z24bkuR+y_R*Tg2RtBB#2ix03ZJC)RCI$21xw?)X{PcwG@C3Il9zP!Lyavt0*FDdGS zx8qb-+tyE}r{P^jKL*iOWc+swdI@;iVDofB4%Fom3S8N9T1~%)*70A2{~9(IUz_iA zi+6cOztm^H0Eb8?otAe?!ZOb$n(5?{d{?6HC~xjPkQdrU zIa#xp3M9H=uYxmxezblnq{;OgonGyw;KWF;y%la^xT{|}@$%ft;%l8lGT9`^)eE{ZO}p=m z1s6EXPv%pbc3g1o1ACr4Ze|4zP?(2tAp}lQ+8S!#(P>2Z3?942T{W-p&~%U>{w-qF z2i<#pRt}-!nvyK9T;p+yXRz*t(-1F#uw*YQel-(kPMp-+>glJzDHIpNbfjLrLq}qF z;$&mib45I>upJgAWR`<9Df|8KeE2^uEiTIPnoXIM1I`|()(bb`h4Bp?3BU`ebMg3h-2{8?Tz!hB%Yprb3#fvxiKs z*)6ZUMy_Fyf~-ACq(|9OC-;%9GKsdKkpsgocRD^rIXi5~kpnF2Y^z~eY}+HtOIKn0 zqZ8Q2Q_80>8R5y3x>x1#Sw_maxx{pv^bI)i6)aB9e~T31$-bA}bC@1$2%JT7J$p)n z-C(k7aL?*5F3g%s%ZR3e9YRv7%V`y?R^>Ob^dC2P*{$U;O_o%$<&X(VTUyl2^w|Z~ zC2Tl0f31{~oui*DlOC5qa^YAa(MEn?xERgqpcR+%xR5)YM`W%{%Mw~9!wQLP>lZoG z-3`eyY!6N>H%Tee4^s>F*Sa^zsS*OQ%)gHK{qr+pIQb0$m_$l4D15G%%#x22?j_yb zgZ=xT*an?4qnk*Q>lSBTS(vpqt|ohB^=3lUMK1yYtED^7-eUjBLR%N_=LhBUU~gjR z^5Ed0-2ltdhlz=V-I-cw5A~1Ozqci(bDoFLPR;?1TpfaoG?p*ibtbV|NgL|HfIoEV zM|ko+|4A_Vqh%+C`VSnoAF40b*Ga{f7VXz{2aOTkqIMbH0PirWGjlHYhMdc^mUmvk z*$24fhZBw(@?hW21!m9n(5Ck~bRVNZ02g?l3?3}%39)I4 zy=kxz;*TLj6bv2`^;rh0EAu#D6U$y=Ytj3r_2%5^Ed5INHtUEn5VBgXv^NFXL9M)} zQ7E&u?1c}k$KewDV5cuiH@YZIvZrDM-o(UQQvi+@%Q{g?H{fx$P^Z2@mOdpCAh%In zAt1jw0w*U|#Dm9scyO*H;FY%0l!WX^%p`Tiu%`|&Bob5DpL>!qVHnvfONeO7o%i@X znM}IRJtZ-Ok~2w;`TCub@>0mKDF_=EZZ2Mdqb*7-(>5grDsf%OCMJ7n)49r_t=v}7 zZaT~ZSHri>>u9G^u0D3r_Tsjiis$=1rh?_(d>Rfu^b@9l&@yhC@*K@Ng9r>yR;WeI zK)fL+T3VydQ{{9kfA%3w+%@(jud7Q-TI+WEV>0)Zvhs5$Gwu&08fVUZIj`a#Ej>y3 z?vv34)zI(w>*&_iclUm@L(!l5nTwFIx`j}Ui6Kp=;UgYxBDNbdKc?xC3O@UwZ&(=L{(BxwWTc7cYQIQ2!Ta+`GvT@nt&!eAZgyJZH_);+V$K z!Rh8??uL=MrCDu@ci+=lCwyXjvqUH5XRc4y7ZKttD<}n-46hE)l1~g(mUuoV7TOdi zgEH^SokrqTT-1Y^kd5JRB4ur!#Kg~TQ?MG-UVC6vc5EshlRVMg;Inp}`}F@+Cj-Z= z2DNnjVfNr;@`5OGqH20C&4xLl35-qXoaoJ|9e9}jmQE9MOycxfM@`ZD6j!cb8l6?Z zyRRO)ZQmsw@dVzd_JGd2JCa8)(_UMm;*M9)d!F_XPD{ed*pqnGdCfVuefbjd&Q2I2 zOoq9K5#kF(AZJ-~lI-dXvg0D(E0Q;XS%lVxxg{!WPHWCM)s|Qv4E&0QqDbsTH5X=I z)%v`-0w*!(3mAMb-{i(Edgb7av>z@s^eYS4?`hu5skI$B)*h~3)OK)B5jw`UeZw)G zc=2%^s@LtEvy?!Cdj$-n4{7lK3)nwB!~b3j_@2%4JH~q9YR}$_@Mg2Of$sO*#RELa z{@eSif1s5Xe{U782Ulyd7hvIoZ7*q;Cn?dhvQ_9kpFA zS`TAcnATNI2fo| zbETvcW&ZoWR@E;j0|^|m^dE|;g?;cv(bYH8vGP>-XR-2)(LcS3&;+uS(sfoGnlnYT zsJ^zmu&itMHP&91d`=LZW^#(jvrObyskrB4M^=ul&Ri^&xxa+g^mX^lA-NdOhelS7XL&EwZ!wK&J{B_-S$3{kMj zXGJ$lzAPsW={xgSo?lfu=OAXCPL+LppYA73R>xTZY38S-i&{z6|F^ox{A<>EnJp>Z z%T6%=hKcMBBm3ICVIE}eQ`hG0tkqYl&DqXq^J8fGTO*#Qh_@Ti%ga3t(=PG!_0dE>1g;nJSC6lred^j?%iXV3OUtNnUNkB_ zQj<^2NhVL-_#va-SFiQ$1EyunUSh+`I4NVgj4wewzLa``O3N;-SLPM==jTcX7v*>G zRSaBvmDF0lUnYIG>hg@$5SH%jO{z!j7PAMLBBXdn$tCKl-jjUtG;n%!Woh7^X8jzS zL3D9X$M!m&4qM)AC|Hoc*{<$kEw3=7Z-t0$v zz3JxWRJ!Y`o>U{o&D9kK7R8L*hh{-|6fZ#RviTFX)CL+PQ((@U|Hc9_JB}|*Im`Vs zS7uE=%LJHU!llo~%#@sPLgLH%QYIu*c`mVNm%||JMzB!pNCIJAMnW<naL_^(*lHG6SxFHwQ*)nD}QNY(#~WblMW_H zCY+mQ>fF-(I<(AdGl+D*aszSS%`TSeW~oA1On{4a53_oi^f5oE_ePlg@hj@dVO#Yq85hfE%zQ^Q` zkYq|;q=|={L&b)vqg~2zz5mQIx0#3}dYh#~%W!j%u(p{nRuZwah;~~x|CPT5b=Xh| z`5?g$G9h;f8NRC5mTur204%nPjYoVgF$fqQD-eKotIX5Uk@_f+lARrUL-=Dr%e zug<@x&finL_thKksW*P1D()G+SzGhgXF|KL4; z7ovehCXLlXe8v*1!IW=XHShX@JHCo7U&Y4j@A{hF_gCyTwC^+wY&8tL)4kO&zIt{e zbk{$=+t5L@?eBOLOd9pK58pZYu>yEBW%!J;&3Ml{`#)AdkD`8~dE@4t%8wO*RiX+C z9~In+7;PJYoznKL()Ndn-yZt#gC##ax)nDN*LLIZBgIdvs5)Gb_7|s?Eg#UXziQ)# z6#zn=1JTr!RY+W<0#zGxR){#P0`c2^D?%Jq0mPuPiit~f`51Aj3N+lFvdW0dRR9JT ztAe;v1!5b1tBSZ<1xivktT=Iv3Y2ZMTeZY>Dp0vGWz`cm==?_FCKaf;U1>EFCsd#~ zHD|RDx9a+|5x1*i7_LgwrIqPe#Ya8JS`Au*rR4?bVAS&Ab2nCjU(zMz@KpEy;jHwk z+H`p}4@yUhe~m34HKX`y$%76REKW`R;N?}mc|jOWQQMquNv4mUNO$z6Ynsw0&Ze8% znN#1A9@w8gFrFSdm_BtrU6)9=cc;tZEYr}+Uwem{*)>4m{!4W5+Qv3J1sEN}*9T{e z4x=PpTxI$2iOz^tTZKeLs;b!v5rtKJ+=>uIRb9JPOoV_c)mDtCR5g6fu*wL_Re6I| zK~$+?%~lmrwJNE#;zS6|(r48Y)v3x+tDdL<;aaRlq9#>y!myeN6EG`UEkvy<-fFcG zwW~IeMJ4d%K*`!YDii`M8hi7ZH*9(6745C zKy;Ak5Yb_xF;(7V9U(#x%w}tX=%^~Ix1J%IG}tu9*lrerU?TgtU>N^^PYOm5%(7tw z!DJZ(!7Qyu5KLmku`Ow}&I!g*tijMn7l_F>VXJ^85ajmL_5SYX?fTNEwCme{+x7X3 z53U?Mki+`P&%yf78(l_mx;SR}@M*I?k!F1&&H6-|^@%j=6WOd!s9B##vp$h#eWE6^ zelt;mtlvU}0Jj5H8&SKk{yxGEGHsHmQ^ogLT}0hv{T`xTvVI>?KUsf(XppQwL^Mp+ zA0Zm$UG@_lAnP9_(#%aXMm9e}G)^=@bd=~BA}}|2{}@|_%nj~8F4$pi=7YH*08UFj zm>W!gMlhHg_?%!cHw3^1!C+|!0BLROq6mN&B>zPSfTE8s5!(WQcc1!_1;B3AvsQqT z=c$wZzZC$Fjr@-bfd0|XKK2Vq?pB?$0wg@$|3puT0OvAyE;vz7P>YptmCgIuK%~S0e;EP>E=LF~U-6ePu-D)cPujDk+t#h!6w44>8bz z5CeS_G0=hPDEjM(8btIr5;jq2HxnhO^|cVSQuMbGLI0~p5OkmpivA=Kf}qzT2s#k- zzitFU2kPZr`iS}|`Ui*xDcpyMwEjn=^*GrqQkE?fST2-N zAsC_X8>}jU)ufHMz#8^jtw2yhpH(jq;qXVTMuAWl2CQa*2_cXc!L97uHi7LVk$nO& zABb5=ft@6hE`i;ok{*GW64Y9K0{clP0|Ezmvmt@Qq?8eXnk)orx)7*!2Z3675I9b9 znGlEo`JfGf4spmAPzM_BxHPhm2d4+}3+D%<5BWkJVi*J>UqB(C9NjS%v*0jfR#7g??KP#3u+aQfn~>A^_@12*@T?=Gk*o`=Z^d zeOBN%yeOz}QNRab6Rts|QjmR+yif>a-=BG5;e=LUgrWU7+TlS6UxY$+W_7<+NQ4lT zwHANFC1{oi5!$XGzFNOyRB!R$q0QRfo!Wz2_-7pYWx;cXamlcheDH~fEuHo7NeOD1xtMV#~ z&wwZmc6?L|WH%i15~``y@}2YWP}8p7ku14%fNG$>?&WW^{pC)(eENN3~;u pwX_#l&WcwE)Jng=YN>i$a19xxN=Hp=*{>e!f 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/generics.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/generics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7fbb2871f341722d3852579b8c4b5dde3751a180 GIT binary patch literal 358 zcmYLEJxc^J5KVSZT<^F83u{x@Y~hJmDPm(Q7NR0cAeY;WYw(gR*?6*c{sTK(TM_&t zmR4>jVqqs-XJx{E`e&tVnUQ zT!7=wS*B!Rxsyg8rVGs?W5VQ&HQj&S25C*gnC1$6smEA5%O24zDEc|u-=U>7ev?vC z7xdbg+$aS$2PX9tv@^D*K@(^}eLkfJa!f1fV7>G#FQB4jEx2|v-)KJ?mUWZt&cE8T hJ%1>OuU5SKjxok>X!{eT?}OEc#g+s2h@%W~%!4VGK^9;X zAP69Q!pp9#Q-^8ib~w6#WPDj^HBO}F*HcJDm9S*O@~cuC+mh!-%j9fl@a4x-+^iR1 znYD&WQ5a^0R>$c|vq~w~Ii*eapEq7s6H%&|1XqeFZD;8tT6i@-qr*K?8tpboDO5pj zw9d7ZU~-^B%|KagYT`A4;>6`MawI0C5*D^g$Fc${Qr4U)EApZLW>D5mw7>l5z{Ku| e7hY{R_Z?!4-_Y(SO5gjN57BEsy^GD7tNa2F{%FPk literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/json_schema.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/json_schema.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f331f1ac9ee237b94484f8fae3f44fc816bb4627 GIT binary patch literal 120013 zcmeFa3v^r8c`gVL00|Nx!T0+CzTedQMM|P5Qg4ZRP?lv#G6ZphBq)%S4?sy|z(jW3 zhDz0%&ZDLqr>0Y z|2|KEpd=@4oLOs*#B&bL*=Ilh{r~^|U;96#r>E&~JoP81Jf{Dw*ZpVuAs-g;M*rZh zQKx%F_mqz596F|FNnZU(lEa{4;rI8yl4>@f3dsv{Lwqc?5D z;;@WZ9ajFm$(ufs;m8=VIcy`Dj!gb6*_$-c?!cm2o)$A*!Oj*a+jW0~GfBbyzYN47Y&jBIsm9ogpCHnQEZePoAY$4I-Qou|q2 zc8u(F?Bw^^-d!WR9lJ+59i9Alj(5*Um!oTBuVe2>x1(FHa~BA98qb{yvS1>PegM;%A`eWCZ*NUx(8d6c+ohksulQuT_bbLubo zZXl@$w~mvkI`=7epSwuD=eOEfwTAk6bDp7bvZ}lvTO=zMUkcdzL?`);w|YCpDTU z7u_!Rv+k#)+Fio?GFI!(c&kpyrJvP17@ix4|GiYC=EC-RbnflLf3JBY-M*>+9X+po z18UzW=cd$pkiTofyJq>FV~Dl5FR)hk5NjJSrRvuD$GX|N7flWiYheavkiJ;|TJl=y z#pkStZFn)+G3+jPUv_&jA|v?L#Wqq;qYqr}KDJ5h1-4nd4y5o=7-d^9GMi{**gm%P zMWbVk?PuF?z4A-+%67DThum_dSDxd&(vEi>@;isX4zQgl&Bw=P*SGaz2Rrdtd*Md&G62p{;FQ|JZ21`-h$p!Z6mBPE$#G>+kR2=^rC%ajE#HUc6{P@c}9Kqey_{tbNlSBQDz?)AMK}Ne0Kks z-R1R;U9q zCf%$pE$z^#^xkWq7#p|yhQ`LdY_#5QA9af#jQiXu6xm1>WgfxZ@Apo0*ilXi+f!@_pveN2JWM?Q`_1L=dMgJ*Qnpq-}Z=P7pU>b>GZ@EcNcSA@wfNR|AXP$n4qakWO=<*G@ zE_vNi^C7$z@A}-&jk__H$j8jw?koLcS0-?8+&4Ntf@{hNmmg_I8`Glcr=K~o&)I!& zU-ywiy$7PHU1F(j7BzH@PDIV!7(Sk7%25wx?~SJPy0207qbYPg;}W8#r$#Z@QDeW$ z=Z~7luDS*9n2R-!Yd4+(H3qyxJUFMbl9Y4_YxP{xlsL1w2HPkB|Ftoh+i6a87L< zP2v_iu-^sr`my6Z`<$l_oj$tHd93Ti2>@fG;o}V7WzUr>Zr0jAH0J4de_S{^HrlF` z0pM$u=Ge!1a!Tg$^$VU6z!ZkFpXR81NJwA*AQMks(YbXFJy^&jrgs=7k}whqq^UK0 z+9iy7Mh9J=!?&jiM{#hl;|8dRqdPa|2Jj_M=CfZBfNcBmhK&pO&d%|+h%RL;iLqE8zKA)hh z#2H-RZNoep8e=~Dz?cBEF1YOs6Ax3ZgIWxHPskjEf-sQaVaz>Bl!GXgFy@te6A6Y~ zS3P5b*j>HACuXN})HULEI-_Y$%t)eZxVJi;&yBmh(wh{gla2K|ows!lXy89S*WG>| z!!jtiMgSCp=dX>8^^c8=xP^WCON*qGPt0u~<~_X5ciwi*OZN(RNa zgjS(k<&c9M zDJ-3taWzk*HfBWgoM??_)Wg|{Q(#oCTtRgw^ZA^Y8rou)ZZ1SK7~1X>;?ha|&|;Tv zkZzbDUP;$4HHkNo`WwIX5B?0(^9#0Dbbe`y>vVx6na7(lFnz$_(N7uu%C}5;+oQYi zwoW%?@|)yN^C!!9at>d#1q?`6i*(5WT_Bk_+NqR43ZCJ1%6!unFw?W)RQXHw8Ze0I z<-GK|TO~%_t$L&GrVZccP@aB^oE|yx+~w5tn}+6Ao>Aw~O{L;5Es%uon(>_lb+L$b z@u$li#3##`S(zG$m>Fr%FQ1%0Dw@+WD8 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≻q!$X-N3MurcV7nNUbb8agzeYc=u z+a^m~pfcKp>|`TBJjhmykwv0{g8}yfIAly}uyR4VaeNEmw#JzjC$KC=9=@1uHI15m zN&Y{^Ov?d;Xp87@2o0$MrwH!s!95BP4u-AT56@o^BtV;jxjO9!WhHMh##G{mghrE% zgs2=3CAWd>ml}NB|bFk?i6X+i`2a9!L$q z==C^U4B`%v)n2h2PY$F9GT76UfGgl;clOatU)Bdkff|l#%XuGPl>XBgJ3C`|DBQCY zkBN+Hplk-V1Ss(-*2cp=r}xP-{W$h^L1s-G433ytAdiv3f&Oz4y3_iA zfNwAetXh!M*>o zd@s}@J8T3G$A&61fmVS^bg`x(vizMEprO2hHzG!<1x3#)V)>Z64|{LD(bmdu-` zR^yOll|OnLJ-A_l{}mv&I8a(4OSEY6PR)U+OxPDdXl()El!KUp78Fgm!1H9>&o|H> zT`)GNM@|Fzr&craY_{qd4=P{sN|LT8>QlKVOrw{;9b6}YeZlk>tzBFk(@YbOIVMF< zio(L9N}Qs*UjCF3Mt@4#PEzs$o+hY${#QI-R=KJVXBh1GU{4N?#Zcc<^exY$4#bMj z%AQF1QEtgZ=RH@}WXmspW(om}%BFYBT$HNTMcsKfGOlM#U7SAs@^jFZzpwnh+7H4kIAA6$ zyAd5P3tTb!{7R>&7=61Y)U^ zv1Zfc{%Cf|)ES5vXI4qs4fuOEuLkcIl2URiqLsB=Yy2iGakfv{qeYd|!;#u93IB?^ zq7^lfid|C0uG@7|#UZiy(B1qRdc7VR(d*SPoPy}#OZy?wH6^4Vx! z{?zU-J@;notp7XN^DDN3YhF-(H@jkb)t&6>cO9mZ6%U-Itm3K8*V^YZeLpHFn`~3x zT1?f-{ozR6 z!Ef_oDQ@%t8Bi@DB%Cj)Ypi@bk7=f`FueLOaE#S~AvU2Zg~3O&5KH4e1o{X2hT?gA z0W7SsRR$|m<^m%uDxt;QptAIA&vBeI;(osdT$ zU1;Gml(eB|@{)^L&-D)mV#xt!6d?RQUMJudzlleNIt$c&rI8ou1JGx_YPz458_8;v zvKnUsvz_6rO%o{yPANJ{?>Vzy+IMZ=RPB7_<~z-__ z5vk=@$kxs3KaaJmpK5U9IIYSY#j*v7(4+{>i^-HH2r4`w@aRJQ5QNC;yTqX*)xu#$ zVGwp8=fym;3D-wtcuFR6bo7kO8YBXyhcyS}OZgl$-ywuj`fy4oO`*wvyg=!MLbqIE zqF`lx#Hk)NQIJ9+xR~1Wc_`5^+E5r8(C9E-7ga&`CbbzxPjVTxmw*%X5l7F6%v0gm z61Bi0&G2^AIpnk-tqB&}Sgmv^&x0m_GcM?k=17@b)WO#-#sbQg+ow=RWTCQZ8>5Q| zt;|uQw>EUH{{rIgH1?hu>hBHK5^ICsD*EPRX2bJ{K@>O ztf_X`VrGi2O3^L{;sV4{FOm_n^XwmS!#o6&97BDr-58OGIt+FV@JWzvz$_aW*{PC= zs7(d?y4uk5#B1F0rb@ObcqJ*}l7yL5R$fHp$rsmwyi~DuLph9L?@@=zNIIja(URo4 zOZWz+A8`pu9Zv{jmJ$^v4%3SeC1;Q*0^QTNN9bi)MJ2=$Q4-W8%5cArXJgFV z**G(P^Kb+@YFqZf6}8M3=jRY6N4@BivSmXYe?1zcED6y2c+W458YNvTp$DvRb$KXx zfD_2KB)&6VG@KO<_Bi+jbi%z@3x0&rLQ<`RKzbQ^Z`Jk9WJti-^yH|r7^yb2+JoL1 z5Pe3P!^)VT;hp?aO0T6KoST#BGO?G8z@o`2qd$2(<;zJgx~$L}zJl;B}XE`qB41gC&t_7 zv|l&{G!LZNzySEJ`i=Bkw0+(|Nua*hX$I>m<)QQg(2cN8HttyL$TkynAibT^VuL zOYZvl6aS3EQC?taf@a#bwko0?Wf8n;M|TOy6yrN-^^jUDqv zJyK)G*A7n~m@(hZ6uY|Tc6Cp+O+EW^yV%$v zxnn+WXEeJ2L{R zdl_b=_-ITBd63{6(*^r1$_ZaW@_}zJC~3hzaH1C6pYEZ)TG-5jAq}JjoLny2^b3N2 zwDu&U(FBRsQ4+f!%aJ9XP1~8g@kyu$!UkJ@8_Uqp_kEE0Duwn?+`1Fnfs7qu_GbHq zPKpdjBGm@(b}UMgBcE8B;bcQ%H0_fofwBJ~1~IndQ1ICi$Qy$vn8w`+t>rzz(Zl+J z)RP9iC;)v|dUBEvajchD!ut6r^%?Z6!OKdwidZdiohK2@~%NW-(j2oBB zm#1&JlWY-}$tkR&DVb0vQkji>efdKW`3;_4rh>7!rnZr^ez}}+)6oto>LX=5426K@ zG8XE)Ni~x8z;c<3^qHwvre?5Q?zr_J!-(bbmg{TY*N+G!m@b$v^bZD?{gQE$(E%p` z%T->iuY6Z%mu%Yqh}jQ~oMK|MWwHzXhMzyKb9?(k%dMXHkAIl7eV1t{e$N~VE?Z;V zSLzgo#)5+n$-PEDIch!t0sZq2ttGBa8CM+=mK#ajR#XV4O;7e9!@{?n&}0poh*Q|qs35O>hR z2N`M$v>@cF>7Y>nY8;f@eg+?9xnaf4f{Q|+?wauS0=l9r zylE-R_T&YVdu&*4AVJI6PQXWa3_FyoaEsVSE&=h&{L}}|B|CU zZhdKkFgmrh>1MSM`V6d#o{l}C|IAt~36M8_LK9vle44*OwF1M?wZ>$8t4!aRS|_m) zmrRvhB5sYVB_1g^s^y{GmgG)mp3y(3V(VVtCAG*CegRrh0M;j27@rR^wdHJtm@-G} ze?vfoB5eqNONst_k>~ZXwuiTrFsW)+j;>KVvviBZtpQz;B}0~{Gj8D%jj~+ExQe$k z=haNFd%65^6>C&W+$<1*5RX0_5ti*h95mcV`Z_z|DD)u(;(BldJ}#H*YTVFpx+!d{ zhSznhjH0YxABp5Z1+1#C(`$kpbU9fIx}iN~HY!cGr0iM7Rv%-_Ks+>j6r&W;@<@)=_YI>)kDR+=_O z$ilhHNrh--V+~WwpH)V{s8PHpUUw`^|JF z?}@!_hdYF?(Qc6iV zC2J{JP03@FY@?);lAV<7rQ`@D$0+er5~PGw8wHZW3Ku9L;j=*UYvBt0yh_P9CD$l< zk&+2YCMkKDl2YI?@@A}Dvi+HJo`z>UsCedl>9R#U!*Mm zKzHv`0xc3Kt5D*hB!`lGN{T4?fU-QG60P*}0sZ_5CEMud4odb=a*&b(l#mj%aE1~x z=Me@dd7CP@M0cZbeBR&G9}E+o>@MUeIhfT;zn7-u-19iCe<*3 zR0jl-tqUa06-Wvre4n2EfRav1G_AiE=_e&I{2%&laJfGZt-o5EeF3{Xx7~cTYr$@6 z-E9^(>=vyBV$r&=bvK?AmPU(LMz`%=NUgIKK?uBH!(S*{qHqK$4IoH94tY8FqKcPH739vrhekrrpz3Kpv@h?cXMmTJpd%uTg1vda|&N6 zYaz*EJ8X^?G%Q%?=6-7Hdp5eEamgdJ{$f42vlmk6&Q1#_6?cnU-L_rk z#j0Wy*j!;tTi9u?Lem9ME1I_@OVpXcG zWihwhcEZfQ9eSDDgpb!_F2q9EP=H2S*g`BquUpe?9p-3J{ep$vY}_v2bUn>)?x&_N z+UV6!OG|BO@0yTc4W^-${0gk=oo2J`q-Xvlxjw73mTw7>*~8m;}eL>W>HRrqFM?o;QC&Jxkebg5Nz}DH&9z z7)hX(k=)tdOjbq+QEQ5S3e$UJxF6n9M!kwlGg3Q0EqjXb$~Gb#;bM9zep2!X4#*;W zAnH0t-n|1Mt}?;0c)7CtL#xv?3Qi%~@<6{I6+l5mb_G{QIxPXtwSmvNJ`zfVpk@H| zSqS+RB?qVoz>6rtR+F|2T012^@9{Qz+h7*lX}O@7Uao9VUBg{)Ho1*YiN+v#-P;0XOiD5)j_$1?0e3i0;Z4Z zI3^|AQn0dQ{Q^NEG=|~*Rj-+npo`Mz?NNkFJ+0m&=qXM0i5>`?_V@LitW%6*&jQJ8 zsC(P24yRe|UnQ%}mqv51T~KbO7~?b~o>Q^&4te9gw>HgG zmO5-G1B>fE@gRQA-cuFJbs2gwm{TTuBV`}p>6nEO@t2r&3w@Fx{A_rs4n-S?kC7=S zG2JK3iSkPMd{A=YetFdaCQKQtudau;hsE1NY^|VwkZuRTlBB<&0)nT5LXQ_K4iCwJ zaF36EsHQi#K@DK@4TqY+5rDPgupb)%q%-O8^`65QNobdr1LTiA+Na=MhO8P65Bq@umwW3u7@!*3ZRu^7aU@w5pP_m1dJD2ki2f;vSKDC zCJFJ_VFqCJx}|kKL{NdD72qO876VL#4^n@ek&^1nvw*N zx`dsSIdjQ;3GZVFf0PQ+;RZ5XHT~pqv&rUt$Gb9`Suo?gwHd~!<;kM8RBSNt@`GQu6L)6pJOHaK^A`AO0~^ z&nqK^EmC32chVyp4oe#j&%2I@*306Pm%~UMN1~3Zh=Vl6W_lw{yQQYx;(;TgqcQ9_ zDq4>+^a!Lo(-dGnjGv}iQrCg-Qw*Y4Mlei-uB7093!zI#@f3=wWMj}SE4rk>(V&vo z1hfHV6R%;b^27*rQcwr@8(Cpo-bf8dK~-QE(P<^54c6^I+-%S?Lr>|tl1lx2DeWak zFXD$nH78r{aoQCJbDWoE)Ym=>oG#|Vy`%FAg0V{i#KJFsNOS0OI<4PJ_@!9Y>@&1Y6EJ+btl+KK_bkMa%K=d;H_gh8(3X%$IDl`7oOJ@6za({3^Qt;w@QaTq!=`od*N`K9lphnJ_UIIj%Q45BqC2~#(0S06OC!k$46yq^b(TN*AJB68ypCphXM)5 z4~PSeEe-Q&DEpJ|a592tPDUBKoPjI7jW$^{GAx#StFadZ!k8U{3ceID#w!FuHbPFB zVIZK6LmoF!44q{^qxj(R^n#x}p!dNX0AgVTzoh`-HUii93!1QKu{7tdpE|5$8(Dx$=&4HG*z=3f{Gw+}@ddI14>-dfs*B z>dtqzYzJO=%A9<6%l2>9&X&&}p2(bNpDd4LHAq22GUr}{+&)t-)Xj%P)V{(UNFTR`NjFwfYKeD3LEAeBWWUsjI zD4IGUI_gAg-TRA0R4a2e@m68Mw(4XUNu{u$$M5{fZ+6*t7a ziO^z(8xG<|uPn~6FLQ4aQ;UY23Usv~1F zRGpc2q=lJ}#ys8U{pW)Gi@`+?>pj!+hdL^=AAbS;3tJ_ZNOgjJ5D+G3X0 zVjzjySy~tQLM7YsuDF2_;}kPxUL-trkIBra0Tr`0lXC(cHK4iz=u7%#^9?g_bzs(` zreC*QGP7^@x>+z|O~7vEX;i1v52uBK9m&5_H-3!O7<^vMOm{QkiJT%FZO7qSpe={{gvo9?@^ zC!E}#1Qn_meN9}D2_V&c#~cCQoxH~ct(-^-Sm80ohF{6FxKefh!HZ1F3s(4$NekHV zH)Yi7bHp;9gz_E1r$dar;Xi<8%FD}P7e@RjIB2OjLgt~~c76D!iZm=McAe;nFW=*B z8w9_Mabix^H8lYNhVH@zaJ7gZDf`%KIv=Q{LysPD6rhor0JBm)jtR8|$j>YBJMa(O z617&&J7Mf*!Uc5ph(Y*u0Z+uoaTpmN(Zx*x`$Z#&h?m9Qv6}d?%B(&i%%-R{Uh($I8{vmkn@M8fl z0L%>4&%RqP)3b?VKPeodCjD31AqyI`)xoE!YY6U~INk+*DfwFK@9XbnA1~BRjT26| zbozPp3i$ZJcR25dQ@c84;Fw_5N|w{FG{FpckmU*-Yh%KN5JVzO!~m58BDjO_FUp2R z5(Fv(%R`XU%o#CmSec8j_6Q{#7`jB02rE@qEyhEYVT=p~ z9cF&SRLqq+s<0=CsRxuzVKK4^k?}QBJ7L&T*9VQN0f|MaOBJ1N#S=Zg zr^D_Hy|KO_*P{HD=kaw*%u4tgk84MZM);3NbZ1q}-c3#y&tP8imdp!(5x^WQ=Aal3 zF_-5n?NiyW7Q9^W<^5q-m1wVGgLpleeUz~{H8_oZETmy+3M;7j2}(!>^>tYp=@s0A zm%NRhZ>OZ4k`79)QNlXypz9_4ABv7PsFXlI!;V;cS#@D+ZM1dk z)pjv$eb~Bn!J1}U5iMG^V4=U8p-h0kOjeJ-5Aw~nYF;r_*Nd9ei@pjj^CC&TwIh}e z*q}AZ6tp4io;?4l2qmH&t~gSyFQ|fFWsM(C#xa}<*KIcK-SOmvlFmT#3pRSH{Rby+ zbWo?j)f*ku_EC$^6|;B9zG3`@=mH&&inAC3xpBve1`t*1{17|c0o|BG7)|b^)X~6z zwtV(!RWk^v$aKkC4I;)*6yCB1^e~qV27}Y!t_|$3YiUZ2D zYOt8hi&nO9Mmca}YZw9|2Fw1GjsRNYA!IZu5R7Tijb(Po-xeT>I2#bo&?+bJ32+2T zR}N}QCH2=bO$xbq@kq^Fre!*crBVGgGBji_LXhM)&iAW&3*uhK)s8a-qrq6nBZ z{feA^>MK9Pl{SwlTcecl$-YiDFAr`>SdU#I7`EE7xTcDXqlQH?#eC^X3 ztFI_S<6qYKGG@O-K2Hu>tWo0`{ zXIsLhz-q<(oXNNxAXSsclOdnOeufEp%5}?&$?&X@u9==2E$}haoj4DJx=qn<8n^u# zd09wK=mdWLnu>85&fwD7c;jQtV2OSC)p z4wWYFej-rluvY6+>%fUeymswuB44dIgkiU=kYTL)(8vX*3P2QzS{MY7?zkiBM5~8_ zKrpT~JLAUQ{)l5@r=jtfs6TOI;!f=pw~AU9{$+*&=Xng5yomM4y>&CdewBVcPl=xr z752v*P_YtZjeE}Pv}@!C$7or7Z&NW=6|sS0Nx{oYwHX9LV8^O;=Q+8KFs4twKxYSO zo*R=KcXLao&V_Tqht?AxQ4diWNGU-2bZgktgeWWykLW16SF_<}_8*k|PD!|C$Hbng zGz7IGj=FpxLD`||)y9__-^`wOHQjUP-$=inzL1oZv)hbwE64jF)s~qBFLo=oM5`OW z(fzgV`RbPW>>W~d%T&kra&E5v(!pCflLy7>mbvU5x2t~8_;#a|{Up4ftjL1H)6{viGBbZN_xaQ#s^KU_k% zix9r+K^}S5Ykzg$%lqD3JD<7opE&#&y9FMCp2**QHDK5+E* z>i>`=9ymIkB(Ch7!((0d(LF-4sJZtSt4%pO&F{l^o%a}sXng4JZgO{SN&CZ6_YR9Q zj?JkeN1qT4C!}NTB$9267>Yv>Ij!~^SUiH83hba|$$0q5Y;}I1vsP&%lRvh2?Ua?# zWU>JXE#$FOW}Eh5xe94RbMqI<3f9C!iwT+3Ru+}=2PCjg&Xg+-Q(BGyL>@QTG-?QQOBGk)AnUZ2o%Au~~l1=0M~{BP@N_Lr$oo?#9u~I z;_rhlXi>{FC3QD$mC#v_XXeHCu+#M@w1Rn19HZ03^G_1~3Va#lO}x~c7Tx)6;3`n~ zI$ZgrCYILR1_7UWDb9;3k6x6itJMfsgBMlcBs`q?inzQ>v63Q0eo+;ywVn)TD)*W% zRs~anJY#QMttxh;ViH-H7mred_E)P5bqvPUu>>1|Uet4_#Q+10tL3`YG+3^y$zp)J zBEpklJ*uZy;=I8L(qFM?PnNNk9kN?tI^gxPYgKqGYYE2_@%*TH4#UNP_UG8G+~?3$ zJmAOJ=je`|WuK+Hzo0C8=OY-p!lmfSKFiMnG>B?JKjliMYHm5_^$iDyn=i;=S-e{Wq96E z6)mlP_591{e|6}3+N5RjNYs-%RX^vcdb4o0<2!5TeUHO?cMgI~=T6mpY0GQJXKmjK z%~vBpQvQvd*LS}1w7`-z_qg zH9aUcW#mt#yp}zmj-ZN}FYUdycPek*S^i$N$>Cn8gWI>Odl;OIr2v2(2Hw?+F{u{@ zN|$+YEz)?l54`awfdvD9TiSntlz;`#$S=PYf0IXTzSLO8A-Dz9IOYDGSjFY#k1R(a zmgb3`_&Oe0mO>s0A0|to${$spLUk!(62fca)+FPm=%pr%eM8mD2v59*N>5J@kE5by zqpU2r0AgN1*V)^Tz^zbU<-eBZ0)|X|kaIEL3Y^zZ_0YxZlGR(4e5&&7(h3zsOfTn9 zip5WUd^_A)Vjrn9)T!0`;zvvU@k3vq%mhwga1G3}&`IwW_SfsJ^wzENmB;moikylo z65ojvoc`PL?K(PtYTk#MT^a%WYYiD z3XpDo?UiL~Ke>E8wX)R>2MZIf_pE9LK%XGH(6v`M+8wPet!`n`ruorQsM{ItZkk+{wPP2!jBswSoZCx3ay!KIJN=xVN< z#-gNx$2%|rwzaAm##!M+C-?Yu<`XovtK+L=6gp^VI=Gn(kw17yg{KlKT*E6Q=T1-w zQ>{ySdV6I3U(`OtJ>GI)Mon?qBo`f0ui`>kfFs56$qIH@4I|~(IK1tTtI8~WEHH&4 zWit!#s7UG*Op~8*0=+s#EVH|tK{yho!M)vi$cPdk3K-J~Ic#8(F<0df7I})N4u5UU z*Vj#*kUT!o>08R#1Tw;V4HYKBf|2s;d9K4EJW1$^%qnNr_asS*=V3F_dPO{>d#Fs$ zPF*BS@Tv(!uBQxyGw&JoM!8fft{zYH__nkufrN~%_>dZ@H+f>O~-|LqEP-(I%uQ_sdtSC7MDw{4GQk>K zZRVoOzUCfV3poAbQfo8Lf;_^EZ#&%>Ew!xePS4Val+JC2t-{%uZj6%QE**FG^Kr4N zeyNh;%P#3OcL$lns?|@iwZ6@7_nMfgb&8U1(^|Fz*GQqIF!LW23@Zlf%TChs; zqk!}Ra3^qSU!h4HwVzhXlnF!TQgkF`dUS+lNSuvYNR0;dNw8r)xK9u6dr+YrIF$+xYMwz_GkUzqfj^fkg}(vL(8#g3Kkcqc4j7db zG5wxh57mo1&S=Fw8Le3Rt)R`YoIl^bC|dlLB=FPnW2tCmWjdR=Si!z8f@^!nEg7}O zX&0a5wp6F)@4ezXETqs@OHp2}yd|YMs)1GDu7lzuThyNTme(<4>sPQwZ71W(@rl;6 zt5qIWsea@UxY?$GH7OJ!ON=L8@Q;|^vSbaMtE7QQrcM*s)+F0eawP%fU`zzLb0n`# zV8QAYg|a4Mv@3V9i7g<@^)bwzbZb0sh@raa(ao>*I<*%lxQP|?RT3W^%M4qP z>vPJWzM^`eUh_H<0HILcYw}4Zb!atkyhDOKj|ey1PTWk~-JYuL)SR6+>WHLiW9S3j z)1Yna{NB@<_SdmnoWvvlwnbkAaI5yfynTmmC(zYL_O2&BI+8ProxLgFVa;)v)K(p) zFEQRwjC#5KCZZUOhKsXNh-EnCWPUnagfV*8RQLtJ%5!L@>K8mD43(aR`Pvs%e)8g@ z63pfXYEV(X`im|~9Dfd&>p$O7Il?EV3IruuLR@8IDn{L8iz*JWS=9`x;TA~ozEwLq zE_9HINfQi)WmRVI|KCpe{hem?w--~WwJ=&-U;u!y0Aa=Q?+A&?@&GZv(JP`%SYfMn z5bnpJ09@$ZF&LUR?;#x{zW!8f47g|Lp%Q+6fV{{JQ%#e@PP&S+aHE7?qsd_vv?0Uz z4d%a;SP4C_fbLVk@tJ1*i;Qb@bZm+o%g1Qr8U01ZLyn#bYJ73kLbt3&(0s@}Dq*6a z%v(r<3?1Gx8B&;*J#ltLqA;Xpd}YZU=gwbHv>+x84iEq7;TTGxHNRQBi0znNYFV4$~5Jid5<1CO#gvu+>pyg$yLKsVuA6hZf9= z>3K&7=s}(C=HvJ zvLS+kOj+#$bM77SZJG-0tk}ysM-b?;EXUcr3h+h5NB^^53^0+7?8YF1oTJk`s9CYN zrDa7F$Won?G63Kx)4G6hsL9{N2^SU_yQ-wck ztzWPXWUbv<>+!6$ktQyYrn~O>ru}-;{s$-KdxrI%VXbLc51-LQ$go(YmBz4O?QDFm zZ+7}-N76^TM3m+bfru8_t5@$!62^|5QUan^_Dk)Z^ZL#Unh0v4j+D5-?6szt9v)+M zmD0NGuau6v?qxxToL^K0KkH9AO{O$hMm4c6EqZe<;SS73=LS=*=A@mBJIZ6W^4Ov` zID2evL|gZg?rlrDf2jKl?YH_!5YKPL5B$T7)}nlMD2FN%|VZFN6f3q=b>%gl8;lz%mV7u4I7Ka#TZOGB23^yj*`HdC(pq@9{) zI@B=t;k}BvYkH_{=5=~#+xq12d}W=Ee~-3d$NYwub^2HKtXR4U)<+N_{W9#7Xoc-SW|M&mi|FNJT&xGsvA07++A5WT1|Aqcgu3Y|L zewehFOs|=an*@{3B$$P)usM?DvzY1G61MuR?APYAvEOW8Hv7%-<>1#EwnuV(xsg0y z9!qZv=ST8=`4NZD!T!z;7eoquh3q*e?2Nd4u1JxuC{pYzj+FRHB5t2MQtB&>tn#gj zl=;dc<-YPrg|8w~>8q6Mukux~`l@}^__c?tA~n96$ZFqe_B}UT9a-aB6Y=;wky>9Z z-sK7T;krn@uRhY?YhZsn!i|w8UsI&n*Bn{vTO0BEypeUjb&(cdOQhA;8fo*jMcRGs zkq%!+WW8@a%To~E5b5-Fvgg9^#z>d1E3(PAiT&*iZ;ov7ZHa94ZDoJE!rLO-ecK~D zd^_0RMd6*1UA|qB-M-!I@8a;D$X?&xNVl&$vd_0K(&Oui^!j?)w~}yQWWR5}*%Wk% zUFe@X{6yqQA7%>ArQrjSgT908c@_Hol<%p?A>X0MVc%hvw=CQrdD{0hdoB+ji5&GE zjU4kGV}DnK2O@*M*&3-V)5tgb#Gv0)8!k@G6l2dxOx`g(Zv)|wanS2pml3Gs3jqJxMCD$Zu64vX>k=wyqh3Cg_&t_r6%h|pNdf6Ea zzhRbpI5uhVZkeh)G=3p8>=_vsJ;P!!5DSf6@I=OiU^v?T_mt3UPUQ#2#>Qj#G(HyX z_hzMXp9qcx#XxLaOywL7T)vDfcxxRVzdV_;3&G%JdO|+uaA5diQ1D+C$1exP*rYc< zRWNw^NT0vw$-bVa4)i~fvUHCjOHUvi4xA4M@e~e3qbCAl%Gw(mj-_%~MWNwT&Y@5Y zHHK3;gOitol)!d;49!8MfoLpcAAc?=hQ|W}no)FQQV5L2Lc_<$gy2YMEGVR$Cj#M+ zz}nv@isPc!lClm2!y~C&Dy=&l3Pe-c$Hy)QhA;g+4Gv1FP)g|yUKWGHfml!&2#pN~ zJJ+WwSNgPJ13H-FA08hY30+9#`-R}}I2)xX-j0MY|Iw7gkAc1t5Cy*&ME(8?G?Jm= zXsW;;86Upne=ZRAM}uOj1b<=f)^9|>JRQ&0%{=3qVUxi}sg4n|YC?5`t%*hPGDKM{=e zjElhm%v&VzWME7PqcQaMV03)U@D{1_dRSN4RORK8!(1Ikmr8{iz~8cB5#r zKgxQ7p(sBRp15#b6Atzm|9elyDtz8viB(mgW(`wJz^OabE`c^%l?s;3}B1gvWUEl|>015Fy5Kp7F zqxcu4)$oETnd3_2)JQosiJV#~r*?krQcg>5n;YWEDiM%!`uPtdWO4utUd*%G-orXJQ?`@K5j>fBxJ+x%y zXFo7y*|Hy^Hj}syH^UmG)yLN8DLi0}W@TQb(`MTH@lD>x@rQbis%ukyWzyE3*)(ao zW$p(AVp;@jKYo9zZ25dfgY>}?5Cp6b8=ExoILb>|Fkew>B_>FuMy9G|B+gb7&^kxO z7dciHhmqtN{EIf=hT*MR{X*ZD`d{py?UJnJNo#JxS}R#=6V^t_+Bh$~Z*38MNN5-n z>JJ+enxWTBF?naF{sWRs3M9Qy7E?zf;}{@yNKI|#W19hX`Pfckf9y}Wbt7|`VH8>->>!>8x_8YL%10SsT|}1LuP7HWq>XsEe%q13vMr%?&lQFOvG2U z-V_#dHpX*ye4J;>b@HV&w<%t?^-kTAeOI!1-3xsQ>uSlmdM<51I!1O9W7vq5t-s;XvfP5ZEn-QQkQI zMXPap!L-nq=sF^G9Z7TvQkM`9j>f~6_Bb>Zftl zW*TA8k$%3Oloj%*)`--a0@j+_Pv7ag+x1?_QtM&X2(K-b&yg$xNbwRKxurJuc&$W8`$H#)_&ZWxz0|!96^!W$+ z2D=9bkNKbM?(aR+cWi)GvU)lBllkF4T&2YCJRM5j|Or=QZ+s51wn~ z=Q=#s^JlcMV6<9onED{(-EL3_51&(LM2@DohG`haw8NZGES6JOaQQg#?pmJ92B6~ZfE>8!p=p)*+N zuTqK)R*w<_NV|foh2Ic1zO1e&b$-{ZnEp3~t_RQWt&=0gW!hXW$TSB;j6+nFrtmZcD&*L<>3qeual+PaiieznB(+R!qu=PM<3e0|AuvWX~OHm6FNaa8`3L1q~9k$O`stBE8&1Hf4d?7!5g;a zH7aj}ZwOE6a&~-%oHv9+x}58g^P9q9UGFypS1Yy9ukhPKzwT=%(tk^MTK8rn-pmU} zbZ@$p{KB_|qZr3c!tV&j@Vgl+@Lvl9FWY=u0IREn@64D+%);Qy4&PSccZK6fu}%0l z!U_Ct7rrB$#P1H__k>gU-6`A@PUCl%a7*yvcQ^7|h2Iy>;CWB5ShNan2xsxUSGX;l z!*93n2f{P>-6#B^;Ky%Iuy^#!Y2b%HM_*a~&bNPsw7;1l?Gr1coz0N;$raLmB}3W+ zE2RBehO`IK*CF)rsbDQ|)uGXUwLFaw5Zt%VEA#}g&agIHDjf7bBEMkBKPvHKWE5Kd(#zdZ&Lesa>Y4#-jJW;-8^A3(-;ch7pAn{`A$8eRi87Iiv46H zOItO<9|_YL+IadAsm1gTMvEMfPIkFn3JP3^kk6xN<((7ZA# z_An$NB>zJH$0uSer<~BEB~+?hRwnV%OjfJ3FgiJgwnZV96+At;-Z(rTq+P#>TOCcsW>EMFHMk52S3JQ0mS z!pM8CHJ4_M4WZ{^AnFNtcryJsjZBO&^+Lv0X*vwU#98y%p~i@Mh7Qx(ZugVsgNshE@`gN+k!hdA@$p#Ncao-h)P;RwL&nC-$`yY^UT=mj zkitt&AOpq@%p~g;)-|opi6|BnB@1|>p-3nk5IvVC#LMG=ve>w~T&PQae?Yu|cDLeb zTnt?Zjq&Hp0SIWZeh8X8A;1XJ(zIbdCc;6b_Gr83aA49CB&qELG+~pT^Fd{N1kd?N z8sTU#V+T<_GU>EJSf@wWI}Wy_DKe~_R$Zqiuv~y>hEbQgngQl)v1DGN=z2_DV1qJl zP|Bx|ZM6D4=<&sIK62{nYbCglu|>wNusLRR>w!(pPjD6hNFT#eU@Hb7t;nz2wY=@> z_j4I*fxbyr;3zOQq?FP|&^F{5O4sxZ@ga+idxVL|Wy~Vi6-1SOvo>d}OkL5RQr8J( zoNBH=s=>+s(W}2o;j*N>zR=Z;O)TF&ovBt_;i2xMgW{jm$JqT*#L`PCA^% z5_m8PP-e1~duE8e($|gTQ1iC;s4CEQmgJmTAt45=T8RCDE<8ic0PXQB%|jWN3Lj;X zZz^j=-FEpWPw@H6;m~j>2J}EB3KJsReb{P@g&4t*v1DZjMsKms&>vb48FpJLRKJU> zE032tbL{adP+*Z@v5hhT#V&fP6 zCOg%jR;bhUxA!V)e^T8>&lz+`+D3^^wP@MpjVRi#Y-vng8yZ$9rE{qoUHg{rYyDGe z)WWm@Cc(64noFh)1uWk;bd4cFHgd@p7iXF|QdV()vph`--J*U-QKPQqZY-+WdRT~Wrg`E?RQljk{5o?&MAL-YvW_6X5{CK5t0i2){>DkGMI$eCamTR&}# zJjE@vd>C(2x$;H^D+`#5;17^Tz;dE^4XsP%Y10kOAt{}BtG}o;eV7!Qic*twT=`_A zFolQLpeMPyf(kgZiNUn#wyNp6YJoD(GGP|WHFJeb#tJa9vfj2S@+>HbvnR8?Ie`u| zsfTQ(K;(PIf>&e$8>AWlD@u5oHd(pr98F_a`TGPE90U77U2Tp_pq6&+s3g# zC<-inW=LM{*u|NNjBf9NRgf5LPy2pO<~%S}YGvyDsin(}!X#o(0&N>X57;~22VFac zqOgz}q8&`P^#IsIjIIc`jgMg~LLqEh^T??gi@|m*Mr~+2(jXRd0hI{)krPmXbr{8N zg&&dIMf?*n2QbB9%mr)Q1ZY@LEF#F3z?fW9d)_fE(b#0{A`SDhRD5X%(9Fx8FbM3h zJX8AG#+qZE=)~pA<038XD;I-f`k8w!6wvWX?Rf)15dWZjhd5SL3mWnW>Z~4*Clw72Fc7T?jtc5yoDzb8Q8M z4=g4}6VuiXGT=wK?0SUGSZ})k5ldEJGh0{@ZkU)({$j;)>X%4gV6o71LBN{2H|U_O zol{=z>Nh}`Lj3FCgycB#aH~*8q+jNI z4y-lHa5x$z^efx5$d*rhT&7lOYk?Ie?_1f(5OpKd3#N~YO|G)pXuNvELg%7$bKJg} z8v{_0%Jo?$7RJoL7`lm7woC&rk$Hxf@dz1adRdzPAI$i#VIstD(Cr3p`q?h!v#N}- zJiSwE(x*KwK~aYJ-+pJ`qH|B&zGwOT(^|05u3m|Ul`K~P*5;{i!wMC95m1*bM$EMd;+43@+1nV||HCfHy=0FgCss&ydXHu_SCOBxoc~32SVqj_rJPI)=_` z7KwBL0DV1eEM>bBR?t*w`UtYu)iiD{i`o-+YgDcfM+42qV1W`4#yqo zl_OWH0eR9yh1!GdJmHlfHbNTu5nx1;$&v66!lb}NIHtp17=A|d{!ZH9yY%RZchS=Xpx*Pal34NN4v0ck%b&1NLzu#*wUqmNxP;^Z^&=2T0*9)))*E$ zzZ9jyRU51oiMUO>M#(BS?Najenr6-CCQT;jPE1#`ujWkWjFSCQ+V$eD%IZ z(^;cvefpI-hth{>>vT35!A#pm$;K+}n$A|z!GmNO_w% zMNBnJQpj&{RpykVwArLxV~)&eFPN{|r|rF_b6>!?0Mroz?tE^#>Y8H^DR{N$r30c$D+ZJUelv zCc~E;SP9E;i=FyydL=NodYQ|i%v#lW;>v`zb4dD3j^(TWb`E!vl>jEA@n zIoB&+wBHvuW2HV4Yn-c>afah+!L$RVbZWVkr{_Qgyiz({khzX&W>ok}Bj&*}@OWd9 ziympChg{ygz(Jr)&O(!1pLl46wx%tLaae~*tS}_29Iu387ZtvYBoNTg=r$u`Nqo-& zE@!(AG=c&%=9ZO8I-!Y%^-1N#b`|*AfRq+Uk%yhDO=XMZ8fjmmtCw#+)FKk8lB!SU zCxW2Dp;g6pC9|U%WkNJQ{Gf>I4hp)~69<9aEttp4=69LF1O5 zWweW{yr_{_QMxb7bm1)U99TVpZ|EAuPn8W4B@p6*Zmn7pZgbjb*DjADyl$lm$B5^b zDY47oA5f}p9AFra7n}%BBOjWf?o(&O&|9YN)6ER4m`w_En`-wQ05!(9aeX&E)HJAr z!6-KmdDhZk$Yg={F{c;5y_){ zGY%)#!1<7XHVfleK1AAJMnTO03Jk4*yo0%a5H-ptLpRcV?D=v-*C)|1w1|XtY((@+ ztQ+b{P0dgJRiunqC#0jnk4hWLiXuiJGSZ8yG}*#SBNH>KA!xFc^|qX>V`L?9yRr~b z(@4_vosmaO15G`jwldjvPGhi*^GSVu8YPQYAXa0G!oVzYpeG>W0}CV}%jDG2BsH+H zOr8|x5syL^IyOTG>npG%KPLjD&e7FB2=S_$79A;Kzhjz6aLuPGD_Ky zcKk{vnX9)F-im%Sh`d~|ESO9H-cRrYfWIMBm2j4{TpqtH`mtf8TpE!0`M10fgdSYP zCz645DrZ>sG_(LdL@&K^M}q-z_##KlfCc|$xF3o{$EET^QMigcJAu_9r1IfcrSypD zn#8A(M!Zb77w85u4&pBkfT|)Ql><`;lDBY|lPgH$Efl{=N%M8fK9$YqF=dXV3gq=B zzsb{z*shQr{#-!8z>gTR~F79l)x#_z*Ztb|!B(>~KHnslV=(k4~O5dt_vud$v*KEO@ zAi3(3uFBU6uNTh6mRt=Vy4-UIC0EnUj&jE_bck>`)+T0zhYC; z)0psVmpt3=Y+m&2o3kaWJWFf0-K*M`?A$VU_-2Dt-I1(r`d0tz{WrUos@H!|UHhOE zl|Cp3<2JW_(baozUW!}AT2yE*Az{aXL^{`sySyVoWw zRwpXfNfqmUT+y0b*O6GaLt3{Ze)M>JBpP40V{u)K@+`WWAM7wy?|87&!_zP)VDJhy%R>XLmEdyZFi zEnHf%?@Kz16V7$_oa^p8s^+@mYc?*NSaR(AFuyR7-*_*-G3h8sIBFzE&7830sQ<{h zYWCT9<@zP(hJ`?4^C4;Tq4?%g$?Cdq9eVxHZ}(sCo$a1|Hd$6a*PW>DlB&Dzm31Y% zHqDt6 z4G>E9#ATq2Af(3R(yj2eSdJ#*RzcC3AHIvX;C!=07pP(-1wJa5LhFw?@m;0?m2dQ` ze1}5DEdB}7JSHEk(a1s;qv%ghn@3eIQLP50d~keyGUaOpzimZLd0Hyv2^^4X+6KBe zlRv4I_}*6<@HGQJ`$A3#^sry0y;&(4(oOSHp0Jw6sxsFzs`AB3tHAlG{;}XbETbxC ztfk1DYm_`s(=KI1-jHXDN(4o23H&W4mMGE3v`Hkarfk;a?mx7Gb)u}>U=aayN-n0n zA<~~dC?r3_T%J3_tyG|;;KaXCfMh%0AP@^~XD^9Fpz$G!RNm`?f}sO6@8^TqvtbOX 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/networks.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/networks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2653c3e5a1e25a80e03e922aa9e16531f6e33a71 GIT binary patch literal 50219 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/parse.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/parse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42f269ea1493f8fa351527523a6729f9bdd143ee GIT binary patch literal 352 zcmYLEJx{|h5VeycLZenrjUs0|gU@C@!S!km zjyq?WlDXwh8hxBB)ys?tlQC9z|9RW!sw2iUSKv!AW9=+^K=Ve<_waC!7S{MpN=cp5 zYhyB_6xa-y)Kk#T*oroqKnv>gDLs;7T1p3-g=cvVB`qq!wUgP_?>mE{s-ykIO9wXg fR~qHzns;9z#`qQOexT&7zkVOR^po4zuK3Ci^*3pZ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/root_model.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/root_model.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfa5d6bdacbe0f21ad2ef7ed203b949d764859da GIT binary patch literal 7813 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 R^@4^+&OqfnKZt1Z{{oN7VvGO) literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/typing.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/typing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7e6460566729ca1ea758edf5cacc3e9dcbed9e7 GIT binary patch literal 350 zcmYL^ze~h06vvbH#Cqip9Gvao(&0|TO~l1j90YGDfn2VMC3yKk8c*ux>ObJ>DuVxr zqm$i49NdK4oP41kz9D(<`+j}i%V5w)VCT-eSG*gCO%|#~bjAb)cURvY)O1yAJWs|+}S7^?0yIBd( zymwT|$}umEKF!zKbxOG@DQ)}zx(iTkLaAm-Kq{ql)k`1IGO+wijt_`+1|}&5DCF9h z(kLZdDX7#7p}lbp2~0wB0`Y>J$Qh}n7b6QQt3*v~!#Aj4^&g`=2O(A8tP+ufzN{bsLcR1$N|VLjV8( literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/utils.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..623b9826fe1a12173b65c4ec18dc10b0d8639d05 GIT binary patch literal 352 zcmYLEJx{|h5VeycLZen_iD%2E|)utg{6DUqxJ|#zDOlo0avvMpepe9wrnX)3^`h90mHEpy%f9b%) g?uu7luQ~S>VvJwW?gvWW`s?@6OFzAd&5Eo101&`wxBvhE literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/validate_call_decorator.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/validate_call_decorator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5431d88566b3f06795e6f193ff8db7f32bc8e76c GIT binary patch literal 5448 zcmbVQO>7&-6`tMY&ywPwB%9I#aHwi;g)}cZ!elwC_?qDR0!9s*Bd8d{JM@AN8jK(LgE~4Z^%z z=G9QDK3bn@h&H4eqm6XTqwY&JMVp}SjW#P@+yr!WYD=m$+R7jnDSp|f_+-CQH^;UC zz|R8@Sqo>hO%6uec*Tb@Y(GH+#mG|9rR7X5W zZhM-K@XPIT(@l4@BgcjJ=le#LgoY(U!@?Z=UzOCPEE&o4yfBwdCyb<)77~)G>XC2B zT4BbllhSF;01_>&Pr|o5BVi*csnBg4&L&mh9WQgvRS&m;Lb2;SgfBZ$f()8I`$ZWR&+3p+$#HUVYm;jeq4q zhT9%rB=Yt=Mx8xSBhhD%Ro~0Vmie%Zg4vB{pG|Ai;UQSNg4n3cFE-nh)pvEa!tFkd z>w=})ZO)49CIdX!dSuTs`Ym|SN1V}MkA2SBl(23^ z1CZ2VQy2#-J;CnHRk-kg(PNK--O3UcU$Doj@9S(0lDcIUkoaip|H%0qJk{MiRFz}* zs;l8z9RpOy;B$2h|0Mp*v{tHr9%T zVr>oHcuv@ZbTZ#&A&ryRJCICQb&cg4o)(dJ&45*6Z{&wSol5A}7qqM@3vtjYlTnjk z8EMW?FwpI`i_k}`3EZBT0GYwiGU0sVxiksn@L?GQBDIjeF}N3~@bntMVJ8{AUm%($ zR7uwr-CkzT;?|19sxeVarjv#!0t`SYifLtud?eGlp-6H#f9L;OpYTiR1Rwyh8k`?Y zvmen=7be*!9JTW!d8mJO@Te`_8rh`!Gkdcuf2v6om24_LoJeE=^FzM`)rX{pg zO2G*Q4$)O54Yf~hHZCQuC~0{XzOT-nNycaOq@fICU{sn{^w~_gqByeaNQxB?iez&5 zAS_6mR_N#^WR(^4FL(WFU$LWqqvP~?$LXT`trF|>1h#yQ8@|qUU*~npKtf7{mn-cRN~RX zPA=#zA%I5iTfJ6v3zVnpLEnS+5<>lpEVTYB>~01g@u5||=x*ChoTbE9 z_YiwgUB{-k^WMU}D9GwNMTk77*)4xBK&W#81gGnVowpbiYX2VK1hyJ_HXFJh{QSX- zh5j>z&@YQK>JG;?21`9AMDq!<)@O{OR$Jk3Tq4I67UJncbL? z)@P)`bQ~5+FcW0Grc>-z+fi7rrJ>|Pt!*VYSKszyi315wbW%Uu9~kRKe`y~acc8y^ z9~@`6FC3on*SRnJ1LK3-7lTgdkAKFRt^_SK&0yv1Ugwteq__@ce!>vC&*|Wc!l;(Wroe0I z6{On>E>53I<-kR5ER{RW<-SPd2$(;iWDMQ*U7)CO+>{*lQXx}xQ%HSK_G-w2OBnJY zBmoJN>wp!T?Q4;-AQ_d6r_(tJ&r@h1Bn^>T%aB_V1gTsSX&*C6!#2UlsBLXlK`wB zsz9|C+jR{i*ZW4|Jb#4FZ@AjySUp%!%EGa=o@ZUjs@E{1at&LgKPlK;)*B?2kN6$- zj^hsZkT?W9Q07+UKl6gN%q&)lYm0}pwzO$P{WHv4i6jV9W@GtK(`5L_fkTCRR3^%lgbg;#aC#fhkDnqdHR!@gVv91vHkf zv6%42o>)6YCP^TCvVwN{QETr;%dz#AV~<*n7aaTk>u@^bOeuhPU%}n-Ww7O*ZqBx$^k5qn(5S9fpL!p_DxTdL;K7VMWTwF4Kv~@?9i61;)2%Ae1$`*oF!6FsG9D)W zi9Mtt{)x#iB&G+7Ik>VwxV3zPoB>Ro$fb~1KtdHJzbIG+>Lfi{!O;v$ zk|f=`@~Iz6X>wLoPT$iLAm-=M%(sPik-`%g5nfhPWg#@Ep} zd_MMethm4CLSH$$ziw>5cjEW0YdvfFTHpH7kz(WM${EPr9WNJ9>$Yovag}25yP)@R z&*48eeaErP(aoSxqVK^I^!?cR()Ugn-{yd<#6qv+g`SCy(~(Vdyu_of-V)c%w9?*Y jN7r|C@ByWiJ?KAB@{nmSYHlx)xsngLj_vrNM-~1bOJRbN literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/__pycache__/validators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/__pycache__/validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15ce17f171a610dc0f8d97265b090b26b4b9e928 GIT binary patch literal 362 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 WTG@9DtD2~uk5syjd=6FLPX7mO+WJ-i literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__init__.py b/backend/venv/Lib/site-packages/pydantic/_internal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5a2089f24633fe9337ae2a082b741bb6d8ccf26 GIT binary patch literal 195 zcmX@j%ge<81flDKGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!N^-V}DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`l_`mNC7H?kKrJPyMR|!i`td+!W=VX!UP0w84x8Nkl+v73yCPPgm5e}K3}Sp_ LW@Kb6Vg|ARQm8h^ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_config.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e4803dec1edc3dd78bfbffd905631938f26828c GIT binary patch literal 15674 zcmbVzYj7J^mfmfk0fGQXJP3df@X;j22Pgs}CF(_64~nGTqGeGJ8R_txC?hjc$OH;H^sAI{5nDbDw?hx#ygF`0KhlD}m?CzdaQ{wVRN?#~1CfsepO% zwtDf7nm4Jz-3?hFg2egsWCQ6%m0x2yt*H39HO>d*L zozf0UIZ8Vz?c%$k)F#T`LuoIieSANp2Waj9P1#KO2l*hRhxjc(hbSH9w*ubAj{x0H z=?;D;;9Zn|H>IQebCB{p#d~ONdnw*W@qS9jXvzVK$0?rRC!y3qiVsnGnD*xgrAKMX zF-ngk{Yxg?%fHBD{-~7n5u<|e=6S+T{elS(@<(B& zn_!;%U}l^7PJRH!^}_qsaF9R6pM;h|%Z9-8AFx<}QEbsvDlJFlcseCb!Fzoyosxws zax$8VUKB(~sW};yWkE~@OiJD9mrqVc#t%=9A3HL2NHLD3mKDo*G?9qTCIqGCcpUhm z35AVCB^m3Er9~kk#pZ=%6kgeBAu;y{Trt?rSRx*k4hbnJA*V&C+&Z34&BZTH#AC8z zo4g{6(X-LSk{~ITqf$DhCL@|m#nQYWDvkIuO)IC|T0fw2*U4o*nv&zOGm;=qiXzl+ zP@1*G31LwbVo_P(r{k%Zuysgjsg^Z7gk3H5QcxR%s$Apg&gv{I|X z%%SO}#l^HJb8~5tizT9x6r7Dp0?*CB+`u7?aNyt5@rybJKVI3XO(NT(y@yFk1_-POp z=CE0)sU=VU$Dih>-efh=5Vi=l63d_AUw}<-<5jh=6q%XtX*4|(v!J7y3 z;9q<(0^NWH7NapiF~(D}Qjb~5cq)<*QWxd~K`qjMX6)n$QAyhOT6Nox7s+i}* zbVf)i&c*cNQUXLnWOg}{iY5ic0h==-q?VGAOR6+#fZsTeEU>ZT7gI?Ay3rUFXX8+j zxEzs}7X>K-G7$#CD-NhQ87WVVVo#)FSUFS@l`?~x(0b(+7|4Y|4k`3)y>Qez>!5`q z7d4@oX)PDWX3OR2{CblhCle7m%N2!2%Y~q|K~5K3(9BbEZDW;lDDa-D(kU-3CWKe8 z4})AN6uO|)!OVd02UeU8rH;-=B%YdsSxsdEnnZ^tt4MKe%&rBH@})B*LO)if7uOVR z?3MKFf)JCTlUPgXV8HpK3gIZ64pQF*#Ul#(N7vIce!ZT!l-{*tXc)`SCDKtDin!t6iO}}tcv67RAV)L7 zXBChH*eE>hL^7U8#I^SeimP0Okc9Ijn#gR{YtY!B$#uox9VQvZ0_CC45!jrxXk;lB zmouDReo3C&h5f~YX~zhndEp8as@EHxU51UO)MF)d9P~ZYr`M2LN+hrxbRTC*rbECf zPF=(~bLth9KDy%6=a3iXqDu)`ap){pceRsCAFipG3cuDEQ)CvJ~*r^ z+?-SnNQ!4Z&I_=%;6w%*5%9d16dSYx-(Yqrp5QZ0bji@=URpBRB5^DxmM%gmNswji zdd80{_LcQVzP_ZKsxnjFP0D6EIi+M6a~$?)hN@GM(lDinD7?NDhs}@~)Mu|Wa?rYP z4%d}~1YEusl;+B+aW6;Guu4T3tm2KO1u-T>KrYP+qJ)AI2AAp5>lc?KIVcJj;iE$R zi_7wSItB0WVeB*&L>i1*P<-W%s1p~7MM2^zO(^zsu@&LdvC^l_^q{zg+0&bXt&MHG zCX}`k^c|Y1i$y^-qf#4Yl`ckAYHG5tVm)ZG7B>x@KPrByuu~eB#6$%2HORUIf;hP- zFGm)m^8D%BjADWoVz0$YHV8pYn1z3!Dltz^1Gqs}45CXeX~=}EFq*c!LLz$VGLcQd zOdr{-A>b|5yPo$pGZkQ!dg#$&6qH-_l%r>xh;|@7>HJl6$X>s}dY&7^ zR&uGBH)>p~mMR?jVpy$RF+Q^nokMi2)LyNVZCX1#%bPwnYYXHJX2pUWVkJinZ&}At zdxeo~43X=!I#w)t53N;Z!K!gUIaHzOv%)U8G+h4OI5#l=9Wej46`SnVxGoWxaXXav zYANO46`R)9ifP4$`sUl6EHRK3vSQM5rb(bS8irkQ0A(r{isAD5ov z7R7j4jLXY`QN6MtmtLgiD~GxkH}l%%sCZGDsg^H8+cWy<@x5%=8`XdVmA8KeU!|Eq zc^G5RPPrdAGRiW_jdAoK!wy&05z_mFym}u-Ih+su6-!|!sUE`33ON3lD4@N%z5+3N zIZ|Q0tJUf)GE%X2G!Ic$YD5s_#mw)%3oAiuX;FBH$xk|ns zB0lcD^Vh7u^)z3bc;IcldHUAgJ0p4Tu4@MshqvHtx$o@EIXiFlez^IA&A$kK;T$T~ z5N}J-O8SOAOn#8Ob2#6-Cu`|0^n^aV@WF*Ud-FX9vX-ugwwC+0_MEN#<`3@KLfLI6 zvfIu)aCaA+V!^xPYm>2|zDSI9^^dH?-j~}v30c`qFK1_x_uQ$hJ@t?q{hW*c$5i&j ze12~{YiWCEao@Kz=Pb?HmM!-zLtnYP*XM4$_U>!%CI7o?)3vdJ!}*hApF27VTrM{&n*{)8DcH)_uTk;02|JdGbF& z(E*M0nV)af07?pQZG3oL1^HoXSxa5ewbU{{Z?kYUp6+D}&@NBB!>8ZlgQ^C_)g{QZIr?v`@E=OSR)KuZor3mo!RpIHYXsf>p zPk)(bu62UE!@gsR8RKvmUjV!QJRC@?EEu+?9~xKK71Mi$x9u#68COlK>@VRKZyNZR z()(o+7>L^7laU{|yxTK`zqN!z0n41IdU`RwG8x(f9Yyf{r0(`p(u^*De<3LV}$ABKp zOpVE0LV$}(4jfi!8qJhkVP)qNj7?mhjLOLjmjve;+8#J-FpsCjB_WjIwBo_pc)z~n_>YY zIt8CZQdmTy5BaE7f=&>;tJM}jz)Tf4IxuQWs8hX&Y|JGIRTb3$C~0%_PFP(Z8@0KL ztiOh0QXA+kpw0P++jrm9nR9hsGe5Ms-Wh#sH0$fn+X7kJ_6K&)J15>cQE*;);2bFU zTmJ|eT7A(@I{Q%5&Tih5=k{jp@PBL8cC2V7PTxD3w=&t5!Mr1wb!;z$wq7@98wYaE z&4u6|gn^uMplBg>x7th~ZyQ(>a<*-sn*Y}NAFSE&Gx=R-v%6j`1cKKNW*d5P_TGn1 z-wo@#)~r8thrQ?A{+apjtaq*1V;8a!{@#9pS`{+|@6NJS@wJsW{r4R`IY-YU((SZD zbH28lbAPq)(}lIheEaa{?Fa6h0rDxI^^6z1gKKl2EZkoBv@stV%X$tJyqj*#eYo(! z!kvzMubQxV?d&Jv+u`i4seJH-tmkCG+kNZohv5&xck1&!`?8+>&q!#ydFih*Kh3Q5 z=R3A#JtGBgU~R`Iqqj%1JC5czAIo}<7rgyzy`K!+9>{J#oF6!n^&EXxO3$rJA7(zt zWVas3_l;*g69w1BbGn!v$~en)ws!ZEJShM81DA>pA$0{yjaW zr>l9osi#w(uBSAg+1)4ep%=5BQ_pBTxOVB2%8V@ z$NcZDzp`eZJDndoll7c^w7ad%{k5snQU8bq^zOv5 z)(D(z8=q&nWHkrl1ksRoUam5{5zIxxvp+Y2i_kQcF${9+x`X!THtfz2fMbNAX3zyt zzUi^bfboOH!I%J>)A%o$8w_}Moh(^q{*Cc61K}3To+)t!ih^I=5E>Fuw1`)MXfAbC zveZ707o%4e#l4xpMk^7#^8$^N)u4?1U*wysBsHzIb!;CkaUWR>D!d;qft<`gOJUD@*_#{tM}NN;P^-;Hgha0fTDLGBF9K zShHrqHLrH&Y1h1({=czDBS5Z_g5CMfk++WIyocB1`&;(qw(PsVWiq#A^4^w1dGF!8 z{qQxW;Oe-=+>~y0W*wWdmQB=u02dTg5Pug^J30Yw8@RA3Ux7i`4&G?di>?yJ8z=E3 zv?_wzm;|iiMfk~h%lEpkAftM@E6zjSclGP*6XRI;pCdv41VxHjz1I`b6$G8S1V4%q zE|SE*L>6>6Kq{VyVjB`n&G_gkpy~)P0R5P$!&?nJeptif`2Z}i?3tzcvOj(k^B(JkC5Q9qmxS4 zn23fyCD>o-$FQsZ8Tk!6{m{u>J@U}y&$E6!JA8T8TW|yQm1s+Qo^3C98uM&p!9%gF zEzh>W_x+3G1z$^^Z7F!0^K5gWnI^Y&=Gjg)1&*u+DCR48$MWo0!M`)l?kxDvTY zhVDGuUBKMNLgW5CyT8z|JJ0Th5_PV>IR3EZXr4V$TA+h^IK%&uu%=ybLYrMh!?3C2p<`3g1i#R2 zPgk)9k%hGM7i$q&iL0Y%Lu4n``p0#Eo*1=~kLDR-Z+^no)V{<#aUWq!)+c8T22+pv zx$sNH;Gh10Jj922g6h%@q6JXV@F_FMLN?4oNKOrJtO%fiFdK-4WGhlE%celB;$9~K zrcukx^o&991^}u`uFEf9ib$b#t|62QR7|5{1+F3HA_JF=fYoQ2h!_kAimbPEw-+e| z=D@Wov~;^9VK8J5Lv2c#mEwjj^^AXAcW8I@o4`Lp3sM~r5I4^q$&Mbq#(rVxQvHyX zhlbu)4tT4%vG|e~5`2Sy_`mRo{|cA`3>AbD)>d-qv2rw?*x>(FyM-Cw0Hf3Z z0(2XrD&t^8!g2vaQk7mmgLK7=5nm}@6yQaCA4uh*QP{;LY5tj?2Q&T=+3^UVN9IFY zbJo`RTf3`ZcYoz*z8U&Bc+auxLEFIE-p{=E+74ZtdT6oVw{+z!UH2`4oF%Xpx@Xx9 z4%pft6nbcP-naLH5`Eu3kh2ebVITbF+Qf#Gf0Xcqcw>wlV3@l`cC3rst??u7Y8~5a zyt~&3cnVJ2p92>iB4B#Hpa>|XXFAty0XY2B_tMdbr(d8}ypA=zi{!^h-a|sq3JcuV zLm-;GEZ)L2TomFjk!&~~Zekh|yuFY> zj}3NH5Ys%55UKKuRz;6S4yrk*+JRjFRfCS2cGO<%!!&B$1`rJ(*^ETD2v3V4eBXiu zH82rw=1X0t#wPYtH8Ih2R7^A&ikh2BO)0dgYpug3tmt>lOtXS1|ekr*q?ngdUcf>Iy<46u5nLsj$M7LWr)^b>jNNw07m`@Ga zV~EhcFPpUMbWjUqQCZs$;sE8>Rcl!=Xxnd^R0xBLdlOA0NN37-Bnw#MhDWw)2{NiY z^r0dJTE=JHJwDMCXmB<$F#~lqb%L7-?p~gC!(WbQ5Sh2VAj(ie(g*J7^5?7TYgz%gi&iFSvAOwTJnm1&x4l*C0CYV6>fS0Y~~Byi&eVm$1PJn(NuR&GzF2N za8HRo98?PjxoGM7x?c!g3~^})7f{3M@Wv4^J+K1kUcs$bayYH`TB$s$%ZkQ!t@lnn z<(V3*+|vJ)PwEeJ3opYAD27NRU{@nl{~F&}9DukAQ2YVDH%v^PJT*B!cKXN*Q;`#s z)6-*zCPkcE#mL7+>SGdR2|aP*t5^t^fa0W)Ne}_1xv>I9)i<(;EUiG+*)H^|my-Rk zIwfou{2p#%slWPz2ae_+tz<3!uWWFs_&$Hn*8RZZe5dZMx_iFBz0DKZ7f*d*nSL-l za_8*d`17uFzw)n*eKz)Y$L}7`zIf(~iL=)`e{$~T*;_B>y?r@%-yQ!obJlh4E4S|_ znOi&Z?t!bv9FLVLGMMs{x?NCG}4YAb=_@VYD6uDS<_nP#S2| zUL+}9q#=tKf-5Oacp)Bv@XvMf1FLIYNv@T9Uzuh zjiu7YpBtg16-w4X8oOYt9Ic9Z6DZy047{w=Ak~EOs^$Cd30Ew#Q>#rAs-V4@m(BDh zz_4n(T)q>~Fij2AWERFTaFK>cl|@8JzHu1cL1RnM@k)blz)>%LkBp?-?OB2n{jM3q z0GIKWJ?o-?mNJd&$+#+$lMr0WD~vVMa~4Bi*7XMb({OJw9|dPSkM{&;w~kJM8RR&- zHF9e5#0zI9CnCotU!E3YFe9bZsj(BKR0zC=KZX%_@h!*|uOTT*R~y9Wi04#aGiYEa z8I{KJoPe){_A5d|Ue;&OanKCv5mIXD(9ma1okI`;qYf29fD;KpmM}rBOiQSN5Ml|# zDN!TG$)b;H>HiJ(lM?RvYU2)+WD#XbN{~V z@e9`+xt3QS>_3=2^yqY|9L|A8rKR4P@IUvaOT< z*^z5Kmkq~rt?|5j;aW}U7`cA&{XhG{vbks@-J{3Rgd1FO zsfAF^3MmPMzeF8SN)5f05hSr5i=RP)eHU>bix^WW;*dqus}wUmk0kZV15bN;1EO^6 z;kF^|ZxTv>je%#3G!Lf`FQQ^4{yQX1NKhJzzd}O2M^v##nXbln8Q~I1{1^C&n@8l4 z{2IxBMM4+gdLu)zJg@q`_KLp;7FeA``WOsi2vK2}FUi)wCyp;k&zHpaCxe+W{E;AW z5~lY{()B;crr(kCUy$=(lHT8u4BSW{{nLWEkqJH` zNJdCQ+ha1^VEB!-zG#Hs-@AO^vS~0pG81>VdGolvK)>ZT)YQ@|(MD1`5RO~>+5pQ#` z6HyoOcNDu3Z9>$8sFyT&i+zat!FN^+AQ~Wz{^DjtgV=*0q7Z56EN($GM4CE_!-%$$ zMy|LG(Fkd5FK$P)gLqnsI}zVYV@wFD8L-ah3V-KRe*wcN8K#6M^EsimW4*>2c zj#E6rV236tKFAQ5#zPbzW{9t)c!c7k3=ZxX#m5;kyrX!6;wgr7bQfQs_#{L8T=7MU zPcg*ZUYw@*G(%cDi)Sc4%aHc&;yH?6qV2v+ahSoWc!lEg(5}CDf#O#g($rRrP&~un z^hXh2bv&78+)N|Ppu>HA;J$k>=N`Q89?rRk^X_f=`jM-)$7UPy67&-6`m!R5H9HwLyZIrYsfm!w=dK{^UI zZ|CQ|H}B_rZ~c${{xpJd>(4joo5KkGo4-UO84}X7&w%(88OV@KWJ!gX#OatBx8#Cs zB?<{ESx8!`LQ2fXO~vXf^ht=wY`~C>gqgN7g^ZOgWMMsNq|AP6pfDhz7`luM~L$z#f=qW#zlY)$9+m5Gs)Un;19Q3dK zW_3|rxU#r#ZE5*(5TCbeLEl=fN{owC_X1hhTn|pkTN<;U#yE>upj>qwTPz>p)Vq3x zSlZ$}k7)~s+qRRf$GCB&27*2I5mhP(d=5eue z(IPH63|Ab}pmrI16@snyR&0PBuu~F~uDEJGoyIWcJ&(~1-y`mvc;|D~nxWYq)z#as zT54a{ox|6uD|lRecV!ueOmJrzIBOne#C6O~0{<_$*zg(GL#tLzstaG`_Z89g<&TtR zIQIDeDYFV15~fximvU!nrmC^BZxP#ri@sMOU_6F9;Dx)q zu(JuL?~vM-!wlSEEWD%Hc)T++-Zo>`E}Wn4yPjj=P0gg>X3(x<N5%KEYLuGTdI_%(>@koZz9< zYYZM{8ulQ;_UBG`8i5^`Rwpo_!j>Rs>c>f$z(Pvf8hSe^_Yp{Kk1*~+-v(o;o>o>t z+8n;+5(7tzaFGqT3tXhQrj?7`%z*2;Rie{UxC*DS&ku%oG^ndHYEc`kWndxThc)Oq zvIVaizU1wludLB8KoHE{+?dL~Rl2lMt-q#dh3<0n^T0 z$OmHU1oPt-bzPCWp5X6Mi|moyMv`vk?#*(scWve3${b!LtfEz2yhX5EaeULj7Gwu- zr7m_o=Ifr%;MM7X&ZG_jod;YJk}Zel8g_|ACtZ&NKAvA)YQtiv{1TVs+u#k)=Mezd zy46WW2*?_QCGZEmoG7ZsowK>yvD1*2H~;eYSfs(2HEh-W&YmQA#|bZ`T$_y zfV)2U4_KB;RQFAg%453Mm^~`<{SfM9pYjCVq#8DAwq`+b;jR!d4)dLo6ejBZpO{d$ z-ru)|e-MoHf@0@n(1{yf0=rS(txtix;W%b6-h2FeY6|0>S8%9zcN=H#pNjerT*uum zV^1Rz9OykLz%__N@&qS3^AXJL#lT?fRU7so#&RwZD5?skB&r&uRn>9~-{f>wRqy(m z*{I}(>wBXbM)kne6o4u!j62QIrhem{6_P1epk-36A_n7 z&>bc`=qSzQoXm#!^a1{WHW{%Ic<8(rzJ6T7!`@;9$rx7oA_TA3(u7q@5ddM|^A)$Kgm0aW>;1cWM z5@)AC7jDCshLMPN-IE?9KT1Vi>7Du|EK)plFl&C>VadjjHozks>_w*|-IEg>LZk$2xk(VP{d zKBg$zCtTzxt%l9CDl)ssQ4T(Cubieg^kv@Tn0d zT#$B&2Ux2CS_er`8B#fjmx&joDclw+DKrs*%�Mk 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_dataclasses.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_dataclasses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7811758ef8e6c6c2056837eec5cc9d591143a158 GIT binary patch literal 13403 zcmcILTWlQHb$9mtB9}{2;!C7Pq$qMJa!EZ*$&_S^B1KuTBFiD|#4FLW!=0hH((EpC zXIAtw%YY4(LIvDdMvF>86GQ=mMy}k(X$vF;3N%R@w?I*VE6U+!EWr*E1N9$m3P|eo zqvzat?2=l!NzsnQyJzn6%(>^D=k>qU)C34TFZ}iAQnLpL`6a$skH-MG4VQzE8{`Ed zkvNe!$)Rv*N8HIF>{MKF7yEU`-R##B_po1Y+zY=h#h3QS{j9HB38aJZAcH+hC|wh; zVX#-JO^4&*bX~kI9f?QM_3`?2L%e~t`IN@=w)nR6_W1U6Q@knN9B*dzex)Vd8gEUv z#oORLAO)2j>GpU#gF{M3dS`qmgKHE%y(_*e-5Kv>@3o3I-4*WwI4spEyVKqA?)0Ac z9`+tldeXh|UIy1I(R5$DFTFRum%TSA{po@D0D~KqSb8u%$lz_tPL>985nEe}W@&m^K3)nw8=7q4;5F3rH=>lj)K82uB>`6p>o55~)o-EZ5(08T5`H z@e^r}pH%)Q^+-Fey5mQscF8GqNISpbtZXgAQm@2c^~8@!QEAszSNtidPwIr3i|`6)W~m-b zW~nTwtY6fj`=|2r@~Dy$Ro#Q&Y4t^~0V<4ahVNJ8q$b#u7iJL~6~@$>gf=nJ>rZFcq6T6oDP=p*a#7Xq_oUCS*D{RNwE*cvu3l<*;YU*M})N)jY z&h=-+#XQ@!QB9+%nVg2Tk#UPvPG@lSBvuB-*hh}1l3EhE$9kLwz-?Rt;0BRNoCAsE z0J+4)osvU#NlxTk$pw&`K^}m-4DtcwXHWp3AcH~x)i9_QpfEzRTdJ4pD!AU0k3<{v zh`lowx?&2j8Rh3q=Hrop#Z(55foOf7%4ai5o)@o(DFs;pUXwB}^6Y5vbE3-6$a01^ zcT$#ks1bQVJ*tAne>^f``%0xFfL=Z;onFiE(IhmS;gK4zofN$U!^02FT zZdG=QwK=(RMQg!FCQr{RvL@s7pP!Rq5G{}5XL2b;LK37@Sjy-r_46PjQnNhvg|CM{ zRZA%fpR-O8Z?J0Y@gHQLPh55i5VbgL0M9OOoLxSr0tvOOfdwwdZ#jEBaJN}k76^}B zwtT>F)z8YBh$o1lDCcR^HsleuXW;K5ac)+}g{T!{py-$;C!X-k&eahH1T_3fnK% z+FfU|S!G(^wyBfFzKguwtwR3C#(KjrQ{smhzb1{8<){EVkN%w(j8Ol`8jt@!*z0@&K1y)eXfmDIFTw0DznYE$X2%D6)+1LZ*s(b)O() z#5Bl3Js=3_tdvs_4hg~+bE0Clcm+YqCZRek2o=^3R0NY~zNA5ZW+i$MmY_peJb?vR z;e_t7ie3QJQ7FDjK5_*7q4j3cv47RKue5Vu)i+S;JhAFKQQCEK)pxSgeq_~mq_m5b z{M4#%>V1Es?i<-~lEAi~`$mk}apELwoc*AY&o*)bfEz@!H@QIWnDCNQvquz2!BKD) zxHq{wrn$Q0D!2+nKqHAgc}LW_sE-*22@|=XXZQrLMHRXW2~)YD%~n=v(Ag05j80|I zW9qgAD$dW#)a=5H1>UT)#YuTkMir=Ori}1sVbfG#E}6ILP-TGX;1}jV7lReVOj%oa z!w1-At1)HNsRt{j)I*iV60>B%Kod-K&PJWI1IR+#u-FSl)J^vzjC)F-#^N{>y2oH# z#(7NlGCt57H(OptCprcraJiYZkVWHkR&h6gY&So3f+nHEo4`-wXrgg?e3e*xtU zQXpu6ZGD#9Qk}$IbuD?I-5Ood>CcJe_@<-a5y~6}Jq5c*fxBdKlwAb?^gs;Qqxmfe zxR5J2-*nzF+c;8ism(A0b7rkx#xD(NHC9cTr#X^$Y2k9ctasPj4zs^IT=v1e5nepVW=*& z6SgQL%K+b`l}zs*Ju926rq^Uoj*FmwBjqUeQ&~L2-uN;Sl|p{gcQD~^57_L&^z)f4 zp9aSk+`ZK7rZvwe;FD!)XpO}5d3zTPT@4mB1}xB*k5zP>Mi&uuo2mUj$Be5A10caj zhi;?oQ&wYLHcKvHrvyYezn=EG($2-w-jstK5Vi!x!0zo6Hno_+4XL#$Q zp>@h0P$~{ffD~MB+At_L5_O)Pf>=t8Dl4;apv>TklMcX0J#2Yj5Hd;ew|JInLP6%bT`C4 zsi=oiYMD+tm%uowTT5w*yx4?R=6Q=($E{78*8TQ|MSb)$FumbBJd2PIi!(Mf43O?R zo6X44-Sj!E9>E$2fZ`Dq&>5vYSUtw7D~>A#h9$ZeLRJ{u(tW@S80u1W7eW+mAH&Q= zolQ|)Qe<z7Zt`d z28E7eLjbTfSJyoT!a4`RYiLvPDq9k6k@e>gZqVI9%*FygYW# z)%Gh_^Ua3aFaK-XJFXXg5p247c5TP--5taCeQh_#?)msqxbaus+H2}cW9*)H@V>9^ zwVFSwDTSo_q3(xnr$6v8P~kE}c9wkGON~2A+jc$ly6Qd4pLtkMTK1NFP4|7_`=Oq7 z52@c-YS_Nk&{u5eE4A-kYd>0SKU%8i*Xs8a>-Use+8;*z{=kMi)Z#(xwyp2*xVM!e zZEKOe#mL^$mHPhG`s2&buDe`j@7`jh_x5(y z`(Z5!hF8M9x4TvYvE{M%yP`NVe}C8ElCSo<^ZMkCmtTMR*5q3E6UFW)-ulvyo?Urf zSbIKOd_KG3baXN_Iv#pR*MYZ&e|TiI^AwKWS>ku&Z+j^i{>{UEB-HaUfu(;QY$}B! zjC8m5-Fp7JFMj*QThH7cz14otH+VnX_}g_qbo%YXMiT1ym^j?qEF%9r+_>(B_fJ$b z0{^KeGT|Zrye%^EBzfE8pBQ$&9d4i4=X`sg8{sD#Pt`g9CCov|)B*4Sdt6Y0kmokg zs6}-EmaNgTsk}m7;V7ibDm`(@7Wg4D2?Af7g-K0SYH2AW@M?yfQBgtkRZ>zj6@~;V zvOW-Heb8tLm~ykJHDAamsmn5xfaV07ti4LX1qL5Ko69h34P_>*DrIHWTmupsN=|~H zZEl7+_p-{&2?#fenunlULFA@E5nX}tC~a+F2NtFg75{XTkInrl)&)v*h6YpO zkI<&76@jN*Z>-dmR*;Sf90(SH{zG9Z2=oGMBHagt5fU?mLjzFDAYxhCQw2Kx7&~@B z0n(wFggS3ce)qz+FRTRj-3=!Gq31_kE2o6jk;KYyV#SqU+HaF#fo6ddIjJ7lz~H15 zx5Q~sZ9LVya>;QSaHMU(b;yZZo<9gzuP;F27y0#nnA^qXj=&tI4_Y}rbxUrT$Aj}g z57bp#9?6~KC}L2h4MwuWj)sbWJ(o}tZ+RqN3L*vH;l9Sf`S73By{35{b$kevA|KX5 zp*tZ+_lARJu_6G)l?6x2foDx_RiXxAWGQ*Lp^aJ){fVNlrCQfx zcYBV3P=p>&7Jcm?=zZJQysbrV>#f~I?;a-Vhl=e(&^}!Bwf-u&eJ!}7i2wR-E<&;5 z>NCQMb%2)c8&6KKtm7uO#GnoEG`Fz~B!8B0z?v7y(qqINWXc__WSm^*rcV*FM<7&~UG7NU9xe7LJ3lj*6 zwOZ|$c34pPS8_9f(opbTszNjBm0Sg%U<(WA^*Cxps<*-Da){9fRC1wkdUe?a{P^l; zTo5jk9DnAx!2!j%aWV~dF5?_Ogna`40|h~_m|PZwkd)t?IpiX*?sk#9BkABEEWhMl zf&fm}|MBcrNa(Me3tZGA-Ub3q$!YL_M4AGZd0x~Yu7iqjt7QN>cSZzX8FPUczX$Kv zNDA6kLV}(5N`;Sl6ce$gc7_~rrhGx9ntjpFr!*V{UYMG~BsqjsQW@~8p?a2P(^atQ z$5=g;nQlkCe;0K4sjPtqniQ~{J;oN*Fslqf6{>>aF+Z>5?ddIh=eXT90bw5V_60`B zQd*23H^MH=o~VdcS!vX*r0ut7PnfzU!J;<_R5)Nhp%?}G=VC4mSu!wvWHYrbvoHhT zn9WN3Oulm4`i#g=AJ(ziZFDhbU5=k2C8R6_;n)XjRXKsJ4`v$}F`(H*nzz0~oSlVh zCbGm9V9a4|^aLjP%_sv*oYD-InuRn_b^!xY@+%_dUPlb8Es=n5A4VSdFKM!>9qUvt zr{+6(1#)~Qyu_ABA)jtC`|y&4WjrN~$;?icdaWF2)s@4Mz|Js(RWC^99LMcB%U#(- zhIKev&P|CU@Sz%i%$_4=90J_AV=U$rHPGtf&t~B^6fztbv&b3d?%EebEUK1w%Gh|| zPb0`=tU3xI4!etau}2Wj_lP~y48^Xe%674djA`c_W2j+1y0-$oe#m_Rt{7tL=VP&$ ziSO|WqEscqiQds@nGQ3*10B#*hOIW}!DPWaL~D^95+@RP(vd2kdcK%=V8Iq8o4w3J zHYRgIz!^tFR0ocTVZ@uh1UfWS#+)8>NCOwcWhza{$MD7q4g&JRiNO125YuEA&Y1NN zynY1;k{C@G(H)5FJaRg$W60<(e=!Gl;S^k6%l@8>{lDP1GKVq>^lsYYD*J2l;-)>= zwQCppQHFrP7Aq!i+*AU&moh#PNxND2_cH;7PME0+Gz<{N*nJ$x2dF3rA?$7O`Z@Em z9HSJjWOHzZ@a)VkWYkV`!d`1fseC1cNdZ%2z?PgyL}UCY9Q<5zj)^T4HIRegAqS9} zHN>F77Ukv4UFRP^Ey#NnWC!R#kcSC~8sWk0J<-qi%=Ez5K4OLU+6RQK6^#N`25VO* zE2t5g6+yWIU1mjUs56L}ii$zYBt(s&#|+#J!(<9$XEmFH94rckTxJ1oQ^IbjFoc(x z;8h1P_KMsqrBE`16O5$AX9~}PMLGN`8C3@ix3O3NxtGr26-+pPxW5qltO!*L0;n|* z__#LPVIVY1`2hA1{a3OXxS7d|_JXQ73wS~r-ndK#n|IET=m%o^4(>I+5OVC03;`sd zHJ6cJfqQ89HY3l8u*KBS6O5Q}NlXHr515IW{DPP_K8&Kdc$Q*7WQtNKqhYuMDWqu@ zeCx~bt~()Pue;&KNLtkcDG)72pqpl(kv3xS3KnJG%!5}4G7<|Q!j;kNe4b+bnJz$K z1_$*CllMEPa1z?a(vDL(i<77FNXM>LKZxAAG?*gWnatE!^uK ze(3h>5B#EgxLCLAdf?{C`{9k8Hou{(Adbq^}t1TZs(+u=^he z{(fL>e&#g>;VQn%|oJ_1u%Ed`}CH=+X|_D`{O3EXNp^IA`yOl$n8G(uCL~oJx7Y6 zu4@z5pDV?Vt;NQQv9X`UP8RF>fFfs0-3P9Ft}ouL>-@+`1}8WudyoF-#sT=O-)!s$ z`1c(8U+R9?yswP9C!XSd>>b@Z5%T?HKfe6r@QEJy`6=(3s3$+&9Rv97`sl@bc6=JbuI`gMdbv~JX~Ij}YAGJ^20V-wac?wn#*tgN2fT$|Pz=ZB+(NDN1rm`%E?t!lY z$wo0EVdP}c%cK}qeaeO07|9k0#m%IqI=A1 zJeWjbDJDiIz1hfz#LU!1`K~#|n1GQuL2q6s6z{1}^u0m68ZwXFSkmi+t%(|R%UKFW z_Zw}gq{?zXdJSajlb3N7$iPq|WmL!VTP(*dYOZ52pqw;Kf(~Y2WSpCE4mxnjfB@2LUUMPB$WlsbQkI~h}%KR%FS4WLLh@sbn2Oe z+;Zzq_Z>BE@;ycW61re`M1}vegRDC_j?>BT2W0;*N$_1#|1JrkF4w%xc$mQ0?_(lvZrs|8{xW3etz8vzwb9j*WK`oshBR-0++fxfek;_ z4UyK4Qg^h}((zGEisR}^{`z$%0&Ell(7B;$-Os=P&Jbi^2y598$j!iPVXWQwf-}U4 z+(t*3+q=G-G_~D4a4WdR?>SMdxnm> Kj~K{eg8vNzmXQPi literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5c3f23e0b1057d6f62ecf1de5ecfbcd3b806148 GIT binary patch literal 36758 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators_v1.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_decorators_v1.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c27a1c9760e0d6522dd6c8f00fd971fc426077c3 GIT binary patch literal 8615 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_discriminated_union.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_discriminated_union.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a65aaec103e6dd9c0827ea6ecd3d5c90ed44874 GIT binary patch literal 20846 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_docs_extraction.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_docs_extraction.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bf88536b896b76465826a04abd9d9c39670fe08 GIT binary patch literal 5308 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 e&FKqo&cC^Vpt{~GFiq=TKl8|)zBZh}mXX;2 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_fields.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..763f15833d41c6dba34752e8eaa0c989772bb6c7 GIT binary patch literal 24290 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 z zDfH*$J%CsIn+vrDhLjzQE*?ogMwuNTVX_Y!^Zz;=Dbv`MZrral?$1=#WKpO!`fkED zrEwcRw9s?_9L>^HvFKPY;|}u2_`fPp)SUy0`gEYEpMWC$K?jOPo5yVCZ`rJ4<+dyr zz{C+Sq=7?S2#}rE3}&&=iP_KgxH){g$~2+!f%kdo8RWyyzrj!5m$syTj%Vhbr&X!M z6F#iu@qP8RH(y(lS3K=_J2CqeqWs3PU7>ovyen6EsRHDzc!x~}^29o9o{;_<>QqgT zp8q@b?tj3`>#|yxHKo8Cr1S|z5?eL+697C%W?Rgh3)4yJ?A6{J%paBoZDDBqLpx&M0p_1G70c;|U|E;d1L1mFM9(whLOliU z1O3?;?1Cw$=fO7-^j_e-d4MdKu0eo%SwJmm63rwm7`c$%g6Y&_i|KQ-S*fw9|v$oBa`QtBLgvAT9jD#_x6u%5>ATeu5rC&vI?>}pHR?OZ7 z>w}EA3Xq8qtW=+mzr4kf~(Uy4)h45OQ z-D<5`E2~-Ztd#ZKFhdJpQN1|*PVDVix_XmRy=kSof2Dlj`uGD^*^T+1-Ms(RY@aYNFmP5gEj>oHPr{q8 z(z3Jq@cm9B*UOZF<)Zdf%LKGQe*UoE&bY?BBb%RH1iz>xQ)6nSPdH5K2{M~Gt9{wT zG8KU0F;Gt}i%64uji!M_EjCN$h zEA>Tduxn;MgasE%&+Dg?jr0qq+0ka2tbxzwl_xm=i}KuOJ<$W2CT2b~->83P_2uWW zQZEKEF*LhI7Pg3;+SC`DIt(eq=JPDAE4zfdFnI-yOC+tb=Dw&Z+MG5VeAAfIYniWM z3wN^cBcO%DlJK6iR`Yxn>mNG*_z0xOYc}3#7&DN7$7;^@S;BXfxx5})7^li@Itj`S zyo}3E`uuQi$+6!0ROaGxb4W>g4p#SkH!Z+X`QOxVX+Zx#?i{RKWoF%}DOJ6i^(1|kEuf{*X26@u(34716NO9k1V;8-5F_m) zua!KqqGNPGwM6mef%Z)?cMgz4hdU?>Y4>4gm}eD7!jtyh)~ys8B5#U326ZJUv_RhL z}gYRFj zdLo-6_6k4zE;VUxrJJ!wky}t@uU3^7@B13e^wtFY=kHUF&8Rc>0(gI6d`{#XJ=G zGCstAzm03W$fvm4?^|50rWDt--o*`V``k5V=9@E)+I2Gp?pL<1TPcA0E85p>Ea>E5 zo5u11cq!TRu$0A4l=SlTtRQ}oy{c{9Mj;p%Hm*A;gmOLWE()Po{liiUP4Qe;Z>D$P zb61$hbU1`{GX?bWEQksK2C<-40}EEiXrsy47NZA dgiLl>$sQ{hzM5&AI>p literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_forward_ref.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_forward_ref.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56b23a00a8f8466d121a110567a5cc2028bf66f2 GIT binary patch literal 1304 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%0AK9FQ3dLJH}0l}e&x|~{^$y}gKrGLo+%}eV& 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

        UX|Zsn{k}Y`Ytj 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 VM9Ae!eu`l%xnB>522>>o{vUJ9>39GD literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_generics.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_generics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6296c31f42de65ae9f3080fba9c76fa3888464d GIT binary patch literal 24331 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 KM%N-O-{K!#dul}h literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_import_utils.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_import_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cc9e69bec7951f64c6f45d2d16eaba9b70ccf96 GIT binary patch literal 823 zcmbVKzl+pB6rRcN><>NV6vgIPY*Kg@b|MxorylAedKQL2$R@LEFp~){*^{7xg@1vK z?X`#CKVqY8U_lWJyVdQid^4MXXy?GZy!XC0-@NZlJ`9IFg6q-y2k9G1$X6M3%V?c- zfzDf!kc4K0Q=d}lYnjG%U#EoWFu+*P3~u_S!i>z~wr?Xw6O%cKbsiaJT4KL8-nFE@ z+hR_Oxqo22y65%3%Sw+nW*o&&7&^m)$M^Tb@$J3wo&CwJW7@bkqLSSc3Cm<~Gi6z_ zpU*^N0jm~}gM|cfd!PDfXm#A{(`Zl;MHQ&%C86X6c}P5c0mBxxm zWlJ0q+4(geUkwTnbBH)k^Lg-0h*)sWAZB5jAF{j>PzTc}e#-JB!1yq@n@)o=t=Odk zv(cQDLC1a>k5mluC_|4I0;+IPrCGUK)Xljzp=OYTQxqI>sThXXh>N@Iqj^QX8Kckr z?T^Ox8bbmOn*Wk+<3W^uvTJU4CdXPTLXhBQ0x&@L@9tD7ikS&Gh47ZF?z;0f-N6Y= zPP~5O&K7xG36Yf`U!<|By1+?-{OLd*+RR*XsJj~j3z$-^$d8Gl+VtUE!7N{PIl~!5>*2J8};wpfCqxz`$Ln zbej%oFvS4qkRsaSa2!;S17G8?^;?&5&?1MeKi7mNSJqs|s6nPOO}}K?a3vEiZ&efh ziiy=T_6Szq{4LH;aG_PEi4a_7c&=2cgkU;l&QmgJm9FrFq*Ep-c72I2_yikn*?!@s zBx42_6(!R0^w3!>(~{)>ETP1bG$+O!6jifvDiodN>`eFFb?DOUxw1qM!VeHF*FbOm d4Gmw=u%5r7o%gNnhogFTG5XvbE=Jma_ybQFVTb?# literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_known_annotated_metadata.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_known_annotated_metadata.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4bcfb4133e0d4e7ba2ccdee6a9ed8293a3b5e1a2 GIT binary patch literal 14226 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_model_construction.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_model_construction.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61a02a15ed365d815575fbeced9721d72b76c5a2 GIT binary patch literal 35105 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_namespace_utils.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_namespace_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fa5c331c166130457dfd7aba71150aa7da94c3b GIT binary patch literal 12313 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

        CYFRGG)9zQ*?V^^ zWNtpTFum9_;JzAI4TSNkUD)#MrPyVCNjQ8z92dvLt26fn`n~r^tJrq`k?msdjjn}` ih0MYxIF|bY?(d%xw~5Ea|2iSQ9uS}WLZFth_kREqk-pIY literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_repr.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_repr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..563fe367e057d640f4b2ca67131c8fddd9619b80 GIT binary patch literal 7853 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 x2^^*Mp!e|+6sANLi({CSGwxk1Ap{Xg>lKG^^O literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_gather.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_gather.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10e0aca9375630579e6dd10720cac2021f0e883c GIT binary patch literal 7640 zcmbsuTWs6bm6Rxn5+&R6Q+Aw~iDO%GVkd6hxJk2gZqlSruS>d@noMOx+EyY_?j_|! zhO@at24q0dxxj#E!#+G#npb%?2>P2oc3H3=TQ4TwCb!GYce!}G z+#$EXyF>1j!|?8uyX01Qcjen+k$)j{j5P&GRkOOJr?RRRbD4fw(xqft(lpaEol?>= zfcW3e&nfbSR8o&|X6Sr2Gndm9`67;*f%93STuII<8OiLvpiHOK6q35EOe;iDla(R= z6@^$(6?&8Dl%y>T*3iX8u?htBx@m|2%$kA8blM`KCGEA+mn|!HHww-BjKaiOnTfkV zS8UuZyA)1#qkR30%t76Q^}ILcGlQ2TeO4it6)l(67rHIdqE4iFg=i^tMkI7(^zktn z*8YyBljGtOmk2CRWmV;x*`Ca%(@GK~lpqx;XpdXcDNTQ;w%TjvAsI&rfXOK>Nm7}V zD(P90(5NuAshG#)6A4wyD2ap_NF*{@IhV$IFp+pKC#CHXUm_uAlhECqNH|oPNc@V~ zMd>`AJ%8rv9LdfQDFai?T)maeCbOB0LXt`%rOqoVOq#!XT}s|mRQW2j=dZqzx_(tl z>B`6)^hz^|c6BZT!C zOh}e2OiY5-Y}*rWNt!s91&&dfdRCM~HLH#&w?P%ylLXThEpd+~abkON`Uaz7cUvhF zi|itkfSUE>!E2_#id!tqnv%hLI88}UlS2TgAuUlPJ@7(3qF*Eu3w`^uJz4?iLsZ<2 zmYA}5@*cOrAEbhsigA>z=>{t_y+qM-L^V0IxR{5u0Rm~qq63RgEJQ3&h?by{57JvH zutKM~3ksTi#Ic?+3k(P9^ua*~JnZgOC~NxI>su~H@qmAMf8(j_M{%F*1%LCM1x!E4 zl#cU`alg#NxF5&!ftX;1EPp(o1rxiiFTDTutRg0J;3BFHx}u$8PE%x2&XETFIlOi> z5D?+9sfa06(85UQe_Bypu}ltUr)Z6e96)d^`r)U& z3dIkZ&p9_ZSb%9ATIUAK+|j>Hoc(m5_?>H|iSHJ)dyDTmbWVfO(ajVvAS4 zUA&=|Uda}@ND*B$yW`?Lyk!SSo4N$N=>zV-P?tzU++eK%XDPEE+r4*Oi>~(% z%TUgP*)6g+Dz4=Kzk%y*covxo1(wOvznFW<6QmdZoEJ*x8`ZYpL0EC-vJVhcq=@7AV?s)3CkuD~ZZ{WE{p{grD{T6yTFW_{V2{ zbY}U+x^Q^uLfI!2eO<-g^PlQQ@9Sk=*yM)|et44~Gx)IwgB$$m9XE6E4Hkf?RObI6H3Q3n?5*84Lc8E(-+MO`zxqCP}^P2kfxB7luj+s zC?)2#Tw(}llM`6lP(bfJ9eiV_%YshQ-@x2y??nNzZ$J=OOvg;_r<|b`!yY0ReF% z{biT>7;t=)mxDHzi|oL>6xN=Xb5P-&)<)-bsb!$SQyMYZZ(FZ(UH-;-a zO`$qr<=r^;H1-9sJqY_0vj1W`W!1aD?E$*(XZ{~fo`!3X&6_Y=FP-frSi?bky%4tC zspE66*MHE)G4i2(OEU5h*u4U!EKFGr&Gfv7KIHugYnw z@)64SpX&HI(#Vhcd!W}(={dcWk@rHP{~x80Lo&CIO!n-V@&JYUu#SU)Jsf-w=nmR+ zEuNd}F!pd_)4g5?wU_Q?pgTnAp0Q=|zvzCMRn<#>@9b?)DWm8*|1`-iC@Qo~|BRw41h3;}5bnVl&5j;S zkDi-LE94l$3pbT~bs#h^rE^NP>7h}n=}XRLQ*ien82&BgCPjXgDsisHM zl{sx8l$LIfWXTA`{t)z=0ccj{3|W14bD`;m2A5a>oy+U9S=AJ;&BkN2ugZ{W_C0)1lKGgRhe#vyZ}w@Bk=g*m3igqiZ2p#TuD^*5r~>I&FrmORbHy&{Sc@Vs@clJRkts@*oWUVhGrg9gO?Dn~0H{zN1~8z+hu$veRJ4f0kmdp7TVf!L zYwIp_el)uD`nIpN*g3f78{FdiR=lge5`S`=Zz}uS3!ydt0EUL%!fhiGT^%a%&y;(_ zm4l_86Zc-j2=TR5-$wA{zunA%liU9GVr0_rPnL!5!Z+81ejLBJa?a>|=E0?h!Lvxu zx90Dw43|3~z$|qfTV}Uf`c~MLiH(+HK&bOL5Gr`r{D;ayq;Sy?j#zZQV)TwZm?#Bb zzyNi6O*m?GLxB41gKs?yex*vjv$yb_Qs>aUi(Adzg~4AAl$xVBfp_J-U-(yHl4t*c zE#SN5E-9z*;M1jjo}+ zr!eu8uid+V;}=$jHiE-2-f z@n`oF*#^v>)OMdYdQpKv(7?cIry-oMnFL!r_bC|u zD^*Qyqfzdsq9@`}J9#47m*Qf3f2Oy6orOWeCpyil#Gl^cI+mvkGaKCC-g_G!OZ47$ z9V+)3#~sa)UU8oBaHGeK9v&9r<{OCL@IY_%_E8&>*`K?vFfo^O4bb1V(%y;)DRF0J zRFqUmxK)o(jkc|=nu4kdoNt;$@{nnReK|w#=pxkY%&M47E0PN7Iy*0S!OGn=&SKxV z0q!`=kQd(_s?CYV_RzZ(dMWLUmEju^zX?eJIGPms3}pqttd9<2Ca39E=9i{@Rk51$ ztx+8nU!4ZDlqSMId;+l+E@=udKr@J<`0oDM+IN9mQklcU2yuy&f~4dq#TgN=K+pgw z%9Lu+vknc5KS&Eg-rkX)24rnN@KN~8fH^Bna>5+9W)=KSVKar2`y%Ox@YyAs!z?|p zk--$VJ}c=!CkZP>`1aArJcr~uD;62yWgiYTW?u-Oj1|Ao_!F7pz#L-`A{V(@ZonV+wC%vo~{d^t+1n>3~WD zQ=+xti3-0VJ#F%5t&dgbND6>4$E0CKbH~lH>_3?!pE1$DGQFQM$~vR`l^NQOe03>s z@6~nYtB<@v_AijP(B6^wt literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_generation_shared.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_schema_generation_shared.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e59aa4c5f8dd80e4e6a1d068b9c75244f9f1daa GIT binary patch literal 6221 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 PSl&2%`riz^>AwF5LWw`l literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_serializers.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_serializers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c5bbd418c85fffd6c42ccf6e5227d9141bc76b3 GIT binary patch literal 2111 zcmb7FO=ufO6n?uqtJSadW7$$1Cm7plq9%0?rH6(PFtPLNpEQaoQI#%h?bumWTB)-u zCvs)5p%4X9DkwBM=2~1zj=kpGON0w@HngN9P6b_(2y`v|bW__A0bVo5T|&>`_QE{CV^{(eRIUVNF2`}q=1Y8zceK#gD2J#olu%jB ziB1eE`N~pGD*JPO4m7~1m~hj38uP`Z=egE*+~N4)D2)!`5S6Hyb~AX|VInx<@S`5? zS`HJ%QHLLMQBU`oaSw4Vhe_asv-3R{^>m*(WYT;J2h z{}+AOP3RqRX;s8WRNr};IPjm3>Q|+&QEsHpX99n*gEO2JQgppyDyCM^jRoop(|SF_ zTj3jZRnbkYuvpeiD^#cuEE|QpxU8%Xs9M4NjE0>VqvDP=n4SG(X?Ee_th{*h>gB5o z^8ECTLVxm{+tH~6>T`SVsPPz9VM8z-f{Eh6$UbVa9nNaNHrKOM*rqeg)&^>zO}+tH zFr^*>;Kj|roiTtsjolD8d;#F0!8Lphaep^7gkr$m=V>nk2am=PH27k~V_j>zZxFsA zWLa+15Zns0Faf6X7Fp0F5P^f+@aW1txG&s>dt8QF$Vh~hYzeE_w2)b^Vk?04S{W0? z#FkH~R1+5`Z z{k8m@wwyO;q7SMRRaUW)ulA?nEZt&aqAR7dvVn=Fl(cnBjHznfI=b&u=F1w^Y5p}$ zkxQCkl3`X5{Th#`*aX`L>5sKlVW=rKO`8`3qc38qHfrOY*kp6s_CqA`?cBq;cKn+~I|AuRI|lx6S4wxJ z^smy$ZZz2p{}CN+FYQDpp8F^Mc^ik==-QL0yZT_Q0Sf9$Y$=e1pBJ@gT5)`;#L zkU44vWqGAW0W8aey$km6N+s;1Hmv9YXG&QvSUx&Iw3W_oE8_M>W=A?hM0_lVIK$dt ziK?Rz>w|^nm=w)gwM3a)juH$yl%eTm+9su7W~n1E5m+IWb*wWoaLF+l>d*FjYena4 zrm|eZ`#^9Xpc!bHy^)W~@_}C(dOtP_KfoT9K!#YI{_}L?YbAVvoTV;%_Qq{0X@5BG zcNl*SiI*_^5+c9B@SpIZjRsHhyD0czZfmY}x|^8jBqnTuVy{rNi-tOAsP$Dhb*hs( zWs4N0lO_h5leWZcKZv0R*SD^>l6HXkK@fw@kL(b$!;E7&PuLOW4}j=z4%$&>$0*lD z!yPo-7VJ1f5-j@K*0q*k4>CUq;y|-*4>5b#iB5J84aS&r{PZu5UpyN*jdxD{p`)I0zQtc!535q_4!Pe({Fv#)t enIUd+R|?t!(?b_}`clEsuSEY_k>Z5?2mK42XY`T) literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_signature.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_signature.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..359e7590a96ddff223b1c69cf2b110a1b4fc1521 GIT binary patch literal 6761 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_typing_extra.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_typing_extra.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7021ff9bbf572ece7dac01d3ccf198359f8a8284 GIT binary patch literal 28180 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_validators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ceef5ac6c87828f9c4975062956ec6122d2c921 GIT binary patch literal 22961 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_config.py b/backend/venv/Lib/site-packages/pydantic/_internal/_config.py new file mode 100644 index 0000000..43c8568 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_config.py @@ -0,0 +1,383 @@ +from __future__ import annotations as _annotations + +import warnings +from contextlib import contextmanager +from re import Pattern +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Literal, + cast, +) + +from pydantic_core import core_schema +from typing_extensions import Self + +from ..aliases import AliasGenerator +from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable +from ..errors import PydanticUserError +from ..warnings import PydanticDeprecatedSince20, PydanticDeprecatedSince210 + +if TYPE_CHECKING: + from .._internal._schema_generation_shared import GenerateSchema + from ..fields import ComputedFieldInfo, FieldInfo + +DEPRECATION_MESSAGE = 'Support for class-based `config` is deprecated, use ConfigDict instead.' + + +class ConfigWrapper: + """Internal wrapper for Config which exposes ConfigDict items as attributes.""" + + __slots__ = ('config_dict',) + + config_dict: ConfigDict + + # all annotations are copied directly from ConfigDict, and should be kept up to date, a test will fail if they + # stop matching + title: str | None + str_to_lower: bool + str_to_upper: bool + str_strip_whitespace: bool + str_min_length: int + str_max_length: int | None + extra: ExtraValues | None + frozen: bool + populate_by_name: bool + use_enum_values: bool + validate_assignment: bool + arbitrary_types_allowed: bool + from_attributes: bool + # whether to use the actual key provided in the data (e.g. alias or first alias for "field required" errors) instead of field_names + # to construct error `loc`s, default `True` + loc_by_alias: bool + alias_generator: Callable[[str], str] | AliasGenerator | None + model_title_generator: Callable[[type], str] | None + field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None + ignored_types: tuple[type, ...] + allow_inf_nan: bool + json_schema_extra: JsonDict | JsonSchemaExtraCallable | None + json_encoders: dict[type[object], JsonEncoder] | None + + # new in V2 + strict: bool + # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' + revalidate_instances: Literal['always', 'never', 'subclass-instances'] + ser_json_timedelta: Literal['iso8601', 'float'] + ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] + val_temporal_unit: Literal['seconds', 'milliseconds', 'infer'] + ser_json_bytes: Literal['utf8', 'base64', 'hex'] + val_json_bytes: Literal['utf8', 'base64', 'hex'] + ser_json_inf_nan: Literal['null', 'constants', 'strings'] + # whether to validate default values during validation, default False + validate_default: bool + validate_return: bool + protected_namespaces: tuple[str | Pattern[str], ...] + hide_input_in_errors: bool + defer_build: bool + plugin_settings: dict[str, object] | None + schema_generator: type[GenerateSchema] | None + json_schema_serialization_defaults_required: bool + json_schema_mode_override: Literal['validation', 'serialization', None] + coerce_numbers_to_str: bool + regex_engine: Literal['rust-regex', 'python-re'] + validation_error_cause: bool + use_attribute_docstrings: bool + cache_strings: bool | Literal['all', 'keys', 'none'] + validate_by_alias: bool + validate_by_name: bool + serialize_by_alias: bool + url_preserve_empty_path: bool + + def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True): + if check: + self.config_dict = prepare_config(config) + else: + self.config_dict = cast(ConfigDict, config) + + @classmethod + def for_model( + cls, + bases: tuple[type[Any], ...], + namespace: dict[str, Any], + raw_annotations: dict[str, Any], + kwargs: dict[str, Any], + ) -> Self: + """Build a new `ConfigWrapper` instance for a `BaseModel`. + + The config wrapper built based on (in descending order of priority): + - options from `kwargs` + - options from the `namespace` + - options from the base classes (`bases`) + + Args: + bases: A tuple of base classes. + namespace: The namespace of the class being created. + raw_annotations: The (non-evaluated) annotations of the model. + kwargs: The kwargs passed to the class being created. + + Returns: + A `ConfigWrapper` instance for `BaseModel`. + """ + config_new = ConfigDict() + for base in bases: + config = getattr(base, 'model_config', None) + if config: + config_new.update(config.copy()) + + config_class_from_namespace = namespace.get('Config') + config_dict_from_namespace = namespace.get('model_config') + + if raw_annotations.get('model_config') and config_dict_from_namespace is None: + raise PydanticUserError( + '`model_config` cannot be used as a model field name. Use `model_config` for model configuration.', + code='model-config-invalid-field-name', + ) + + if config_class_from_namespace and config_dict_from_namespace: + raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both') + + config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace) + + config_new.update(config_from_namespace) + + for k in list(kwargs.keys()): + if k in config_keys: + config_new[k] = kwargs.pop(k) + + return cls(config_new) + + # we don't show `__getattr__` to type checkers so missing attributes cause errors + if not TYPE_CHECKING: # pragma: no branch + + def __getattr__(self, name: str) -> Any: + try: + return self.config_dict[name] + except KeyError: + try: + return config_defaults[name] + except KeyError: + raise AttributeError(f'Config has no attribute {name!r}') from None + + def core_config(self, title: str | None) -> core_schema.CoreConfig: + """Create a pydantic-core config. + + We don't use getattr here since we don't want to populate with defaults. + + Args: + title: The title to use if not set in config. + + Returns: + A `CoreConfig` object created from config. + """ + config = self.config_dict + + if config.get('schema_generator') is not None: + warnings.warn( + 'The `schema_generator` setting has been deprecated since v2.10. This setting no longer has any effect.', + PydanticDeprecatedSince210, + stacklevel=2, + ) + + if (populate_by_name := config.get('populate_by_name')) is not None: + # We include this patch for backwards compatibility purposes, but this config setting will be deprecated in v3.0, and likely removed in v4.0. + # Thus, the above warning and this patch can be removed then as well. + if config.get('validate_by_name') is None: + config['validate_by_alias'] = True + config['validate_by_name'] = populate_by_name + + # We dynamically patch validate_by_name to be True if validate_by_alias is set to False + # and validate_by_name is not explicitly set. + if config.get('validate_by_alias') is False and config.get('validate_by_name') is None: + config['validate_by_name'] = True + + if (not config.get('validate_by_alias', True)) and (not config.get('validate_by_name', False)): + raise PydanticUserError( + 'At least one of `validate_by_alias` or `validate_by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return core_schema.CoreConfig( + **{ # pyright: ignore[reportArgumentType] + k: v + for k, v in ( + ('title', config.get('title') or title or None), + ('extra_fields_behavior', config.get('extra')), + ('allow_inf_nan', config.get('allow_inf_nan')), + ('str_strip_whitespace', config.get('str_strip_whitespace')), + ('str_to_lower', config.get('str_to_lower')), + ('str_to_upper', config.get('str_to_upper')), + ('strict', config.get('strict')), + ('ser_json_timedelta', config.get('ser_json_timedelta')), + ('ser_json_temporal', config.get('ser_json_temporal')), + ('val_temporal_unit', config.get('val_temporal_unit')), + ('ser_json_bytes', config.get('ser_json_bytes')), + ('val_json_bytes', config.get('val_json_bytes')), + ('ser_json_inf_nan', config.get('ser_json_inf_nan')), + ('from_attributes', config.get('from_attributes')), + ('loc_by_alias', config.get('loc_by_alias')), + ('revalidate_instances', config.get('revalidate_instances')), + ('validate_default', config.get('validate_default')), + ('str_max_length', config.get('str_max_length')), + ('str_min_length', config.get('str_min_length')), + ('hide_input_in_errors', config.get('hide_input_in_errors')), + ('coerce_numbers_to_str', config.get('coerce_numbers_to_str')), + ('regex_engine', config.get('regex_engine')), + ('validation_error_cause', config.get('validation_error_cause')), + ('cache_strings', config.get('cache_strings')), + ('validate_by_alias', config.get('validate_by_alias')), + ('validate_by_name', config.get('validate_by_name')), + ('serialize_by_alias', config.get('serialize_by_alias')), + ('url_preserve_empty_path', config.get('url_preserve_empty_path')), + ) + if v is not None + } + ) + + def __repr__(self): + c = ', '.join(f'{k}={v!r}' for k, v in self.config_dict.items()) + return f'ConfigWrapper({c})' + + +class ConfigWrapperStack: + """A stack of `ConfigWrapper` instances.""" + + def __init__(self, config_wrapper: ConfigWrapper): + self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper] + + @property + def tail(self) -> ConfigWrapper: + return self._config_wrapper_stack[-1] + + @contextmanager + def push(self, config_wrapper: ConfigWrapper | ConfigDict | None): + if config_wrapper is None: + yield + return + + if not isinstance(config_wrapper, ConfigWrapper): + config_wrapper = ConfigWrapper(config_wrapper, check=False) + + self._config_wrapper_stack.append(config_wrapper) + try: + yield + finally: + self._config_wrapper_stack.pop() + + +config_defaults = ConfigDict( + title=None, + str_to_lower=False, + str_to_upper=False, + str_strip_whitespace=False, + str_min_length=0, + str_max_length=None, + # let the model / dataclass decide how to handle it + extra=None, + frozen=False, + populate_by_name=False, + use_enum_values=False, + validate_assignment=False, + arbitrary_types_allowed=False, + from_attributes=False, + loc_by_alias=True, + alias_generator=None, + model_title_generator=None, + field_title_generator=None, + ignored_types=(), + allow_inf_nan=True, + json_schema_extra=None, + strict=False, + revalidate_instances='never', + ser_json_timedelta='iso8601', + ser_json_temporal='iso8601', + val_temporal_unit='infer', + ser_json_bytes='utf8', + val_json_bytes='utf8', + ser_json_inf_nan='null', + validate_default=False, + validate_return=False, + protected_namespaces=('model_validate', 'model_dump'), + hide_input_in_errors=False, + json_encoders=None, + defer_build=False, + schema_generator=None, + plugin_settings=None, + json_schema_serialization_defaults_required=False, + json_schema_mode_override=None, + coerce_numbers_to_str=False, + regex_engine='rust-regex', + validation_error_cause=False, + use_attribute_docstrings=False, + cache_strings=True, + validate_by_alias=True, + validate_by_name=False, + serialize_by_alias=False, + url_preserve_empty_path=False, +) + + +def prepare_config(config: ConfigDict | dict[str, Any] | type[Any] | None) -> ConfigDict: + """Create a `ConfigDict` instance from an existing dict, a class (e.g. old class-based config) or None. + + Args: + config: The input config. + + Returns: + A ConfigDict object created from config. + """ + if config is None: + return ConfigDict() + + if not isinstance(config, dict): + warnings.warn(DEPRECATION_MESSAGE, PydanticDeprecatedSince20, stacklevel=4) + config = {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} + + config_dict = cast(ConfigDict, config) + check_deprecated(config_dict) + return config_dict + + +config_keys = set(ConfigDict.__annotations__.keys()) + + +V2_REMOVED_KEYS = { + 'allow_mutation', + 'error_msg_templates', + 'fields', + 'getter_dict', + 'smart_union', + 'underscore_attrs_are_private', + 'json_loads', + 'json_dumps', + 'copy_on_model_validation', + 'post_init_call', +} +V2_RENAMED_KEYS = { + 'allow_population_by_field_name': 'validate_by_name', + 'anystr_lower': 'str_to_lower', + 'anystr_strip_whitespace': 'str_strip_whitespace', + 'anystr_upper': 'str_to_upper', + 'keep_untouched': 'ignored_types', + 'max_anystr_length': 'str_max_length', + 'min_anystr_length': 'str_min_length', + 'orm_mode': 'from_attributes', + 'schema_extra': 'json_schema_extra', + 'validate_all': 'validate_default', +} + + +def check_deprecated(config_dict: ConfigDict) -> None: + """Check for deprecated config keys and warn the user. + + Args: + config_dict: The input config. + """ + deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys() + deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys() + if deprecated_removed_keys or deprecated_renamed_keys: + renamings = {k: V2_RENAMED_KEYS[k] for k in sorted(deprecated_renamed_keys)} + renamed_bullets = [f'* {k!r} has been renamed to {v!r}' for k, v in renamings.items()] + removed_bullets = [f'* {k!r} has been removed' for k in sorted(deprecated_removed_keys)] + message = '\n'.join(['Valid config keys have changed in V2:'] + renamed_bullets + removed_bullets) + warnings.warn(message, UserWarning) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_core_metadata.py b/backend/venv/Lib/site-packages/pydantic/_internal/_core_metadata.py new file mode 100644 index 0000000..9f2510c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_core_metadata.py @@ -0,0 +1,97 @@ +from __future__ import annotations as _annotations + +from typing import TYPE_CHECKING, Any, TypedDict, cast +from warnings import warn + +if TYPE_CHECKING: + from ..config import JsonDict, JsonSchemaExtraCallable + from ._schema_generation_shared import ( + GetJsonSchemaFunction, + ) + + +class CoreMetadata(TypedDict, total=False): + """A `TypedDict` for holding the metadata dict of the schema. + + Attributes: + pydantic_js_functions: List of JSON schema functions that resolve refs during application. + pydantic_js_annotation_functions: List of JSON schema functions that don't resolve refs during application. + pydantic_js_prefer_positional_arguments: Whether JSON schema generator will + prefer positional over keyword arguments for an 'arguments' schema. + custom validation function. Only applies to before, plain, and wrap validators. + pydantic_js_updates: key / value pair updates to apply to the JSON schema for a type. + pydantic_js_extra: WIP, either key/value pair updates to apply to the JSON schema, or a custom callable. + pydantic_internal_union_tag_key: Used internally by the `Tag` metadata to specify the tag used for a discriminated union. + pydantic_internal_union_discriminator: Used internally to specify the discriminator value for a discriminated union + when the discriminator was applied to a `'definition-ref'` schema, and that reference was missing at the time + of the annotation application. + + TODO: Perhaps we should move this structure to pydantic-core. At the moment, though, + it's easier to iterate on if we leave it in pydantic until we feel there is a semi-stable API. + + TODO: It's unfortunate how functionally oriented JSON schema generation is, especially that which occurs during + the core schema generation process. It's inevitable that we need to store some json schema related information + on core schemas, given that we generate JSON schemas directly from core schemas. That being said, debugging related + issues is quite difficult when JSON schema information is disguised via dynamically defined functions. + """ + + pydantic_js_functions: list[GetJsonSchemaFunction] + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] + pydantic_js_prefer_positional_arguments: bool + pydantic_js_updates: JsonDict + pydantic_js_extra: JsonDict | JsonSchemaExtraCallable + pydantic_internal_union_tag_key: str + pydantic_internal_union_discriminator: str + + +def update_core_metadata( + core_metadata: Any, + /, + *, + pydantic_js_functions: list[GetJsonSchemaFunction] | None = None, + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] | None = None, + pydantic_js_updates: JsonDict | None = None, + pydantic_js_extra: JsonDict | JsonSchemaExtraCallable | None = None, +) -> None: + from ..json_schema import PydanticJsonSchemaWarning + + """Update CoreMetadata instance in place. When we make modifications in this function, they + take effect on the `core_metadata` reference passed in as the first (and only) positional argument. + + First, cast to `CoreMetadata`, then finish with a cast to `dict[str, Any]` for core schema compatibility. + We do this here, instead of before / after each call to this function so that this typing hack + can be easily removed if/when we move `CoreMetadata` to `pydantic-core`. + + For parameter descriptions, see `CoreMetadata` above. + """ + core_metadata = cast(CoreMetadata, core_metadata) + + if pydantic_js_functions: + core_metadata.setdefault('pydantic_js_functions', []).extend(pydantic_js_functions) + + if pydantic_js_annotation_functions: + core_metadata.setdefault('pydantic_js_annotation_functions', []).extend(pydantic_js_annotation_functions) + + if pydantic_js_updates: + if (existing_updates := core_metadata.get('pydantic_js_updates')) is not None: + core_metadata['pydantic_js_updates'] = {**existing_updates, **pydantic_js_updates} + else: + core_metadata['pydantic_js_updates'] = pydantic_js_updates + + if pydantic_js_extra is not None: + existing_pydantic_js_extra = core_metadata.get('pydantic_js_extra') + if existing_pydantic_js_extra is None: + core_metadata['pydantic_js_extra'] = pydantic_js_extra + if isinstance(existing_pydantic_js_extra, dict): + if isinstance(pydantic_js_extra, dict): + core_metadata['pydantic_js_extra'] = {**existing_pydantic_js_extra, **pydantic_js_extra} + if callable(pydantic_js_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported.' + 'The `callable` type is being ignored.' + "If you'd like support for this behavior, please open an issue on pydantic.", + PydanticJsonSchemaWarning, + ) + if callable(existing_pydantic_js_extra): + # if ever there's a case of a callable, we'll just keep the last json schema extra spec + core_metadata['pydantic_js_extra'] = pydantic_js_extra diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_core_utils.py b/backend/venv/Lib/site-packages/pydantic/_internal/_core_utils.py new file mode 100644 index 0000000..caa51e8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_core_utils.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +import inspect +from collections.abc import Mapping, Sequence +from typing import TYPE_CHECKING, Any, Union + +from pydantic_core import CoreSchema, core_schema +from typing_extensions import TypeGuard, get_args, get_origin +from typing_inspection import typing_objects + +from . import _repr +from ._typing_extra import is_generic_alias + +if TYPE_CHECKING: + from rich.console import Console + +AnyFunctionSchema = Union[ + core_schema.AfterValidatorFunctionSchema, + core_schema.BeforeValidatorFunctionSchema, + core_schema.WrapValidatorFunctionSchema, + core_schema.PlainValidatorFunctionSchema, +] + + +FunctionSchemaWithInnerSchema = Union[ + core_schema.AfterValidatorFunctionSchema, + core_schema.BeforeValidatorFunctionSchema, + core_schema.WrapValidatorFunctionSchema, +] + +CoreSchemaField = Union[ + core_schema.ModelField, core_schema.DataclassField, core_schema.TypedDictField, core_schema.ComputedField +] +CoreSchemaOrField = Union[core_schema.CoreSchema, CoreSchemaField] + +_CORE_SCHEMA_FIELD_TYPES = {'typed-dict-field', 'dataclass-field', 'model-field', 'computed-field'} +_FUNCTION_WITH_INNER_SCHEMA_TYPES = {'function-before', 'function-after', 'function-wrap'} +_LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES = {'list', 'set', 'frozenset'} + + +def is_core_schema( + schema: CoreSchemaOrField, +) -> TypeGuard[CoreSchema]: + return schema['type'] not in _CORE_SCHEMA_FIELD_TYPES + + +def is_core_schema_field( + schema: CoreSchemaOrField, +) -> TypeGuard[CoreSchemaField]: + return schema['type'] in _CORE_SCHEMA_FIELD_TYPES + + +def is_function_with_inner_schema( + schema: CoreSchemaOrField, +) -> TypeGuard[FunctionSchemaWithInnerSchema]: + return schema['type'] in _FUNCTION_WITH_INNER_SCHEMA_TYPES + + +def is_list_like_schema_with_items_schema( + schema: CoreSchema, +) -> TypeGuard[core_schema.ListSchema | core_schema.SetSchema | core_schema.FrozenSetSchema]: + return schema['type'] in _LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES + + +def get_type_ref(type_: Any, args_override: tuple[type[Any], ...] | None = None) -> str: + """Produces the ref to be used for this type by pydantic_core's core schemas. + + This `args_override` argument was added for the purpose of creating valid recursive references + when creating generic models without needing to create a concrete class. + """ + origin = get_origin(type_) or type_ + + args = get_args(type_) if is_generic_alias(type_) else (args_override or ()) + generic_metadata = getattr(type_, '__pydantic_generic_metadata__', None) + if generic_metadata: + origin = generic_metadata['origin'] or origin + args = generic_metadata['args'] or args + + module_name = getattr(origin, '__module__', '') + if typing_objects.is_typealiastype(origin): + type_ref = f'{module_name}.{origin.__name__}:{id(origin)}' + else: + try: + qualname = getattr(origin, '__qualname__', f'') + except Exception: + qualname = getattr(origin, '__qualname__', '') + type_ref = f'{module_name}.{qualname}:{id(origin)}' + + arg_refs: list[str] = [] + for arg in args: + if isinstance(arg, str): + # Handle string literals as a special case; we may be able to remove this special handling if we + # wrap them in a ForwardRef at some point. + arg_ref = f'{arg}:str-{id(arg)}' + else: + arg_ref = f'{_repr.display_as_type(arg)}:{id(arg)}' + arg_refs.append(arg_ref) + if arg_refs: + type_ref = f'{type_ref}[{",".join(arg_refs)}]' + return type_ref + + +def get_ref(s: core_schema.CoreSchema) -> None | str: + """Get the ref from the schema if it has one. + This exists just for type checking to work correctly. + """ + return s.get('ref', None) + + +def _clean_schema_for_pretty_print(obj: Any, strip_metadata: bool = True) -> Any: # pragma: no cover + """A utility function to remove irrelevant information from a core schema.""" + if isinstance(obj, Mapping): + new_dct = {} + for k, v in obj.items(): + if k == 'metadata' and strip_metadata: + new_metadata = {} + + for meta_k, meta_v in v.items(): + if meta_k in ('pydantic_js_functions', 'pydantic_js_annotation_functions'): + new_metadata['js_metadata'] = '' + else: + new_metadata[meta_k] = _clean_schema_for_pretty_print(meta_v, strip_metadata=strip_metadata) + + if list(new_metadata.keys()) == ['js_metadata']: + new_metadata = {''} + + new_dct[k] = new_metadata + # Remove some defaults: + elif k in ('custom_init', 'root_model') and not v: + continue + else: + new_dct[k] = _clean_schema_for_pretty_print(v, strip_metadata=strip_metadata) + + return new_dct + elif isinstance(obj, Sequence) and not isinstance(obj, str): + return [_clean_schema_for_pretty_print(v, strip_metadata=strip_metadata) for v in obj] + else: + return obj + + +def pretty_print_core_schema( + val: Any, + *, + console: Console | None = None, + max_depth: int | None = None, + strip_metadata: bool = True, +) -> None: # pragma: no cover + """Pretty-print a core schema using the `rich` library. + + Args: + val: The core schema to print, or a Pydantic model/dataclass/type adapter + (in which case the cached core schema is fetched and printed). + console: A rich console to use when printing. Defaults to the global rich console instance. + max_depth: The number of nesting levels which may be printed. + strip_metadata: Whether to strip metadata in the output. If `True` any known core metadata + attributes will be stripped (but custom attributes are kept). Defaults to `True`. + """ + # lazy import: + from rich.pretty import pprint + + # circ. imports: + from pydantic import BaseModel, TypeAdapter + from pydantic.dataclasses import is_pydantic_dataclass + + if (inspect.isclass(val) and issubclass(val, BaseModel)) or is_pydantic_dataclass(val): + val = val.__pydantic_core_schema__ + if isinstance(val, TypeAdapter): + val = val.core_schema + cleaned_schema = _clean_schema_for_pretty_print(val, strip_metadata=strip_metadata) + + pprint(cleaned_schema, console=console, max_depth=max_depth) + + +pps = pretty_print_core_schema diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_dataclasses.py b/backend/venv/Lib/site-packages/pydantic/_internal/_dataclasses.py new file mode 100644 index 0000000..869286b --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_dataclasses.py @@ -0,0 +1,315 @@ +"""Private logic for creating pydantic dataclasses.""" + +from __future__ import annotations as _annotations + +import copy +import dataclasses +import sys +import warnings +from collections.abc import Generator +from contextlib import contextmanager +from functools import partial +from typing import TYPE_CHECKING, Any, ClassVar, Protocol, cast + +from pydantic_core import ( + ArgsKwargs, + SchemaSerializer, + SchemaValidator, + core_schema, +) +from typing_extensions import TypeAlias, TypeIs + +from ..errors import PydanticUndefinedAnnotation +from ..fields import FieldInfo +from ..plugin._schema_validator import PluggableSchemaValidator, create_schema_validator +from ..warnings import PydanticDeprecatedSince20 +from . import _config, _decorators +from ._fields import collect_dataclass_fields +from ._generate_schema import GenerateSchema, InvalidSchemaError +from ._generics import get_standard_typevars_map +from ._mock_val_ser import set_dataclass_mocks +from ._namespace_utils import NsResolver +from ._signature import generate_pydantic_signature +from ._utils import LazyClassAttribute + +if TYPE_CHECKING: + from _typeshed import DataclassInstance as StandardDataclass + + from ..config import ConfigDict + + class PydanticDataclass(StandardDataclass, Protocol): + """A protocol containing attributes only available once a class has been decorated as a Pydantic dataclass. + + Attributes: + __pydantic_config__: Pydantic-specific configuration settings for the dataclass. + __pydantic_complete__: Whether dataclass building is completed, or if there are still undefined fields. + __pydantic_core_schema__: The pydantic-core schema used to build the SchemaValidator and SchemaSerializer. + __pydantic_decorators__: Metadata containing the decorators defined on the dataclass. + __pydantic_fields__: Metadata about the fields defined on the dataclass. + __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the dataclass. + __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the dataclass. + """ + + __pydantic_config__: ClassVar[ConfigDict] + __pydantic_complete__: ClassVar[bool] + __pydantic_core_schema__: ClassVar[core_schema.CoreSchema] + __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos] + __pydantic_fields__: ClassVar[dict[str, FieldInfo]] + __pydantic_serializer__: ClassVar[SchemaSerializer] + __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] + + @classmethod + def __pydantic_fields_complete__(cls) -> bool: ... + + +def set_dataclass_fields( + cls: type[StandardDataclass], + config_wrapper: _config.ConfigWrapper, + ns_resolver: NsResolver | None = None, +) -> None: + """Collect and set `cls.__pydantic_fields__`. + + Args: + cls: The class. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting dataclass annotations. + """ + typevars_map = get_standard_typevars_map(cls) + fields = collect_dataclass_fields( + cls, ns_resolver=ns_resolver, typevars_map=typevars_map, config_wrapper=config_wrapper + ) + + cls.__pydantic_fields__ = fields # type: ignore + + +def complete_dataclass( + cls: type[Any], + config_wrapper: _config.ConfigWrapper, + *, + raise_errors: bool = True, + ns_resolver: NsResolver | None = None, + _force_build: bool = False, +) -> bool: + """Finish building a pydantic dataclass. + + This logic is called on a class which has already been wrapped in `dataclasses.dataclass()`. + + This is somewhat analogous to `pydantic._internal._model_construction.complete_model_class`. + + Args: + cls: The class. + config_wrapper: The config wrapper instance. + raise_errors: Whether to raise errors, defaults to `True`. + ns_resolver: The namespace resolver instance to use when collecting dataclass fields + and during schema building. + _force_build: Whether to force building the dataclass, no matter if + [`defer_build`][pydantic.config.ConfigDict.defer_build] is set. + + Returns: + `True` if building a pydantic dataclass is successfully completed, `False` otherwise. + + Raises: + PydanticUndefinedAnnotation: If `raise_error` is `True` and there is an undefined annotations. + """ + original_init = cls.__init__ + + # dataclass.__init__ must be defined here so its `__qualname__` can be changed since functions can't be copied, + # and so that the mock validator is used if building was deferred: + def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) -> None: + __tracebackhide__ = True + s = __dataclass_self__ + s.__pydantic_validator__.validate_python(ArgsKwargs(args, kwargs), self_instance=s) + + __init__.__qualname__ = f'{cls.__qualname__}.__init__' + + cls.__init__ = __init__ # type: ignore + cls.__pydantic_config__ = config_wrapper.config_dict # type: ignore + + set_dataclass_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) + + if not _force_build and config_wrapper.defer_build: + set_dataclass_mocks(cls) + return False + + if hasattr(cls, '__post_init_post_parse__'): + warnings.warn( + 'Support for `__post_init_post_parse__` has been dropped, the method will not be called', + PydanticDeprecatedSince20, + ) + + typevars_map = get_standard_typevars_map(cls) + gen_schema = GenerateSchema( + config_wrapper, + ns_resolver=ns_resolver, + typevars_map=typevars_map, + ) + + # set __signature__ attr only for the class, but not for its instances + # (because instances can define `__call__`, and `inspect.signature` shouldn't + # use the `__signature__` attribute and instead generate from `__call__`). + cls.__signature__ = LazyClassAttribute( + '__signature__', + partial( + generate_pydantic_signature, + # It's important that we reference the `original_init` here, + # as it is the one synthesized by the stdlib `dataclass` module: + init=original_init, + fields=cls.__pydantic_fields__, # type: ignore + validate_by_name=config_wrapper.validate_by_name, + extra=config_wrapper.extra, + is_dataclass=True, + ), + ) + + try: + schema = gen_schema.generate_schema(cls) + except PydanticUndefinedAnnotation as e: + if raise_errors: + raise + set_dataclass_mocks(cls, f'`{e.name}`') + return False + + core_config = config_wrapper.core_config(title=cls.__name__) + + try: + schema = gen_schema.clean_schema(schema) + except InvalidSchemaError: + set_dataclass_mocks(cls) + return False + + # We are about to set all the remaining required properties expected for this cast; + # __pydantic_decorators__ and __pydantic_fields__ should already be set + cls = cast('type[PydanticDataclass]', cls) + + cls.__pydantic_core_schema__ = schema + cls.__pydantic_validator__ = create_schema_validator( + schema, cls, cls.__module__, cls.__qualname__, 'dataclass', core_config, config_wrapper.plugin_settings + ) + cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) + cls.__pydantic_complete__ = True + return True + + +def is_stdlib_dataclass(cls: type[Any], /) -> TypeIs[type[StandardDataclass]]: + """Returns `True` if the class is a stdlib dataclass and *not* a Pydantic dataclass. + + Unlike the stdlib `dataclasses.is_dataclass()` function, this does *not* include subclasses + of a dataclass that are themselves not dataclasses. + + Args: + cls: The class. + + Returns: + `True` if the class is a stdlib dataclass, `False` otherwise. + """ + return '__dataclass_fields__' in cls.__dict__ and not hasattr(cls, '__pydantic_validator__') + + +def as_dataclass_field(pydantic_field: FieldInfo) -> dataclasses.Field[Any]: + field_args: dict[str, Any] = {'default': pydantic_field} + + # Needed because if `doc` is set, the dataclass slots will be a dict (field name -> doc) instead of a tuple: + if sys.version_info >= (3, 14) and pydantic_field.description is not None: + field_args['doc'] = pydantic_field.description + + # Needed as the stdlib dataclass module processes kw_only in a specific way during class construction: + if sys.version_info >= (3, 10) and pydantic_field.kw_only: + field_args['kw_only'] = True + + # Needed as the stdlib dataclass modules generates `__repr__()` during class construction: + if pydantic_field.repr is not True: + field_args['repr'] = pydantic_field.repr + + return dataclasses.field(**field_args) + + +DcFields: TypeAlias = dict[str, dataclasses.Field[Any]] + + +@contextmanager +def patch_base_fields(cls: type[Any]) -> Generator[None]: + """Temporarily patch the stdlib dataclasses bases of `cls` if the Pydantic `Field()` function is used. + + When creating a Pydantic dataclass, it is possible to inherit from stdlib dataclasses, where + the Pydantic `Field()` function is used. To create this Pydantic dataclass, we first apply + the stdlib `@dataclass` decorator on it. During the construction of the stdlib dataclass, + the `kw_only` and `repr` field arguments need to be understood by the stdlib *during* the + dataclass construction. To do so, we temporarily patch the fields dictionary of the affected + bases. + + For instance, with the following example: + + ```python {test="skip" lint="skip"} + import dataclasses as stdlib_dc + + import pydantic + import pydantic.dataclasses as pydantic_dc + + @stdlib_dc.dataclass + class A: + a: int = pydantic.Field(repr=False) + + # Notice that the `repr` attribute of the dataclass field is `True`: + A.__dataclass_fields__['a'] + #> dataclass.Field(default=FieldInfo(repr=False), repr=True, ...) + + @pydantic_dc.dataclass + class B(A): + b: int = pydantic.Field(repr=False) + ``` + + When passing `B` to the stdlib `@dataclass` decorator, it will look for fields in the parent classes + and reuse them directly. When this context manager is active, `A` will be temporarily patched to be + equivalent to: + + ```python {test="skip" lint="skip"} + @stdlib_dc.dataclass + class A: + a: int = stdlib_dc.field(default=Field(repr=False), repr=False) + ``` + + !!! note + This is only applied to the bases of `cls`, and not `cls` itself. The reason is that the Pydantic + dataclass decorator "owns" `cls` (in the previous example, `B`). As such, we instead modify the fields + directly (in the previous example, we simply do `setattr(B, 'b', as_dataclass_field(pydantic_field))`). + + !!! note + This approach is far from ideal, and can probably be the source of unwanted side effects/race conditions. + The previous implemented approach was mutating the `__annotations__` dict of `cls`, which is no longer a + safe operation in Python 3.14+, and resulted in unexpected behavior with field ordering anyway. + """ + # A list of two-tuples, the first element being a reference to the + # dataclass fields dictionary, the second element being a mapping between + # the field names that were modified, and their original `Field`: + original_fields_list: list[tuple[DcFields, DcFields]] = [] + + for base in cls.__mro__[1:]: + dc_fields: dict[str, dataclasses.Field[Any]] = base.__dict__.get('__dataclass_fields__', {}) + dc_fields_with_pydantic_field_defaults = { + field_name: field + for field_name, field in dc_fields.items() + if isinstance(field.default, FieldInfo) + # Only do the patching if one of the affected attributes is set: + and (field.default.description is not None or field.default.kw_only or field.default.repr is not True) + } + if dc_fields_with_pydantic_field_defaults: + original_fields_list.append((dc_fields, dc_fields_with_pydantic_field_defaults)) + for field_name, field in dc_fields_with_pydantic_field_defaults.items(): + default = cast(FieldInfo, field.default) + # `dataclasses.Field` isn't documented as working with `copy.copy()`. + # It is a class with `__slots__`, so should work (and we hope for the best): + new_dc_field = copy.copy(field) + # For base fields, no need to set `doc` from `FieldInfo.description`, this is only relevant + # for the class under construction and handled in `as_dataclass_field()`. + if sys.version_info >= (3, 10) and default.kw_only: + new_dc_field.kw_only = True + if default.repr is not True: + new_dc_field.repr = default.repr + dc_fields[field_name] = new_dc_field + + try: + yield + finally: + for fields, original_fields in original_fields_list: + for field_name, original_field in original_fields.items(): + fields[field_name] = original_field diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_decorators.py b/backend/venv/Lib/site-packages/pydantic/_internal/_decorators.py new file mode 100644 index 0000000..2a43bbb --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_decorators.py @@ -0,0 +1,858 @@ +"""Logic related to validators applied to models etc. via the `@field_validator` and `@model_validator` decorators.""" + +from __future__ import annotations as _annotations + +import sys +import types +from collections import deque +from collections.abc import Iterable +from dataclasses import dataclass, field +from functools import cached_property, partial, partialmethod +from inspect import Parameter, Signature, isdatadescriptor, ismethoddescriptor, signature +from itertools import islice +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, Literal, TypeVar, Union + +from pydantic_core import PydanticUndefined, PydanticUndefinedType, core_schema +from typing_extensions import TypeAlias, is_typeddict + +from ..errors import PydanticUserError +from ._core_utils import get_type_ref +from ._internal_dataclass import slots_true +from ._namespace_utils import GlobalsNamespace, MappingNamespace +from ._typing_extra import get_function_type_hints +from ._utils import can_be_positional + +if TYPE_CHECKING: + from ..fields import ComputedFieldInfo + from ..functional_validators import FieldValidatorModes + from ._config import ConfigWrapper + + +@dataclass(**slots_true) +class ValidatorDecoratorInfo: + """A container for data from `@validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@validator'. + fields: A tuple of field names the validator should be called on. + mode: The proposed validator mode. + each_item: For complex objects (sets, lists etc.) whether to validate individual + elements rather than the whole object. + always: Whether this method and other validators should be called even if the value is missing. + check_fields: Whether to check that the fields actually exist on the model. + """ + + decorator_repr: ClassVar[str] = '@validator' + + fields: tuple[str, ...] + mode: Literal['before', 'after'] + each_item: bool + always: bool + check_fields: bool | None + + +@dataclass(**slots_true) +class FieldValidatorDecoratorInfo: + """A container for data from `@field_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@field_validator'. + fields: A tuple of field names the validator should be called on. + mode: The proposed validator mode. + check_fields: Whether to check that the fields actually exist on the model. + json_schema_input_type: The input type of the function. This is only used to generate + the appropriate JSON Schema (in validation mode) and can only specified + when `mode` is either `'before'`, `'plain'` or `'wrap'`. + """ + + decorator_repr: ClassVar[str] = '@field_validator' + + fields: tuple[str, ...] + mode: FieldValidatorModes + check_fields: bool | None + json_schema_input_type: Any + + +@dataclass(**slots_true) +class RootValidatorDecoratorInfo: + """A container for data from `@root_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@root_validator'. + mode: The proposed validator mode. + """ + + decorator_repr: ClassVar[str] = '@root_validator' + mode: Literal['before', 'after'] + + +@dataclass(**slots_true) +class FieldSerializerDecoratorInfo: + """A container for data from `@field_serializer` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@field_serializer'. + fields: A tuple of field names the serializer should be called on. + mode: The proposed serializer mode. + return_type: The type of the serializer's return value. + when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`, + and `'json-unless-none'`. + check_fields: Whether to check that the fields actually exist on the model. + """ + + decorator_repr: ClassVar[str] = '@field_serializer' + fields: tuple[str, ...] + mode: Literal['plain', 'wrap'] + return_type: Any + when_used: core_schema.WhenUsed + check_fields: bool | None + + +@dataclass(**slots_true) +class ModelSerializerDecoratorInfo: + """A container for data from `@model_serializer` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@model_serializer'. + mode: The proposed serializer mode. + return_type: The type of the serializer's return value. + when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`, + and `'json-unless-none'`. + """ + + decorator_repr: ClassVar[str] = '@model_serializer' + mode: Literal['plain', 'wrap'] + return_type: Any + when_used: core_schema.WhenUsed + + +@dataclass(**slots_true) +class ModelValidatorDecoratorInfo: + """A container for data from `@model_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@model_validator'. + mode: The proposed serializer mode. + """ + + decorator_repr: ClassVar[str] = '@model_validator' + mode: Literal['wrap', 'before', 'after'] + + +DecoratorInfo: TypeAlias = """Union[ + ValidatorDecoratorInfo, + FieldValidatorDecoratorInfo, + RootValidatorDecoratorInfo, + FieldSerializerDecoratorInfo, + ModelSerializerDecoratorInfo, + ModelValidatorDecoratorInfo, + ComputedFieldInfo, +]""" + +ReturnType = TypeVar('ReturnType') +DecoratedType: TypeAlias = ( + 'Union[classmethod[Any, Any, ReturnType], staticmethod[Any, ReturnType], Callable[..., ReturnType], property]' +) + + +@dataclass # can't use slots here since we set attributes on `__post_init__` +class PydanticDescriptorProxy(Generic[ReturnType]): + """Wrap a classmethod, staticmethod, property or unbound function + and act as a descriptor that allows us to detect decorated items + from the class' attributes. + + This class' __get__ returns the wrapped item's __get__ result, + which makes it transparent for classmethods and staticmethods. + + Attributes: + wrapped: The decorator that has to be wrapped. + decorator_info: The decorator info. + shim: A wrapper function to wrap V1 style function. + """ + + wrapped: DecoratedType[ReturnType] + decorator_info: DecoratorInfo + shim: Callable[[Callable[..., Any]], Callable[..., Any]] | None = None + + def __post_init__(self): + for attr in 'setter', 'deleter': + if hasattr(self.wrapped, attr): + f = partial(self._call_wrapped_attr, name=attr) + setattr(self, attr, f) + + def _call_wrapped_attr(self, func: Callable[[Any], None], *, name: str) -> PydanticDescriptorProxy[ReturnType]: + self.wrapped = getattr(self.wrapped, name)(func) + if isinstance(self.wrapped, property): + # update ComputedFieldInfo.wrapped_property + from ..fields import ComputedFieldInfo + + if isinstance(self.decorator_info, ComputedFieldInfo): + self.decorator_info.wrapped_property = self.wrapped + return self + + def __get__(self, obj: object | None, obj_type: type[object] | None = None) -> PydanticDescriptorProxy[ReturnType]: + try: + return self.wrapped.__get__(obj, obj_type) # pyright: ignore[reportReturnType] + except AttributeError: + # not a descriptor, e.g. a partial object + return self.wrapped # type: ignore[return-value] + + def __set_name__(self, instance: Any, name: str) -> None: + if hasattr(self.wrapped, '__set_name__'): + self.wrapped.__set_name__(instance, name) # pyright: ignore[reportFunctionMemberAccess] + + def __getattr__(self, name: str, /) -> Any: + """Forward checks for __isabstractmethod__ and such.""" + return getattr(self.wrapped, name) + + +DecoratorInfoType = TypeVar('DecoratorInfoType', bound=DecoratorInfo) + + +@dataclass(**slots_true) +class Decorator(Generic[DecoratorInfoType]): + """A generic container class to join together the decorator metadata + (metadata from decorator itself, which we have when the + decorator is called but not when we are building the core-schema) + and the bound function (which we have after the class itself is created). + + Attributes: + cls_ref: The class ref. + cls_var_name: The decorated function name. + func: The decorated function. + shim: A wrapper function to wrap V1 style function. + info: The decorator info. + """ + + cls_ref: str + cls_var_name: str + func: Callable[..., Any] + shim: Callable[[Any], Any] | None + info: DecoratorInfoType + + @staticmethod + def build( + cls_: Any, + *, + cls_var_name: str, + shim: Callable[[Any], Any] | None, + info: DecoratorInfoType, + ) -> Decorator[DecoratorInfoType]: + """Build a new decorator. + + Args: + cls_: The class. + cls_var_name: The decorated function name. + shim: A wrapper function to wrap V1 style function. + info: The decorator info. + + Returns: + The new decorator instance. + """ + func = get_attribute_from_bases(cls_, cls_var_name) + if shim is not None: + func = shim(func) + func = unwrap_wrapped_function(func, unwrap_partial=False) + if not callable(func): + # This branch will get hit for classmethod properties + attribute = get_attribute_from_base_dicts(cls_, cls_var_name) # prevents the binding call to `__get__` + if isinstance(attribute, PydanticDescriptorProxy): + func = unwrap_wrapped_function(attribute.wrapped) + return Decorator( + cls_ref=get_type_ref(cls_), + cls_var_name=cls_var_name, + func=func, + shim=shim, + info=info, + ) + + def bind_to_cls(self, cls: Any) -> Decorator[DecoratorInfoType]: + """Bind the decorator to a class. + + Args: + cls: the class. + + Returns: + The new decorator instance. + """ + return self.build( + cls, + cls_var_name=self.cls_var_name, + shim=self.shim, + info=self.info, + ) + + +def get_bases(tp: type[Any]) -> tuple[type[Any], ...]: + """Get the base classes of a class or typeddict. + + Args: + tp: The type or class to get the bases. + + Returns: + The base classes. + """ + if is_typeddict(tp): + return tp.__orig_bases__ # type: ignore + try: + return tp.__bases__ + except AttributeError: + return () + + +def mro(tp: type[Any]) -> tuple[type[Any], ...]: + """Calculate the Method Resolution Order of bases using the C3 algorithm. + + See https://www.python.org/download/releases/2.3/mro/ + """ + # try to use the existing mro, for performance mainly + # but also because it helps verify the implementation below + if not is_typeddict(tp): + try: + return tp.__mro__ + except AttributeError: + # GenericAlias and some other cases + pass + + bases = get_bases(tp) + return (tp,) + mro_for_bases(bases) + + +def mro_for_bases(bases: tuple[type[Any], ...]) -> tuple[type[Any], ...]: + def merge_seqs(seqs: list[deque[type[Any]]]) -> Iterable[type[Any]]: + while True: + non_empty = [seq for seq in seqs if seq] + if not non_empty: + # Nothing left to process, we're done. + return + candidate: type[Any] | None = None + for seq in non_empty: # Find merge candidates among seq heads. + candidate = seq[0] + not_head = [s for s in non_empty if candidate in islice(s, 1, None)] + if not_head: + # Reject the candidate. + candidate = None + else: + break + if not candidate: + raise TypeError('Inconsistent hierarchy, no C3 MRO is possible') + yield candidate + for seq in non_empty: + # Remove candidate. + if seq[0] == candidate: + seq.popleft() + + seqs = [deque(mro(base)) for base in bases] + [deque(bases)] + return tuple(merge_seqs(seqs)) + + +_sentinel = object() + + +def get_attribute_from_bases(tp: type[Any] | tuple[type[Any], ...], name: str) -> Any: + """Get the attribute from the next class in the MRO that has it, + aiming to simulate calling the method on the actual class. + + The reason for iterating over the mro instead of just getting + the attribute (which would do that for us) is to support TypedDict, + which lacks a real __mro__, but can have a virtual one constructed + from its bases (as done here). + + Args: + tp: The type or class to search for the attribute. If a tuple, this is treated as a set of base classes. + name: The name of the attribute to retrieve. + + Returns: + Any: The attribute value, if found. + + Raises: + AttributeError: If the attribute is not found in any class in the MRO. + """ + if isinstance(tp, tuple): + for base in mro_for_bases(tp): + attribute = base.__dict__.get(name, _sentinel) + if attribute is not _sentinel: + attribute_get = getattr(attribute, '__get__', None) + if attribute_get is not None: + return attribute_get(None, tp) + return attribute + raise AttributeError(f'{name} not found in {tp}') + else: + try: + return getattr(tp, name) + except AttributeError: + return get_attribute_from_bases(mro(tp), name) + + +def get_attribute_from_base_dicts(tp: type[Any], name: str) -> Any: + """Get an attribute out of the `__dict__` following the MRO. + This prevents the call to `__get__` on the descriptor, and allows + us to get the original function for classmethod properties. + + Args: + tp: The type or class to search for the attribute. + name: The name of the attribute to retrieve. + + Returns: + Any: The attribute value, if found. + + Raises: + KeyError: If the attribute is not found in any class's `__dict__` in the MRO. + """ + for base in reversed(mro(tp)): + if name in base.__dict__: + return base.__dict__[name] + return tp.__dict__[name] # raise the error + + +@dataclass(**slots_true) +class DecoratorInfos: + """Mapping of name in the class namespace to decorator info. + + note that the name in the class namespace is the function or attribute name + not the field name! + """ + + validators: dict[str, Decorator[ValidatorDecoratorInfo]] = field(default_factory=dict) + field_validators: dict[str, Decorator[FieldValidatorDecoratorInfo]] = field(default_factory=dict) + root_validators: dict[str, Decorator[RootValidatorDecoratorInfo]] = field(default_factory=dict) + field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]] = field(default_factory=dict) + model_serializers: dict[str, Decorator[ModelSerializerDecoratorInfo]] = field(default_factory=dict) + model_validators: dict[str, Decorator[ModelValidatorDecoratorInfo]] = field(default_factory=dict) + computed_fields: dict[str, Decorator[ComputedFieldInfo]] = field(default_factory=dict) + + @staticmethod + def build(model_dc: type[Any]) -> DecoratorInfos: # noqa: C901 (ignore complexity) + """We want to collect all DecFunc instances that exist as + attributes in the namespace of the class (a BaseModel or dataclass) + that called us + But we want to collect these in the order of the bases + So instead of getting them all from the leaf class (the class that called us), + we traverse the bases from root (the oldest ancestor class) to leaf + and collect all of the instances as we go, taking care to replace + any duplicate ones with the last one we see to mimic how function overriding + works with inheritance. + If we do replace any functions we put the replacement into the position + the replaced function was in; that is, we maintain the order. + """ + # reminder: dicts are ordered and replacement does not alter the order + res = DecoratorInfos() + for base in reversed(mro(model_dc)[1:]): + existing: DecoratorInfos | None = base.__dict__.get('__pydantic_decorators__') + if existing is None: + existing = DecoratorInfos.build(base) + res.validators.update({k: v.bind_to_cls(model_dc) for k, v in existing.validators.items()}) + res.field_validators.update({k: v.bind_to_cls(model_dc) for k, v in existing.field_validators.items()}) + res.root_validators.update({k: v.bind_to_cls(model_dc) for k, v in existing.root_validators.items()}) + res.field_serializers.update({k: v.bind_to_cls(model_dc) for k, v in existing.field_serializers.items()}) + res.model_serializers.update({k: v.bind_to_cls(model_dc) for k, v in existing.model_serializers.items()}) + res.model_validators.update({k: v.bind_to_cls(model_dc) for k, v in existing.model_validators.items()}) + res.computed_fields.update({k: v.bind_to_cls(model_dc) for k, v in existing.computed_fields.items()}) + + to_replace: list[tuple[str, Any]] = [] + + for var_name, var_value in vars(model_dc).items(): + if isinstance(var_value, PydanticDescriptorProxy): + info = var_value.decorator_info + if isinstance(info, ValidatorDecoratorInfo): + res.validators[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, FieldValidatorDecoratorInfo): + res.field_validators[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, RootValidatorDecoratorInfo): + res.root_validators[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, FieldSerializerDecoratorInfo): + # check whether a serializer function is already registered for fields + for field_serializer_decorator in res.field_serializers.values(): + # check that each field has at most one serializer function. + # serializer functions for the same field in subclasses are allowed, + # and are treated as overrides + if field_serializer_decorator.cls_var_name == var_name: + continue + for f in info.fields: + if f in field_serializer_decorator.info.fields: + raise PydanticUserError( + 'Multiple field serializer functions were defined ' + f'for field {f!r}, this is not allowed.', + code='multiple-field-serializers', + ) + res.field_serializers[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, ModelValidatorDecoratorInfo): + res.model_validators[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, ModelSerializerDecoratorInfo): + res.model_serializers[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=var_value.shim, info=info + ) + else: + from ..fields import ComputedFieldInfo + + isinstance(var_value, ComputedFieldInfo) + res.computed_fields[var_name] = Decorator.build( + model_dc, cls_var_name=var_name, shim=None, info=info + ) + to_replace.append((var_name, var_value.wrapped)) + if to_replace: + # If we can save `__pydantic_decorators__` on the class we'll be able to check for it above + # so then we don't need to re-process the type, which means we can discard our descriptor wrappers + # and replace them with the thing they are wrapping (see the other setattr call below) + # which allows validator class methods to also function as regular class methods + model_dc.__pydantic_decorators__ = res + for name, value in to_replace: + setattr(model_dc, name, value) + return res + + def update_from_config(self, config_wrapper: ConfigWrapper) -> None: + """Update the decorator infos from the configuration of the class they are attached to.""" + for name, computed_field_dec in self.computed_fields.items(): + computed_field_dec.info._update_from_config(config_wrapper, name) + + +def inspect_validator( + validator: Callable[..., Any], *, mode: FieldValidatorModes, type: Literal['field', 'model'] +) -> bool: + """Look at a field or model validator function and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + validator: The validator function to inspect. + mode: The proposed validator mode. + type: The type of validator, either 'field' or 'model'. + + Returns: + Whether the validator takes an info argument. + """ + try: + sig = _signature_no_eval(validator) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present: + return False + n_positional = count_positional_required_params(sig) + if mode == 'wrap': + if n_positional == 3: + return True + elif n_positional == 2: + return False + else: + assert mode in {'before', 'after', 'plain'}, f"invalid mode: {mode!r}, expected 'before', 'after' or 'plain" + if n_positional == 2: + return True + elif n_positional == 1: + return False + + raise PydanticUserError( + f'Unrecognized {type} validator function signature for {validator} with `mode={mode}`: {sig}', + code='validator-signature', + ) + + +def inspect_field_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> tuple[bool, bool]: + """Look at a field serializer function and determine if it is a field serializer, + and whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to inspect. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + Tuple of (is_field_serializer, info_arg). + """ + try: + sig = _signature_no_eval(serializer) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present and this is not a method: + return (False, False) + + first = next(iter(sig.parameters.values()), None) + is_field_serializer = first is not None and first.name == 'self' + + n_positional = count_positional_required_params(sig) + if is_field_serializer: + # -1 to correct for self parameter + info_arg = _serializer_info_arg(mode, n_positional - 1) + else: + info_arg = _serializer_info_arg(mode, n_positional) + + if info_arg is None: + raise PydanticUserError( + f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='field-serializer-signature', + ) + + return is_field_serializer, info_arg + + +def inspect_annotated_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool: + """Look at a serializer function used via `Annotated` and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to check. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + info_arg + """ + try: + sig = _signature_no_eval(serializer) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present: + return False + info_arg = _serializer_info_arg(mode, count_positional_required_params(sig)) + if info_arg is None: + raise PydanticUserError( + f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='field-serializer-signature', + ) + else: + return info_arg + + +def inspect_model_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool: + """Look at a model serializer function and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to check. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + `info_arg` - whether the function expects an info argument. + """ + if isinstance(serializer, (staticmethod, classmethod)) or not is_instance_method_from_sig(serializer): + raise PydanticUserError( + '`@model_serializer` must be applied to instance methods', code='model-serializer-instance-method' + ) + + sig = _signature_no_eval(serializer) + info_arg = _serializer_info_arg(mode, count_positional_required_params(sig)) + if info_arg is None: + raise PydanticUserError( + f'Unrecognized model_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='model-serializer-signature', + ) + else: + return info_arg + + +def _serializer_info_arg(mode: Literal['plain', 'wrap'], n_positional: int) -> bool | None: + if mode == 'plain': + if n_positional == 1: + # (input_value: Any, /) -> Any + return False + elif n_positional == 2: + # (model: Any, input_value: Any, /) -> Any + return True + else: + assert mode == 'wrap', f"invalid mode: {mode!r}, expected 'plain' or 'wrap'" + if n_positional == 2: + # (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any + return False + elif n_positional == 3: + # (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any + return True + + return None + + +AnyDecoratorCallable: TypeAlias = ( + 'Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any], Callable[..., Any]]' +) + + +def is_instance_method_from_sig(function: AnyDecoratorCallable) -> bool: + """Whether the function is an instance method. + + It will consider a function as instance method if the first parameter of + function is `self`. + + Args: + function: The function to check. + + Returns: + `True` if the function is an instance method, `False` otherwise. + """ + sig = _signature_no_eval(unwrap_wrapped_function(function)) + first = next(iter(sig.parameters.values()), None) + if first and first.name == 'self': + return True + return False + + +def ensure_classmethod_based_on_signature(function: AnyDecoratorCallable) -> Any: + """Apply the `@classmethod` decorator on the function. + + Args: + function: The function to apply the decorator on. + + Return: + The `@classmethod` decorator applied function. + """ + if not isinstance( + unwrap_wrapped_function(function, unwrap_class_static_method=False), classmethod + ) and _is_classmethod_from_sig(function): + return classmethod(function) # type: ignore[arg-type] + return function + + +def _is_classmethod_from_sig(function: AnyDecoratorCallable) -> bool: + sig = _signature_no_eval(unwrap_wrapped_function(function)) + first = next(iter(sig.parameters.values()), None) + if first and first.name == 'cls': + return True + return False + + +def unwrap_wrapped_function( + func: Any, + *, + unwrap_partial: bool = True, + unwrap_class_static_method: bool = True, +) -> Any: + """Recursively unwraps a wrapped function until the underlying function is reached. + This handles property, functools.partial, functools.partialmethod, staticmethod, and classmethod. + + Args: + func: The function to unwrap. + unwrap_partial: If True (default), unwrap partial and partialmethod decorators. + unwrap_class_static_method: If True (default), also unwrap classmethod and staticmethod + decorators. If False, only unwrap partial and partialmethod decorators. + + Returns: + The underlying function of the wrapped function. + """ + # Define the types we want to check against as a single tuple. + unwrap_types = ( + (property, cached_property) + + ((partial, partialmethod) if unwrap_partial else ()) + + ((staticmethod, classmethod) if unwrap_class_static_method else ()) + ) + + while isinstance(func, unwrap_types): + if unwrap_class_static_method and isinstance(func, (classmethod, staticmethod)): + func = func.__func__ + elif isinstance(func, (partial, partialmethod)): + func = func.func + elif isinstance(func, property): + func = func.fget # arbitrary choice, convenient for computed fields + else: + # Make coverage happy as it can only get here in the last possible case + assert isinstance(func, cached_property) + func = func.func # type: ignore + + return func + + +_function_like = ( + partial, + partialmethod, + types.FunctionType, + types.BuiltinFunctionType, + types.MethodType, + types.WrapperDescriptorType, + types.MethodWrapperType, + types.MemberDescriptorType, +) + + +def get_callable_return_type( + callable_obj: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any | PydanticUndefinedType: + """Get the callable return type. + + Args: + callable_obj: The callable to analyze. + globalns: The globals namespace to use during type annotation evaluation. + localns: The locals namespace to use during type annotation evaluation. + + Returns: + The function return type. + """ + if isinstance(callable_obj, type): + # types are callables, and we assume the return type + # is the type itself (e.g. `int()` results in an instance of `int`). + return callable_obj + + if not isinstance(callable_obj, _function_like): + call_func = getattr(type(callable_obj), '__call__', None) # noqa: B004 + if call_func is not None: + callable_obj = call_func + + hints = get_function_type_hints( + unwrap_wrapped_function(callable_obj), + include_keys={'return'}, + globalns=globalns, + localns=localns, + ) + return hints.get('return', PydanticUndefined) + + +def count_positional_required_params(sig: Signature) -> int: + """Get the number of positional (required) arguments of a signature. + + This function should only be used to inspect signatures of validation and serialization functions. + The first argument (the value being serialized or validated) is counted as a required argument + even if a default value exists. + + Returns: + The number of positional arguments of a signature. + """ + parameters = list(sig.parameters.values()) + return sum( + 1 + for param in parameters + if can_be_positional(param) + # First argument is the value being validated/serialized, and can have a default value + # (e.g. `float`, which has signature `(x=0, /)`). We assume other parameters (the info arg + # for instance) should be required, and thus without any default value. + and (param.default is Parameter.empty or param is parameters[0]) + ) + + +def ensure_property(f: Any) -> Any: + """Ensure that a function is a `property` or `cached_property`, or is a valid descriptor. + + Args: + f: The function to check. + + Returns: + The function, or a `property` or `cached_property` instance wrapping the function. + """ + if ismethoddescriptor(f) or isdatadescriptor(f): + return f + else: + return property(f) + + +def _signature_no_eval(f: Callable[..., Any]) -> Signature: + """Get the signature of a callable without evaluating any annotations.""" + if sys.version_info >= (3, 14): + from annotationlib import Format + + return signature(f, annotation_format=Format.FORWARDREF) + else: + return signature(f) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_decorators_v1.py b/backend/venv/Lib/site-packages/pydantic/_internal/_decorators_v1.py new file mode 100644 index 0000000..3427377 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_decorators_v1.py @@ -0,0 +1,174 @@ +"""Logic for V1 validators, e.g. `@validator` and `@root_validator`.""" + +from __future__ import annotations as _annotations + +from inspect import Parameter, signature +from typing import Any, Union, cast + +from pydantic_core import core_schema +from typing_extensions import Protocol + +from ..errors import PydanticUserError +from ._utils import can_be_positional + + +class V1OnlyValueValidator(Protocol): + """A simple validator, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any) -> Any: ... + + +class V1ValidatorWithValues(Protocol): + """A validator with `values` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, values: dict[str, Any]) -> Any: ... + + +class V1ValidatorWithValuesKwOnly(Protocol): + """A validator with keyword only `values` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, *, values: dict[str, Any]) -> Any: ... + + +class V1ValidatorWithKwargs(Protocol): + """A validator with `kwargs` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, **kwargs: Any) -> Any: ... + + +class V1ValidatorWithValuesAndKwargs(Protocol): + """A validator with `values` and `kwargs` arguments, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, values: dict[str, Any], **kwargs: Any) -> Any: ... + + +V1Validator = Union[ + V1ValidatorWithValues, V1ValidatorWithValuesKwOnly, V1ValidatorWithKwargs, V1ValidatorWithValuesAndKwargs +] + + +def can_be_keyword(param: Parameter) -> bool: + return param.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) + + +def make_generic_v1_field_validator(validator: V1Validator) -> core_schema.WithInfoValidatorFunction: + """Wrap a V1 style field validator for V2 compatibility. + + Args: + validator: The V1 style field validator. + + Returns: + A wrapped V2 style field validator. + + Raises: + PydanticUserError: If the signature is not supported or the parameters are + not available in Pydantic V2. + """ + sig = signature(validator) + + needs_values_kw = False + + for param_num, (param_name, parameter) in enumerate(sig.parameters.items()): + if can_be_keyword(parameter) and param_name in ('field', 'config'): + raise PydanticUserError( + 'The `field` and `config` parameters are not available in Pydantic V2, ' + 'please use the `info` parameter instead.', + code='validator-field-config-info', + ) + if parameter.kind is Parameter.VAR_KEYWORD: + needs_values_kw = True + elif can_be_keyword(parameter) and param_name == 'values': + needs_values_kw = True + elif can_be_positional(parameter) and param_num == 0: + # value + continue + elif parameter.default is Parameter.empty: # ignore params with defaults e.g. bound by functools.partial + raise PydanticUserError( + f'Unsupported signature for V1 style validator {validator}: {sig} is not supported.', + code='validator-v1-signature', + ) + + if needs_values_kw: + # (v, **kwargs), (v, values, **kwargs), (v, *, values, **kwargs) or (v, *, values) + val1 = cast(V1ValidatorWithValues, validator) + + def wrapper1(value: Any, info: core_schema.ValidationInfo) -> Any: + return val1(value, values=info.data) + + return wrapper1 + else: + val2 = cast(V1OnlyValueValidator, validator) + + def wrapper2(value: Any, _: core_schema.ValidationInfo) -> Any: + return val2(value) + + return wrapper2 + + +RootValidatorValues = dict[str, Any] +# technically tuple[model_dict, model_extra, fields_set] | tuple[dataclass_dict, init_vars] +RootValidatorFieldsTuple = tuple[Any, ...] + + +class V1RootValidatorFunction(Protocol): + """A simple root validator, supported for V1 validators and V2 validators.""" + + def __call__(self, __values: RootValidatorValues) -> RootValidatorValues: ... + + +class V2CoreBeforeRootValidator(Protocol): + """V2 validator with mode='before'.""" + + def __call__(self, __values: RootValidatorValues, __info: core_schema.ValidationInfo) -> RootValidatorValues: ... + + +class V2CoreAfterRootValidator(Protocol): + """V2 validator with mode='after'.""" + + def __call__( + self, __fields_tuple: RootValidatorFieldsTuple, __info: core_schema.ValidationInfo + ) -> RootValidatorFieldsTuple: ... + + +def make_v1_generic_root_validator( + validator: V1RootValidatorFunction, pre: bool +) -> V2CoreBeforeRootValidator | V2CoreAfterRootValidator: + """Wrap a V1 style root validator for V2 compatibility. + + Args: + validator: The V1 style field validator. + pre: Whether the validator is a pre validator. + + Returns: + A wrapped V2 style validator. + """ + if pre is True: + # mode='before' for pydantic-core + def _wrapper1(values: RootValidatorValues, _: core_schema.ValidationInfo) -> RootValidatorValues: + return validator(values) + + return _wrapper1 + + # mode='after' for pydantic-core + def _wrapper2(fields_tuple: RootValidatorFieldsTuple, _: core_schema.ValidationInfo) -> RootValidatorFieldsTuple: + if len(fields_tuple) == 2: + # dataclass, this is easy + values, init_vars = fields_tuple + values = validator(values) + return values, init_vars + else: + # ugly hack: to match v1 behaviour, we merge values and model_extra, then split them up based on fields + # afterwards + model_dict, model_extra, fields_set = fields_tuple + if model_extra: + fields = set(model_dict.keys()) + model_dict.update(model_extra) + model_dict_new = validator(model_dict) + for k in list(model_dict_new.keys()): + if k not in fields: + model_extra[k] = model_dict_new.pop(k) + else: + model_dict_new = validator(model_dict) + return model_dict_new, model_extra, fields_set + + return _wrapper2 diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_discriminated_union.py b/backend/venv/Lib/site-packages/pydantic/_internal/_discriminated_union.py new file mode 100644 index 0000000..5dd6fda --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_discriminated_union.py @@ -0,0 +1,479 @@ +from __future__ import annotations as _annotations + +from collections.abc import Hashable, Sequence +from typing import TYPE_CHECKING, Any, cast + +from pydantic_core import CoreSchema, core_schema + +from ..errors import PydanticUserError +from . import _core_utils +from ._core_utils import ( + CoreSchemaField, +) + +if TYPE_CHECKING: + from ..types import Discriminator + from ._core_metadata import CoreMetadata + + +class MissingDefinitionForUnionRef(Exception): + """Raised when applying a discriminated union discriminator to a schema + requires a definition that is not yet defined + """ + + def __init__(self, ref: str) -> None: + self.ref = ref + super().__init__(f'Missing definition for ref {self.ref!r}') + + +def set_discriminator_in_metadata(schema: CoreSchema, discriminator: Any) -> None: + metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) + metadata['pydantic_internal_union_discriminator'] = discriminator + + +def apply_discriminator( + schema: core_schema.CoreSchema, + discriminator: str | Discriminator, + definitions: dict[str, core_schema.CoreSchema] | None = None, +) -> core_schema.CoreSchema: + """Applies the discriminator and returns a new core schema. + + Args: + schema: The input schema. + discriminator: The name of the field which will serve as the discriminator. + definitions: A mapping of schema ref to schema. + + Returns: + The new core schema. + + Raises: + TypeError: + - If `discriminator` is used with invalid union variant. + - If `discriminator` is used with `Union` type with one variant. + - If `discriminator` value mapped to multiple choices. + MissingDefinitionForUnionRef: + If the definition for ref is missing. + PydanticUserError: + - If a model in union doesn't have a discriminator field. + - If discriminator field has a non-string alias. + - If discriminator fields have different aliases. + - If discriminator field not of type `Literal`. + """ + from ..types import Discriminator + + if isinstance(discriminator, Discriminator): + if isinstance(discriminator.discriminator, str): + discriminator = discriminator.discriminator + else: + return discriminator._convert_schema(schema) + + return _ApplyInferredDiscriminator(discriminator, definitions or {}).apply(schema) + + +class _ApplyInferredDiscriminator: + """This class is used to convert an input schema containing a union schema into one where that union is + replaced with a tagged-union, with all the associated debugging and performance benefits. + + This is done by: + * Validating that the input schema is compatible with the provided discriminator + * Introspecting the schema to determine which discriminator values should map to which union choices + * Handling various edge cases such as 'definitions', 'default', 'nullable' schemas, and more + + I have chosen to implement the conversion algorithm in this class, rather than a function, + to make it easier to maintain state while recursively walking the provided CoreSchema. + """ + + def __init__(self, discriminator: str, definitions: dict[str, core_schema.CoreSchema]): + # `discriminator` should be the name of the field which will serve as the discriminator. + # It must be the python name of the field, and *not* the field's alias. Note that as of now, + # all members of a discriminated union _must_ use a field with the same name as the discriminator. + # This may change if/when we expose a way to manually specify the TaggedUnionSchema's choices. + self.discriminator = discriminator + + # `definitions` should contain a mapping of schema ref to schema for all schemas which might + # be referenced by some choice + self.definitions = definitions + + # `_discriminator_alias` will hold the value, if present, of the alias for the discriminator + # + # Note: following the v1 implementation, we currently disallow the use of different aliases + # for different choices. This is not a limitation of pydantic_core, but if we try to handle + # this, the inference logic gets complicated very quickly, and could result in confusing + # debugging challenges for users making subtle mistakes. + # + # Rather than trying to do the most powerful inference possible, I think we should eventually + # expose a way to more-manually control the way the TaggedUnionSchema is constructed through + # the use of a new type which would be placed as an Annotation on the Union type. This would + # provide the full flexibility/power of pydantic_core's TaggedUnionSchema where necessary for + # more complex cases, without over-complicating the inference logic for the common cases. + self._discriminator_alias: str | None = None + + # `_should_be_nullable` indicates whether the converted union has `None` as an allowed value. + # If `None` is an acceptable value of the (possibly-wrapped) union, we ignore it while + # constructing the TaggedUnionSchema, but set the `_should_be_nullable` attribute to True. + # Once we have constructed the TaggedUnionSchema, if `_should_be_nullable` is True, we ensure + # that the final schema gets wrapped as a NullableSchema. This has the same semantics on the + # python side, but resolves the issue that `None` cannot correspond to any discriminator values. + self._should_be_nullable = False + + # `_is_nullable` is used to track if the final produced schema will definitely be nullable; + # we set it to True if the input schema is wrapped in a nullable schema that we know will be preserved + # as an indication that, even if None is discovered as one of the union choices, we will not need to wrap + # the final value in another nullable schema. + # + # This is more complicated than just checking for the final outermost schema having type 'nullable' thanks + # to the possible presence of other wrapper schemas such as DefinitionsSchema, WithDefaultSchema, etc. + self._is_nullable = False + + # `_choices_to_handle` serves as a stack of choices to add to the tagged union. Initially, choices + # from the union in the wrapped schema will be appended to this list, and the recursive choice-handling + # algorithm may add more choices to this stack as (nested) unions are encountered. + self._choices_to_handle: list[core_schema.CoreSchema] = [] + + # `_tagged_union_choices` is built during the call to `apply`, and will hold the choices to be included + # in the output TaggedUnionSchema that will replace the union from the input schema + self._tagged_union_choices: dict[Hashable, core_schema.CoreSchema] = {} + + # `_used` is changed to True after applying the discriminator to prevent accidental reuse + self._used = False + + def apply(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Return a new CoreSchema based on `schema` that uses a tagged-union with the discriminator provided + to this class. + + Args: + schema: The input schema. + + Returns: + The new core schema. + + Raises: + TypeError: + - If `discriminator` is used with invalid union variant. + - If `discriminator` is used with `Union` type with one variant. + - If `discriminator` value mapped to multiple choices. + ValueError: + If the definition for ref is missing. + PydanticUserError: + - If a model in union doesn't have a discriminator field. + - If discriminator field has a non-string alias. + - If discriminator fields have different aliases. + - If discriminator field not of type `Literal`. + """ + assert not self._used + schema = self._apply_to_root(schema) + if self._should_be_nullable and not self._is_nullable: + schema = core_schema.nullable_schema(schema) + self._used = True + return schema + + def _apply_to_root(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """This method handles the outer-most stage of recursion over the input schema: + unwrapping nullable or definitions schemas, and calling the `_handle_choice` + method iteratively on the choices extracted (recursively) from the possibly-wrapped union. + """ + if schema['type'] == 'nullable': + self._is_nullable = True + wrapped = self._apply_to_root(schema['schema']) + nullable_wrapper = schema.copy() + nullable_wrapper['schema'] = wrapped + return nullable_wrapper + + if schema['type'] == 'definitions': + wrapped = self._apply_to_root(schema['schema']) + definitions_wrapper = schema.copy() + definitions_wrapper['schema'] = wrapped + return definitions_wrapper + + if schema['type'] != 'union': + # If the schema is not a union, it probably means it just had a single member and + # was flattened by pydantic_core. + # However, it still may make sense to apply the discriminator to this schema, + # as a way to get discriminated-union-style error messages, so we allow this here. + schema = core_schema.union_schema([schema]) + + # Reverse the choices list before extending the stack so that they get handled in the order they occur + choices_schemas = [v[0] if isinstance(v, tuple) else v for v in schema['choices'][::-1]] + self._choices_to_handle.extend(choices_schemas) + while self._choices_to_handle: + choice = self._choices_to_handle.pop() + self._handle_choice(choice) + + if self._discriminator_alias is not None and self._discriminator_alias != self.discriminator: + # * We need to annotate `discriminator` as a union here to handle both branches of this conditional + # * We need to annotate `discriminator` as list[list[str | int]] and not list[list[str]] due to the + # invariance of list, and because list[list[str | int]] is the type of the discriminator argument + # to tagged_union_schema below + # * See the docstring of pydantic_core.core_schema.tagged_union_schema for more details about how to + # interpret the value of the discriminator argument to tagged_union_schema. (The list[list[str]] here + # is the appropriate way to provide a list of fallback attributes to check for a discriminator value.) + discriminator: str | list[list[str | int]] = [[self.discriminator], [self._discriminator_alias]] + else: + discriminator = self.discriminator + return core_schema.tagged_union_schema( + choices=self._tagged_union_choices, + discriminator=discriminator, + custom_error_type=schema.get('custom_error_type'), + custom_error_message=schema.get('custom_error_message'), + custom_error_context=schema.get('custom_error_context'), + strict=False, + from_attributes=True, + ref=schema.get('ref'), + metadata=schema.get('metadata'), + serialization=schema.get('serialization'), + ) + + def _handle_choice(self, choice: core_schema.CoreSchema) -> None: + """This method handles the "middle" stage of recursion over the input schema. + Specifically, it is responsible for handling each choice of the outermost union + (and any "coalesced" choices obtained from inner unions). + + Here, "handling" entails: + * Coalescing nested unions and compatible tagged-unions + * Tracking the presence of 'none' and 'nullable' schemas occurring as choices + * Validating that each allowed discriminator value maps to a unique choice + * Updating the _tagged_union_choices mapping that will ultimately be used to build the TaggedUnionSchema. + """ + if choice['type'] == 'definition-ref': + if choice['schema_ref'] not in self.definitions: + raise MissingDefinitionForUnionRef(choice['schema_ref']) + + if choice['type'] == 'none': + self._should_be_nullable = True + elif choice['type'] == 'definitions': + self._handle_choice(choice['schema']) + elif choice['type'] == 'nullable': + self._should_be_nullable = True + self._handle_choice(choice['schema']) # unwrap the nullable schema + elif choice['type'] == 'union': + # Reverse the choices list before extending the stack so that they get handled in the order they occur + choices_schemas = [v[0] if isinstance(v, tuple) else v for v in choice['choices'][::-1]] + self._choices_to_handle.extend(choices_schemas) + elif choice['type'] not in { + 'model', + 'typed-dict', + 'tagged-union', + 'lax-or-strict', + 'dataclass', + 'dataclass-args', + 'definition-ref', + } and not _core_utils.is_function_with_inner_schema(choice): + # We should eventually handle 'definition-ref' as well + err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.' + if choice['type'] == 'list': + err_str += ( + ' If you are making use of a list of union types, make sure the discriminator is applied to the ' + 'union type and not the list (e.g. `list[Annotated[ | , Field(discriminator=...)]]`).' + ) + raise TypeError(err_str) + else: + if choice['type'] == 'tagged-union' and self._is_discriminator_shared(choice): + # In this case, this inner tagged-union is compatible with the outer tagged-union, + # and its choices can be coalesced into the outer TaggedUnionSchema. + subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))] + # Reverse the choices list before extending the stack so that they get handled in the order they occur + self._choices_to_handle.extend(subchoices[::-1]) + return + + inferred_discriminator_values = self._infer_discriminator_values_for_choice(choice, source_name=None) + self._set_unique_choice_for_values(choice, inferred_discriminator_values) + + def _is_discriminator_shared(self, choice: core_schema.TaggedUnionSchema) -> bool: + """This method returns a boolean indicating whether the discriminator for the `choice` + is the same as that being used for the outermost tagged union. This is used to + determine whether this TaggedUnionSchema choice should be "coalesced" into the top level, + or whether it should be treated as a separate (nested) choice. + """ + inner_discriminator = choice['discriminator'] + return inner_discriminator == self.discriminator or ( + isinstance(inner_discriminator, list) + and (self.discriminator in inner_discriminator or [self.discriminator] in inner_discriminator) + ) + + def _infer_discriminator_values_for_choice( # noqa C901 + self, choice: core_schema.CoreSchema, source_name: str | None + ) -> list[str | int]: + """This function recurses over `choice`, extracting all discriminator values that should map to this choice. + + `model_name` is accepted for the purpose of producing useful error messages. + """ + if choice['type'] == 'definitions': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name) + + elif _core_utils.is_function_with_inner_schema(choice): + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name) + + elif choice['type'] == 'lax-or-strict': + return sorted( + set( + self._infer_discriminator_values_for_choice(choice['lax_schema'], source_name=None) + + self._infer_discriminator_values_for_choice(choice['strict_schema'], source_name=None) + ) + ) + + elif choice['type'] == 'tagged-union': + values: list[str | int] = [] + # Ignore str/int "choices" since these are just references to other choices + subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))] + for subchoice in subchoices: + subchoice_values = self._infer_discriminator_values_for_choice(subchoice, source_name=None) + values.extend(subchoice_values) + return values + + elif choice['type'] == 'union': + values = [] + for subchoice in choice['choices']: + subchoice_schema = subchoice[0] if isinstance(subchoice, tuple) else subchoice + subchoice_values = self._infer_discriminator_values_for_choice(subchoice_schema, source_name=None) + values.extend(subchoice_values) + return values + + elif choice['type'] == 'nullable': + self._should_be_nullable = True + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=None) + + elif choice['type'] == 'model': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__) + + elif choice['type'] == 'dataclass': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__) + + elif choice['type'] == 'model-fields': + return self._infer_discriminator_values_for_model_choice(choice, source_name=source_name) + + elif choice['type'] == 'dataclass-args': + return self._infer_discriminator_values_for_dataclass_choice(choice, source_name=source_name) + + elif choice['type'] == 'typed-dict': + return self._infer_discriminator_values_for_typed_dict_choice(choice, source_name=source_name) + + elif choice['type'] == 'definition-ref': + schema_ref = choice['schema_ref'] + if schema_ref not in self.definitions: + raise MissingDefinitionForUnionRef(schema_ref) + return self._infer_discriminator_values_for_choice(self.definitions[schema_ref], source_name=source_name) + else: + err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.' + if choice['type'] == 'list': + err_str += ( + ' If you are making use of a list of union types, make sure the discriminator is applied to the ' + 'union type and not the list (e.g. `list[Annotated[ | , Field(discriminator=...)]]`).' + ) + raise TypeError(err_str) + + def _infer_discriminator_values_for_typed_dict_choice( + self, choice: core_schema.TypedDictSchema, source_name: str | None = None + ) -> list[str | int]: + """This method just extracts the _infer_discriminator_values_for_choice logic specific to TypedDictSchema + for the sake of readability. + """ + source = 'TypedDict' if source_name is None else f'TypedDict {source_name!r}' + field = choice['fields'].get(self.discriminator) + if field is None: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_model_choice( + self, choice: core_schema.ModelFieldsSchema, source_name: str | None = None + ) -> list[str | int]: + source = 'ModelFields' if source_name is None else f'Model {source_name!r}' + field = choice['fields'].get(self.discriminator) + if field is None: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_dataclass_choice( + self, choice: core_schema.DataclassArgsSchema, source_name: str | None = None + ) -> list[str | int]: + source = 'DataclassArgs' if source_name is None else f'Dataclass {source_name!r}' + for field in choice['fields']: + if field['name'] == self.discriminator: + break + else: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_field(self, field: CoreSchemaField, source: str) -> list[str | int]: + if field['type'] == 'computed-field': + # This should never occur as a discriminator, as it is only relevant to serialization + return [] + alias = field.get('validation_alias', self.discriminator) + if not isinstance(alias, str): + raise PydanticUserError( + f'Alias {alias!r} is not supported in a discriminated union', code='discriminator-alias-type' + ) + if self._discriminator_alias is None: + self._discriminator_alias = alias + elif self._discriminator_alias != alias: + raise PydanticUserError( + f'Aliases for discriminator {self.discriminator!r} must be the same ' + f'(got {alias}, {self._discriminator_alias})', + code='discriminator-alias', + ) + return self._infer_discriminator_values_for_inner_schema(field['schema'], source) + + def _infer_discriminator_values_for_inner_schema( + self, schema: core_schema.CoreSchema, source: str + ) -> list[str | int]: + """When inferring discriminator values for a field, we typically extract the expected values from a literal + schema. This function does that, but also handles nested unions and defaults. + """ + if schema['type'] == 'literal': + return schema['expected'] + + elif schema['type'] == 'union': + # Generally when multiple values are allowed they should be placed in a single `Literal`, but + # we add this case to handle the situation where a field is annotated as a `Union` of `Literal`s. + # For example, this lets us handle `Union[Literal['key'], Union[Literal['Key'], Literal['KEY']]]` + values: list[Any] = [] + for choice in schema['choices']: + choice_schema = choice[0] if isinstance(choice, tuple) else choice + choice_values = self._infer_discriminator_values_for_inner_schema(choice_schema, source) + values.extend(choice_values) + return values + + elif schema['type'] == 'default': + # This will happen if the field has a default value; we ignore it while extracting the discriminator values + return self._infer_discriminator_values_for_inner_schema(schema['schema'], source) + + elif schema['type'] == 'function-after': + # After validators don't affect the discriminator values + return self._infer_discriminator_values_for_inner_schema(schema['schema'], source) + + elif schema['type'] in {'function-before', 'function-wrap', 'function-plain'}: + validator_type = repr(schema['type'].split('-')[1]) + raise PydanticUserError( + f'Cannot use a mode={validator_type} validator in the' + f' discriminator field {self.discriminator!r} of {source}', + code='discriminator-validator', + ) + + else: + raise PydanticUserError( + f'{source} needs field {self.discriminator!r} to be of type `Literal`', + code='discriminator-needs-literal', + ) + + def _set_unique_choice_for_values(self, choice: core_schema.CoreSchema, values: Sequence[str | int]) -> None: + """This method updates `self.tagged_union_choices` so that all provided (discriminator) `values` map to the + provided `choice`, validating that none of these values already map to another (different) choice. + """ + for discriminator_value in values: + if discriminator_value in self._tagged_union_choices: + # It is okay if `value` is already in tagged_union_choices as long as it maps to the same value. + # Because tagged_union_choices may map values to other values, we need to walk the choices dict + # until we get to a "real" choice, and confirm that is equal to the one assigned. + existing_choice = self._tagged_union_choices[discriminator_value] + if existing_choice != choice: + raise TypeError( + f'Value {discriminator_value!r} for discriminator ' + f'{self.discriminator!r} mapped to multiple choices' + ) + else: + self._tagged_union_choices[discriminator_value] = choice diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_docs_extraction.py b/backend/venv/Lib/site-packages/pydantic/_internal/_docs_extraction.py new file mode 100644 index 0000000..6df77bf --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_docs_extraction.py @@ -0,0 +1,113 @@ +"""Utilities related to attribute docstring extraction.""" + +from __future__ import annotations + +import ast +import inspect +import sys +import textwrap +from typing import Any + + +class DocstringVisitor(ast.NodeVisitor): + def __init__(self) -> None: + super().__init__() + + self.target: str | None = None + self.attrs: dict[str, str] = {} + self.previous_node_type: type[ast.AST] | None = None + + def visit(self, node: ast.AST) -> Any: + node_result = super().visit(node) + self.previous_node_type = type(node) + return node_result + + def visit_AnnAssign(self, node: ast.AnnAssign) -> Any: + if isinstance(node.target, ast.Name): + self.target = node.target.id + + def visit_Expr(self, node: ast.Expr) -> Any: + if ( + isinstance(node.value, ast.Constant) + and isinstance(node.value.value, str) + and self.previous_node_type is ast.AnnAssign + ): + docstring = inspect.cleandoc(node.value.value) + if self.target: + self.attrs[self.target] = docstring + self.target = None + + +def _dedent_source_lines(source: list[str]) -> str: + # Required for nested class definitions, e.g. in a function block + dedent_source = textwrap.dedent(''.join(source)) + if dedent_source.startswith((' ', '\t')): + # We are in the case where there's a dedented (usually multiline) string + # at a lower indentation level than the class itself. We wrap our class + # in a function as a workaround. + dedent_source = f'def dedent_workaround():\n{dedent_source}' + return dedent_source + + +def _extract_source_from_frame(cls: type[Any]) -> list[str] | None: + frame = inspect.currentframe() + + while frame: + if inspect.getmodule(frame) is inspect.getmodule(cls): + lnum = frame.f_lineno + try: + lines, _ = inspect.findsource(frame) + except OSError: # pragma: no cover + # Source can't be retrieved (maybe because running in an interactive terminal), + # we don't want to error here. + pass + else: + block_lines = inspect.getblock(lines[lnum - 1 :]) + dedent_source = _dedent_source_lines(block_lines) + try: + block_tree = ast.parse(dedent_source) + except SyntaxError: + pass + else: + stmt = block_tree.body[0] + if isinstance(stmt, ast.FunctionDef) and stmt.name == 'dedent_workaround': + # `_dedent_source_lines` wrapped the class around the workaround function + stmt = stmt.body[0] + if isinstance(stmt, ast.ClassDef) and stmt.name == cls.__name__: + return block_lines + + frame = frame.f_back + + +def extract_docstrings_from_cls(cls: type[Any], use_inspect: bool = False) -> dict[str, str]: + """Map model attributes and their corresponding docstring. + + Args: + cls: The class of the Pydantic model to inspect. + use_inspect: Whether to skip usage of frames to find the object and use + the `inspect` module instead. + + Returns: + A mapping containing attribute names and their corresponding docstring. + """ + if use_inspect or sys.version_info >= (3, 13): + # On Python < 3.13, `inspect.getsourcelines()` might not work as expected + # if two classes have the same name in the same source file. + # On Python 3.13+, it will use the new `__firstlineno__` class attribute, + # making it way more robust. + try: + source, _ = inspect.getsourcelines(cls) + except OSError: # pragma: no cover + return {} + else: + # TODO remove this implementation when we drop support for Python 3.12: + source = _extract_source_from_frame(cls) + + if not source: + return {} + + dedent_source = _dedent_source_lines(source) + + visitor = DocstringVisitor() + visitor.visit(ast.parse(dedent_source)) + return visitor.attrs diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_fields.py b/backend/venv/Lib/site-packages/pydantic/_internal/_fields.py new file mode 100644 index 0000000..aad2ac9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_fields.py @@ -0,0 +1,635 @@ +"""Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`.""" + +from __future__ import annotations as _annotations + +import dataclasses +import warnings +from collections.abc import Mapping +from functools import cache +from inspect import Parameter, ismethoddescriptor, signature +from re import Pattern +from typing import TYPE_CHECKING, Any, Callable, TypeVar + +from pydantic_core import PydanticUndefined +from typing_extensions import TypeIs +from typing_inspection.introspection import AnnotationSource + +from pydantic import PydanticDeprecatedSince211 +from pydantic.errors import PydanticUserError + +from ..aliases import AliasGenerator +from . import _generics, _typing_extra +from ._config import ConfigWrapper +from ._docs_extraction import extract_docstrings_from_cls +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._namespace_utils import NsResolver +from ._repr import Representation +from ._utils import can_be_positional, get_first_not_none + +if TYPE_CHECKING: + from annotated_types import BaseMetadata + + from ..fields import FieldInfo + from ..main import BaseModel + from ._dataclasses import PydanticDataclass, StandardDataclass + from ._decorators import DecoratorInfos + + +class PydanticMetadata(Representation): + """Base class for annotation markers like `Strict`.""" + + __slots__ = () + + +def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: + """Create a new `_PydanticGeneralMetadata` class with the given metadata. + + Args: + **metadata: The metadata to add. + + Returns: + The new `_PydanticGeneralMetadata` class. + """ + return _general_metadata_cls()(metadata) # type: ignore + + +@cache +def _general_metadata_cls() -> type[BaseMetadata]: + """Do it this way to avoid importing `annotated_types` at import time.""" + from annotated_types import BaseMetadata + + class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): + """Pydantic general metadata like `max_digits`.""" + + def __init__(self, metadata: Any): + self.__dict__ = metadata + + return _PydanticGeneralMetadata # type: ignore + + +def _check_protected_namespaces( + protected_namespaces: tuple[str | Pattern[str], ...], + ann_name: str, + bases: tuple[type[Any], ...], + cls_name: str, +) -> None: + BaseModel = import_cached_base_model() + + for protected_namespace in protected_namespaces: + ns_violation = False + if isinstance(protected_namespace, Pattern): + ns_violation = protected_namespace.match(ann_name) is not None + elif isinstance(protected_namespace, str): + ns_violation = ann_name.startswith(protected_namespace) + + if ns_violation: + for b in bases: + if hasattr(b, ann_name): + if not (issubclass(b, BaseModel) and ann_name in getattr(b, '__pydantic_fields__', {})): + raise ValueError( + f'Field {ann_name!r} conflicts with member {getattr(b, ann_name)}' + f' of protected namespace {protected_namespace!r}.' + ) + else: + valid_namespaces: list[str] = [] + for pn in protected_namespaces: + if isinstance(pn, Pattern): + if not pn.match(ann_name): + valid_namespaces.append(f're.compile({pn.pattern!r})') + else: + if not ann_name.startswith(pn): + valid_namespaces.append(f"'{pn}'") + + valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}' + + warnings.warn( + f'Field {ann_name!r} in {cls_name!r} conflicts with protected namespace {protected_namespace!r}.\n\n' + f"You may be able to solve this by setting the 'protected_namespaces' configuration to {valid_namespaces_str}.", + UserWarning, + stacklevel=5, + ) + + +def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], use_inspect: bool = False) -> None: + fields_docs = extract_docstrings_from_cls(cls, use_inspect=use_inspect) + for ann_name, field_info in fields.items(): + if field_info.description is None and ann_name in fields_docs: + field_info.description = fields_docs[ann_name] + + +def _apply_field_title_generator_to_field_info( + title_generator: Callable[[str, FieldInfo], str], + field_name: str, + field_info: FieldInfo, +): + if field_info.title is None: + title = title_generator(field_name, field_info) + if not isinstance(title, str): + raise TypeError(f'field_title_generator {title_generator} must return str, not {title.__class__}') + + field_info.title = title + + +def _apply_alias_generator_to_field_info( + alias_generator: Callable[[str], str] | AliasGenerator, field_name: str, field_info: FieldInfo +): + """Apply an alias generator to aliases on a `FieldInfo` instance if appropriate. + + Args: + alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance. + field_name: The name of the field from which to generate the alias. + field_info: The `FieldInfo` instance to which the alias generator is (maybe) applied. + """ + # Apply an alias_generator if + # 1. An alias is not specified + # 2. An alias is specified, but the priority is <= 1 + if ( + field_info.alias_priority is None + or field_info.alias_priority <= 1 + or field_info.alias is None + or field_info.validation_alias is None + or field_info.serialization_alias is None + ): + alias, validation_alias, serialization_alias = None, None, None + + if isinstance(alias_generator, AliasGenerator): + alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name) + elif callable(alias_generator): + alias = alias_generator(field_name) + if not isinstance(alias, str): + raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}') + + # if priority is not set, we set to 1 + # which supports the case where the alias_generator from a child class is used + # to generate an alias for a field in a parent class + if field_info.alias_priority is None or field_info.alias_priority <= 1: + field_info.alias_priority = 1 + + # if the priority is 1, then we set the aliases to the generated alias + if field_info.alias_priority == 1: + field_info.serialization_alias = get_first_not_none(serialization_alias, alias) + field_info.validation_alias = get_first_not_none(validation_alias, alias) + field_info.alias = alias + + # if any of the aliases are not set, then we set them to the corresponding generated alias + if field_info.alias is None: + field_info.alias = alias + if field_info.serialization_alias is None: + field_info.serialization_alias = get_first_not_none(serialization_alias, alias) + if field_info.validation_alias is None: + field_info.validation_alias = get_first_not_none(validation_alias, alias) + + +def update_field_from_config(config_wrapper: ConfigWrapper, field_name: str, field_info: FieldInfo) -> None: + """Update the `FieldInfo` instance from the configuration set on the model it belongs to. + + This will apply the title and alias generators from the configuration. + + Args: + config_wrapper: The configuration from the model. + field_name: The field name the `FieldInfo` instance is attached to. + field_info: The `FieldInfo` instance to update. + """ + field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator + if field_title_generator is not None: + _apply_field_title_generator_to_field_info(field_title_generator, field_name, field_info) + if config_wrapper.alias_generator is not None: + _apply_alias_generator_to_field_info(config_wrapper.alias_generator, field_name, field_info) + + +_deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'} + +_deprecated_classmethod_names = { + 'parse_obj', + 'parse_raw', + 'parse_file', + 'from_orm', + 'construct', + 'schema', + 'schema_json', + 'validate', + 'update_forward_refs', + '_get_value', +} + + +def collect_model_fields( # noqa: C901 + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None, + *, + typevars_map: Mapping[TypeVar, Any] | None = None, +) -> tuple[dict[str, FieldInfo], set[str]]: + """Collect the fields and class variables names of a nascent Pydantic model. + + The fields collection process is *lenient*, meaning it won't error if string annotations + fail to evaluate. If this happens, the original annotation (and assigned value, if any) + is stored on the created `FieldInfo` instance. + + The `rebuild_model_fields()` should be called at a later point (e.g. when rebuilding the model), + and will make use of these stored attributes. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting model annotations. + typevars_map: A dictionary mapping type variables to their concrete types. + + Returns: + A two-tuple containing model fields and class variables names. + + Raises: + NameError: + - If there is a conflict between a field name and protected namespaces. + - If there is a field other than `root` in `RootModel`. + - If a field shadows an attribute in the parent model. + """ + FieldInfo_ = import_cached_field_info() + BaseModel_ = import_cached_base_model() + + bases = cls.__bases__ + parent_fields_lookup: dict[str, FieldInfo] = {} + for base in reversed(bases): + if model_fields := getattr(base, '__pydantic_fields__', None): + parent_fields_lookup.update(model_fields) + + type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver) + + # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older + # annotations is only used for finding fields in parent classes + annotations = _typing_extra.safe_get_annotations(cls) + + fields: dict[str, FieldInfo] = {} + + class_vars: set[str] = set() + for ann_name, (ann_type, evaluated) in type_hints.items(): + if ann_name == 'model_config': + # We never want to treat `model_config` as a field + # Note: we may need to change this logic if/when we introduce a `BareModel` class with no + # protected namespaces (where `model_config` might be allowed as a field name) + continue + + _check_protected_namespaces( + protected_namespaces=config_wrapper.protected_namespaces, + ann_name=ann_name, + bases=bases, + cls_name=cls.__name__, + ) + + if _typing_extra.is_classvar_annotation(ann_type): + class_vars.add(ann_name) + continue + + assigned_value = getattr(cls, ann_name, PydanticUndefined) + if assigned_value is not PydanticUndefined and ( + # One of the deprecated instance methods was used as a field name (e.g. `dict()`): + any(getattr(BaseModel_, depr_name, None) is assigned_value for depr_name in _deprecated_method_names) + # One of the deprecated class methods was used as a field name (e.g. `schema()`): + or ( + hasattr(assigned_value, '__func__') + and any( + getattr(getattr(BaseModel_, depr_name, None), '__func__', None) is assigned_value.__func__ # pyright: ignore[reportAttributeAccessIssue] + for depr_name in _deprecated_classmethod_names + ) + ) + ): + # Then `assigned_value` would be the method, even though no default was specified: + assigned_value = PydanticUndefined + + if not is_valid_field_name(ann_name): + continue + if cls.__pydantic_root_model__ and ann_name != 'root': + raise NameError( + f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`" + ) + + # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get + # "... shadows an attribute" warnings + generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') + for base in bases: + dataclass_fields = { + field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ()) + } + if hasattr(base, ann_name): + if base is generic_origin: + # Don't warn when "shadowing" of attributes in parametrized generics + continue + + if ann_name in dataclass_fields: + # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set + # on the class instance. + continue + + if ann_name not in annotations: + # Don't warn when a field exists in a parent class but has not been defined in the current class + continue + + warnings.warn( + f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent ' + f'"{base.__qualname__}"', + UserWarning, + stacklevel=4, + ) + + if assigned_value is PydanticUndefined: # no assignment, just a plain annotation + if ann_name in annotations or ann_name not in parent_fields_lookup: + # field is either: + # - present in the current model's annotations (and *not* from parent classes) + # - not found on any base classes; this seems to be caused by fields bot getting + # generated due to models not being fully defined while initializing recursive models. + # Nothing stops us from just creating a `FieldInfo` for this type hint, so we do this. + field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS) + if not evaluated: + field_info._complete = False + # Store the original annotation that should be used to rebuild + # the field info later: + field_info._original_annotation = ann_type + else: + # The field was present on one of the (possibly multiple) base classes + # copy the field to make sure typevar substitutions don't cause issues with the base classes + field_info = parent_fields_lookup[ann_name]._copy() + + else: # An assigned value is present (either the default value, or a `Field()` function) + if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default): + # `assigned_value` was fetched using `getattr`, which triggers a call to `__get__` + # for descriptors, so we do the same if the `= field(default=...)` form is used. + # Note that we only do this for method descriptors for now, we might want to + # extend this to any descriptor in the future (by simply checking for + # `hasattr(assigned_value.default, '__get__')`). + default = assigned_value.default.__get__(None, cls) + assigned_value.default = default + assigned_value._attributes_set['default'] = default + + field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS) + # Store the original annotation and assignment value that should be used to rebuild the field info later. + # Note that the assignment is always stored as the annotation might contain a type var that is later + # parameterized with an unknown forward reference (and we'll need it to rebuild the field info): + field_info._original_assignment = assigned_value + if not evaluated: + field_info._complete = False + field_info._original_annotation = ann_type + elif 'final' in field_info._qualifiers and not field_info.is_required(): + warnings.warn( + f'Annotation {ann_name!r} is marked as final and has a default value. Pydantic treats {ann_name!r} as a ' + 'class variable, but it will be considered as a normal field in V3 to be aligned with dataclasses. If you ' + f'still want {ann_name!r} to be considered as a class variable, annotate it as: `ClassVar[] = .`', + category=PydanticDeprecatedSince211, + # Incorrect when `create_model` is used, but the chance that final with a default is used is low in that case: + stacklevel=4, + ) + class_vars.add(ann_name) + continue + + # attributes which are fields are removed from the class namespace: + # 1. To match the behaviour of annotation-only fields + # 2. To avoid false positives in the NameError check above + try: + delattr(cls, ann_name) + except AttributeError: + pass # indicates the attribute was on a parent class + + # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__ + # to make sure the decorators have already been built for this exact class + decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__'] + if ann_name in decorators.computed_fields: + raise TypeError( + f'Field {ann_name!r} of class {cls.__name__!r} overrides symbol of same name in a parent class. ' + 'This override with a computed_field is incompatible.' + ) + fields[ann_name] = field_info + + if field_info._complete: + # If not complete, this will be called in `rebuild_model_fields()`: + update_field_from_config(config_wrapper, ann_name, field_info) + + if typevars_map: + for field in fields.values(): + if field._complete: + field.apply_typevars_map(typevars_map) + + if config_wrapper.use_attribute_docstrings: + _update_fields_from_docstrings(cls, fields) + return fields, class_vars + + +def rebuild_model_fields( + cls: type[BaseModel], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + typevars_map: Mapping[TypeVar, Any], +) -> dict[str, FieldInfo]: + """Rebuild the (already present) model fields by trying to reevaluate annotations. + + This function should be called whenever a model with incomplete fields is encountered. + + Raises: + NameError: If one of the annotations failed to evaluate. + + Note: + This function *doesn't* mutate the model fields in place, as it can be called during + schema generation, where you don't want to mutate other model's fields. + """ + FieldInfo_ = import_cached_field_info() + + rebuilt_fields: dict[str, FieldInfo] = {} + with ns_resolver.push(cls): + for f_name, field_info in cls.__pydantic_fields__.items(): + if field_info._complete: + rebuilt_fields[f_name] = field_info + else: + existing_desc = field_info.description + ann = _typing_extra.eval_type( + field_info._original_annotation, + *ns_resolver.types_namespace, + ) + ann = _generics.replace_types(ann, typevars_map) + + if (assign := field_info._original_assignment) is PydanticUndefined: + new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS) + else: + new_field = FieldInfo_.from_annotated_attribute(ann, assign, _source=AnnotationSource.CLASS) + # The description might come from the docstring if `use_attribute_docstrings` was `True`: + new_field.description = new_field.description if new_field.description is not None else existing_desc + update_field_from_config(config_wrapper, f_name, new_field) + rebuilt_fields[f_name] = new_field + + return rebuilt_fields + + +def collect_dataclass_fields( + cls: type[StandardDataclass], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None = None, + typevars_map: dict[Any, Any] | None = None, +) -> dict[str, FieldInfo]: + """Collect the fields of a dataclass. + + Args: + cls: dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting dataclass annotations. + Defaults to an empty instance. + typevars_map: A dictionary mapping type variables to their concrete types. + + Returns: + The dataclass fields. + """ + FieldInfo_ = import_cached_field_info() + + fields: dict[str, FieldInfo] = {} + ns_resolver = ns_resolver or NsResolver() + dataclass_fields = cls.__dataclass_fields__ + + # The logic here is similar to `_typing_extra.get_cls_type_hints`, + # although we do it manually as stdlib dataclasses already have annotations + # collected in each class: + for base in reversed(cls.__mro__): + if not dataclasses.is_dataclass(base): + continue + + with ns_resolver.push(base): + for ann_name, dataclass_field in dataclass_fields.items(): + base_anns = _typing_extra.safe_get_annotations(base) + + if ann_name not in base_anns: + # `__dataclass_fields__`contains every field, even the ones from base classes. + # Only collect the ones defined on `base`. + continue + + globalns, localns = ns_resolver.types_namespace + ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns) + + if _typing_extra.is_classvar_annotation(ann_type): + continue + + if ( + not dataclass_field.init + and dataclass_field.default is dataclasses.MISSING + and dataclass_field.default_factory is dataclasses.MISSING + ): + # TODO: We should probably do something with this so that validate_assignment behaves properly + # Issue: https://github.com/pydantic/pydantic/issues/5470 + continue + + if isinstance(dataclass_field.default, FieldInfo_): + if dataclass_field.default.init_var: + if dataclass_field.default.init is False: + raise PydanticUserError( + f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.', + code='clashing-init-and-init-var', + ) + + # TODO: same note as above re validate_assignment + continue + field_info = FieldInfo_.from_annotated_attribute( + ann_type, dataclass_field.default, _source=AnnotationSource.DATACLASS + ) + field_info._original_assignment = dataclass_field.default + else: + field_info = FieldInfo_.from_annotated_attribute( + ann_type, dataclass_field, _source=AnnotationSource.DATACLASS + ) + field_info._original_assignment = dataclass_field + + if not evaluated: + field_info._complete = False + field_info._original_annotation = ann_type + + fields[ann_name] = field_info + update_field_from_config(config_wrapper, ann_name, field_info) + + if field_info.default is not PydanticUndefined and isinstance( + getattr(cls, ann_name, field_info), FieldInfo_ + ): + # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo + setattr(cls, ann_name, field_info.default) + + if typevars_map: + for field in fields.values(): + # We don't pass any ns, as `field.annotation` + # was already evaluated. TODO: is this method relevant? + # Can't we juste use `_generics.replace_types`? + field.apply_typevars_map(typevars_map) + + if config_wrapper.use_attribute_docstrings: + _update_fields_from_docstrings( + cls, + fields, + # We can't rely on the (more reliable) frame inspection method + # for stdlib dataclasses: + use_inspect=not hasattr(cls, '__is_pydantic_dataclass__'), + ) + + return fields + + +def rebuild_dataclass_fields( + cls: type[PydanticDataclass], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + typevars_map: Mapping[TypeVar, Any], +) -> dict[str, FieldInfo]: + """Rebuild the (already present) dataclass fields by trying to reevaluate annotations. + + This function should be called whenever a dataclass with incomplete fields is encountered. + + Raises: + NameError: If one of the annotations failed to evaluate. + + Note: + This function *doesn't* mutate the dataclass fields in place, as it can be called during + schema generation, where you don't want to mutate other dataclass's fields. + """ + FieldInfo_ = import_cached_field_info() + + rebuilt_fields: dict[str, FieldInfo] = {} + with ns_resolver.push(cls): + for f_name, field_info in cls.__pydantic_fields__.items(): + if field_info._complete: + rebuilt_fields[f_name] = field_info + else: + existing_desc = field_info.description + ann = _typing_extra.eval_type( + field_info._original_annotation, + *ns_resolver.types_namespace, + ) + ann = _generics.replace_types(ann, typevars_map) + new_field = FieldInfo_.from_annotated_attribute( + ann, + field_info._original_assignment, + _source=AnnotationSource.DATACLASS, + ) + + # The description might come from the docstring if `use_attribute_docstrings` was `True`: + new_field.description = new_field.description if new_field.description is not None else existing_desc + update_field_from_config(config_wrapper, f_name, new_field) + rebuilt_fields[f_name] = new_field + + return rebuilt_fields + + +def is_valid_field_name(name: str) -> bool: + return not name.startswith('_') + + +def is_valid_privateattr_name(name: str) -> bool: + return name.startswith('_') and not name.startswith('__') + + +def takes_validated_data_argument( + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any], +) -> TypeIs[Callable[[dict[str, Any]], Any]]: + """Whether the provided default factory callable has a validated data parameter.""" + try: + sig = signature(default_factory) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no data argument is present: + return False + + parameters = list(sig.parameters.values()) + + return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_forward_ref.py b/backend/venv/Lib/site-packages/pydantic/_internal/_forward_ref.py new file mode 100644 index 0000000..231f81d --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_forward_ref.py @@ -0,0 +1,23 @@ +from __future__ import annotations as _annotations + +from dataclasses import dataclass +from typing import Union + + +@dataclass +class PydanticRecursiveRef: + type_ref: str + + __name__ = 'PydanticRecursiveRef' + __hash__ = object.__hash__ + + def __call__(self) -> None: + """Defining __call__ is necessary for the `typing` module to let you use an instance of + this class as the result of resolving a standard ForwardRef. + """ + + def __or__(self, other): + return Union[self, other] # type: ignore + + def __ror__(self, other): + return Union[other, self] # type: ignore diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_generate_schema.py b/backend/venv/Lib/site-packages/pydantic/_internal/_generate_schema.py new file mode 100644 index 0000000..839764c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_generate_schema.py @@ -0,0 +1,2867 @@ +"""Convert python types to pydantic-core schema.""" + +from __future__ import annotations as _annotations + +import collections.abc +import dataclasses +import datetime +import inspect +import os +import pathlib +import re +import sys +import typing +import warnings +from collections.abc import Generator, Iterable, Iterator, Mapping +from contextlib import contextmanager +from copy import copy +from decimal import Decimal +from enum import Enum +from fractions import Fraction +from functools import partial +from inspect import Parameter, _ParameterKind, signature +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from itertools import chain +from operator import attrgetter +from types import FunctionType, GenericAlias, LambdaType, MethodType +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Final, + ForwardRef, + Literal, + TypeVar, + Union, + cast, + overload, +) +from uuid import UUID +from zoneinfo import ZoneInfo + +import typing_extensions +from pydantic_core import ( + MISSING, + CoreSchema, + MultiHostUrl, + PydanticCustomError, + PydanticSerializationUnexpectedValue, + PydanticUndefined, + Url, + core_schema, + to_jsonable_python, +) +from typing_extensions import TypeAlias, TypeAliasType, get_args, get_origin, is_typeddict +from typing_inspection import typing_objects +from typing_inspection.introspection import AnnotationSource, get_literal_values, is_union_origin + +from ..aliases import AliasChoices, AliasPath +from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from ..config import ConfigDict, JsonDict, JsonEncoder, JsonSchemaExtraCallable +from ..errors import PydanticSchemaGenerationError, PydanticUndefinedAnnotation, PydanticUserError +from ..functional_validators import AfterValidator, BeforeValidator, FieldValidatorModes, PlainValidator, WrapValidator +from ..json_schema import JsonSchemaValue +from ..version import version_short +from ..warnings import ( + ArbitraryTypeWarning, + PydanticDeprecatedSince20, + TypedDictExtraConfigWarning, + UnsupportedFieldAttributeWarning, +) +from . import _decorators, _discriminated_union, _known_annotated_metadata, _repr, _typing_extra +from ._config import ConfigWrapper, ConfigWrapperStack +from ._core_metadata import CoreMetadata, update_core_metadata +from ._core_utils import ( + get_ref, + get_type_ref, + is_list_like_schema_with_items_schema, +) +from ._decorators import ( + Decorator, + DecoratorInfos, + FieldSerializerDecoratorInfo, + FieldValidatorDecoratorInfo, + ModelSerializerDecoratorInfo, + ModelValidatorDecoratorInfo, + RootValidatorDecoratorInfo, + ValidatorDecoratorInfo, + get_attribute_from_bases, + inspect_field_serializer, + inspect_model_serializer, + inspect_validator, +) +from ._docs_extraction import extract_docstrings_from_cls +from ._fields import ( + collect_dataclass_fields, + rebuild_dataclass_fields, + rebuild_model_fields, + takes_validated_data_argument, + update_field_from_config, +) +from ._forward_ref import PydanticRecursiveRef +from ._generics import get_standard_typevars_map, replace_types +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._mock_val_ser import MockCoreSchema +from ._namespace_utils import NamespacesTuple, NsResolver +from ._schema_gather import MissingDefinitionError, gather_schemas_for_cleaning +from ._schema_generation_shared import CallbackGetCoreSchemaHandler +from ._utils import lenient_issubclass, smart_deepcopy + +if TYPE_CHECKING: + from ..fields import ComputedFieldInfo, FieldInfo + from ..main import BaseModel + from ..types import Discriminator + from ._dataclasses import StandardDataclass + from ._schema_generation_shared import GetJsonSchemaFunction + +_SUPPORTS_TYPEDDICT = sys.version_info >= (3, 12) + +FieldDecoratorInfo = Union[ValidatorDecoratorInfo, FieldValidatorDecoratorInfo, FieldSerializerDecoratorInfo] +FieldDecoratorInfoType = TypeVar('FieldDecoratorInfoType', bound=FieldDecoratorInfo) +AnyFieldDecorator = Union[ + Decorator[ValidatorDecoratorInfo], + Decorator[FieldValidatorDecoratorInfo], + Decorator[FieldSerializerDecoratorInfo], +] + +ModifyCoreSchemaWrapHandler: TypeAlias = GetCoreSchemaHandler +GetCoreSchemaFunction: TypeAlias = Callable[[Any, ModifyCoreSchemaWrapHandler], core_schema.CoreSchema] +ParametersCallback: TypeAlias = "Callable[[int, str, Any], Literal['skip'] | None]" + +TUPLE_TYPES: list[type] = [typing.Tuple, tuple] # noqa: UP006 +LIST_TYPES: list[type] = [typing.List, list, collections.abc.MutableSequence] # noqa: UP006 +SET_TYPES: list[type] = [typing.Set, set, collections.abc.MutableSet] # noqa: UP006 +FROZEN_SET_TYPES: list[type] = [typing.FrozenSet, frozenset, collections.abc.Set] # noqa: UP006 +DICT_TYPES: list[type] = [typing.Dict, dict] # noqa: UP006 +IP_TYPES: list[type] = [IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network] +SEQUENCE_TYPES: list[type] = [typing.Sequence, collections.abc.Sequence] +ITERABLE_TYPES: list[type] = [typing.Iterable, collections.abc.Iterable, typing.Generator, collections.abc.Generator] +TYPE_TYPES: list[type] = [typing.Type, type] # noqa: UP006 +PATTERN_TYPES: list[type] = [typing.Pattern, re.Pattern] +PATH_TYPES: list[type] = [ + os.PathLike, + pathlib.Path, + pathlib.PurePath, + pathlib.PosixPath, + pathlib.PurePosixPath, + pathlib.PureWindowsPath, +] +MAPPING_TYPES = [ + typing.Mapping, + typing.MutableMapping, + collections.abc.Mapping, + collections.abc.MutableMapping, + collections.OrderedDict, + typing_extensions.OrderedDict, + typing.DefaultDict, # noqa: UP006 + collections.defaultdict, +] +COUNTER_TYPES = [collections.Counter, typing.Counter] +DEQUE_TYPES: list[type] = [collections.deque, typing.Deque] # noqa: UP006 + +# Note: This does not play very well with type checkers. For example, +# `a: LambdaType = lambda x: x` will raise a type error by Pyright. +ValidateCallSupportedTypes = Union[ + LambdaType, + FunctionType, + MethodType, + partial, +] + +VALIDATE_CALL_SUPPORTED_TYPES = get_args(ValidateCallSupportedTypes) +UNSUPPORTED_STANDALONE_FIELDINFO_ATTRIBUTES: list[tuple[str, Any]] = [ + ('alias', None), + ('validation_alias', None), + ('serialization_alias', None), + # will be set if any alias is set, so disable it to avoid double warnings: + # 'alias_priority', + ('default', PydanticUndefined), + ('default_factory', None), + ('exclude', None), + ('deprecated', None), + ('repr', True), + ('validate_default', None), + ('frozen', None), + ('init', None), + ('init_var', None), + ('kw_only', None), +] +"""`FieldInfo` attributes (and their default value) that can't be used outside of a model (e.g. in a type adapter or a PEP 695 type alias).""" + +_mode_to_validator: dict[ + FieldValidatorModes, type[BeforeValidator | AfterValidator | PlainValidator | WrapValidator] +] = {'before': BeforeValidator, 'after': AfterValidator, 'plain': PlainValidator, 'wrap': WrapValidator} + + +def check_validator_fields_against_field_name( + info: FieldDecoratorInfo, + field: str, +) -> bool: + """Check if field name is in validator fields. + + Args: + info: The field info. + field: The field name to check. + + Returns: + `True` if field name is in validator fields, `False` otherwise. + """ + fields = info.fields + return '*' in fields or field in fields + + +def check_decorator_fields_exist(decorators: Iterable[AnyFieldDecorator], fields: Iterable[str]) -> None: + """Check if the defined fields in decorators exist in `fields` param. + + It ignores the check for a decorator if the decorator has `*` as field or `check_fields=False`. + + Args: + decorators: An iterable of decorators. + fields: An iterable of fields name. + + Raises: + PydanticUserError: If one of the field names does not exist in `fields` param. + """ + fields = set(fields) + for dec in decorators: + if '*' in dec.info.fields: + continue + if dec.info.check_fields is False: + continue + for field in dec.info.fields: + if field not in fields: + raise PydanticUserError( + f'Decorators defined with incorrect fields: {dec.cls_ref}.{dec.cls_var_name}' + " (use check_fields=False if you're inheriting from the model and intended this)", + code='decorator-missing-field', + ) + + +def filter_field_decorator_info_by_field( + validator_functions: Iterable[Decorator[FieldDecoratorInfoType]], field: str +) -> list[Decorator[FieldDecoratorInfoType]]: + return [dec for dec in validator_functions if check_validator_fields_against_field_name(dec.info, field)] + + +def apply_each_item_validators( + schema: core_schema.CoreSchema, + each_item_validators: list[Decorator[ValidatorDecoratorInfo]], +) -> core_schema.CoreSchema: + # This V1 compatibility shim should eventually be removed + + # fail early if each_item_validators is empty + if not each_item_validators: + return schema + + # push down any `each_item=True` validators + # note that this won't work for any Annotated types that get wrapped by a function validator + # but that's okay because that didn't exist in V1 + if schema['type'] == 'nullable': + schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators) + return schema + elif schema['type'] == 'tuple': + if (variadic_item_index := schema.get('variadic_item_index')) is not None: + schema['items_schema'][variadic_item_index] = apply_validators( + schema['items_schema'][variadic_item_index], + each_item_validators, + ) + elif is_list_like_schema_with_items_schema(schema): + inner_schema = schema.get('items_schema', core_schema.any_schema()) + schema['items_schema'] = apply_validators(inner_schema, each_item_validators) + elif schema['type'] == 'dict': + inner_schema = schema.get('values_schema', core_schema.any_schema()) + schema['values_schema'] = apply_validators(inner_schema, each_item_validators) + else: + raise TypeError( + f'`@validator(..., each_item=True)` cannot be applied to fields with a schema of {schema["type"]}' + ) + return schema + + +def _extract_json_schema_info_from_field_info( + info: FieldInfo | ComputedFieldInfo, +) -> tuple[JsonDict | None, JsonDict | JsonSchemaExtraCallable | None]: + json_schema_updates = { + 'title': info.title, + 'description': info.description, + 'deprecated': bool(info.deprecated) or info.deprecated == '' or None, + 'examples': to_jsonable_python(info.examples), + } + json_schema_updates = {k: v for k, v in json_schema_updates.items() if v is not None} + return (json_schema_updates or None, info.json_schema_extra) + + +JsonEncoders = dict[type[Any], JsonEncoder] + + +def _add_custom_serialization_from_json_encoders( + json_encoders: JsonEncoders | None, tp: Any, schema: CoreSchema +) -> CoreSchema: + """Iterate over the json_encoders and add the first matching encoder to the schema. + + Args: + json_encoders: A dictionary of types and their encoder functions. + tp: The type to check for a matching encoder. + schema: The schema to add the encoder to. + """ + if not json_encoders: + return schema + if 'serialization' in schema: + return schema + # Check the class type and its superclasses for a matching encoder + # Decimal.__class__.__mro__ (and probably other cases) doesn't include Decimal itself + # if the type is a GenericAlias (e.g. from list[int]) we need to use __class__ instead of .__mro__ + for base in (tp, *getattr(tp, '__mro__', tp.__class__.__mro__)[:-1]): + encoder = json_encoders.get(base) + if encoder is None: + continue + + warnings.warn( + f'`json_encoders` is deprecated. See https://docs.pydantic.dev/{version_short()}/concepts/serialization/#custom-serializers for alternatives', + PydanticDeprecatedSince20, + ) + + # TODO: in theory we should check that the schema accepts a serialization key + schema['serialization'] = core_schema.plain_serializer_function_ser_schema(encoder, when_used='json') + return schema + + return schema + + +class InvalidSchemaError(Exception): + """The core schema is invalid.""" + + +class GenerateSchema: + """Generate core schema for a Pydantic model, dataclass and types like `str`, `datetime`, ... .""" + + __slots__ = ( + '_config_wrapper_stack', + '_ns_resolver', + '_typevars_map', + 'field_name_stack', + 'model_type_stack', + 'defs', + ) + + def __init__( + self, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None = None, + typevars_map: Mapping[TypeVar, Any] | None = None, + ) -> None: + # we need a stack for recursing into nested models + self._config_wrapper_stack = ConfigWrapperStack(config_wrapper) + self._ns_resolver = ns_resolver or NsResolver() + self._typevars_map = typevars_map + self.field_name_stack = _FieldNameStack() + self.model_type_stack = _ModelTypeStack() + self.defs = _Definitions() + + def __init_subclass__(cls) -> None: + super().__init_subclass__() + warnings.warn( + 'Subclassing `GenerateSchema` is not supported. The API is highly subject to change in minor versions.', + UserWarning, + stacklevel=2, + ) + + @property + def _config_wrapper(self) -> ConfigWrapper: + return self._config_wrapper_stack.tail + + @property + def _types_namespace(self) -> NamespacesTuple: + return self._ns_resolver.types_namespace + + @property + def _arbitrary_types(self) -> bool: + return self._config_wrapper.arbitrary_types_allowed + + # the following methods can be overridden but should be considered + # unstable / private APIs + def _list_schema(self, items_type: Any) -> CoreSchema: + return core_schema.list_schema(self.generate_schema(items_type)) + + def _dict_schema(self, keys_type: Any, values_type: Any) -> CoreSchema: + return core_schema.dict_schema(self.generate_schema(keys_type), self.generate_schema(values_type)) + + def _set_schema(self, items_type: Any) -> CoreSchema: + return core_schema.set_schema(self.generate_schema(items_type)) + + def _frozenset_schema(self, items_type: Any) -> CoreSchema: + return core_schema.frozenset_schema(self.generate_schema(items_type)) + + def _enum_schema(self, enum_type: type[Enum]) -> CoreSchema: + cases: list[Any] = list(enum_type.__members__.values()) + + enum_ref = get_type_ref(enum_type) + description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) + if ( + description == 'An enumeration.' + ): # This is the default value provided by enum.EnumMeta.__new__; don't use it + description = None + js_updates = {'title': enum_type.__name__, 'description': description} + js_updates = {k: v for k, v in js_updates.items() if v is not None} + + sub_type: Literal['str', 'int', 'float'] | None = None + if issubclass(enum_type, int): + sub_type = 'int' + value_ser_type: core_schema.SerSchema = core_schema.simple_ser_schema('int') + elif issubclass(enum_type, str): + # this handles `StrEnum` (3.11 only), and also `Foobar(str, Enum)` + sub_type = 'str' + value_ser_type = core_schema.simple_ser_schema('str') + elif issubclass(enum_type, float): + sub_type = 'float' + value_ser_type = core_schema.simple_ser_schema('float') + else: + # TODO this is an ugly hack, how do we trigger an Any schema for serialization? + value_ser_type = core_schema.plain_serializer_function_ser_schema(lambda x: x) + + if cases: + + def get_json_schema(schema: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(schema) + original_schema = handler.resolve_ref_schema(json_schema) + original_schema.update(js_updates) + return json_schema + + # we don't want to add the missing to the schema if it's the default one + default_missing = getattr(enum_type._missing_, '__func__', None) is Enum._missing_.__func__ # pyright: ignore[reportFunctionMemberAccess] + enum_schema = core_schema.enum_schema( + enum_type, + cases, + sub_type=sub_type, + missing=None if default_missing else enum_type._missing_, + ref=enum_ref, + metadata={'pydantic_js_functions': [get_json_schema]}, + ) + + if self._config_wrapper.use_enum_values: + enum_schema = core_schema.no_info_after_validator_function( + attrgetter('value'), enum_schema, serialization=value_ser_type + ) + + return enum_schema + + else: + + def get_json_schema_no_cases(_, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(core_schema.enum_schema(enum_type, cases, sub_type=sub_type, ref=enum_ref)) + original_schema = handler.resolve_ref_schema(json_schema) + original_schema.update(js_updates) + return json_schema + + # Use an isinstance check for enums with no cases. + # The most important use case for this is creating TypeVar bounds for generics that should + # be restricted to enums. This is more consistent than it might seem at first, since you can only + # subclass enum.Enum (or subclasses of enum.Enum) if all parent classes have no cases. + # We use the get_json_schema function when an Enum subclass has been declared with no cases + # so that we can still generate a valid json schema. + return core_schema.is_instance_schema( + enum_type, + metadata={'pydantic_js_functions': [get_json_schema_no_cases]}, + ) + + def _ip_schema(self, tp: Any) -> CoreSchema: + from ._validators import IP_VALIDATOR_LOOKUP, IpType + + ip_type_json_schema_format: dict[type[IpType], str] = { + IPv4Address: 'ipv4', + IPv4Network: 'ipv4network', + IPv4Interface: 'ipv4interface', + IPv6Address: 'ipv6', + IPv6Network: 'ipv6network', + IPv6Interface: 'ipv6interface', + } + + def ser_ip(ip: Any, info: core_schema.SerializationInfo) -> str | IpType: + if not isinstance(ip, (tp, str)): + raise PydanticSerializationUnexpectedValue( + f"Expected `{tp}` but got `{type(ip)}` with value `'{ip}'` - serialized value may not be as expected." + ) + if info.mode == 'python': + return ip + return str(ip) + + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.no_info_plain_validator_function(IP_VALIDATOR_LOOKUP[tp]), + strict_schema=core_schema.json_or_python_schema( + json_schema=core_schema.no_info_after_validator_function(tp, core_schema.str_schema()), + python_schema=core_schema.is_instance_schema(tp), + ), + serialization=core_schema.plain_serializer_function_ser_schema(ser_ip, info_arg=True, when_used='always'), + metadata={ + 'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': ip_type_json_schema_format[tp]}] + }, + ) + + def _path_schema(self, tp: Any, path_type: Any) -> CoreSchema: + if tp is os.PathLike and (path_type not in {str, bytes} and not typing_objects.is_any(path_type)): + raise PydanticUserError( + '`os.PathLike` can only be used with `str`, `bytes` or `Any`', code='schema-for-unknown-type' + ) + + path_constructor = pathlib.PurePath if tp is os.PathLike else tp + strict_inner_schema = ( + core_schema.bytes_schema(strict=True) if (path_type is bytes) else core_schema.str_schema(strict=True) + ) + lax_inner_schema = core_schema.bytes_schema() if (path_type is bytes) else core_schema.str_schema() + + def path_validator(input_value: str | bytes) -> os.PathLike[Any]: # type: ignore + try: + if path_type is bytes: + if isinstance(input_value, bytes): + try: + input_value = input_value.decode() + except UnicodeDecodeError as e: + raise PydanticCustomError('bytes_type', 'Input must be valid bytes') from e + else: + raise PydanticCustomError('bytes_type', 'Input must be bytes') + elif not isinstance(input_value, str): + raise PydanticCustomError('path_type', 'Input is not a valid path') + + return path_constructor(input_value) # type: ignore + except TypeError as e: + raise PydanticCustomError('path_type', 'Input is not a valid path') from e + + def ser_path(path: Any, info: core_schema.SerializationInfo) -> str | os.PathLike[Any]: + if not isinstance(path, (tp, str)): + raise PydanticSerializationUnexpectedValue( + f"Expected `{tp}` but got `{type(path)}` with value `'{path}'` - serialized value may not be as expected." + ) + if info.mode == 'python': + return path + return str(path) + + instance_schema = core_schema.json_or_python_schema( + json_schema=core_schema.no_info_after_validator_function(path_validator, lax_inner_schema), + python_schema=core_schema.is_instance_schema(tp), + ) + + schema = core_schema.lax_or_strict_schema( + lax_schema=core_schema.union_schema( + [ + instance_schema, + core_schema.no_info_after_validator_function(path_validator, strict_inner_schema), + ], + custom_error_type='path_type', + custom_error_message=f'Input is not a valid path for {tp}', + ), + strict_schema=instance_schema, + serialization=core_schema.plain_serializer_function_ser_schema(ser_path, info_arg=True, when_used='always'), + metadata={'pydantic_js_functions': [lambda source, handler: {**handler(source), 'format': 'path'}]}, + ) + return schema + + def _deque_schema(self, items_type: Any) -> CoreSchema: + from ._serializers import serialize_sequence_via_list + from ._validators import deque_validator + + item_type_schema = self.generate_schema(items_type) + + # we have to use a lax list schema here, because we need to validate the deque's + # items via a list schema, but it's ok if the deque itself is not a list + list_schema = core_schema.list_schema(item_type_schema, strict=False) + + check_instance = core_schema.json_or_python_schema( + json_schema=list_schema, + python_schema=core_schema.is_instance_schema(collections.deque, cls_repr='Deque'), + ) + + lax_schema = core_schema.no_info_wrap_validator_function(deque_validator, list_schema) + + return core_schema.lax_or_strict_schema( + lax_schema=lax_schema, + strict_schema=core_schema.chain_schema([check_instance, lax_schema]), + serialization=core_schema.wrap_serializer_function_ser_schema( + serialize_sequence_via_list, schema=item_type_schema, info_arg=True + ), + ) + + def _mapping_schema(self, tp: Any, keys_type: Any, values_type: Any) -> CoreSchema: + from ._validators import MAPPING_ORIGIN_MAP, defaultdict_validator, get_defaultdict_default_default_factory + + mapped_origin = MAPPING_ORIGIN_MAP[tp] + keys_schema = self.generate_schema(keys_type) + with warnings.catch_warnings(): + # We kind of abused `Field()` default factories to be able to specify + # the `defaultdict`'s `default_factory`. As a consequence, we get warnings + # as normally `FieldInfo.default_factory` is unsupported in the context where + # `Field()` is used and our only solution is to ignore them (note that this might + # wrongfully ignore valid warnings, e.g. if the `value_type` is a PEP 695 type alias + # with unsupported metadata). + warnings.simplefilter('ignore', category=UnsupportedFieldAttributeWarning) + values_schema = self.generate_schema(values_type) + dict_schema = core_schema.dict_schema(keys_schema, values_schema, strict=False) + + if mapped_origin is dict: + schema = dict_schema + else: + check_instance = core_schema.json_or_python_schema( + json_schema=dict_schema, + python_schema=core_schema.is_instance_schema(mapped_origin), + ) + + if tp is collections.defaultdict: + default_default_factory = get_defaultdict_default_default_factory(values_type) + coerce_instance_wrap = partial( + core_schema.no_info_wrap_validator_function, + partial(defaultdict_validator, default_default_factory=default_default_factory), + ) + else: + coerce_instance_wrap = partial(core_schema.no_info_after_validator_function, mapped_origin) + + lax_schema = coerce_instance_wrap(dict_schema) + strict_schema = core_schema.chain_schema([check_instance, lax_schema]) + + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, + strict_schema=strict_schema, + serialization=core_schema.wrap_serializer_function_ser_schema( + lambda v, h: h(v), schema=dict_schema, info_arg=False + ), + ) + + return schema + + def _fraction_schema(self) -> CoreSchema: + """Support for [`fractions.Fraction`][fractions.Fraction].""" + from ._validators import fraction_validator + + # TODO: note, this is a fairly common pattern, re lax / strict for attempted type coercion, + # can we use a helper function to reduce boilerplate? + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.no_info_plain_validator_function(fraction_validator), + strict_schema=core_schema.json_or_python_schema( + json_schema=core_schema.no_info_plain_validator_function(fraction_validator), + python_schema=core_schema.is_instance_schema(Fraction), + ), + # use str serialization to guarantee round trip behavior + serialization=core_schema.to_string_ser_schema(when_used='always'), + metadata={'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'fraction'}]}, + ) + + def _arbitrary_type_schema(self, tp: Any) -> CoreSchema: + if not isinstance(tp, type): + warnings.warn( + f'{tp!r} is not a Python type (it may be an instance of an object),' + ' Pydantic will allow any object with no validation since we cannot even' + ' enforce that the input is an instance of the given type.' + ' To get rid of this error wrap the type with `pydantic.SkipValidation`.', + ArbitraryTypeWarning, + ) + return core_schema.any_schema() + return core_schema.is_instance_schema(tp) + + def _unknown_type_schema(self, obj: Any) -> CoreSchema: + raise PydanticSchemaGenerationError( + f'Unable to generate pydantic-core schema for {obj!r}. ' + 'Set `arbitrary_types_allowed=True` in the model_config to ignore this error' + ' or implement `__get_pydantic_core_schema__` on your type to fully support it.' + '\n\nIf you got this error by calling handler() within' + ' `__get_pydantic_core_schema__` then you likely need to call' + ' `handler.generate_schema()` since we do not call' + ' `__get_pydantic_core_schema__` on `` otherwise to avoid infinite recursion.' + ) + + def _apply_discriminator_to_union( + self, schema: CoreSchema, discriminator: str | Discriminator | None + ) -> CoreSchema: + if discriminator is None: + return schema + try: + return _discriminated_union.apply_discriminator( + schema, + discriminator, + self.defs._definitions, + ) + except _discriminated_union.MissingDefinitionForUnionRef: + # defer until defs are resolved + _discriminated_union.set_discriminator_in_metadata( + schema, + discriminator, + ) + return schema + + def clean_schema(self, schema: CoreSchema) -> CoreSchema: + return self.defs.finalize_schema(schema) + + def _add_js_function(self, metadata_schema: CoreSchema, js_function: Callable[..., Any]) -> None: + metadata = metadata_schema.get('metadata', {}) + pydantic_js_functions = metadata.setdefault('pydantic_js_functions', []) + # because of how we generate core schemas for nested generic models + # we can end up adding `BaseModel.__get_pydantic_json_schema__` multiple times + # this check may fail to catch duplicates if the function is a `functools.partial` + # or something like that, but if it does it'll fail by inserting the duplicate + if js_function not in pydantic_js_functions: + pydantic_js_functions.append(js_function) + metadata_schema['metadata'] = metadata + + def generate_schema( + self, + obj: Any, + ) -> core_schema.CoreSchema: + """Generate core schema. + + Args: + obj: The object to generate core schema for. + + Returns: + The generated core schema. + + Raises: + PydanticUndefinedAnnotation: + If it is not possible to evaluate forward reference. + PydanticSchemaGenerationError: + If it is not possible to generate pydantic-core schema. + TypeError: + - If `alias_generator` returns a disallowed type (must be str, AliasPath or AliasChoices). + - If V1 style validator with `each_item=True` applied on a wrong field. + PydanticUserError: + - If `typing.TypedDict` is used instead of `typing_extensions.TypedDict` on Python < 3.12. + - If `__modify_schema__` method is used instead of `__get_pydantic_json_schema__`. + """ + schema = self._generate_schema_from_get_schema_method(obj, obj) + + if schema is None: + schema = self._generate_schema_inner(obj) + + metadata_js_function = _extract_get_pydantic_json_schema(obj) + if metadata_js_function is not None: + metadata_schema = resolve_original_schema(schema, self.defs) + if metadata_schema: + self._add_js_function(metadata_schema, metadata_js_function) + + schema = _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, obj, schema) + + return schema + + def _model_schema(self, cls: type[BaseModel]) -> core_schema.CoreSchema: + """Generate schema for a Pydantic model.""" + BaseModel_ = import_cached_base_model() + + with self.defs.get_schema_or_ref(cls) as (model_ref, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + schema = cls.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, MockCoreSchema): + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + else: + return schema + + config_wrapper = ConfigWrapper(cls.model_config, check=False) + + with self._config_wrapper_stack.push(config_wrapper), self._ns_resolver.push(cls): + core_config = self._config_wrapper.core_config(title=cls.__name__) + + if cls.__pydantic_fields_complete__ or cls is BaseModel_: + fields = getattr(cls, '__pydantic_fields__', {}) + else: + if '__pydantic_fields__' not in cls.__dict__: + # This happens when we have a loop in the schema generation: + # class Base[T](BaseModel): + # t: T + # + # class Other(BaseModel): + # b: 'Base[Other]' + # When we build fields for `Other`, we evaluate the forward annotation. + # At this point, `Other` doesn't have the model fields set. We create + # `Base[Other]`; model fields are successfully built, and we try to generate + # a schema for `t: Other`. As `Other.__pydantic_fields__` aren't set, we abort. + raise PydanticUndefinedAnnotation( + name=cls.__name__, + message=f'Class {cls.__name__!r} is not defined', + ) + try: + fields = rebuild_model_fields( + cls, + config_wrapper=self._config_wrapper, + ns_resolver=self._ns_resolver, + typevars_map=self._typevars_map or {}, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + decorators = cls.__pydantic_decorators__ + computed_fields = decorators.computed_fields + check_decorator_fields_exist( + chain( + decorators.field_validators.values(), + decorators.field_serializers.values(), + decorators.validators.values(), + ), + {*fields.keys(), *computed_fields.keys()}, + ) + + model_validators = decorators.model_validators.values() + + extras_schema = None + extras_keys_schema = None + if core_config.get('extra_fields_behavior') == 'allow': + assert cls.__mro__[0] is cls + assert cls.__mro__[-1] is object + for candidate_cls in cls.__mro__[:-1]: + extras_annotation = getattr(candidate_cls, '__annotations__', {}).get( + '__pydantic_extra__', None + ) + if extras_annotation is not None: + if isinstance(extras_annotation, str): + extras_annotation = _typing_extra.eval_type_backport( + _typing_extra._make_forward_ref( + extras_annotation, is_argument=False, is_class=True + ), + *self._types_namespace, + ) + tp = get_origin(extras_annotation) + if tp not in DICT_TYPES: + raise PydanticSchemaGenerationError( + 'The type annotation for `__pydantic_extra__` must be `dict[str, ...]`' + ) + extra_keys_type, extra_items_type = self._get_args_resolving_forward_refs( + extras_annotation, + required=True, + ) + if extra_keys_type is not str: + extras_keys_schema = self.generate_schema(extra_keys_type) + if not typing_objects.is_any(extra_items_type): + extras_schema = self.generate_schema(extra_items_type) + if extras_keys_schema is not None or extras_schema is not None: + break + + generic_origin: type[BaseModel] | None = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') + + if cls.__pydantic_root_model__: + # FIXME: should the common field metadata be used here? + inner_schema, _ = self._common_field_schema('root', fields['root'], decorators) + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + model_schema = core_schema.model_schema( + cls, + inner_schema, + generic_origin=generic_origin, + custom_init=getattr(cls, '__pydantic_custom_init__', None), + root_model=True, + post_init=getattr(cls, '__pydantic_post_init__', None), + config=core_config, + ref=model_ref, + ) + else: + fields_schema: core_schema.CoreSchema = core_schema.model_fields_schema( + {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()}, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in computed_fields.values() + ], + extras_schema=extras_schema, + extras_keys_schema=extras_keys_schema, + model_name=cls.__name__, + ) + inner_schema = apply_validators(fields_schema, decorators.root_validators.values()) + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + + model_schema = core_schema.model_schema( + cls, + inner_schema, + generic_origin=generic_origin, + custom_init=getattr(cls, '__pydantic_custom_init__', None), + root_model=False, + post_init=getattr(cls, '__pydantic_post_init__', None), + config=core_config, + ref=model_ref, + ) + + schema = self._apply_model_serializers(model_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, model_validators, 'outer') + return self.defs.create_definition_reference_schema(schema) + + def _resolve_self_type(self, obj: Any) -> Any: + obj = self.model_type_stack.get() + if obj is None: + raise PydanticUserError('`typing.Self` is invalid in this context', code='invalid-self-type') + return obj + + def _generate_schema_from_get_schema_method(self, obj: Any, source: Any) -> core_schema.CoreSchema | None: + BaseModel_ = import_cached_base_model() + + get_schema = getattr(obj, '__get_pydantic_core_schema__', None) + is_base_model_get_schema = ( + getattr(get_schema, '__func__', None) is BaseModel_.__get_pydantic_core_schema__.__func__ # pyright: ignore[reportFunctionMemberAccess] + ) + + if ( + get_schema is not None + # BaseModel.__get_pydantic_core_schema__ is defined for backwards compatibility, + # to allow existing code to call `super().__get_pydantic_core_schema__` in Pydantic + # model that overrides `__get_pydantic_core_schema__`. However, it raises a deprecation + # warning stating that the method will be removed, and during the core schema gen we actually + # don't call the method: + and not is_base_model_get_schema + ): + # Some referenceable types might have a `__get_pydantic_core_schema__` method + # defined on it by users (e.g. on a dataclass). This generally doesn't play well + # as these types are already recognized by the `GenerateSchema` class and isn't ideal + # as we might end up calling `get_schema_or_ref` (expensive) on types that are actually + # not referenceable: + with self.defs.get_schema_or_ref(obj) as (_, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + if obj is source: + ref_mode = 'unpack' + else: + ref_mode = 'to-def' + schema = get_schema( + source, CallbackGetCoreSchemaHandler(self._generate_schema_inner, self, ref_mode=ref_mode) + ) + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + + # Note: if schema is of type `'definition-ref'`, we might want to copy it as a + # safety measure (because these are inlined in place -- i.e. mutated directly) + return schema + + if get_schema is None and (validators := getattr(obj, '__get_validators__', None)) is not None: + from pydantic.v1 import BaseModel as BaseModelV1 + + if issubclass(obj, BaseModelV1): + warnings.warn( + f'Mixing V1 models and V2 models (or constructs, like `TypeAdapter`) is not supported. Please upgrade `{obj.__name__}` to V2.', + UserWarning, + ) + else: + warnings.warn( + '`__get_validators__` is deprecated and will be removed, use `__get_pydantic_core_schema__` instead.', + PydanticDeprecatedSince20, + ) + return core_schema.chain_schema([core_schema.with_info_plain_validator_function(v) for v in validators()]) + + def _resolve_forward_ref(self, obj: Any) -> Any: + # we assume that types_namespace has the target of forward references in its scope, + # but this could fail, for example, if calling Validator on an imported type which contains + # forward references to other types only defined in the module from which it was imported + # `Validator(SomeImportedTypeAliasWithAForwardReference)` + # or the equivalent for BaseModel + # class Model(BaseModel): + # x: SomeImportedTypeAliasWithAForwardReference + try: + obj = _typing_extra.eval_type_backport(obj, *self._types_namespace) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + # if obj is still a ForwardRef, it means we can't evaluate it, raise PydanticUndefinedAnnotation + if isinstance(obj, ForwardRef): + raise PydanticUndefinedAnnotation(obj.__forward_arg__, f'Unable to evaluate forward reference {obj}') + + if self._typevars_map: + obj = replace_types(obj, self._typevars_map) + + return obj + + @overload + def _get_args_resolving_forward_refs(self, obj: Any, required: Literal[True]) -> tuple[Any, ...]: ... + + @overload + def _get_args_resolving_forward_refs(self, obj: Any) -> tuple[Any, ...] | None: ... + + def _get_args_resolving_forward_refs(self, obj: Any, required: bool = False) -> tuple[Any, ...] | None: + args = get_args(obj) + if args: + if isinstance(obj, GenericAlias): + # PEP 585 generic aliases don't convert args to ForwardRefs, unlike `typing.List/Dict` etc. + args = (_typing_extra._make_forward_ref(a) if isinstance(a, str) else a for a in args) + args = tuple(self._resolve_forward_ref(a) if isinstance(a, ForwardRef) else a for a in args) + elif required: # pragma: no cover + raise TypeError(f'Expected {obj} to have generic parameters but it had none') + return args + + def _get_first_arg_or_any(self, obj: Any) -> Any: + args = self._get_args_resolving_forward_refs(obj) + if not args: + return Any + return args[0] + + def _get_first_two_args_or_any(self, obj: Any) -> tuple[Any, Any]: + args = self._get_args_resolving_forward_refs(obj) + if not args: + return (Any, Any) + if len(args) < 2: + origin = get_origin(obj) + raise TypeError(f'Expected two type arguments for {origin}, got 1') + return args[0], args[1] + + def _generate_schema_inner(self, obj: Any) -> core_schema.CoreSchema: + if typing_objects.is_self(obj): + obj = self._resolve_self_type(obj) + + if typing_objects.is_annotated(get_origin(obj)): + return self._annotated_schema(obj) + + if isinstance(obj, dict): + # we assume this is already a valid schema + return obj # type: ignore[return-value] + + if isinstance(obj, str): + obj = ForwardRef(obj) + + if isinstance(obj, ForwardRef): + return self.generate_schema(self._resolve_forward_ref(obj)) + + BaseModel = import_cached_base_model() + + if lenient_issubclass(obj, BaseModel): + with self.model_type_stack.push(obj): + return self._model_schema(obj) + + if isinstance(obj, PydanticRecursiveRef): + return core_schema.definition_reference_schema(schema_ref=obj.type_ref) + + return self.match_type(obj) + + def match_type(self, obj: Any) -> core_schema.CoreSchema: # noqa: C901 + """Main mapping of types to schemas. + + The general structure is a series of if statements starting with the simple cases + (non-generic primitive types) and then handling generics and other more complex cases. + + Each case either generates a schema directly, calls into a public user-overridable method + (like `GenerateSchema.tuple_variable_schema`) or calls into a private method that handles some + boilerplate before calling into the user-facing method (e.g. `GenerateSchema._tuple_schema`). + + The idea is that we'll evolve this into adding more and more user facing methods over time + as they get requested and we figure out what the right API for them is. + """ + if obj is str: + return core_schema.str_schema() + elif obj is bytes: + return core_schema.bytes_schema() + elif obj is int: + return core_schema.int_schema() + elif obj is float: + return core_schema.float_schema() + elif obj is bool: + return core_schema.bool_schema() + elif obj is complex: + return core_schema.complex_schema() + elif typing_objects.is_any(obj) or obj is object: + return core_schema.any_schema() + elif obj is datetime.date: + return core_schema.date_schema() + elif obj is datetime.datetime: + return core_schema.datetime_schema() + elif obj is datetime.time: + return core_schema.time_schema() + elif obj is datetime.timedelta: + return core_schema.timedelta_schema() + elif obj is Decimal: + return core_schema.decimal_schema() + elif obj is UUID: + return core_schema.uuid_schema() + elif obj is Url: + return core_schema.url_schema() + elif obj is Fraction: + return self._fraction_schema() + elif obj is MultiHostUrl: + return core_schema.multi_host_url_schema() + elif obj is None or obj is _typing_extra.NoneType: + return core_schema.none_schema() + if obj is MISSING: + return core_schema.missing_sentinel_schema() + elif obj in IP_TYPES: + return self._ip_schema(obj) + elif obj in TUPLE_TYPES: + return self._tuple_schema(obj) + elif obj in LIST_TYPES: + return self._list_schema(Any) + elif obj in SET_TYPES: + return self._set_schema(Any) + elif obj in FROZEN_SET_TYPES: + return self._frozenset_schema(Any) + elif obj in SEQUENCE_TYPES: + return self._sequence_schema(Any) + elif obj in ITERABLE_TYPES: + return self._iterable_schema(obj) + elif obj in DICT_TYPES: + return self._dict_schema(Any, Any) + elif obj in PATH_TYPES: + return self._path_schema(obj, Any) + elif obj in DEQUE_TYPES: + return self._deque_schema(Any) + elif obj in MAPPING_TYPES: + return self._mapping_schema(obj, Any, Any) + elif obj in COUNTER_TYPES: + return self._mapping_schema(obj, Any, int) + elif typing_objects.is_typealiastype(obj): + return self._type_alias_type_schema(obj) + elif obj is type: + return self._type_schema() + elif _typing_extra.is_callable(obj): + return core_schema.callable_schema() + elif typing_objects.is_literal(get_origin(obj)): + return self._literal_schema(obj) + elif is_typeddict(obj): + return self._typed_dict_schema(obj, None) + elif _typing_extra.is_namedtuple(obj): + return self._namedtuple_schema(obj, None) + elif typing_objects.is_newtype(obj): + # NewType, can't use isinstance because it fails <3.10 + return self.generate_schema(obj.__supertype__) + elif obj in PATTERN_TYPES: + return self._pattern_schema(obj) + elif _typing_extra.is_hashable(obj): + return self._hashable_schema() + elif isinstance(obj, typing.TypeVar): + return self._unsubstituted_typevar_schema(obj) + elif _typing_extra.is_finalvar(obj): + if obj is Final: + return core_schema.any_schema() + return self.generate_schema( + self._get_first_arg_or_any(obj), + ) + elif isinstance(obj, VALIDATE_CALL_SUPPORTED_TYPES): + return self._call_schema(obj) + elif inspect.isclass(obj) and issubclass(obj, Enum): + return self._enum_schema(obj) + elif obj is ZoneInfo: + return self._zoneinfo_schema() + + # dataclasses.is_dataclass coerces dc instances to types, but we only handle + # the case of a dc type here + if dataclasses.is_dataclass(obj): + return self._dataclass_schema(obj, None) # pyright: ignore[reportArgumentType] + + origin = get_origin(obj) + if origin is not None: + return self._match_generic_type(obj, origin) + + if self._arbitrary_types: + return self._arbitrary_type_schema(obj) + return self._unknown_type_schema(obj) + + def _match_generic_type(self, obj: Any, origin: Any) -> CoreSchema: # noqa: C901 + # Need to handle generic dataclasses before looking for the schema properties because attribute accesses + # on _GenericAlias delegate to the origin type, so lose the information about the concrete parametrization + # As a result, currently, there is no way to cache the schema for generic dataclasses. This may be possible + # to resolve by modifying the value returned by `Generic.__class_getitem__`, but that is a dangerous game. + if dataclasses.is_dataclass(origin): + return self._dataclass_schema(obj, origin) # pyright: ignore[reportArgumentType] + if _typing_extra.is_namedtuple(origin): + return self._namedtuple_schema(obj, origin) + + schema = self._generate_schema_from_get_schema_method(origin, obj) + if schema is not None: + return schema + + if typing_objects.is_typealiastype(origin): + return self._type_alias_type_schema(obj) + elif is_union_origin(origin): + return self._union_schema(obj) + elif origin in TUPLE_TYPES: + return self._tuple_schema(obj) + elif origin in LIST_TYPES: + return self._list_schema(self._get_first_arg_or_any(obj)) + elif origin in SET_TYPES: + return self._set_schema(self._get_first_arg_or_any(obj)) + elif origin in FROZEN_SET_TYPES: + return self._frozenset_schema(self._get_first_arg_or_any(obj)) + elif origin in DICT_TYPES: + return self._dict_schema(*self._get_first_two_args_or_any(obj)) + elif origin in PATH_TYPES: + return self._path_schema(origin, self._get_first_arg_or_any(obj)) + elif origin in DEQUE_TYPES: + return self._deque_schema(self._get_first_arg_or_any(obj)) + elif origin in MAPPING_TYPES: + return self._mapping_schema(origin, *self._get_first_two_args_or_any(obj)) + elif origin in COUNTER_TYPES: + return self._mapping_schema(origin, self._get_first_arg_or_any(obj), int) + elif is_typeddict(origin): + return self._typed_dict_schema(obj, origin) + elif origin in TYPE_TYPES: + return self._subclass_schema(obj) + elif origin in SEQUENCE_TYPES: + return self._sequence_schema(self._get_first_arg_or_any(obj)) + elif origin in ITERABLE_TYPES: + return self._iterable_schema(obj) + elif origin in PATTERN_TYPES: + return self._pattern_schema(obj) + + if self._arbitrary_types: + return self._arbitrary_type_schema(origin) + return self._unknown_type_schema(obj) + + def _generate_td_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + *, + required: bool = True, + ) -> core_schema.TypedDictField: + """Prepare a TypedDictField to represent a model or typeddict field.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.typed_dict_field( + schema, + required=False if not field_info.is_required() else required, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + metadata=metadata, + ) + + def _generate_md_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + ) -> core_schema.ModelField: + """Prepare a ModelField to represent a model field.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.model_field( + schema, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + frozen=field_info.frozen, + metadata=metadata, + ) + + def _generate_dc_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + ) -> core_schema.DataclassField: + """Prepare a DataclassField to represent the parameter/field, of a dataclass.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.dataclass_field( + name, + schema, + init=field_info.init, + init_only=field_info.init_var or None, + kw_only=None if field_info.kw_only else False, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + frozen=field_info.frozen, + metadata=metadata, + ) + + def _common_field_schema( # C901 + self, name: str, field_info: FieldInfo, decorators: DecoratorInfos + ) -> tuple[CoreSchema, dict[str, Any]]: + source_type, annotations = field_info.annotation, field_info.metadata + + def set_discriminator(schema: CoreSchema) -> CoreSchema: + schema = self._apply_discriminator_to_union(schema, field_info.discriminator) + return schema + + # Convert `@field_validator` decorators to `Before/After/Plain/WrapValidator` instances: + validators_from_decorators = [ + _mode_to_validator[decorator.info.mode]._from_decorator(decorator) + for decorator in filter_field_decorator_info_by_field(decorators.field_validators.values(), name) + ] + + with self.field_name_stack.push(name): + if field_info.discriminator is not None: + schema = self._apply_annotations( + source_type, annotations + validators_from_decorators, transform_inner_schema=set_discriminator + ) + else: + schema = self._apply_annotations( + source_type, + annotations + validators_from_decorators, + ) + + # This V1 compatibility shim should eventually be removed + # push down any `each_item=True` validators + # note that this won't work for any Annotated types that get wrapped by a function validator + # but that's okay because that didn't exist in V1 + this_field_validators = filter_field_decorator_info_by_field(decorators.validators.values(), name) + if _validators_require_validate_default(this_field_validators): + field_info.validate_default = True + each_item_validators = [v for v in this_field_validators if v.info.each_item is True] + this_field_validators = [v for v in this_field_validators if v not in each_item_validators] + schema = apply_each_item_validators(schema, each_item_validators) + + schema = apply_validators(schema, this_field_validators) + + # the default validator needs to go outside of any other validators + # so that it is the topmost validator for the field validator + # which uses it to check if the field has a default value or not + if not field_info.is_required(): + schema = wrap_default(field_info, schema) + + schema = self._apply_field_serializers( + schema, filter_field_decorator_info_by_field(decorators.field_serializers.values(), name) + ) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(field_info) + core_metadata: dict[str, Any] = {} + update_core_metadata( + core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra + ) + + return schema, core_metadata + + def _union_schema(self, union_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Union.""" + args = self._get_args_resolving_forward_refs(union_type, required=True) + choices: list[CoreSchema] = [] + nullable = False + for arg in args: + if arg is None or arg is _typing_extra.NoneType: + nullable = True + else: + choices.append(self.generate_schema(arg)) + + if len(choices) == 1: + s = choices[0] + else: + choices_with_tags: list[CoreSchema | tuple[CoreSchema, str]] = [] + for choice in choices: + tag = cast(CoreMetadata, choice.get('metadata', {})).get('pydantic_internal_union_tag_key') + if tag is not None: + choices_with_tags.append((choice, tag)) + else: + choices_with_tags.append(choice) + s = core_schema.union_schema(choices_with_tags) + + if nullable: + s = core_schema.nullable_schema(s) + return s + + def _type_alias_type_schema(self, obj: TypeAliasType) -> CoreSchema: + with self.defs.get_schema_or_ref(obj) as (ref, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + origin: TypeAliasType = get_origin(obj) or obj + typevars_map = get_standard_typevars_map(obj) + + with self._ns_resolver.push(origin): + try: + annotation = _typing_extra.eval_type(origin.__value__, *self._types_namespace) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + annotation = replace_types(annotation, typevars_map) + schema = self.generate_schema(annotation) + assert schema['type'] != 'definitions' + schema['ref'] = ref # type: ignore + return self.defs.create_definition_reference_schema(schema) + + def _literal_schema(self, literal_type: Any) -> CoreSchema: + """Generate schema for a Literal.""" + expected = list(get_literal_values(literal_type, type_check=False, unpack_type_aliases='eager')) + assert expected, f'literal "expected" cannot be empty, obj={literal_type}' + schema = core_schema.literal_schema(expected) + + if self._config_wrapper.use_enum_values and any(isinstance(v, Enum) for v in expected): + schema = core_schema.no_info_after_validator_function( + lambda v: v.value if isinstance(v, Enum) else v, schema + ) + + return schema + + def _typed_dict_schema(self, typed_dict_cls: Any, origin: Any) -> core_schema.CoreSchema: + """Generate a core schema for a `TypedDict` class. + + To be able to build a `DecoratorInfos` instance for the `TypedDict` class (which will include + validators, serializers, etc.), we need to have access to the original bases of the class + (see https://docs.python.org/3/library/types.html#types.get_original_bases). + However, the `__orig_bases__` attribute was only added in 3.12 (https://github.com/python/cpython/pull/103698). + + For this reason, we require Python 3.12 (or using the `typing_extensions` backport). + """ + FieldInfo = import_cached_field_info() + + with ( + self.model_type_stack.push(typed_dict_cls), + self.defs.get_schema_or_ref(typed_dict_cls) as ( + typed_dict_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + + typevars_map = get_standard_typevars_map(typed_dict_cls) + if origin is not None: + typed_dict_cls = origin + + if not _SUPPORTS_TYPEDDICT and type(typed_dict_cls).__module__ == 'typing': + raise PydanticUserError( + 'Please use `typing_extensions.TypedDict` instead of `typing.TypedDict` on Python < 3.12.', + code='typed-dict-version', + ) + + try: + # if a typed dictionary class doesn't have config, we use the parent's config, hence a default of `None` + # see https://github.com/pydantic/pydantic/issues/10917 + config: ConfigDict | None = get_attribute_from_bases(typed_dict_cls, '__pydantic_config__') + except AttributeError: + config = None + + with self._config_wrapper_stack.push(config): + core_config = self._config_wrapper.core_config(title=typed_dict_cls.__name__) + + required_keys: frozenset[str] = typed_dict_cls.__required_keys__ + + fields: dict[str, core_schema.TypedDictField] = {} + + decorators = DecoratorInfos.build(typed_dict_cls) + decorators.update_from_config(self._config_wrapper) + + if self._config_wrapper.use_attribute_docstrings: + field_docstrings = extract_docstrings_from_cls(typed_dict_cls, use_inspect=True) + else: + field_docstrings = None + + try: + annotations = _typing_extra.get_cls_type_hints(typed_dict_cls, ns_resolver=self._ns_resolver) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + readonly_fields: list[str] = [] + + for field_name, annotation in annotations.items(): + field_info = FieldInfo.from_annotation(annotation, _source=AnnotationSource.TYPED_DICT) + field_info.annotation = replace_types(field_info.annotation, typevars_map) + + required = ( + field_name in required_keys or 'required' in field_info._qualifiers + ) and 'not_required' not in field_info._qualifiers + if 'read_only' in field_info._qualifiers: + readonly_fields.append(field_name) + + if ( + field_docstrings is not None + and field_info.description is None + and field_name in field_docstrings + ): + field_info.description = field_docstrings[field_name] + update_field_from_config(self._config_wrapper, field_name, field_info) + + fields[field_name] = self._generate_td_field_schema( + field_name, field_info, decorators, required=required + ) + + if readonly_fields: + fields_repr = ', '.join(repr(f) for f in readonly_fields) + plural = len(readonly_fields) >= 2 + warnings.warn( + f'Item{"s" if plural else ""} {fields_repr} on TypedDict class {typed_dict_cls.__name__!r} ' + f'{"are" if plural else "is"} using the `ReadOnly` qualifier. Pydantic will not protect items ' + 'from any mutation on dictionary instances.', + UserWarning, + ) + + extra_behavior: core_schema.ExtraBehavior = 'ignore' + extras_schema: CoreSchema | None = None # For 'allow', equivalent to `Any` - no validation performed. + + # `__closed__` is `None` when not specified (equivalent to `False`): + is_closed = bool(getattr(typed_dict_cls, '__closed__', False)) + extra_items = getattr(typed_dict_cls, '__extra_items__', typing_extensions.NoExtraItems) + if is_closed: + extra_behavior = 'forbid' + extras_schema = None + elif not typing_objects.is_noextraitems(extra_items): + extra_behavior = 'allow' + extras_schema = self.generate_schema(replace_types(extra_items, typevars_map)) + + if (config_extra := self._config_wrapper.extra) in ('allow', 'forbid'): + if is_closed and config_extra == 'allow': + warnings.warn( + f"TypedDict class {typed_dict_cls.__qualname__!r} is closed, but 'extra' configuration " + "is set to `'allow'`. The 'extra' configuration value will be ignored.", + category=TypedDictExtraConfigWarning, + ) + elif not typing_objects.is_noextraitems(extra_items) and config_extra == 'forbid': + warnings.warn( + f"TypedDict class {typed_dict_cls.__qualname__!r} allows extra items, but 'extra' configuration " + "is set to `'forbid'`. The 'extra' configuration value will be ignored.", + category=TypedDictExtraConfigWarning, + ) + else: + extra_behavior = config_extra + + td_schema = core_schema.typed_dict_schema( + fields, + cls=typed_dict_cls, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in decorators.computed_fields.values() + ], + extra_behavior=extra_behavior, + extras_schema=extras_schema, + ref=typed_dict_ref, + config=core_config, + ) + + schema = self._apply_model_serializers(td_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, decorators.model_validators.values(), 'all') + return self.defs.create_definition_reference_schema(schema) + + def _namedtuple_schema(self, namedtuple_cls: Any, origin: Any) -> core_schema.CoreSchema: + """Generate schema for a NamedTuple.""" + with ( + self.model_type_stack.push(namedtuple_cls), + self.defs.get_schema_or_ref(namedtuple_cls) as ( + namedtuple_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + typevars_map = get_standard_typevars_map(namedtuple_cls) + if origin is not None: + namedtuple_cls = origin + + try: + annotations = _typing_extra.get_cls_type_hints(namedtuple_cls, ns_resolver=self._ns_resolver) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + if not annotations: + # annotations is empty, happens if namedtuple_cls defined via collections.namedtuple(...) + annotations: dict[str, Any] = dict.fromkeys(namedtuple_cls._fields, Any) + + if typevars_map: + annotations = { + field_name: replace_types(annotation, typevars_map) + for field_name, annotation in annotations.items() + } + + arguments_schema = core_schema.arguments_schema( + [ + self._generate_parameter_schema( + field_name, + annotation, + source=AnnotationSource.NAMED_TUPLE, + default=namedtuple_cls._field_defaults.get(field_name, Parameter.empty), + ) + for field_name, annotation in annotations.items() + ], + metadata={'pydantic_js_prefer_positional_arguments': True}, + ) + schema = core_schema.call_schema(arguments_schema, namedtuple_cls, ref=namedtuple_ref) + return self.defs.create_definition_reference_schema(schema) + + def _generate_parameter_schema( + self, + name: str, + annotation: type[Any], + source: AnnotationSource, + default: Any = Parameter.empty, + mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] | None = None, + ) -> core_schema.ArgumentsParameter: + """Generate the definition of a field in a namedtuple or a parameter in a function signature. + + This definition is meant to be used for the `'arguments'` core schema, which will be replaced + in V3 by the `'arguments-v3`'. + """ + FieldInfo = import_cached_field_info() + + if default is Parameter.empty: + field = FieldInfo.from_annotation(annotation, _source=source) + else: + field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) + + assert field.annotation is not None, 'field.annotation should not be None when generating a schema' + update_field_from_config(self._config_wrapper, name, field) + + with self.field_name_stack.push(name): + schema = self._apply_annotations( + field.annotation, + [field], + # Because we pass `field` as metadata above (required for attributes relevant for + # JSON Scheme generation), we need to ignore the potential warnings about `FieldInfo` + # attributes that will not be used: + check_unsupported_field_info_attributes=False, + ) + + if not field.is_required(): + schema = wrap_default(field, schema) + + parameter_schema = core_schema.arguments_parameter( + name, + schema, + mode=mode, + alias=_convert_to_aliases(field.validation_alias), + ) + + return parameter_schema + + def _generate_parameter_v3_schema( + self, + name: str, + annotation: Any, + source: AnnotationSource, + mode: Literal[ + 'positional_only', + 'positional_or_keyword', + 'keyword_only', + 'var_args', + 'var_kwargs_uniform', + 'var_kwargs_unpacked_typed_dict', + ], + default: Any = Parameter.empty, + ) -> core_schema.ArgumentsV3Parameter: + """Generate the definition of a parameter in a function signature. + + This definition is meant to be used for the `'arguments-v3'` core schema, which will replace + the `'arguments`' schema in V3. + """ + FieldInfo = import_cached_field_info() + + if default is Parameter.empty: + field = FieldInfo.from_annotation(annotation, _source=source) + else: + field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) + update_field_from_config(self._config_wrapper, name, field) + + with self.field_name_stack.push(name): + schema = self._apply_annotations( + field.annotation, + [field], + # Because we pass `field` as metadata above (required for attributes relevant for + # JSON Scheme generation), we need to ignore the potential warnings about `FieldInfo` + # attributes that will not be used: + check_unsupported_field_info_attributes=False, + ) + + if not field.is_required(): + schema = wrap_default(field, schema) + + parameter_schema = core_schema.arguments_v3_parameter( + name=name, + schema=schema, + mode=mode, + alias=_convert_to_aliases(field.validation_alias), + ) + + return parameter_schema + + def _tuple_schema(self, tuple_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Tuple, e.g. `tuple[int, str]` or `tuple[int, ...]`.""" + # TODO: do we really need to resolve type vars here? + typevars_map = get_standard_typevars_map(tuple_type) + params = self._get_args_resolving_forward_refs(tuple_type) + + if typevars_map and params: + params = tuple(replace_types(param, typevars_map) for param in params) + + # NOTE: subtle difference: `tuple[()]` gives `params=()`, whereas `typing.Tuple[()]` gives `params=((),)` + # This is only true for <3.11, on Python 3.11+ `typing.Tuple[()]` gives `params=()` + if not params: + if tuple_type in TUPLE_TYPES: + return core_schema.tuple_schema([core_schema.any_schema()], variadic_item_index=0) + else: + # special case for `tuple[()]` which means `tuple[]` - an empty tuple + return core_schema.tuple_schema([]) + elif params[-1] is Ellipsis: + if len(params) == 2: + return core_schema.tuple_schema([self.generate_schema(params[0])], variadic_item_index=0) + else: + # TODO: something like https://github.com/pydantic/pydantic/issues/5952 + raise ValueError('Variable tuples can only have one type') + elif len(params) == 1 and params[0] == (): + # special case for `tuple[()]` which means `tuple[]` - an empty tuple + # NOTE: This conditional can be removed when we drop support for Python 3.10. + return core_schema.tuple_schema([]) + else: + return core_schema.tuple_schema([self.generate_schema(param) for param in params]) + + def _type_schema(self) -> core_schema.CoreSchema: + return core_schema.custom_error_schema( + core_schema.is_instance_schema(type), + custom_error_type='is_type', + custom_error_message='Input should be a type', + ) + + def _zoneinfo_schema(self) -> core_schema.CoreSchema: + """Generate schema for a zone_info.ZoneInfo object""" + from ._validators import validate_str_is_valid_iana_tz + + metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'zoneinfo'}]} + return core_schema.no_info_plain_validator_function( + validate_str_is_valid_iana_tz, + serialization=core_schema.to_string_ser_schema(), + metadata=metadata, + ) + + def _union_is_subclass_schema(self, union_type: Any) -> core_schema.CoreSchema: + """Generate schema for `type[Union[X, ...]]`.""" + args = self._get_args_resolving_forward_refs(union_type, required=True) + return core_schema.union_schema([self.generate_schema(type[args]) for args in args]) + + def _subclass_schema(self, type_: Any) -> core_schema.CoreSchema: + """Generate schema for a type, e.g. `type[int]`.""" + type_param = self._get_first_arg_or_any(type_) + + # Assume `type[Annotated[, ...]]` is equivalent to `type[]`: + type_param = _typing_extra.annotated_type(type_param) or type_param + + if typing_objects.is_any(type_param): + return self._type_schema() + elif typing_objects.is_typealiastype(type_param): + return self.generate_schema(type[type_param.__value__]) + elif typing_objects.is_typevar(type_param): + if type_param.__bound__: + if is_union_origin(get_origin(type_param.__bound__)): + return self._union_is_subclass_schema(type_param.__bound__) + return core_schema.is_subclass_schema(type_param.__bound__) + elif type_param.__constraints__: + return core_schema.union_schema([self.generate_schema(type[c]) for c in type_param.__constraints__]) + else: + return self._type_schema() + elif is_union_origin(get_origin(type_param)): + return self._union_is_subclass_schema(type_param) + else: + if typing_objects.is_self(type_param): + type_param = self._resolve_self_type(type_param) + if _typing_extra.is_generic_alias(type_param): + raise PydanticUserError( + 'Subscripting `type[]` with an already parametrized type is not supported. ' + f'Instead of using type[{type_param!r}], use type[{_repr.display_as_type(get_origin(type_param))}].', + code=None, + ) + if not inspect.isclass(type_param): + # when using type[None], this doesn't type convert to type[NoneType], and None isn't a class + # so we handle it manually here + if type_param is None: + return core_schema.is_subclass_schema(_typing_extra.NoneType) + raise TypeError(f'Expected a class, got {type_param!r}') + return core_schema.is_subclass_schema(type_param) + + def _sequence_schema(self, items_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Sequence, e.g. `Sequence[int]`.""" + from ._serializers import serialize_sequence_via_list + + item_type_schema = self.generate_schema(items_type) + list_schema = core_schema.list_schema(item_type_schema) + + json_schema = smart_deepcopy(list_schema) + python_schema = core_schema.is_instance_schema(typing.Sequence, cls_repr='Sequence') + if not typing_objects.is_any(items_type): + from ._validators import sequence_validator + + python_schema = core_schema.chain_schema( + [python_schema, core_schema.no_info_wrap_validator_function(sequence_validator, list_schema)], + ) + + serialization = core_schema.wrap_serializer_function_ser_schema( + serialize_sequence_via_list, schema=item_type_schema, info_arg=True + ) + return core_schema.json_or_python_schema( + json_schema=json_schema, python_schema=python_schema, serialization=serialization + ) + + def _iterable_schema(self, type_: Any) -> core_schema.GeneratorSchema: + """Generate a schema for an `Iterable`.""" + item_type = self._get_first_arg_or_any(type_) + + return core_schema.generator_schema(self.generate_schema(item_type)) + + def _pattern_schema(self, pattern_type: Any) -> core_schema.CoreSchema: + from . import _validators + + metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'regex'}]} + ser = core_schema.plain_serializer_function_ser_schema( + attrgetter('pattern'), when_used='json', return_schema=core_schema.str_schema() + ) + if pattern_type is typing.Pattern or pattern_type is re.Pattern: + # bare type + return core_schema.no_info_plain_validator_function( + _validators.pattern_either_validator, serialization=ser, metadata=metadata + ) + + param = self._get_args_resolving_forward_refs( + pattern_type, + required=True, + )[0] + if param is str: + return core_schema.no_info_plain_validator_function( + _validators.pattern_str_validator, serialization=ser, metadata=metadata + ) + elif param is bytes: + return core_schema.no_info_plain_validator_function( + _validators.pattern_bytes_validator, serialization=ser, metadata=metadata + ) + else: + raise PydanticSchemaGenerationError(f'Unable to generate pydantic-core schema for {pattern_type!r}.') + + def _hashable_schema(self) -> core_schema.CoreSchema: + return core_schema.custom_error_schema( + schema=core_schema.json_or_python_schema( + json_schema=core_schema.chain_schema( + [core_schema.any_schema(), core_schema.is_instance_schema(collections.abc.Hashable)] + ), + python_schema=core_schema.is_instance_schema(collections.abc.Hashable), + ), + custom_error_type='is_hashable', + custom_error_message='Input should be hashable', + ) + + def _dataclass_schema( + self, dataclass: type[StandardDataclass], origin: type[StandardDataclass] | None + ) -> core_schema.CoreSchema: + """Generate schema for a dataclass.""" + with ( + self.model_type_stack.push(dataclass), + self.defs.get_schema_or_ref(dataclass) as ( + dataclass_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + + schema = dataclass.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, MockCoreSchema): + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + else: + return schema + + typevars_map = get_standard_typevars_map(dataclass) + if origin is not None: + dataclass = origin + + # if (plain) dataclass doesn't have config, we use the parent's config, hence a default of `None` + # (Pydantic dataclasses have an empty dict config by default). + # see https://github.com/pydantic/pydantic/issues/10917 + config = getattr(dataclass, '__pydantic_config__', None) + + from ..dataclasses import is_pydantic_dataclass + + with self._ns_resolver.push(dataclass), self._config_wrapper_stack.push(config): + if is_pydantic_dataclass(dataclass): + if dataclass.__pydantic_fields_complete__(): + # Copy the field info instances to avoid mutating the `FieldInfo` instances + # of the generic dataclass generic origin (e.g. `apply_typevars_map` below). + # Note that we don't apply `deepcopy` on `__pydantic_fields__` because we + # don't want to copy the `FieldInfo` attributes: + fields = { + f_name: copy(field_info) for f_name, field_info in dataclass.__pydantic_fields__.items() + } + if typevars_map: + for field in fields.values(): + field.apply_typevars_map(typevars_map, *self._types_namespace) + else: + try: + fields = rebuild_dataclass_fields( + dataclass, + config_wrapper=self._config_wrapper, + ns_resolver=self._ns_resolver, + typevars_map=typevars_map or {}, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + else: + fields = collect_dataclass_fields( + dataclass, + typevars_map=typevars_map, + config_wrapper=self._config_wrapper, + ) + + if self._config_wrapper.extra == 'allow': + # disallow combination of init=False on a dataclass field and extra='allow' on a dataclass + for field_name, field in fields.items(): + if field.init is False: + raise PydanticUserError( + f'Field {field_name} has `init=False` and dataclass has config setting `extra="allow"`. ' + f'This combination is not allowed.', + code='dataclass-init-false-extra-allow', + ) + + decorators = dataclass.__dict__.get('__pydantic_decorators__') + if decorators is None: + decorators = DecoratorInfos.build(dataclass) + decorators.update_from_config(self._config_wrapper) + # Move kw_only=False args to the start of the list, as this is how vanilla dataclasses work. + # Note that when kw_only is missing or None, it is treated as equivalent to kw_only=True + args = sorted( + (self._generate_dc_field_schema(k, v, decorators) for k, v in fields.items()), + key=lambda a: a.get('kw_only') is not False, + ) + has_post_init = hasattr(dataclass, '__post_init__') + has_slots = hasattr(dataclass, '__slots__') + + args_schema = core_schema.dataclass_args_schema( + dataclass.__name__, + args, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in decorators.computed_fields.values() + ], + collect_init_only=has_post_init, + ) + + inner_schema = apply_validators(args_schema, decorators.root_validators.values()) + + model_validators = decorators.model_validators.values() + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + + core_config = self._config_wrapper.core_config(title=dataclass.__name__) + + dc_schema = core_schema.dataclass_schema( + dataclass, + inner_schema, + generic_origin=origin, + post_init=has_post_init, + ref=dataclass_ref, + fields=[field.name for field in dataclasses.fields(dataclass)], + slots=has_slots, + config=core_config, + # we don't use a custom __setattr__ for dataclasses, so we must + # pass along the frozen config setting to the pydantic-core schema + frozen=self._config_wrapper_stack.tail.frozen, + ) + schema = self._apply_model_serializers(dc_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, model_validators, 'outer') + return self.defs.create_definition_reference_schema(schema) + + def _call_schema(self, function: ValidateCallSupportedTypes) -> core_schema.CallSchema: + """Generate schema for a Callable. + + TODO support functional validators once we support them in Config + """ + arguments_schema = self._arguments_schema(function) + + return_schema: core_schema.CoreSchema | None = None + config_wrapper = self._config_wrapper + if config_wrapper.validate_return: + sig = signature(function) + return_hint = sig.return_annotation + if return_hint is not sig.empty: + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints( + function, globalns=globalns, localns=localns, include_keys={'return'} + ) + return_schema = self.generate_schema(type_hints['return']) + + return core_schema.call_schema( + arguments_schema, + function, + return_schema=return_schema, + ) + + def _arguments_schema( + self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None + ) -> core_schema.ArgumentsSchema: + """Generate schema for a Signature.""" + mode_lookup: dict[_ParameterKind, Literal['positional_only', 'positional_or_keyword', 'keyword_only']] = { + Parameter.POSITIONAL_ONLY: 'positional_only', + Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword', + Parameter.KEYWORD_ONLY: 'keyword_only', + } + + sig = signature(function) + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) + + arguments_list: list[core_schema.ArgumentsParameter] = [] + var_args_schema: core_schema.CoreSchema | None = None + var_kwargs_schema: core_schema.CoreSchema | None = None + var_kwargs_mode: core_schema.VarKwargsMode | None = None + + for i, (name, p) in enumerate(sig.parameters.items()): + if p.annotation is sig.empty: + annotation = typing.cast(Any, Any) + else: + annotation = type_hints[name] + + if parameters_callback is not None: + result = parameters_callback(i, name, annotation) + if result == 'skip': + continue + + parameter_mode = mode_lookup.get(p.kind) + if parameter_mode is not None: + arg_schema = self._generate_parameter_schema( + name, annotation, AnnotationSource.FUNCTION, p.default, parameter_mode + ) + arguments_list.append(arg_schema) + elif p.kind == Parameter.VAR_POSITIONAL: + var_args_schema = self.generate_schema(annotation) + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + + unpack_type = _typing_extra.unpack_type(annotation) + if unpack_type is not None: + origin = get_origin(unpack_type) or unpack_type + if not is_typeddict(origin): + raise PydanticUserError( + f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}', + code='unpack-typed-dict', + ) + non_pos_only_param_names = { + name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY + } + overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) + if overlapping_params: + raise PydanticUserError( + f'Typed dictionary {origin.__name__!r} overlaps with parameter' + f'{"s" if len(overlapping_params) >= 2 else ""} ' + f'{", ".join(repr(p) for p in sorted(overlapping_params))}', + code='overlapping-unpack-typed-dict', + ) + + var_kwargs_mode = 'unpacked-typed-dict' + var_kwargs_schema = self._typed_dict_schema(unpack_type, get_origin(unpack_type)) + else: + var_kwargs_mode = 'uniform' + var_kwargs_schema = self.generate_schema(annotation) + + return core_schema.arguments_schema( + arguments_list, + var_args_schema=var_args_schema, + var_kwargs_mode=var_kwargs_mode, + var_kwargs_schema=var_kwargs_schema, + validate_by_name=self._config_wrapper.validate_by_name, + ) + + def _arguments_v3_schema( + self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None + ) -> core_schema.ArgumentsV3Schema: + mode_lookup: dict[ + _ParameterKind, Literal['positional_only', 'positional_or_keyword', 'var_args', 'keyword_only'] + ] = { + Parameter.POSITIONAL_ONLY: 'positional_only', + Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword', + Parameter.VAR_POSITIONAL: 'var_args', + Parameter.KEYWORD_ONLY: 'keyword_only', + } + + sig = signature(function) + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) + + parameters_list: list[core_schema.ArgumentsV3Parameter] = [] + + for i, (name, p) in enumerate(sig.parameters.items()): + if parameters_callback is not None: + result = parameters_callback(i, name, p.annotation) + if result == 'skip': + continue + + if p.annotation is Parameter.empty: + annotation = typing.cast(Any, Any) + else: + annotation = type_hints[name] + + parameter_mode = mode_lookup.get(p.kind) + if parameter_mode is None: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + + unpack_type = _typing_extra.unpack_type(annotation) + if unpack_type is not None: + origin = get_origin(unpack_type) or unpack_type + if not is_typeddict(origin): + raise PydanticUserError( + f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}', + code='unpack-typed-dict', + ) + non_pos_only_param_names = { + name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY + } + overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) + if overlapping_params: + raise PydanticUserError( + f'Typed dictionary {origin.__name__!r} overlaps with parameter' + f'{"s" if len(overlapping_params) >= 2 else ""} ' + f'{", ".join(repr(p) for p in sorted(overlapping_params))}', + code='overlapping-unpack-typed-dict', + ) + parameter_mode = 'var_kwargs_unpacked_typed_dict' + annotation = unpack_type + else: + parameter_mode = 'var_kwargs_uniform' + + parameters_list.append( + self._generate_parameter_v3_schema( + name, annotation, AnnotationSource.FUNCTION, parameter_mode, default=p.default + ) + ) + + return core_schema.arguments_v3_schema( + parameters_list, + validate_by_name=self._config_wrapper.validate_by_name, + ) + + def _unsubstituted_typevar_schema(self, typevar: typing.TypeVar) -> core_schema.CoreSchema: + try: + has_default = typevar.has_default() # pyright: ignore[reportAttributeAccessIssue] + except AttributeError: + # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13 + pass + else: + if has_default: + return self.generate_schema(typevar.__default__) # pyright: ignore[reportAttributeAccessIssue] + + if constraints := typevar.__constraints__: + return self._union_schema(typing.Union[constraints]) + + if bound := typevar.__bound__: + schema = self.generate_schema(bound) + schema['serialization'] = core_schema.simple_ser_schema('any') + return schema + + return core_schema.any_schema() + + def _computed_field_schema( + self, + d: Decorator[ComputedFieldInfo], + field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]], + ) -> core_schema.ComputedField: + if d.info.return_type is not PydanticUndefined: + return_type = d.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type(d.func, localns=self._types_namespace.locals) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + if return_type is PydanticUndefined: + raise PydanticUserError( + 'Computed field is missing return type annotation or specifying `return_type`' + ' to the `@computed_field` decorator (e.g. `@computed_field(return_type=int | str)`)', + code='model-field-missing-annotation', + ) + + return_type = replace_types(return_type, self._typevars_map) + # Create a new ComputedFieldInfo so that different type parametrizations of the same + # generic model's computed field can have different return types. + d.info = dataclasses.replace(d.info, return_type=return_type) + return_type_schema = self.generate_schema(return_type) + # Apply serializers to computed field if there exist + return_type_schema = self._apply_field_serializers( + return_type_schema, + filter_field_decorator_info_by_field(field_serializers.values(), d.cls_var_name), + ) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(d.info) + core_metadata: dict[str, Any] = {} + update_core_metadata( + core_metadata, + pydantic_js_updates={'readOnly': True, **(pydantic_js_updates if pydantic_js_updates else {})}, + pydantic_js_extra=pydantic_js_extra, + ) + return core_schema.computed_field( + d.cls_var_name, return_schema=return_type_schema, alias=d.info.alias, metadata=core_metadata + ) + + def _annotated_schema(self, annotated_type: Any) -> core_schema.CoreSchema: + """Generate schema for an Annotated type, e.g. `Annotated[int, Field(...)]` or `Annotated[int, Gt(0)]`.""" + FieldInfo = import_cached_field_info() + source_type, *annotations = self._get_args_resolving_forward_refs( + annotated_type, + required=True, + ) + schema = self._apply_annotations(source_type, annotations) + # put the default validator last so that TypeAdapter.get_default_value() works + # even if there are function validators involved + for annotation in annotations: + if isinstance(annotation, FieldInfo): + schema = wrap_default(annotation, schema) + return schema + + def _apply_annotations( + self, + source_type: Any, + annotations: list[Any], + transform_inner_schema: Callable[[CoreSchema], CoreSchema] = lambda x: x, + check_unsupported_field_info_attributes: bool = True, + ) -> CoreSchema: + """Apply arguments from `Annotated` or from `FieldInfo` to a schema. + + This gets called by `GenerateSchema._annotated_schema` but differs from it in that it does + not expect `source_type` to be an `Annotated` object, it expects it to be the first argument of that + (in other words, `GenerateSchema._annotated_schema` just unpacks `Annotated`, this process it). + """ + annotations = list(_known_annotated_metadata.expand_grouped_metadata(annotations)) + + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] = [] + + def inner_handler(obj: Any) -> CoreSchema: + schema = self._generate_schema_from_get_schema_method(obj, source_type) + + if schema is None: + schema = self._generate_schema_inner(obj) + + metadata_js_function = _extract_get_pydantic_json_schema(obj) + if metadata_js_function is not None: + metadata_schema = resolve_original_schema(schema, self.defs) + if metadata_schema is not None: + self._add_js_function(metadata_schema, metadata_js_function) + return transform_inner_schema(schema) + + get_inner_schema = CallbackGetCoreSchemaHandler(inner_handler, self) + + for annotation in annotations: + if annotation is None: + continue + get_inner_schema = self._get_wrapped_inner_schema( + get_inner_schema, + annotation, + pydantic_js_annotation_functions, + check_unsupported_field_info_attributes=check_unsupported_field_info_attributes, + ) + + schema = get_inner_schema(source_type) + if pydantic_js_annotation_functions: + core_metadata = schema.setdefault('metadata', {}) + update_core_metadata(core_metadata, pydantic_js_annotation_functions=pydantic_js_annotation_functions) + return _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, source_type, schema) + + def _apply_single_annotation( + self, + schema: core_schema.CoreSchema, + metadata: Any, + check_unsupported_field_info_attributes: bool = True, + ) -> core_schema.CoreSchema: + FieldInfo = import_cached_field_info() + + if isinstance(metadata, FieldInfo): + if ( + check_unsupported_field_info_attributes + # HACK: we don't want to emit the warning for `FieldInfo` subclasses, because FastAPI does weird manipulations + # with its subclasses and their annotations: + and type(metadata) is FieldInfo + ): + for attr, value in (unsupported_attributes := self._get_unsupported_field_info_attributes(metadata)): + warnings.warn( + f'The {attr!r} attribute with value {value!r} was provided to the `Field()` function, ' + f'which has no effect in the context it was used. {attr!r} is field-specific metadata, ' + 'and can only be attached to a model field using `Annotated` metadata or by assignment. ' + 'This may have happened because an `Annotated` type alias using the `type` statement was ' + 'used, or if the `Field()` function was attached to a single member of a union type.', + category=UnsupportedFieldAttributeWarning, + ) + + if ( + metadata.default_factory_takes_validated_data + and self.model_type_stack.get() is None + and 'defaut_factory' not in unsupported_attributes + ): + warnings.warn( + "A 'default_factory' taking validated data as an argument was provided to the `Field()` function, " + 'but no validated data is available in the context it was used.', + category=UnsupportedFieldAttributeWarning, + ) + + for field_metadata in metadata.metadata: + schema = self._apply_single_annotation(schema, field_metadata) + + if metadata.discriminator is not None: + schema = self._apply_discriminator_to_union(schema, metadata.discriminator) + return schema + + if schema['type'] == 'nullable': + # for nullable schemas, metadata is automatically applied to the inner schema + inner = schema.get('schema', core_schema.any_schema()) + inner = self._apply_single_annotation(inner, metadata) + if inner: + schema['schema'] = inner + return schema + + original_schema = schema + ref = schema.get('ref') + if ref is not None: + schema = schema.copy() + new_ref = ref + f'_{repr(metadata)}' + if (existing := self.defs.get_schema_from_ref(new_ref)) is not None: + return existing + schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues] + elif schema['type'] == 'definition-ref': + ref = schema['schema_ref'] + if (referenced_schema := self.defs.get_schema_from_ref(ref)) is not None: + schema = referenced_schema.copy() + new_ref = ref + f'_{repr(metadata)}' + if (existing := self.defs.get_schema_from_ref(new_ref)) is not None: + return existing + schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues] + + maybe_updated_schema = _known_annotated_metadata.apply_known_metadata(metadata, schema) + + if maybe_updated_schema is not None: + return maybe_updated_schema + return original_schema + + def _apply_single_annotation_json_schema( + self, schema: core_schema.CoreSchema, metadata: Any + ) -> core_schema.CoreSchema: + FieldInfo = import_cached_field_info() + + if isinstance(metadata, FieldInfo): + for field_metadata in metadata.metadata: + schema = self._apply_single_annotation_json_schema(schema, field_metadata) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(metadata) + core_metadata = schema.setdefault('metadata', {}) + update_core_metadata( + core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra + ) + return schema + + def _get_unsupported_field_info_attributes(self, field_info: FieldInfo) -> list[tuple[str, Any]]: + """Get the list of unsupported `FieldInfo` attributes when not directly used in `Annotated` for field annotations.""" + unused_metadata: list[tuple[str, Any]] = [] + for unused_metadata_name, unset_value in UNSUPPORTED_STANDALONE_FIELDINFO_ATTRIBUTES: + if ( + (unused_metadata_value := getattr(field_info, unused_metadata_name)) is not unset_value + # `default` and `default_factory` can still be used with a type adapter, so only include them + # if used with a model-like class: + and ( + unused_metadata_name not in ('default', 'default_factory') + or self.model_type_stack.get() is not None + ) + # Setting `alias` will set `validation/serialization_alias` as well, so we want to avoid duplicate warnings: + and ( + unused_metadata_name not in ('validation_alias', 'serialization_alias') + or 'alias' not in field_info._attributes_set + ) + ): + unused_metadata.append((unused_metadata_name, unused_metadata_value)) + + return unused_metadata + + def _get_wrapped_inner_schema( + self, + get_inner_schema: GetCoreSchemaHandler, + annotation: Any, + pydantic_js_annotation_functions: list[GetJsonSchemaFunction], + check_unsupported_field_info_attributes: bool = False, + ) -> CallbackGetCoreSchemaHandler: + annotation_get_schema: GetCoreSchemaFunction | None = getattr(annotation, '__get_pydantic_core_schema__', None) + + def new_handler(source: Any) -> core_schema.CoreSchema: + if annotation_get_schema is not None: + schema = annotation_get_schema(source, get_inner_schema) + else: + schema = get_inner_schema(source) + schema = self._apply_single_annotation( + schema, + annotation, + check_unsupported_field_info_attributes=check_unsupported_field_info_attributes, + ) + schema = self._apply_single_annotation_json_schema(schema, annotation) + + metadata_js_function = _extract_get_pydantic_json_schema(annotation) + if metadata_js_function is not None: + pydantic_js_annotation_functions.append(metadata_js_function) + return schema + + return CallbackGetCoreSchemaHandler(new_handler, self) + + def _apply_field_serializers( + self, + schema: core_schema.CoreSchema, + serializers: list[Decorator[FieldSerializerDecoratorInfo]], + ) -> core_schema.CoreSchema: + """Apply field serializers to a schema.""" + if serializers: + schema = copy(schema) + if schema['type'] == 'definitions': + inner_schema = schema['schema'] + schema['schema'] = self._apply_field_serializers(inner_schema, serializers) + return schema + elif 'ref' in schema: + schema = self.defs.create_definition_reference_schema(schema) + + # use the last serializer to make it easy to override a serializer set on a parent model + serializer = serializers[-1] + is_field_serializer, info_arg = inspect_field_serializer(serializer.func, serializer.info.mode) + + if serializer.info.return_type is not PydanticUndefined: + return_type = serializer.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + serializer.func, localns=self._types_namespace.locals + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + if return_type is PydanticUndefined: + return_schema = None + else: + return_schema = self.generate_schema(return_type) + + if serializer.info.mode == 'wrap': + schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + serializer.func, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + else: + assert serializer.info.mode == 'plain' + schema['serialization'] = core_schema.plain_serializer_function_ser_schema( + serializer.func, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + return schema + + def _apply_model_serializers( + self, schema: core_schema.CoreSchema, serializers: Iterable[Decorator[ModelSerializerDecoratorInfo]] + ) -> core_schema.CoreSchema: + """Apply model serializers to a schema.""" + ref: str | None = schema.pop('ref', None) # type: ignore + if serializers: + serializer = list(serializers)[-1] + info_arg = inspect_model_serializer(serializer.func, serializer.info.mode) + + if serializer.info.return_type is not PydanticUndefined: + return_type = serializer.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + serializer.func, localns=self._types_namespace.locals + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + if return_type is PydanticUndefined: + return_schema = None + else: + return_schema = self.generate_schema(return_type) + + if serializer.info.mode == 'wrap': + ser_schema: core_schema.SerSchema = core_schema.wrap_serializer_function_ser_schema( + serializer.func, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + else: + # plain + ser_schema = core_schema.plain_serializer_function_ser_schema( + serializer.func, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + schema['serialization'] = ser_schema + if ref: + schema['ref'] = ref # type: ignore + return schema + + +_VALIDATOR_F_MATCH: Mapping[ + tuple[FieldValidatorModes, Literal['no-info', 'with-info']], + Callable[[Callable[..., Any], core_schema.CoreSchema], core_schema.CoreSchema], +] = { + ('before', 'no-info'): lambda f, schema: core_schema.no_info_before_validator_function(f, schema), + ('after', 'no-info'): lambda f, schema: core_schema.no_info_after_validator_function(f, schema), + ('plain', 'no-info'): lambda f, _: core_schema.no_info_plain_validator_function(f), + ('wrap', 'no-info'): lambda f, schema: core_schema.no_info_wrap_validator_function(f, schema), + ('before', 'with-info'): lambda f, schema: core_schema.with_info_before_validator_function(f, schema), + ('after', 'with-info'): lambda f, schema: core_schema.with_info_after_validator_function(f, schema), + ('plain', 'with-info'): lambda f, _: core_schema.with_info_plain_validator_function(f), + ('wrap', 'with-info'): lambda f, schema: core_schema.with_info_wrap_validator_function(f, schema), +} + + +# TODO V3: this function is only used for deprecated decorators. It should +# be removed once we drop support for those. +def apply_validators( + schema: core_schema.CoreSchema, + validators: Iterable[Decorator[RootValidatorDecoratorInfo]] + | Iterable[Decorator[ValidatorDecoratorInfo]] + | Iterable[Decorator[FieldValidatorDecoratorInfo]], +) -> core_schema.CoreSchema: + """Apply validators to a schema. + + Args: + schema: The schema to apply validators on. + validators: An iterable of validators. + field_name: The name of the field if validators are being applied to a model field. + + Returns: + The updated schema. + """ + for validator in validators: + # Actually, type could be 'field' or 'model', but this is only used for deprecated + # decorators, so let's not worry about it. + info_arg = inspect_validator(validator.func, mode=validator.info.mode, type='field') + val_type = 'with-info' if info_arg else 'no-info' + + schema = _VALIDATOR_F_MATCH[(validator.info.mode, val_type)](validator.func, schema) + return schema + + +def _validators_require_validate_default(validators: Iterable[Decorator[ValidatorDecoratorInfo]]) -> bool: + """In v1, if any of the validators for a field had `always=True`, the default value would be validated. + + This serves as an auxiliary function for re-implementing that logic, by looping over a provided + collection of (v1-style) ValidatorDecoratorInfo's and checking if any of them have `always=True`. + + We should be able to drop this function and the associated logic calling it once we drop support + for v1-style validator decorators. (Or we can extend it and keep it if we add something equivalent + to the v1-validator `always` kwarg to `field_validator`.) + """ + for validator in validators: + if validator.info.always: + return True + return False + + +def _convert_to_aliases( + alias: str | AliasChoices | AliasPath | None, +) -> str | list[str | int] | list[list[str | int]] | None: + if isinstance(alias, (AliasChoices, AliasPath)): + return alias.convert_to_aliases() + else: + return alias + + +def apply_model_validators( + schema: core_schema.CoreSchema, + validators: Iterable[Decorator[ModelValidatorDecoratorInfo]], + mode: Literal['inner', 'outer', 'all'], +) -> core_schema.CoreSchema: + """Apply model validators to a schema. + + If mode == 'inner', only "before" validators are applied + If mode == 'outer', validators other than "before" are applied + If mode == 'all', all validators are applied + + Args: + schema: The schema to apply validators on. + validators: An iterable of validators. + mode: The validator mode. + + Returns: + The updated schema. + """ + ref: str | None = schema.pop('ref', None) # type: ignore + for validator in validators: + if mode == 'inner' and validator.info.mode != 'before': + continue + if mode == 'outer' and validator.info.mode == 'before': + continue + info_arg = inspect_validator(validator.func, mode=validator.info.mode, type='model') + if validator.info.mode == 'wrap': + if info_arg: + schema = core_schema.with_info_wrap_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_wrap_validator_function(function=validator.func, schema=schema) + elif validator.info.mode == 'before': + if info_arg: + schema = core_schema.with_info_before_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_before_validator_function(function=validator.func, schema=schema) + else: + assert validator.info.mode == 'after' + if info_arg: + schema = core_schema.with_info_after_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_after_validator_function(function=validator.func, schema=schema) + if ref: + schema['ref'] = ref # type: ignore + return schema + + +def wrap_default(field_info: FieldInfo, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Wrap schema with default schema if default value or `default_factory` are available. + + Args: + field_info: The field info object. + schema: The schema to apply default on. + + Returns: + Updated schema by default value or `default_factory`. + """ + if field_info.default_factory: + return core_schema.with_default_schema( + schema, + default_factory=field_info.default_factory, + default_factory_takes_data=takes_validated_data_argument(field_info.default_factory), + validate_default=field_info.validate_default, + ) + elif field_info.default is not PydanticUndefined: + return core_schema.with_default_schema( + schema, default=field_info.default, validate_default=field_info.validate_default + ) + else: + return schema + + +def _extract_get_pydantic_json_schema(tp: Any) -> GetJsonSchemaFunction | None: + """Extract `__get_pydantic_json_schema__` from a type, handling the deprecated `__modify_schema__`.""" + js_modify_function = getattr(tp, '__get_pydantic_json_schema__', None) + + if hasattr(tp, '__modify_schema__'): + BaseModel = import_cached_base_model() + + has_custom_v2_modify_js_func = ( + js_modify_function is not None + and BaseModel.__get_pydantic_json_schema__.__func__ # type: ignore + not in (js_modify_function, getattr(js_modify_function, '__func__', None)) + ) + + if not has_custom_v2_modify_js_func: + cls_name = getattr(tp, '__name__', None) + raise PydanticUserError( + f'The `__modify_schema__` method is not supported in Pydantic v2. ' + f'Use `__get_pydantic_json_schema__` instead{f" in class `{cls_name}`" if cls_name else ""}.', + code='custom-json-schema', + ) + + if (origin := get_origin(tp)) is not None: + # Generic aliases proxy attribute access to the origin, *except* dunder attributes, + # such as `__get_pydantic_json_schema__`, hence the explicit check. + return _extract_get_pydantic_json_schema(origin) + + if js_modify_function is None: + return None + + return js_modify_function + + +def resolve_original_schema(schema: CoreSchema, definitions: _Definitions) -> CoreSchema | None: + if schema['type'] == 'definition-ref': + return definitions.get_schema_from_ref(schema['schema_ref']) + elif schema['type'] == 'definitions': + return schema['schema'] + else: + return schema + + +def _inlining_behavior( + def_ref: core_schema.DefinitionReferenceSchema, +) -> Literal['inline', 'keep', 'preserve_metadata']: + """Determine the inlining behavior of the `'definition-ref'` schema. + + - If no `'serialization'` schema and no metadata is attached, the schema can safely be inlined. + - If it has metadata but only related to the deferred discriminator application, it can be inlined + provided that such metadata is kept. + - Otherwise, the schema should not be inlined. Doing so would remove the `'serialization'` schema or metadata. + """ + if 'serialization' in def_ref: + return 'keep' + metadata = def_ref.get('metadata') + if not metadata: + return 'inline' + if len(metadata) == 1 and 'pydantic_internal_union_discriminator' in metadata: + return 'preserve_metadata' + return 'keep' + + +class _Definitions: + """Keeps track of references and definitions.""" + + _recursively_seen: set[str] + """A set of recursively seen references. + + When a referenceable type is encountered, the `get_schema_or_ref` context manager is + entered to compute the reference. If the type references itself by some way (e.g. for + a dataclass a Pydantic model, the class can be referenced as a field annotation), + entering the context manager again will yield a `'definition-ref'` schema that should + short-circuit the normal generation process, as the reference was already in this set. + """ + + _definitions: dict[str, core_schema.CoreSchema] + """A mapping of references to their corresponding schema. + + When a schema for a referenceable type is generated, it is stored in this mapping. If the + same type is encountered again, the reference is yielded by the `get_schema_or_ref` context + manager. + """ + + def __init__(self) -> None: + self._recursively_seen = set() + self._definitions = {} + + @contextmanager + def get_schema_or_ref(self, tp: Any, /) -> Generator[tuple[str, core_schema.DefinitionReferenceSchema | None]]: + """Get a definition for `tp` if one exists. + + If a definition exists, a tuple of `(ref_string, CoreSchema)` is returned. + If no definition exists yet, a tuple of `(ref_string, None)` is returned. + + Note that the returned `CoreSchema` will always be a `DefinitionReferenceSchema`, + not the actual definition itself. + + This should be called for any type that can be identified by reference. + This includes any recursive types. + + At present the following types can be named/recursive: + + - Pydantic model + - Pydantic and stdlib dataclasses + - Typed dictionaries + - Named tuples + - `TypeAliasType` instances + - Enums + """ + ref = get_type_ref(tp) + # return the reference if we're either (1) in a cycle or (2) it the reference was already encountered: + if ref in self._recursively_seen or ref in self._definitions: + yield (ref, core_schema.definition_reference_schema(ref)) + else: + self._recursively_seen.add(ref) + try: + yield (ref, None) + finally: + self._recursively_seen.discard(ref) + + def get_schema_from_ref(self, ref: str) -> CoreSchema | None: + """Resolve the schema from the given reference.""" + return self._definitions.get(ref) + + def create_definition_reference_schema(self, schema: CoreSchema) -> core_schema.DefinitionReferenceSchema: + """Store the schema as a definition and return a `'definition-reference'` schema pointing to it. + + The schema must have a reference attached to it. + """ + ref = schema['ref'] # pyright: ignore + self._definitions[ref] = schema + return core_schema.definition_reference_schema(ref) + + def unpack_definitions(self, schema: core_schema.DefinitionsSchema) -> CoreSchema: + """Store the definitions of the `'definitions'` core schema and return the inner core schema.""" + for def_schema in schema['definitions']: + self._definitions[def_schema['ref']] = def_schema # pyright: ignore + return schema['schema'] + + def finalize_schema(self, schema: CoreSchema) -> CoreSchema: + """Finalize the core schema. + + This traverses the core schema and referenced definitions, replaces `'definition-ref'` schemas + by the referenced definition if possible, and applies deferred discriminators. + """ + definitions = self._definitions + try: + gather_result = gather_schemas_for_cleaning( + schema, + definitions=definitions, + ) + except MissingDefinitionError as e: + raise InvalidSchemaError from e + + remaining_defs: dict[str, CoreSchema] = {} + + # Note: this logic doesn't play well when core schemas with deferred discriminator metadata + # and references are encountered. See the `test_deferred_discriminated_union_and_references()` test. + for ref, inlinable_def_ref in gather_result['collected_references'].items(): + if inlinable_def_ref is not None and (inlining_behavior := _inlining_behavior(inlinable_def_ref)) != 'keep': + if inlining_behavior == 'inline': + # `ref` was encountered, and only once: + # - `inlinable_def_ref` is a `'definition-ref'` schema and is guaranteed to be + # the only one. Transform it into the definition it points to. + # - Do not store the definition in the `remaining_defs`. + inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue] + inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore + elif inlining_behavior == 'preserve_metadata': + # `ref` was encountered, and only once, but contains discriminator metadata. + # We will do the same thing as if `inlining_behavior` was `'inline'`, but make + # sure to keep the metadata for the deferred discriminator application logic below. + meta = inlinable_def_ref.pop('metadata') + inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue] + inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore + inlinable_def_ref['metadata'] = meta + else: + # `ref` was encountered, at least two times (or only once, but with metadata or a serialization schema): + # - Do not inline the `'definition-ref'` schemas (they are not provided in the gather result anyway). + # - Store the the definition in the `remaining_defs` + remaining_defs[ref] = self._resolve_definition(ref, definitions) + + for cs in gather_result['deferred_discriminator_schemas']: + discriminator: str | None = cs['metadata'].pop('pydantic_internal_union_discriminator', None) # pyright: ignore[reportTypedDictNotRequiredAccess] + if discriminator is None: + # This can happen in rare scenarios, when a deferred schema is present multiple times in the + # gather result (e.g. when using the `Sequence` type -- see `test_sequence_discriminated_union()`). + # In this case, a previous loop iteration applied the discriminator and so we can just skip it here. + continue + applied = _discriminated_union.apply_discriminator(cs.copy(), discriminator, remaining_defs) + # Mutate the schema directly to have the discriminator applied + cs.clear() # pyright: ignore[reportAttributeAccessIssue] + cs.update(applied) # pyright: ignore + + if remaining_defs: + schema = core_schema.definitions_schema(schema=schema, definitions=[*remaining_defs.values()]) + return schema + + def _resolve_definition(self, ref: str, definitions: dict[str, CoreSchema]) -> CoreSchema: + definition = definitions[ref] + if definition['type'] != 'definition-ref': + return definition + + # Some `'definition-ref'` schemas might act as "intermediate" references (e.g. when using + # a PEP 695 type alias (which is referenceable) that references another PEP 695 type alias): + visited: set[str] = set() + while definition['type'] == 'definition-ref' and _inlining_behavior(definition) == 'inline': + schema_ref = definition['schema_ref'] + if schema_ref in visited: + raise PydanticUserError( + f'{ref} contains a circular reference to itself.', code='circular-reference-schema' + ) + visited.add(schema_ref) + definition = definitions[schema_ref] + return {**definition, 'ref': ref} # pyright: ignore[reportReturnType] + + +class _FieldNameStack: + __slots__ = ('_stack',) + + def __init__(self) -> None: + self._stack: list[str] = [] + + @contextmanager + def push(self, field_name: str) -> Iterator[None]: + self._stack.append(field_name) + yield + self._stack.pop() + + def get(self) -> str | None: + if self._stack: + return self._stack[-1] + else: + return None + + +class _ModelTypeStack: + __slots__ = ('_stack',) + + def __init__(self) -> None: + self._stack: list[type] = [] + + @contextmanager + def push(self, type_obj: type) -> Iterator[None]: + self._stack.append(type_obj) + yield + self._stack.pop() + + def get(self) -> type | None: + if self._stack: + return self._stack[-1] + else: + return None diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_generics.py b/backend/venv/Lib/site-packages/pydantic/_internal/_generics.py new file mode 100644 index 0000000..f9f88a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_generics.py @@ -0,0 +1,543 @@ +from __future__ import annotations + +import operator +import sys +import types +import typing +from collections import ChainMap +from collections.abc import Iterator, Mapping +from contextlib import contextmanager +from contextvars import ContextVar +from functools import reduce +from itertools import zip_longest +from types import prepare_class +from typing import TYPE_CHECKING, Annotated, Any, TypedDict, TypeVar, cast +from weakref import WeakValueDictionary + +import typing_extensions +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from . import _typing_extra +from ._core_utils import get_type_ref +from ._forward_ref import PydanticRecursiveRef +from ._utils import all_identical, is_model_class + +if TYPE_CHECKING: + from ..main import BaseModel + +GenericTypesCacheKey = tuple[Any, Any, tuple[Any, ...]] + +# Note: We want to remove LimitedDict, but to do this, we'd need to improve the handling of generics caching. +# Right now, to handle recursive generics, we some types must remain cached for brief periods without references. +# By chaining the WeakValuesDict with a LimitedDict, we have a way to retain caching for all types with references, +# while also retaining a limited number of types even without references. This is generally enough to build +# specific recursive generic models without losing required items out of the cache. + +KT = TypeVar('KT') +VT = TypeVar('VT') +_LIMITED_DICT_SIZE = 100 + + +class LimitedDict(dict[KT, VT]): + def __init__(self, size_limit: int = _LIMITED_DICT_SIZE) -> None: + self.size_limit = size_limit + super().__init__() + + def __setitem__(self, key: KT, value: VT, /) -> None: + super().__setitem__(key, value) + if len(self) > self.size_limit: + excess = len(self) - self.size_limit + self.size_limit // 10 + to_remove = list(self.keys())[:excess] + for k in to_remove: + del self[k] + + +# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected +# once they are no longer referenced by the caller. +GenericTypesCache = WeakValueDictionary[GenericTypesCacheKey, 'type[BaseModel]'] + +if TYPE_CHECKING: + + class DeepChainMap(ChainMap[KT, VT]): # type: ignore + ... + +else: + + class DeepChainMap(ChainMap): + """Variant of ChainMap that allows direct updates to inner scopes. + + Taken from https://docs.python.org/3/library/collections.html#collections.ChainMap, + with some light modifications for this use case. + """ + + def clear(self) -> None: + for mapping in self.maps: + mapping.clear() + + def __setitem__(self, key: KT, value: VT) -> None: + for mapping in self.maps: + mapping[key] = value + + def __delitem__(self, key: KT) -> None: + hit = False + for mapping in self.maps: + if key in mapping: + del mapping[key] + hit = True + if not hit: + raise KeyError(key) + + +# Despite the fact that LimitedDict _seems_ no longer necessary, I'm very nervous to actually remove it +# and discover later on that we need to re-add all this infrastructure... +# _GENERIC_TYPES_CACHE = DeepChainMap(GenericTypesCache(), LimitedDict()) + +_GENERIC_TYPES_CACHE: ContextVar[GenericTypesCache | None] = ContextVar('_GENERIC_TYPES_CACHE', default=None) + + +class PydanticGenericMetadata(TypedDict): + origin: type[BaseModel] | None # analogous to typing._GenericAlias.__origin__ + args: tuple[Any, ...] # analogous to typing._GenericAlias.__args__ + parameters: tuple[TypeVar, ...] # analogous to typing.Generic.__parameters__ + + +def create_generic_submodel( + model_name: str, origin: type[BaseModel], args: tuple[Any, ...], params: tuple[Any, ...] +) -> type[BaseModel]: + """Dynamically create a submodel of a provided (generic) BaseModel. + + This is used when producing concrete parametrizations of generic models. This function + only *creates* the new subclass; the schema/validators/serialization must be updated to + reflect a concrete parametrization elsewhere. + + Args: + model_name: The name of the newly created model. + origin: The base class for the new model to inherit from. + args: A tuple of generic metadata arguments. + params: A tuple of generic metadata parameters. + + Returns: + The created submodel. + """ + namespace: dict[str, Any] = {'__module__': origin.__module__} + bases = (origin,) + meta, ns, kwds = prepare_class(model_name, bases) + namespace.update(ns) + created_model = meta( + model_name, + bases, + namespace, + __pydantic_generic_metadata__={ + 'origin': origin, + 'args': args, + 'parameters': params, + }, + __pydantic_reset_parent_namespace__=False, + **kwds, + ) + + model_module, called_globally = _get_caller_frame_info(depth=3) + if called_globally: # create global reference and therefore allow pickling + object_by_reference = None + reference_name = model_name + reference_module_globals = sys.modules[created_model.__module__].__dict__ + while object_by_reference is not created_model: + object_by_reference = reference_module_globals.setdefault(reference_name, created_model) + reference_name += '_' + + return created_model + + +def _get_caller_frame_info(depth: int = 2) -> tuple[str | None, bool]: + """Used inside a function to check whether it was called globally. + + Args: + depth: The depth to get the frame. + + Returns: + A tuple contains `module_name` and `called_globally`. + + Raises: + RuntimeError: If the function is not called inside a function. + """ + try: + previous_caller_frame = sys._getframe(depth) + except ValueError as e: + raise RuntimeError('This function must be used inside another function') from e + except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it + return None, False + frame_globals = previous_caller_frame.f_globals + return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals + + +DictValues: type[Any] = {}.values().__class__ + + +def iter_contained_typevars(v: Any) -> Iterator[TypeVar]: + """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found. + + This is inspired as an alternative to directly accessing the `__parameters__` attribute of a GenericAlias, + since __parameters__ of (nested) generic BaseModel subclasses won't show up in that list. + """ + if isinstance(v, TypeVar): + yield v + elif is_model_class(v): + yield from v.__pydantic_generic_metadata__['parameters'] + elif isinstance(v, (DictValues, list)): + for var in v: + yield from iter_contained_typevars(var) + else: + args = get_args(v) + for arg in args: + yield from iter_contained_typevars(arg) + + +def get_args(v: Any) -> Any: + pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None) + if pydantic_generic_metadata: + return pydantic_generic_metadata.get('args') + return typing_extensions.get_args(v) + + +def get_origin(v: Any) -> Any: + pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None) + if pydantic_generic_metadata: + return pydantic_generic_metadata.get('origin') + return typing_extensions.get_origin(v) + + +def get_standard_typevars_map(cls: Any) -> dict[TypeVar, Any] | None: + """Package a generic type's typevars and parametrization (if present) into a dictionary compatible with the + `replace_types` function. Specifically, this works with standard typing generics and typing._GenericAlias. + """ + origin = get_origin(cls) + if origin is None: + return None + if not hasattr(origin, '__parameters__'): + return None + + # In this case, we know that cls is a _GenericAlias, and origin is the generic type + # So it is safe to access cls.__args__ and origin.__parameters__ + args: tuple[Any, ...] = cls.__args__ # type: ignore + parameters: tuple[TypeVar, ...] = origin.__parameters__ + return dict(zip(parameters, args)) + + +def get_model_typevars_map(cls: type[BaseModel]) -> dict[TypeVar, Any]: + """Package a generic BaseModel's typevars and concrete parametrization (if present) into a dictionary compatible + with the `replace_types` function. + + Since BaseModel.__class_getitem__ does not produce a typing._GenericAlias, and the BaseModel generic info is + stored in the __pydantic_generic_metadata__ attribute, we need special handling here. + """ + # TODO: This could be unified with `get_standard_typevars_map` if we stored the generic metadata + # in the __origin__, __args__, and __parameters__ attributes of the model. + generic_metadata = cls.__pydantic_generic_metadata__ + origin = generic_metadata['origin'] + args = generic_metadata['args'] + if not args: + # No need to go into `iter_contained_typevars`: + return {} + return dict(zip(iter_contained_typevars(origin), args)) + + +def replace_types(type_: Any, type_map: Mapping[TypeVar, Any] | None) -> Any: + """Return type with all occurrences of `type_map` keys recursively replaced with their values. + + Args: + type_: The class or generic alias. + type_map: Mapping from `TypeVar` instance to concrete types. + + Returns: + A new type representing the basic structure of `type_` with all + `typevar_map` keys recursively replaced. + + Example: + ```python + from typing import Union + + from pydantic._internal._generics import replace_types + + replace_types(tuple[str, Union[list[str], float]], {str: int}) + #> tuple[int, Union[list[int], float]] + ``` + """ + if not type_map: + return type_ + + type_args = get_args(type_) + origin_type = get_origin(type_) + + if typing_objects.is_annotated(origin_type): + annotated_type, *annotations = type_args + annotated_type = replace_types(annotated_type, type_map) + # TODO remove parentheses when we drop support for Python 3.10: + return Annotated[(annotated_type, *annotations)] + + # Having type args is a good indicator that this is a typing special form + # instance or a generic alias of some sort. + if type_args: + resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args) + if all_identical(type_args, resolved_type_args): + # If all arguments are the same, there is no need to modify the + # type or create a new object at all + return type_ + + if ( + origin_type is not None + and isinstance(type_, _typing_extra.typing_base) + and not isinstance(origin_type, _typing_extra.typing_base) + and getattr(type_, '_name', None) is not None + ): + # In python < 3.9 generic aliases don't exist so any of these like `list`, + # `type` or `collections.abc.Callable` need to be translated. + # See: https://www.python.org/dev/peps/pep-0585 + origin_type = getattr(typing, type_._name) + assert origin_type is not None + + if is_union_origin(origin_type): + if any(typing_objects.is_any(arg) for arg in resolved_type_args): + # `Any | T` ~ `Any`: + resolved_type_args = (Any,) + # `Never | T` ~ `T`: + resolved_type_args = tuple( + arg + for arg in resolved_type_args + if not (typing_objects.is_noreturn(arg) or typing_objects.is_never(arg)) + ) + + # PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__. + # We also cannot use isinstance() since we have to compare types. + if sys.version_info >= (3, 10) and origin_type is types.UnionType: + return reduce(operator.or_, resolved_type_args) + # NotRequired[T] and Required[T] don't support tuple type resolved_type_args, hence the condition below + return origin_type[resolved_type_args[0] if len(resolved_type_args) == 1 else resolved_type_args] + + # We handle pydantic generic models separately as they don't have the same + # semantics as "typing" classes or generic aliases + + if not origin_type and is_model_class(type_): + parameters = type_.__pydantic_generic_metadata__['parameters'] + if not parameters: + return type_ + resolved_type_args = tuple(replace_types(t, type_map) for t in parameters) + if all_identical(parameters, resolved_type_args): + return type_ + return type_[resolved_type_args] + + # Handle special case for typehints that can have lists as arguments. + # `typing.Callable[[int, str], int]` is an example for this. + if isinstance(type_, list): + resolved_list = [replace_types(element, type_map) for element in type_] + if all_identical(type_, resolved_list): + return type_ + return resolved_list + + # If all else fails, we try to resolve the type directly and otherwise just + # return the input with no modifications. + return type_map.get(type_, type_) + + +def map_generic_model_arguments(cls: type[BaseModel], args: tuple[Any, ...]) -> dict[TypeVar, Any]: + """Return a mapping between the parameters of a generic model and the provided arguments during parameterization. + + Raises: + TypeError: If the number of arguments does not match the parameters (i.e. if providing too few or too many arguments). + + Example: + ```python {test="skip" lint="skip"} + class Model[T, U, V = int](BaseModel): ... + + map_generic_model_arguments(Model, (str, bytes)) + #> {T: str, U: bytes, V: int} + + map_generic_model_arguments(Model, (str,)) + #> TypeError: Too few arguments for ; actual 1, expected at least 2 + + map_generic_model_arguments(Model, (str, bytes, int, complex)) + #> TypeError: Too many arguments for ; actual 4, expected 3 + ``` + + Note: + This function is analogous to the private `typing._check_generic_specialization` function. + """ + parameters = cls.__pydantic_generic_metadata__['parameters'] + expected_len = len(parameters) + typevars_map: dict[TypeVar, Any] = {} + + _missing = object() + for parameter, argument in zip_longest(parameters, args, fillvalue=_missing): + if parameter is _missing: + raise TypeError(f'Too many arguments for {cls}; actual {len(args)}, expected {expected_len}') + + if argument is _missing: + param = cast(TypeVar, parameter) + try: + has_default = param.has_default() # pyright: ignore[reportAttributeAccessIssue] + except AttributeError: + # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13. + has_default = False + if has_default: + # The default might refer to other type parameters. For an example, see: + # https://typing.python.org/en/latest/spec/generics.html#type-parameters-as-parameters-to-generics + typevars_map[param] = replace_types(param.__default__, typevars_map) # pyright: ignore[reportAttributeAccessIssue] + else: + expected_len -= sum(hasattr(p, 'has_default') and p.has_default() for p in parameters) # pyright: ignore[reportAttributeAccessIssue] + raise TypeError(f'Too few arguments for {cls}; actual {len(args)}, expected at least {expected_len}') + else: + param = cast(TypeVar, parameter) + typevars_map[param] = argument + + return typevars_map + + +_generic_recursion_cache: ContextVar[set[str] | None] = ContextVar('_generic_recursion_cache', default=None) + + +@contextmanager +def generic_recursion_self_type( + origin: type[BaseModel], args: tuple[Any, ...] +) -> Iterator[PydanticRecursiveRef | None]: + """This contextmanager should be placed around the recursive calls used to build a generic type, + and accept as arguments the generic origin type and the type arguments being passed to it. + + If the same origin and arguments are observed twice, it implies that a self-reference placeholder + can be used while building the core schema, and will produce a schema_ref that will be valid in the + final parent schema. + """ + previously_seen_type_refs = _generic_recursion_cache.get() + if previously_seen_type_refs is None: + previously_seen_type_refs = set() + token = _generic_recursion_cache.set(previously_seen_type_refs) + else: + token = None + + try: + type_ref = get_type_ref(origin, args_override=args) + if type_ref in previously_seen_type_refs: + self_type = PydanticRecursiveRef(type_ref=type_ref) + yield self_type + else: + previously_seen_type_refs.add(type_ref) + yield + previously_seen_type_refs.remove(type_ref) + finally: + if token: + _generic_recursion_cache.reset(token) + + +def recursively_defined_type_refs() -> set[str]: + visited = _generic_recursion_cache.get() + if not visited: + return set() # not in a generic recursion, so there are no types + + return visited.copy() # don't allow modifications + + +def get_cached_generic_type_early(parent: type[BaseModel], typevar_values: Any) -> type[BaseModel] | None: + """The use of a two-stage cache lookup approach was necessary to have the highest performance possible for + repeated calls to `__class_getitem__` on generic types (which may happen in tighter loops during runtime), + while still ensuring that certain alternative parametrizations ultimately resolve to the same type. + + As a concrete example, this approach was necessary to make Model[List[T]][int] equal to Model[List[int]]. + The approach could be modified to not use two different cache keys at different points, but the + _early_cache_key is optimized to be as quick to compute as possible (for repeated-access speed), and the + _late_cache_key is optimized to be as "correct" as possible, so that two types that will ultimately be the + same after resolving the type arguments will always produce cache hits. + + If we wanted to move to only using a single cache key per type, we would either need to always use the + slower/more computationally intensive logic associated with _late_cache_key, or would need to accept + that Model[List[T]][int] is a different type than Model[List[T]][int]. Because we rely on subclass relationships + during validation, I think it is worthwhile to ensure that types that are functionally equivalent are actually + equal. + """ + generic_types_cache = _GENERIC_TYPES_CACHE.get() + if generic_types_cache is None: + generic_types_cache = GenericTypesCache() + _GENERIC_TYPES_CACHE.set(generic_types_cache) + return generic_types_cache.get(_early_cache_key(parent, typevar_values)) + + +def get_cached_generic_type_late( + parent: type[BaseModel], typevar_values: Any, origin: type[BaseModel], args: tuple[Any, ...] +) -> type[BaseModel] | None: + """See the docstring of `get_cached_generic_type_early` for more information about the two-stage cache lookup.""" + generic_types_cache = _GENERIC_TYPES_CACHE.get() + if ( + generic_types_cache is None + ): # pragma: no cover (early cache is guaranteed to run first and initialize the cache) + generic_types_cache = GenericTypesCache() + _GENERIC_TYPES_CACHE.set(generic_types_cache) + cached = generic_types_cache.get(_late_cache_key(origin, args, typevar_values)) + if cached is not None: + set_cached_generic_type(parent, typevar_values, cached, origin, args) + return cached + + +def set_cached_generic_type( + parent: type[BaseModel], + typevar_values: tuple[Any, ...], + type_: type[BaseModel], + origin: type[BaseModel] | None = None, + args: tuple[Any, ...] | None = None, +) -> None: + """See the docstring of `get_cached_generic_type_early` for more information about why items are cached with + two different keys. + """ + generic_types_cache = _GENERIC_TYPES_CACHE.get() + if ( + generic_types_cache is None + ): # pragma: no cover (cache lookup is guaranteed to run first and initialize the cache) + generic_types_cache = GenericTypesCache() + _GENERIC_TYPES_CACHE.set(generic_types_cache) + generic_types_cache[_early_cache_key(parent, typevar_values)] = type_ + if len(typevar_values) == 1: + generic_types_cache[_early_cache_key(parent, typevar_values[0])] = type_ + if origin and args: + generic_types_cache[_late_cache_key(origin, args, typevar_values)] = type_ + + +def _union_orderings_key(typevar_values: Any) -> Any: + """This is intended to help differentiate between Union types with the same arguments in different order. + + Thanks to caching internal to the `typing` module, it is not possible to distinguish between + List[Union[int, float]] and List[Union[float, int]] (and similarly for other "parent" origins besides List) + because `typing` considers Union[int, float] to be equal to Union[float, int]. + + However, you _can_ distinguish between (top-level) Union[int, float] vs. Union[float, int]. + Because we parse items as the first Union type that is successful, we get slightly more consistent behavior + if we make an effort to distinguish the ordering of items in a union. It would be best if we could _always_ + get the exact-correct order of items in the union, but that would require a change to the `typing` module itself. + (See https://github.com/python/cpython/issues/86483 for reference.) + """ + if isinstance(typevar_values, tuple): + return tuple(_union_orderings_key(value) for value in typevar_values) + elif typing_objects.is_union(typing_extensions.get_origin(typevar_values)): + return get_args(typevar_values) + else: + return () + + +def _early_cache_key(cls: type[BaseModel], typevar_values: Any) -> GenericTypesCacheKey: + """This is intended for minimal computational overhead during lookups of cached types. + + Note that this is overly simplistic, and it's possible that two different cls/typevar_values + inputs would ultimately result in the same type being created in BaseModel.__class_getitem__. + To handle this, we have a fallback _late_cache_key that is checked later if the _early_cache_key + lookup fails, and should result in a cache hit _precisely_ when the inputs to __class_getitem__ + would result in the same type. + """ + return cls, typevar_values, _union_orderings_key(typevar_values) + + +def _late_cache_key(origin: type[BaseModel], args: tuple[Any, ...], typevar_values: Any) -> GenericTypesCacheKey: + """This is intended for use later in the process of creating a new type, when we have more information + about the exact args that will be passed. If it turns out that a different set of inputs to + __class_getitem__ resulted in the same inputs to the generic type creation process, we can still + return the cached type, and update the cache with the _early_cache_key as well. + """ + # The _union_orderings_key is placed at the start here to ensure there cannot be a collision with an + # _early_cache_key, as that function will always produce a BaseModel subclass as the first item in the key, + # whereas this function will always produce a tuple as the first item in the key. + return _union_orderings_key(typevar_values), origin, args diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_git.py b/backend/venv/Lib/site-packages/pydantic/_internal/_git.py new file mode 100644 index 0000000..96dcda2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_git.py @@ -0,0 +1,27 @@ +"""Git utilities, adopted from mypy's git utilities (https://github.com/python/mypy/blob/master/mypy/git.py).""" + +from __future__ import annotations + +import subprocess +from pathlib import Path + + +def is_git_repo(dir: Path) -> bool: + """Is the given directory version-controlled with git?""" + return dir.joinpath('.git').exists() + + +def have_git() -> bool: # pragma: no cover + """Can we run the git executable?""" + try: + subprocess.check_output(['git', '--help']) + return True + except subprocess.CalledProcessError: + return False + except OSError: + return False + + +def git_revision(dir: Path) -> str: + """Get the SHA-1 of the HEAD of a git repository.""" + return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=dir).decode('utf-8').strip() diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_import_utils.py b/backend/venv/Lib/site-packages/pydantic/_internal/_import_utils.py new file mode 100644 index 0000000..638102f --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_import_utils.py @@ -0,0 +1,20 @@ +from functools import cache +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pydantic import BaseModel + from pydantic.fields import FieldInfo + + +@cache +def import_cached_base_model() -> type['BaseModel']: + from pydantic import BaseModel + + return BaseModel + + +@cache +def import_cached_field_info() -> type['FieldInfo']: + from pydantic.fields import FieldInfo + + return FieldInfo diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_internal_dataclass.py b/backend/venv/Lib/site-packages/pydantic/_internal/_internal_dataclass.py new file mode 100644 index 0000000..33e152c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_internal_dataclass.py @@ -0,0 +1,7 @@ +import sys + +# `slots` is available on Python >= 3.10 +if sys.version_info >= (3, 10): + slots_true = {'slots': True} +else: + slots_true = {} diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_known_annotated_metadata.py b/backend/venv/Lib/site-packages/pydantic/_internal/_known_annotated_metadata.py new file mode 100644 index 0000000..7d61f4a --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_known_annotated_metadata.py @@ -0,0 +1,401 @@ +from __future__ import annotations + +from collections import defaultdict +from collections.abc import Iterable +from copy import copy +from functools import lru_cache, partial +from typing import TYPE_CHECKING, Any + +from pydantic_core import CoreSchema, PydanticCustomError, ValidationError, to_jsonable_python +from pydantic_core import core_schema as cs + +from ._fields import PydanticMetadata +from ._import_utils import import_cached_field_info + +if TYPE_CHECKING: + pass + +STRICT = {'strict'} +FAIL_FAST = {'fail_fast'} +LENGTH_CONSTRAINTS = {'min_length', 'max_length'} +INEQUALITY = {'le', 'ge', 'lt', 'gt'} +NUMERIC_CONSTRAINTS = {'multiple_of', *INEQUALITY} +ALLOW_INF_NAN = {'allow_inf_nan'} + +STR_CONSTRAINTS = { + *LENGTH_CONSTRAINTS, + *STRICT, + 'strip_whitespace', + 'to_lower', + 'to_upper', + 'pattern', + 'coerce_numbers_to_str', +} +BYTES_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} + +LIST_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +TUPLE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +SET_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +DICT_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} +GENERATOR_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} +SEQUENCE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *FAIL_FAST} + +FLOAT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT} +DECIMAL_CONSTRAINTS = {'max_digits', 'decimal_places', *FLOAT_CONSTRAINTS} +INT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT} +BOOL_CONSTRAINTS = STRICT +UUID_CONSTRAINTS = STRICT + +DATE_TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +TIMEDELTA_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +LAX_OR_STRICT_CONSTRAINTS = STRICT +ENUM_CONSTRAINTS = STRICT +COMPLEX_CONSTRAINTS = STRICT + +UNION_CONSTRAINTS = {'union_mode'} +URL_CONSTRAINTS = { + 'max_length', + 'allowed_schemes', + 'host_required', + 'default_host', + 'default_port', + 'default_path', +} + +TEXT_SCHEMA_TYPES = ('str', 'bytes', 'url', 'multi-host-url') +SEQUENCE_SCHEMA_TYPES = ('list', 'tuple', 'set', 'frozenset', 'generator', *TEXT_SCHEMA_TYPES) +NUMERIC_SCHEMA_TYPES = ('float', 'int', 'date', 'time', 'timedelta', 'datetime') + +CONSTRAINTS_TO_ALLOWED_SCHEMAS: dict[str, set[str]] = defaultdict(set) + +constraint_schema_pairings: list[tuple[set[str], tuple[str, ...]]] = [ + (STR_CONSTRAINTS, TEXT_SCHEMA_TYPES), + (BYTES_CONSTRAINTS, ('bytes',)), + (LIST_CONSTRAINTS, ('list',)), + (TUPLE_CONSTRAINTS, ('tuple',)), + (SET_CONSTRAINTS, ('set', 'frozenset')), + (DICT_CONSTRAINTS, ('dict',)), + (GENERATOR_CONSTRAINTS, ('generator',)), + (FLOAT_CONSTRAINTS, ('float',)), + (INT_CONSTRAINTS, ('int',)), + (DATE_TIME_CONSTRAINTS, ('date', 'time', 'datetime', 'timedelta')), + # TODO: this is a bit redundant, we could probably avoid some of these + (STRICT, (*TEXT_SCHEMA_TYPES, *SEQUENCE_SCHEMA_TYPES, *NUMERIC_SCHEMA_TYPES, 'typed-dict', 'model')), + (UNION_CONSTRAINTS, ('union',)), + (URL_CONSTRAINTS, ('url', 'multi-host-url')), + (BOOL_CONSTRAINTS, ('bool',)), + (UUID_CONSTRAINTS, ('uuid',)), + (LAX_OR_STRICT_CONSTRAINTS, ('lax-or-strict',)), + (ENUM_CONSTRAINTS, ('enum',)), + (DECIMAL_CONSTRAINTS, ('decimal',)), + (COMPLEX_CONSTRAINTS, ('complex',)), +] + +for constraints, schemas in constraint_schema_pairings: + for c in constraints: + CONSTRAINTS_TO_ALLOWED_SCHEMAS[c].update(schemas) + + +def as_jsonable_value(v: Any) -> Any: + if type(v) not in (int, str, float, bytes, bool, type(None)): + return to_jsonable_python(v) + return v + + +def expand_grouped_metadata(annotations: Iterable[Any]) -> Iterable[Any]: + """Expand the annotations. + + Args: + annotations: An iterable of annotations. + + Returns: + An iterable of expanded annotations. + + Example: + ```python + from annotated_types import Ge, Len + + from pydantic._internal._known_annotated_metadata import expand_grouped_metadata + + print(list(expand_grouped_metadata([Ge(4), Len(5)]))) + #> [Ge(ge=4), MinLen(min_length=5)] + ``` + """ + import annotated_types as at + + FieldInfo = import_cached_field_info() + + for annotation in annotations: + if isinstance(annotation, at.GroupedMetadata): + yield from annotation + elif isinstance(annotation, FieldInfo): + yield from annotation.metadata + # this is a bit problematic in that it results in duplicate metadata + # all of our "consumers" can handle it, but it is not ideal + # we probably should split up FieldInfo into: + # - annotated types metadata + # - individual metadata known only to Pydantic + annotation = copy(annotation) + annotation.metadata = [] + yield annotation + else: + yield annotation + + +@lru_cache +def _get_at_to_constraint_map() -> dict[type, str]: + """Return a mapping of annotated types to constraints. + + Normally, we would define a mapping like this in the module scope, but we can't do that + because we don't permit module level imports of `annotated_types`, in an attempt to speed up + the import time of `pydantic`. We still only want to have this dictionary defined in one place, + so we use this function to cache the result. + """ + import annotated_types as at + + return { + at.Gt: 'gt', + at.Ge: 'ge', + at.Lt: 'lt', + at.Le: 'le', + at.MultipleOf: 'multiple_of', + at.MinLen: 'min_length', + at.MaxLen: 'max_length', + } + + +def apply_known_metadata(annotation: Any, schema: CoreSchema) -> CoreSchema | None: # noqa: C901 + """Apply `annotation` to `schema` if it is an annotation we know about (Gt, Le, etc.). + Otherwise return `None`. + + This does not handle all known annotations. If / when it does, it can always + return a CoreSchema and return the unmodified schema if the annotation should be ignored. + + Assumes that GroupedMetadata has already been expanded via `expand_grouped_metadata`. + + Args: + annotation: The annotation. + schema: The schema. + + Returns: + An updated schema with annotation if it is an annotation we know about, `None` otherwise. + + Raises: + RuntimeError: If a constraint can't be applied to a specific schema type. + ValueError: If an unknown constraint is encountered. + """ + import annotated_types as at + + from ._validators import NUMERIC_VALIDATOR_LOOKUP, forbid_inf_nan_check + + schema = schema.copy() + schema_update, other_metadata = collect_known_metadata([annotation]) + schema_type = schema['type'] + + chain_schema_constraints: set[str] = { + 'pattern', + 'strip_whitespace', + 'to_lower', + 'to_upper', + 'coerce_numbers_to_str', + } + chain_schema_steps: list[CoreSchema] = [] + + for constraint, value in schema_update.items(): + if constraint not in CONSTRAINTS_TO_ALLOWED_SCHEMAS: + raise ValueError(f'Unknown constraint {constraint}') + allowed_schemas = CONSTRAINTS_TO_ALLOWED_SCHEMAS[constraint] + + # if it becomes necessary to handle more than one constraint + # in this recursive case with function-after or function-wrap, we should refactor + # this is a bit challenging because we sometimes want to apply constraints to the inner schema, + # whereas other times we want to wrap the existing schema with a new one that enforces a new constraint. + if schema_type in {'function-before', 'function-wrap', 'function-after'} and constraint == 'strict': + schema['schema'] = apply_known_metadata(annotation, schema['schema']) # type: ignore # schema is function schema + return schema + + # if we're allowed to apply constraint directly to the schema, like le to int, do that + if schema_type in allowed_schemas: + if constraint == 'union_mode' and schema_type == 'union': + schema['mode'] = value # type: ignore # schema is UnionSchema + else: + schema[constraint] = value + continue + + # else, apply a function after validator to the schema to enforce the corresponding constraint + if constraint in chain_schema_constraints: + + def _apply_constraint_with_incompatibility_info( + value: Any, handler: cs.ValidatorFunctionWrapHandler + ) -> Any: + try: + x = handler(value) + except ValidationError as ve: + # if the error is about the type, it's likely that the constraint is incompatible the type of the field + # for example, the following invalid schema wouldn't be caught during schema build, but rather at this point + # with a cryptic 'string_type' error coming from the string validator, + # that we'd rather express as a constraint incompatibility error (TypeError) + # Annotated[list[int], Field(pattern='abc')] + if 'type' in ve.errors()[0]['type']: + raise TypeError( + f"Unable to apply constraint '{constraint}' to supplied value {value} for schema of type '{schema_type}'" # noqa: B023 + ) + raise ve + return x + + chain_schema_steps.append( + cs.no_info_wrap_validator_function( + _apply_constraint_with_incompatibility_info, cs.str_schema(**{constraint: value}) + ) + ) + elif constraint in NUMERIC_VALIDATOR_LOOKUP: + if constraint in LENGTH_CONSTRAINTS: + inner_schema = schema + while inner_schema['type'] in {'function-before', 'function-wrap', 'function-after'}: + inner_schema = inner_schema['schema'] # type: ignore + inner_schema_type = inner_schema['type'] + if inner_schema_type == 'list' or ( + inner_schema_type == 'json-or-python' and inner_schema['json_schema']['type'] == 'list' # type: ignore + ): + js_constraint_key = 'minItems' if constraint == 'min_length' else 'maxItems' + else: + js_constraint_key = 'minLength' if constraint == 'min_length' else 'maxLength' + else: + js_constraint_key = constraint + + schema = cs.no_info_after_validator_function( + partial(NUMERIC_VALIDATOR_LOOKUP[constraint], **{constraint: value}), schema + ) + metadata = schema.get('metadata', {}) + if (existing_json_schema_updates := metadata.get('pydantic_js_updates')) is not None: + metadata['pydantic_js_updates'] = { + **existing_json_schema_updates, + **{js_constraint_key: as_jsonable_value(value)}, + } + else: + metadata['pydantic_js_updates'] = {js_constraint_key: as_jsonable_value(value)} + schema['metadata'] = metadata + elif constraint == 'allow_inf_nan' and value is False: + schema = cs.no_info_after_validator_function( + forbid_inf_nan_check, + schema, + ) + else: + # It's rare that we'd get here, but it's possible if we add a new constraint and forget to handle it + # Most constraint errors are caught at runtime during attempted application + raise RuntimeError(f"Unable to apply constraint '{constraint}' to schema of type '{schema_type}'") + + for annotation in other_metadata: + if (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()): + constraint = at_to_constraint_map[annotation_type] + validator = NUMERIC_VALIDATOR_LOOKUP.get(constraint) + if validator is None: + raise ValueError(f'Unknown constraint {constraint}') + schema = cs.no_info_after_validator_function( + partial(validator, {constraint: getattr(annotation, constraint)}), schema + ) + continue + elif isinstance(annotation, (at.Predicate, at.Not)): + predicate_name = f'{annotation.func.__qualname__!r} ' if hasattr(annotation.func, '__qualname__') else '' + + # Note: B023 is ignored because even though we iterate over `other_metadata`, it is guaranteed + # to be of length 1. `apply_known_metadata()` is called from `GenerateSchema`, where annotations + # were already expanded via `expand_grouped_metadata()`. Confusing, but this falls into the annotations + # refactor. + if isinstance(annotation, at.Predicate): + + def val_func(v: Any) -> Any: + predicate_satisfied = annotation.func(v) # noqa: B023 + if not predicate_satisfied: + raise PydanticCustomError( + 'predicate_failed', + f'Predicate {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023 + ) + return v + + else: + + def val_func(v: Any) -> Any: + predicate_satisfied = annotation.func(v) # noqa: B023 + if predicate_satisfied: + raise PydanticCustomError( + 'not_operation_failed', + f'Not of {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023 + ) + return v + + schema = cs.no_info_after_validator_function(val_func, schema) + else: + # ignore any other unknown metadata + return None + + if chain_schema_steps: + chain_schema_steps = [schema] + chain_schema_steps + return cs.chain_schema(chain_schema_steps) + + return schema + + +def collect_known_metadata(annotations: Iterable[Any]) -> tuple[dict[str, Any], list[Any]]: + """Split `annotations` into known metadata and unknown annotations. + + Args: + annotations: An iterable of annotations. + + Returns: + A tuple contains a dict of known metadata and a list of unknown annotations. + + Example: + ```python + from annotated_types import Gt, Len + + from pydantic._internal._known_annotated_metadata import collect_known_metadata + + print(collect_known_metadata([Gt(1), Len(42), ...])) + #> ({'gt': 1, 'min_length': 42}, [Ellipsis]) + ``` + """ + annotations = expand_grouped_metadata(annotations) + + res: dict[str, Any] = {} + remaining: list[Any] = [] + + for annotation in annotations: + # isinstance(annotation, PydanticMetadata) also covers ._fields:_PydanticGeneralMetadata + if isinstance(annotation, PydanticMetadata): + res.update(annotation.__dict__) + # we don't use dataclasses.asdict because that recursively calls asdict on the field values + elif (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()): + constraint = at_to_constraint_map[annotation_type] + res[constraint] = getattr(annotation, constraint) + elif isinstance(annotation, type) and issubclass(annotation, PydanticMetadata): + # also support PydanticMetadata classes being used without initialisation, + # e.g. `Annotated[int, Strict]` as well as `Annotated[int, Strict()]` + res.update({k: v for k, v in vars(annotation).items() if not k.startswith('_')}) + else: + remaining.append(annotation) + # Nones can sneak in but pydantic-core will reject them + # it'd be nice to clean things up so we don't put in None (we probably don't _need_ to, it was just easier) + # but this is simple enough to kick that can down the road + res = {k: v for k, v in res.items() if v is not None} + return res, remaining + + +def check_metadata(metadata: dict[str, Any], allowed: Iterable[str], source_type: Any) -> None: + """A small utility function to validate that the given metadata can be applied to the target. + More than saving lines of code, this gives us a consistent error message for all of our internal implementations. + + Args: + metadata: A dict of metadata. + allowed: An iterable of allowed metadata. + source_type: The source type. + + Raises: + TypeError: If there is metadatas that can't be applied on source type. + """ + unknown = metadata.keys() - set(allowed) + if unknown: + raise TypeError( + f'The following constraints cannot be applied to {source_type!r}: {", ".join([f"{k!r}" for k in unknown])}' + ) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_mock_val_ser.py b/backend/venv/Lib/site-packages/pydantic/_internal/_mock_val_ser.py new file mode 100644 index 0000000..9125ab3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_mock_val_ser.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +from collections.abc import Iterator, Mapping +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar, Union + +from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator + +from ..errors import PydanticErrorCodes, PydanticUserError +from ..plugin._schema_validator import PluggableSchemaValidator + +if TYPE_CHECKING: + from ..dataclasses import PydanticDataclass + from ..main import BaseModel + from ..type_adapter import TypeAdapter + + +ValSer = TypeVar('ValSer', bound=Union[SchemaValidator, PluggableSchemaValidator, SchemaSerializer]) +T = TypeVar('T') + + +class MockCoreSchema(Mapping[str, Any]): + """Mocker for `pydantic_core.CoreSchema` which optionally attempts to + rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails. + """ + + __slots__ = '_error_message', '_code', '_attempt_rebuild', '_built_memo' + + def __init__( + self, + error_message: str, + *, + code: PydanticErrorCodes, + attempt_rebuild: Callable[[], CoreSchema | None] | None = None, + ) -> None: + self._error_message = error_message + self._code: PydanticErrorCodes = code + self._attempt_rebuild = attempt_rebuild + self._built_memo: CoreSchema | None = None + + def __getitem__(self, key: str) -> Any: + return self._get_built().__getitem__(key) + + def __len__(self) -> int: + return self._get_built().__len__() + + def __iter__(self) -> Iterator[str]: + return self._get_built().__iter__() + + def _get_built(self) -> CoreSchema: + if self._built_memo is not None: + return self._built_memo + + if self._attempt_rebuild: + schema = self._attempt_rebuild() + if schema is not None: + self._built_memo = schema + return schema + raise PydanticUserError(self._error_message, code=self._code) + + def rebuild(self) -> CoreSchema | None: + self._built_memo = None + if self._attempt_rebuild: + schema = self._attempt_rebuild() + if schema is not None: + return schema + else: + raise PydanticUserError(self._error_message, code=self._code) + return None + + +class MockValSer(Generic[ValSer]): + """Mocker for `pydantic_core.SchemaValidator` or `pydantic_core.SchemaSerializer` which optionally attempts to + rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails. + """ + + __slots__ = '_error_message', '_code', '_val_or_ser', '_attempt_rebuild' + + def __init__( + self, + error_message: str, + *, + code: PydanticErrorCodes, + val_or_ser: Literal['validator', 'serializer'], + attempt_rebuild: Callable[[], ValSer | None] | None = None, + ) -> None: + self._error_message = error_message + self._val_or_ser = SchemaValidator if val_or_ser == 'validator' else SchemaSerializer + self._code: PydanticErrorCodes = code + self._attempt_rebuild = attempt_rebuild + + def __getattr__(self, item: str) -> None: + __tracebackhide__ = True + if self._attempt_rebuild: + val_ser = self._attempt_rebuild() + if val_ser is not None: + return getattr(val_ser, item) + + # raise an AttributeError if `item` doesn't exist + getattr(self._val_or_ser, item) + raise PydanticUserError(self._error_message, code=self._code) + + def rebuild(self) -> ValSer | None: + if self._attempt_rebuild: + val_ser = self._attempt_rebuild() + if val_ser is not None: + return val_ser + else: + raise PydanticUserError(self._error_message, code=self._code) + return None + + +def set_type_adapter_mocks(adapter: TypeAdapter) -> None: + """Set `core_schema`, `validator` and `serializer` to mock core types on a type adapter instance. + + Args: + adapter: The type adapter instance to set the mocks on + """ + type_repr = str(adapter._type) + undefined_type_error_message = ( + f'`TypeAdapter[{type_repr}]` is not fully defined; you should define `{type_repr}` and all referenced types,' + f' then call `.rebuild()` on the instance.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[TypeAdapter], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if adapter.rebuild(raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(adapter) + return None + + return handler + + adapter.core_schema = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.core_schema), + ) + adapter.validator = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.validator), + ) + adapter.serializer = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.serializer), + ) + + +def set_model_mocks(cls: type[BaseModel], undefined_name: str = 'all referenced types') -> None: + """Set `__pydantic_core_schema__`, `__pydantic_validator__` and `__pydantic_serializer__` to mock core types on a model. + + Args: + cls: The model class to set the mocks on + undefined_name: Name of the undefined thing, used in error messages + """ + undefined_type_error_message = ( + f'`{cls.__name__}` is not fully defined; you should define {undefined_name},' + f' then call `{cls.__name__}.model_rebuild()`.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[type[BaseModel]], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(cls) + return None + + return handler + + cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__), + ) + cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__), + ) + cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__), + ) + + +def set_dataclass_mocks(cls: type[PydanticDataclass], undefined_name: str = 'all referenced types') -> None: + """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a dataclass. + + Args: + cls: The model class to set the mocks on + undefined_name: Name of the undefined thing, used in error messages + """ + from ..dataclasses import rebuild_dataclass + + undefined_type_error_message = ( + f'`{cls.__name__}` is not fully defined; you should define {undefined_name},' + f' then call `pydantic.dataclasses.rebuild_dataclass({cls.__name__})`.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[type[PydanticDataclass]], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(cls) + return None + + return handler + + cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__), + ) + cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__), + ) + cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__), + ) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_model_construction.py b/backend/venv/Lib/site-packages/pydantic/_internal/_model_construction.py new file mode 100644 index 0000000..4fe223c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_model_construction.py @@ -0,0 +1,848 @@ +"""Private logic for creating models.""" + +from __future__ import annotations as _annotations + +import operator +import sys +import typing +import warnings +import weakref +from abc import ABCMeta +from functools import cache, partial, wraps +from types import FunctionType +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, cast + +from pydantic_core import PydanticUndefined, SchemaSerializer +from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args, get_origin +from typing_inspection import typing_objects + +from ..errors import PydanticUndefinedAnnotation, PydanticUserError +from ..plugin._schema_validator import create_schema_validator +from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 +from ._config import ConfigWrapper +from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function +from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name, rebuild_model_fields +from ._generate_schema import GenerateSchema, InvalidSchemaError +from ._generics import PydanticGenericMetadata, get_model_typevars_map +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._mock_val_ser import set_model_mocks +from ._namespace_utils import NsResolver +from ._signature import generate_pydantic_signature +from ._typing_extra import ( + _make_forward_ref, + eval_type_backport, + is_classvar_annotation, + parent_frame_namespace, +) +from ._utils import LazyClassAttribute, SafeGetItemProxy + +if TYPE_CHECKING: + from ..fields import Field as PydanticModelField + from ..fields import FieldInfo, ModelPrivateAttr + from ..fields import PrivateAttr as PydanticModelPrivateAttr + from ..main import BaseModel +else: + PydanticModelField = object() + PydanticModelPrivateAttr = object() + +object_setattr = object.__setattr__ + + +class _ModelNamespaceDict(dict): + """A dictionary subclass that intercepts attribute setting on model classes and + warns about overriding of decorators. + """ + + def __setitem__(self, k: str, v: object) -> None: + existing: Any = self.get(k, None) + if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): + warnings.warn( + f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator', + stacklevel=2, + ) + + return super().__setitem__(k, v) + + +def NoInitField( + *, + init: Literal[False] = False, +) -> Any: + """Only for typing purposes. Used as default value of `__pydantic_fields_set__`, + `__pydantic_extra__`, `__pydantic_private__`, so they could be ignored when + synthesizing the `__init__` signature. + """ + + +# For ModelMetaclass.register(): +_T = TypeVar('_T') + + +@dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr, NoInitField)) +class ModelMetaclass(ABCMeta): + def __new__( + mcs, + cls_name: str, + bases: tuple[type[Any], ...], + namespace: dict[str, Any], + __pydantic_generic_metadata__: PydanticGenericMetadata | None = None, + __pydantic_reset_parent_namespace__: bool = True, + _create_model_module: str | None = None, + **kwargs: Any, + ) -> type: + """Metaclass for creating Pydantic models. + + Args: + cls_name: The name of the class to be created. + bases: The base classes of the class to be created. + namespace: The attribute dictionary of the class to be created. + __pydantic_generic_metadata__: Metadata for generic models. + __pydantic_reset_parent_namespace__: Reset parent namespace. + _create_model_module: The module of the class to be created, if created by `create_model`. + **kwargs: Catch-all for any other keyword arguments. + + Returns: + The new class created by the metaclass. + """ + # Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we rely on the fact + # that `BaseModel` itself won't have any bases, but any subclass of it will, to determine whether the `__new__` + # call we're in the middle of is for the `BaseModel` class. + if bases: + raw_annotations: dict[str, Any] + if sys.version_info >= (3, 14): + if ( + '__annotations__' in namespace + ): # `from __future__ import annotations` was used in the model's module + raw_annotations = namespace['__annotations__'] + else: + # See https://docs.python.org/3.14/library/annotationlib.html#using-annotations-in-a-metaclass: + from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace + + if annotate := get_annotate_from_class_namespace(namespace): + raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) + else: + raw_annotations = {} + else: + raw_annotations = namespace.get('__annotations__', {}) + + base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) + + config_wrapper = ConfigWrapper.for_model(bases, namespace, raw_annotations, kwargs) + namespace['model_config'] = config_wrapper.config_dict + private_attributes = inspect_namespace( + namespace, raw_annotations, config_wrapper.ignored_types, class_vars, base_field_names + ) + if private_attributes or base_private_attributes: + original_model_post_init = get_model_post_init(namespace, bases) + if original_model_post_init is not None: + # if there are private_attributes and a model_post_init function, we handle both + + @wraps(original_model_post_init) + def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: + """We need to both initialize private attributes and call the user-defined model_post_init + method. + """ + init_private_attributes(self, context) + original_model_post_init(self, context) + + namespace['model_post_init'] = wrapped_model_post_init + else: + namespace['model_post_init'] = init_private_attributes + + namespace['__class_vars__'] = class_vars + namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} + + cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs)) + BaseModel_ = import_cached_base_model() + + mro = cls.__mro__ + if Generic in mro and mro.index(Generic) < mro.index(BaseModel_): + warnings.warn( + GenericBeforeBaseModelWarning( + 'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) ' + 'for pydantic generics to work properly.' + ), + stacklevel=2, + ) + + cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False) + cls.__pydantic_post_init__ = ( + None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init' + ) + + cls.__pydantic_setattr_handlers__ = {} + + cls.__pydantic_decorators__ = DecoratorInfos.build(cls) + cls.__pydantic_decorators__.update_from_config(config_wrapper) + + # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class + if __pydantic_generic_metadata__: + cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ + else: + parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) + parameters = getattr(cls, '__parameters__', None) or parent_parameters + if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): + from ..root_model import RootModelRootType + + missing_parameters = tuple(x for x in parameters if x not in parent_parameters) + if RootModelRootType in parent_parameters and RootModelRootType not in parameters: + # This is a special case where the user has subclassed `RootModel`, but has not parametrized + # RootModel with the generic type identifiers being used. Ex: + # class MyModel(RootModel, Generic[T]): + # root: T + # Should instead just be: + # class MyModel(RootModel[T]): + # root: T + parameters_str = ', '.join([x.__name__ for x in missing_parameters]) + error_message = ( + f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) ' + f'{parameters_str} in its parameters. ' + f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.' + ) + else: + combined_parameters = parent_parameters + missing_parameters + parameters_str = ', '.join([str(x) for x in combined_parameters]) + generic_type_label = f'typing.Generic[{parameters_str}]' + error_message = ( + f'All parameters must be present on typing.Generic;' + f' you should inherit from {generic_type_label}.' + ) + if Generic not in bases: # pragma: no cover + # We raise an error here not because it is desirable, but because some cases are mishandled. + # It would be nice to remove this error and still have things behave as expected, it's just + # challenging because we are using a custom `__class_getitem__` to parametrize generic models, + # and not returning a typing._GenericAlias from it. + bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label]) + error_message += ( + f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)' + ) + raise TypeError(error_message) + + cls.__pydantic_generic_metadata__ = { + 'origin': None, + 'args': (), + 'parameters': parameters, + } + + cls.__pydantic_complete__ = False # Ensure this specific class gets completed + + # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487 + # for attributes not in `new_namespace` (e.g. private attributes) + for name, obj in private_attributes.items(): + obj.__set_name__(cls, name) + + if __pydantic_reset_parent_namespace__: + cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) + parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None) + if isinstance(parent_namespace, dict): + parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) + + ns_resolver = NsResolver(parent_namespace=parent_namespace) + + set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) + + # This is also set in `complete_model_class()`, after schema gen because they are recreated. + # We set them here as well for backwards compatibility: + cls.__pydantic_computed_fields__ = { + k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items() + } + + if config_wrapper.defer_build: + set_model_mocks(cls) + else: + # Any operation that requires accessing the field infos instances should be put inside + # `complete_model_class()`: + complete_model_class( + cls, + config_wrapper, + ns_resolver, + raise_errors=False, + create_model_module=_create_model_module, + ) + + if config_wrapper.frozen and '__hash__' not in namespace: + set_default_hash_func(cls, bases) + + # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__ + # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is + # only hit for _proper_ subclasses of BaseModel + super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc] + return cls + else: + # These are instance variables, but have been assigned to `NoInitField` to trick the type checker. + for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__': + namespace.pop( + instance_slot, + None, # In case the metaclass is used with a class other than `BaseModel`. + ) + namespace.get('__annotations__', {}).clear() + return super().__new__(mcs, cls_name, bases, namespace, **kwargs) + + if not TYPE_CHECKING: # pragma: no branch + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """This is necessary to keep attribute access working for class attribute access.""" + private_attributes = self.__dict__.get('__private_attributes__') + if private_attributes and item in private_attributes: + return private_attributes[item] + raise AttributeError(item) + + @classmethod + def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]: + return _ModelNamespaceDict() + + # Due to performance and memory issues, in the ABCMeta.__subclasscheck__ implementation, we don't support + # registered virtual subclasses. See https://github.com/python/cpython/issues/92810#issuecomment-2762454345. + # This may change once the CPython gets fixed (possibly in 3.15), in which case we should conditionally + # define `register()`. + def register(self, subclass: type[_T]) -> type[_T]: + warnings.warn( + f"For performance reasons, virtual subclasses registered using '{self.__qualname__}.register()' " + "are not supported in 'isinstance()' and 'issubclass()' checks.", + stacklevel=2, + ) + return super().register(subclass) + + __instancecheck__ = type.__instancecheck__ # pyright: ignore[reportAssignmentType] + __subclasscheck__ = type.__subclasscheck__ # pyright: ignore[reportAssignmentType] + + @staticmethod + def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]: + BaseModel = import_cached_base_model() + + field_names: set[str] = set() + class_vars: set[str] = set() + private_attributes: dict[str, ModelPrivateAttr] = {} + for base in bases: + if issubclass(base, BaseModel) and base is not BaseModel: + # model_fields might not be defined yet in the case of generics, so we use getattr here: + field_names.update(getattr(base, '__pydantic_fields__', {}).keys()) + class_vars.update(base.__class_vars__) + private_attributes.update(base.__private_attributes__) + return field_names, class_vars, private_attributes + + @property + @deprecated( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', category=None + ) + def __fields__(self) -> dict[str, FieldInfo]: + warnings.warn( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + return getattr(self, '__pydantic_fields__', {}) + + @property + def __pydantic_fields_complete__(self) -> bool: + """Whether the fields where successfully collected (i.e. type hints were successfully resolves). + + This is a private attribute, not meant to be used outside Pydantic. + """ + if '__pydantic_fields__' not in self.__dict__: + return False + + field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue] + + return all(field_info._complete for field_info in field_infos.values()) + + def __dir__(self) -> list[str]: + attributes = list(super().__dir__()) + if '__fields__' in attributes: + attributes.remove('__fields__') + return attributes + + +def init_private_attributes(self: BaseModel, context: Any, /) -> None: + """This function is meant to behave like a BaseModel method to initialise private attributes. + + It takes context as an argument since that's what pydantic-core passes when calling it. + + Args: + self: The BaseModel instance. + context: The context. + """ + if getattr(self, '__pydantic_private__', None) is None: + pydantic_private = {} + for name, private_attr in self.__private_attributes__.items(): + default = private_attr.get_default() + if default is not PydanticUndefined: + pydantic_private[name] = default + object_setattr(self, '__pydantic_private__', pydantic_private) + + +def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None: + """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined.""" + if 'model_post_init' in namespace: + return namespace['model_post_init'] + + BaseModel = import_cached_base_model() + + model_post_init = get_attribute_from_bases(bases, 'model_post_init') + if model_post_init is not BaseModel.model_post_init: + return model_post_init + + +def inspect_namespace( # noqa C901 + namespace: dict[str, Any], + raw_annotations: dict[str, Any], + ignored_types: tuple[type[Any], ...], + base_class_vars: set[str], + base_class_fields: set[str], +) -> dict[str, ModelPrivateAttr]: + """Iterate over the namespace and: + * gather private attributes + * check for items which look like fields but are not (e.g. have no annotation) and warn. + + Args: + namespace: The attribute dictionary of the class to be created. + raw_annotations: The (non-evaluated) annotations of the model. + ignored_types: A tuple of ignore types. + base_class_vars: A set of base class class variables. + base_class_fields: A set of base class fields. + + Returns: + A dict contains private attributes info. + + Raises: + TypeError: If there is a `__root__` field in model. + NameError: If private attribute name is invalid. + PydanticUserError: + - If a field does not have a type annotation. + - If a field on base class was overridden by a non-annotated attribute. + """ + from ..fields import ModelPrivateAttr, PrivateAttr + + FieldInfo = import_cached_field_info() + + all_ignored_types = ignored_types + default_ignored_types() + + private_attributes: dict[str, ModelPrivateAttr] = {} + + if '__root__' in raw_annotations or '__root__' in namespace: + raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'") + + ignored_names: set[str] = set() + for var_name, value in list(namespace.items()): + if var_name == 'model_config' or var_name == '__pydantic_extra__': + continue + elif ( + isinstance(value, type) + and value.__module__ == namespace['__module__'] + and '__qualname__' in namespace + and value.__qualname__.startswith(f'{namespace["__qualname__"]}.') + ): + # `value` is a nested type defined in this namespace; don't error + continue + elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools': + ignored_names.add(var_name) + continue + elif isinstance(value, ModelPrivateAttr): + if var_name.startswith('__'): + raise NameError( + 'Private attributes must not use dunder names;' + f' use a single underscore prefix instead of {var_name!r}.' + ) + elif is_valid_field_name(var_name): + raise NameError( + 'Private attributes must not use valid field names;' + f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.' + ) + private_attributes[var_name] = value + del namespace[var_name] + elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): + suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name + raise NameError( + f'Fields must not use names with leading underscores;' + f' e.g., use {suggested_name!r} instead of {var_name!r}.' + ) + + elif var_name.startswith('__'): + continue + elif is_valid_privateattr_name(var_name): + if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): + private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) + del namespace[var_name] + elif var_name in base_class_vars: + continue + elif var_name not in raw_annotations: + if var_name in base_class_fields: + raise PydanticUserError( + f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. ' + f'All field definitions, including overrides, require a type annotation.', + code='model-field-overridden', + ) + elif isinstance(value, FieldInfo): + raise PydanticUserError( + f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation' + ) + else: + raise PydanticUserError( + f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a ' + f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this ' + f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.", + code='model-field-missing-annotation', + ) + + for ann_name, ann_type in raw_annotations.items(): + if ( + is_valid_privateattr_name(ann_name) + and ann_name not in private_attributes + and ann_name not in ignored_names + # This condition can be a false negative when `ann_type` is stringified, + # but it is handled in most cases in `set_model_fields`: + and not is_classvar_annotation(ann_type) + and ann_type not in all_ignored_types + and getattr(ann_type, '__module__', None) != 'functools' + ): + if isinstance(ann_type, str): + # Walking up the frames to get the module namespace where the model is defined + # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`): + frame = sys._getframe(2) + if frame is not None: + try: + ann_type = eval_type_backport( + _make_forward_ref(ann_type, is_argument=False, is_class=True), + globalns=frame.f_globals, + localns=frame.f_locals, + ) + except (NameError, TypeError): + pass + + if typing_objects.is_annotated(get_origin(ann_type)): + _, *metadata = get_args(ann_type) + private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) + if private_attr is not None: + private_attributes[ann_name] = private_attr + continue + private_attributes[ann_name] = PrivateAttr() + + return private_attributes + + +def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None: + base_hash_func = get_attribute_from_bases(bases, '__hash__') + new_hash_func = make_hash_func(cls) + if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__: + # If `__hash__` is some default, we generate a hash function. + # It will be `None` if not overridden from BaseModel. + # It may be `object.__hash__` if there is another + # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`). + # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model. + # In the last case we still need a new hash function to account for new `model_fields`. + cls.__hash__ = new_hash_func + + +def make_hash_func(cls: type[BaseModel]) -> Any: + getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0 + + def hash_func(self: Any) -> int: + try: + return hash(getter(self.__dict__)) + except KeyError: + # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain + # all model fields, which is how we can get here. + # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys, + # and wrapping it in a `try` doesn't slow things down much in the common case. + return hash(getter(SafeGetItemProxy(self.__dict__))) + + return hash_func + + +def set_model_fields( + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None, +) -> None: + """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting model annotations. + """ + typevars_map = get_model_typevars_map(cls) + fields, class_vars = collect_model_fields(cls, config_wrapper, ns_resolver, typevars_map=typevars_map) + + cls.__pydantic_fields__ = fields + cls.__class_vars__.update(class_vars) + + for k in class_vars: + # Class vars should not be private attributes + # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars, + # but private attributes are determined by inspecting the namespace _prior_ to class creation. + # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using + # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it + # evaluated to a classvar + + value = cls.__private_attributes__.pop(k, None) + if value is not None and value.default is not PydanticUndefined: + setattr(cls, k, value.default) + + +def complete_model_class( + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + *, + raise_errors: bool = True, + call_on_complete_hook: bool = True, + create_model_module: str | None = None, +) -> bool: + """Finish building a model class. + + This logic must be called after class has been created since validation functions must be bound + and `get_type_hints` requires a class object. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: The namespace resolver instance to use during schema building. + raise_errors: Whether to raise errors. + call_on_complete_hook: Whether to call the `__pydantic_on_complete__` hook. + create_model_module: The module of the class to be created, if created by `create_model`. + + Returns: + `True` if the model is successfully completed, else `False`. + + Raises: + PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__` + and `raise_errors=True`. + """ + typevars_map = get_model_typevars_map(cls) + + if not cls.__pydantic_fields_complete__: + # Note: when coming from `ModelMetaclass.__new__()`, this results in fields being built twice. + # We do so a second time here so that we can get the `NameError` for the specific undefined annotation. + # Alternatively, we could let `GenerateSchema()` raise the error, but there are cases where incomplete + # fields are inherited in `collect_model_fields()` and can actually have their annotation resolved in the + # generate schema process. As we want to avoid having `__pydantic_fields_complete__` set to `False` + # when `__pydantic_complete__` is `True`, we rebuild here: + try: + cls.__pydantic_fields__ = rebuild_model_fields( + cls, + config_wrapper=config_wrapper, + ns_resolver=ns_resolver, + typevars_map=typevars_map, + ) + except NameError as e: + exc = PydanticUndefinedAnnotation.from_name_error(e) + set_model_mocks(cls, f'`{exc.name}`') + if raise_errors: + raise exc from e + + if not raise_errors and not cls.__pydantic_fields_complete__: + # No need to continue with schema gen, it is guaranteed to fail + return False + + assert cls.__pydantic_fields_complete__ + + gen_schema = GenerateSchema( + config_wrapper, + ns_resolver, + typevars_map, + ) + + try: + schema = gen_schema.generate_schema(cls) + except PydanticUndefinedAnnotation as e: + if raise_errors: + raise + set_model_mocks(cls, f'`{e.name}`') + return False + + core_config = config_wrapper.core_config(title=cls.__name__) + + try: + schema = gen_schema.clean_schema(schema) + except InvalidSchemaError: + set_model_mocks(cls) + return False + + # This needs to happen *after* model schema generation, as the return type + # of the properties are evaluated and the `ComputedFieldInfo` are recreated: + cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} + + set_deprecated_descriptors(cls) + + cls.__pydantic_core_schema__ = schema + + cls.__pydantic_validator__ = create_schema_validator( + schema, + cls, + create_model_module or cls.__module__, + cls.__qualname__, + 'create_model' if create_model_module else 'BaseModel', + core_config, + config_wrapper.plugin_settings, + ) + cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) + + # set __signature__ attr only for model class, but not for its instances + # (because instances can define `__call__`, and `inspect.signature` shouldn't + # use the `__signature__` attribute and instead generate from `__call__`). + cls.__signature__ = LazyClassAttribute( + '__signature__', + partial( + generate_pydantic_signature, + init=cls.__init__, + fields=cls.__pydantic_fields__, + validate_by_name=config_wrapper.validate_by_name, + extra=config_wrapper.extra, + ), + ) + + cls.__pydantic_complete__ = True + + if call_on_complete_hook: + cls.__pydantic_on_complete__() + + return True + + +def set_deprecated_descriptors(cls: type[BaseModel]) -> None: + """Set data descriptors on the class for deprecated fields.""" + for field, field_info in cls.__pydantic_fields__.items(): + if (msg := field_info.deprecation_message) is not None: + desc = _DeprecatedFieldDescriptor(msg) + desc.__set_name__(cls, field) + setattr(cls, field, desc) + + for field, computed_field_info in cls.__pydantic_computed_fields__.items(): + if ( + (msg := computed_field_info.deprecation_message) is not None + # Avoid having two warnings emitted: + and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__') + ): + desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) + desc.__set_name__(cls, field) + setattr(cls, field, desc) + + +class _DeprecatedFieldDescriptor: + """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field. + + Attributes: + msg: The deprecation message to be emitted. + wrapped_property: The property instance if the deprecated field is a computed field, or `None`. + field_name: The name of the field being deprecated. + """ + + field_name: str + + def __init__(self, msg: str, wrapped_property: property | None = None) -> None: + self.msg = msg + self.wrapped_property = wrapped_property + + def __set_name__(self, cls: type[BaseModel], name: str) -> None: + self.field_name = name + + def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: + if obj is None: + if self.wrapped_property is not None: + return self.wrapped_property.__get__(None, obj_type) + raise AttributeError(self.field_name) + + warnings.warn(self.msg, DeprecationWarning, stacklevel=2) + + if self.wrapped_property is not None: + return self.wrapped_property.__get__(obj, obj_type) + return obj.__dict__[self.field_name] + + # Defined to make it a data descriptor and take precedence over the instance's dictionary. + # Note that it will not be called when setting a value on a model instance + # as `BaseModel.__setattr__` is defined and takes priority. + def __set__(self, obj: Any, value: Any) -> NoReturn: + raise AttributeError(self.field_name) + + +class _PydanticWeakRef: + """Wrapper for `weakref.ref` that enables `pickle` serialization. + + Cloudpickle fails to serialize `weakref.ref` objects due to an arcane error related + to abstract base classes (`abc.ABC`). This class works around the issue by wrapping + `weakref.ref` instead of subclassing it. + + See https://github.com/pydantic/pydantic/issues/6763 for context. + + Semantics: + - If not pickled, behaves the same as a `weakref.ref`. + - If pickled along with the referenced object, the same `weakref.ref` behavior + will be maintained between them after unpickling. + - If pickled without the referenced object, after unpickling the underlying + reference will be cleared (`__call__` will always return `None`). + """ + + def __init__(self, obj: Any): + if obj is None: + # The object will be `None` upon deserialization if the serialized weakref + # had lost its underlying object. + self._wr = None + else: + self._wr = weakref.ref(obj) + + def __call__(self) -> Any: + if self._wr is None: + return None + else: + return self._wr() + + def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]: + return _PydanticWeakRef, (self(),) + + +def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: + """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs. + + We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values + in a WeakValueDictionary. + + The `unpack_lenient_weakvaluedict` function can be used to reverse this operation. + """ + if d is None: + return None + result = {} + for k, v in d.items(): + try: + proxy = _PydanticWeakRef(v) + except TypeError: + proxy = v + result[k] = proxy + return result + + +def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: + """Inverts the transform performed by `build_lenient_weakvaluedict`.""" + if d is None: + return None + + result = {} + for k, v in d.items(): + if isinstance(v, _PydanticWeakRef): + v = v() + if v is not None: + result[k] = v + else: + result[k] = v + return result + + +@cache +def default_ignored_types() -> tuple[type[Any], ...]: + from ..fields import ComputedFieldInfo + + ignored_types = [ + FunctionType, + property, + classmethod, + staticmethod, + PydanticDescriptorProxy, + ComputedFieldInfo, + TypeAliasType, # from `typing_extensions` + ] + + if sys.version_info >= (3, 12): + ignored_types.append(typing.TypeAliasType) + + return tuple(ignored_types) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_namespace_utils.py b/backend/venv/Lib/site-packages/pydantic/_internal/_namespace_utils.py new file mode 100644 index 0000000..af0cddb --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_namespace_utils.py @@ -0,0 +1,293 @@ +from __future__ import annotations + +import sys +from collections.abc import Generator, Iterator, Mapping +from contextlib import contextmanager +from functools import cached_property +from typing import Any, Callable, NamedTuple, TypeVar + +from typing_extensions import ParamSpec, TypeAlias, TypeAliasType, TypeVarTuple + +GlobalsNamespace: TypeAlias = 'dict[str, Any]' +"""A global namespace. + +In most cases, this is a reference to the `__dict__` attribute of a module. +This namespace type is expected as the `globals` argument during annotations evaluation. +""" + +MappingNamespace: TypeAlias = Mapping[str, Any] +"""Any kind of namespace. + +In most cases, this is a local namespace (e.g. the `__dict__` attribute of a class, +the [`f_locals`][frame.f_locals] attribute of a frame object, when dealing with types +defined inside functions). +This namespace type is expected as the `locals` argument during annotations evaluation. +""" + +_TypeVarLike: TypeAlias = 'TypeVar | ParamSpec | TypeVarTuple' + + +class NamespacesTuple(NamedTuple): + """A tuple of globals and locals to be used during annotations evaluation. + + This datastructure is defined as a named tuple so that it can easily be unpacked: + + ```python {lint="skip" test="skip"} + def eval_type(typ: type[Any], ns: NamespacesTuple) -> None: + return eval(typ, *ns) + ``` + """ + + globals: GlobalsNamespace + """The namespace to be used as the `globals` argument during annotations evaluation.""" + + locals: MappingNamespace + """The namespace to be used as the `locals` argument during annotations evaluation.""" + + +def get_module_ns_of(obj: Any) -> dict[str, Any]: + """Get the namespace of the module where the object is defined. + + Caution: this function does not return a copy of the module namespace, so the result + should not be mutated. The burden of enforcing this is on the caller. + """ + module_name = getattr(obj, '__module__', None) + if module_name: + try: + return sys.modules[module_name].__dict__ + except KeyError: + # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363 + return {} + return {} + + +# Note that this class is almost identical to `collections.ChainMap`, but need to enforce +# immutable mappings here: +class LazyLocalNamespace(Mapping[str, Any]): + """A lazily evaluated mapping, to be used as the `locals` argument during annotations evaluation. + + While the [`eval`][eval] function expects a mapping as the `locals` argument, it only + performs `__getitem__` calls. The [`Mapping`][collections.abc.Mapping] abstract base class + is fully implemented only for type checking purposes. + + Args: + *namespaces: The namespaces to consider, in ascending order of priority. + + Example: + ```python {lint="skip" test="skip"} + ns = LazyLocalNamespace({'a': 1, 'b': 2}, {'a': 3}) + ns['a'] + #> 3 + ns['b'] + #> 2 + ``` + """ + + def __init__(self, *namespaces: MappingNamespace) -> None: + self._namespaces = namespaces + + @cached_property + def data(self) -> dict[str, Any]: + return {k: v for ns in self._namespaces for k, v in ns.items()} + + def __len__(self) -> int: + return len(self.data) + + def __getitem__(self, key: str) -> Any: + return self.data[key] + + def __contains__(self, key: object) -> bool: + return key in self.data + + def __iter__(self) -> Iterator[str]: + return iter(self.data) + + +def ns_for_function(obj: Callable[..., Any], parent_namespace: MappingNamespace | None = None) -> NamespacesTuple: + """Return the global and local namespaces to be used when evaluating annotations for the provided function. + + The global namespace will be the `__dict__` attribute of the module the function was defined in. + The local namespace will contain the `__type_params__` introduced by PEP 695. + + Args: + obj: The object to use when building namespaces. + parent_namespace: Optional namespace to be added with the lowest priority in the local namespace. + If the passed function is a method, the `parent_namespace` will be the namespace of the class + the method is defined in. Thus, we also fetch type `__type_params__` from there (i.e. the + class-scoped type variables). + """ + locals_list: list[MappingNamespace] = [] + if parent_namespace is not None: + locals_list.append(parent_namespace) + + # Get the `__type_params__` attribute introduced by PEP 695. + # Note that the `typing._eval_type` function expects type params to be + # passed as a separate argument. However, internally, `_eval_type` calls + # `ForwardRef._evaluate` which will merge type params with the localns, + # essentially mimicking what we do here. + type_params: tuple[_TypeVarLike, ...] = getattr(obj, '__type_params__', ()) + if parent_namespace is not None: + # We also fetch type params from the parent namespace. If present, it probably + # means the function was defined in a class. This is to support the following: + # https://github.com/python/cpython/issues/124089. + type_params += parent_namespace.get('__type_params__', ()) + + locals_list.append({t.__name__: t for t in type_params}) + + # What about short-circuiting to `obj.__globals__`? + globalns = get_module_ns_of(obj) + + return NamespacesTuple(globalns, LazyLocalNamespace(*locals_list)) + + +class NsResolver: + """A class responsible for the namespaces resolving logic for annotations evaluation. + + This class handles the namespace logic when evaluating annotations mainly for class objects. + + It holds a stack of classes that are being inspected during the core schema building, + and the `types_namespace` property exposes the globals and locals to be used for + type annotation evaluation. Additionally -- if no class is present in the stack -- a + fallback globals and locals can be provided using the `namespaces_tuple` argument + (this is useful when generating a schema for a simple annotation, e.g. when using + `TypeAdapter`). + + The namespace creation logic is unfortunately flawed in some cases, for backwards + compatibility reasons and to better support valid edge cases. See the description + for the `parent_namespace` argument and the example for more details. + + Args: + namespaces_tuple: The default globals and locals to use if no class is present + on the stack. This can be useful when using the `GenerateSchema` class + with `TypeAdapter`, where the "type" being analyzed is a simple annotation. + parent_namespace: An optional parent namespace that will be added to the locals + with the lowest priority. For a given class defined in a function, the locals + of this function are usually used as the parent namespace: + + ```python {lint="skip" test="skip"} + from pydantic import BaseModel + + def func() -> None: + SomeType = int + + class Model(BaseModel): + f: 'SomeType' + + # when collecting fields, an namespace resolver instance will be created + # this way: + # ns_resolver = NsResolver(parent_namespace={'SomeType': SomeType}) + ``` + + For backwards compatibility reasons and to support valid edge cases, this parent + namespace will be used for *every* type being pushed to the stack. In the future, + we might want to be smarter by only doing so when the type being pushed is defined + in the same module as the parent namespace. + + Example: + ```python {lint="skip" test="skip"} + ns_resolver = NsResolver( + parent_namespace={'fallback': 1}, + ) + + class Sub: + m: 'Model' + + class Model: + some_local = 1 + sub: Sub + + ns_resolver = NsResolver() + + # This is roughly what happens when we build a core schema for `Model`: + with ns_resolver.push(Model): + ns_resolver.types_namespace + #> NamespacesTuple({'Sub': Sub}, {'Model': Model, 'some_local': 1}) + # First thing to notice here, the model being pushed is added to the locals. + # Because `NsResolver` is being used during the model definition, it is not + # yet added to the globals. This is useful when resolving self-referencing annotations. + + with ns_resolver.push(Sub): + ns_resolver.types_namespace + #> NamespacesTuple({'Sub': Sub}, {'Sub': Sub, 'Model': Model}) + # Second thing to notice: `Sub` is present in both the globals and locals. + # This is not an issue, just that as described above, the model being pushed + # is added to the locals, but it happens to be present in the globals as well + # because it is already defined. + # Third thing to notice: `Model` is also added in locals. This is a backwards + # compatibility workaround that allows for `Sub` to be able to resolve `'Model'` + # correctly (as otherwise models would have to be rebuilt even though this + # doesn't look necessary). + ``` + """ + + def __init__( + self, + namespaces_tuple: NamespacesTuple | None = None, + parent_namespace: MappingNamespace | None = None, + ) -> None: + self._base_ns_tuple = namespaces_tuple or NamespacesTuple({}, {}) + self._parent_ns = parent_namespace + self._types_stack: list[type[Any] | TypeAliasType] = [] + + @cached_property + def types_namespace(self) -> NamespacesTuple: + """The current global and local namespaces to be used for annotations evaluation.""" + if not self._types_stack: + # TODO: should we merge the parent namespace here? + # This is relevant for TypeAdapter, where there are no types on the stack, and we might + # need access to the parent_ns. Right now, we sidestep this in `type_adapter.py` by passing + # locals to both parent_ns and the base_ns_tuple, but this is a bit hacky. + # we might consider something like: + # if self._parent_ns is not None: + # # Hacky workarounds, see class docstring: + # # An optional parent namespace that will be added to the locals with the lowest priority + # locals_list: list[MappingNamespace] = [self._parent_ns, self._base_ns_tuple.locals] + # return NamespacesTuple(self._base_ns_tuple.globals, LazyLocalNamespace(*locals_list)) + return self._base_ns_tuple + + typ = self._types_stack[-1] + + globalns = get_module_ns_of(typ) + + locals_list: list[MappingNamespace] = [] + # Hacky workarounds, see class docstring: + # An optional parent namespace that will be added to the locals with the lowest priority + if self._parent_ns is not None: + locals_list.append(self._parent_ns) + if len(self._types_stack) > 1: + first_type = self._types_stack[0] + locals_list.append({first_type.__name__: first_type}) + + # Adding `__type_params__` *before* `vars(typ)`, as the latter takes priority + # (see https://github.com/python/cpython/pull/120272). + # TODO `typ.__type_params__` when we drop support for Python 3.11: + type_params: tuple[_TypeVarLike, ...] = getattr(typ, '__type_params__', ()) + if type_params: + # Adding `__type_params__` is mostly useful for generic classes defined using + # PEP 695 syntax *and* using forward annotations (see the example in + # https://github.com/python/cpython/issues/114053). For TypeAliasType instances, + # it is way less common, but still required if using a string annotation in the alias + # value, e.g. `type A[T] = 'T'` (which is not necessary in most cases). + locals_list.append({t.__name__: t for t in type_params}) + + # TypeAliasType instances don't have a `__dict__` attribute, so the check + # is necessary: + if hasattr(typ, '__dict__'): + locals_list.append(vars(typ)) + + # The `len(self._types_stack) > 1` check above prevents this from being added twice: + locals_list.append({typ.__name__: typ}) + + return NamespacesTuple(globalns, LazyLocalNamespace(*locals_list)) + + @contextmanager + def push(self, typ: type[Any] | TypeAliasType, /) -> Generator[None]: + """Push a type to the stack.""" + self._types_stack.append(typ) + # Reset the cached property: + self.__dict__.pop('types_namespace', None) + try: + yield + finally: + self._types_stack.pop() + self.__dict__.pop('types_namespace', None) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_repr.py b/backend/venv/Lib/site-packages/pydantic/_internal/_repr.py new file mode 100644 index 0000000..7e80a9c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_repr.py @@ -0,0 +1,124 @@ +"""Tools to provide pretty/human-readable display of objects.""" + +from __future__ import annotations as _annotations + +import types +from collections.abc import Callable, Collection, Generator, Iterable +from typing import TYPE_CHECKING, Any, ForwardRef, cast + +import typing_extensions +from typing_extensions import TypeAlias +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from . import _typing_extra + +if TYPE_CHECKING: + # TODO remove type error comments when we drop support for Python 3.9 + ReprArgs: TypeAlias = Iterable[tuple[str | None, Any]] # pyright: ignore[reportGeneralTypeIssues] + RichReprResult: TypeAlias = Iterable[Any | tuple[Any] | tuple[str, Any] | tuple[str, Any, Any]] # pyright: ignore[reportGeneralTypeIssues] + + +class PlainRepr(str): + """String class where repr doesn't include quotes. Useful with Representation when you want to return a string + representation of something that is valid (or pseudo-valid) python. + """ + + def __repr__(self) -> str: + return str(self) + + +class Representation: + # Mixin to provide `__str__`, `__repr__`, and `__pretty__` and `__rich_repr__` methods. + # `__pretty__` is used by [devtools](https://python-devtools.helpmanual.io/). + # `__rich_repr__` is used by [rich](https://rich.readthedocs.io/en/stable/pretty.html). + # (this is not a docstring to avoid adding a docstring to classes which inherit from Representation) + + __slots__ = () + + def __repr_args__(self) -> ReprArgs: + """Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden. + + Can either return: + * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]` + * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]` + """ + attrs_names = cast(Collection[str], self.__slots__) + if not attrs_names and hasattr(self, '__dict__'): + attrs_names = self.__dict__.keys() + attrs = ((s, getattr(self, s)) for s in attrs_names) + return [(a, v if v is not self else self.__repr_recursion__(v)) for a, v in attrs if v is not None] + + def __repr_name__(self) -> str: + """Name of the instance's class, used in __repr__.""" + return self.__class__.__name__ + + def __repr_recursion__(self, object: Any) -> str: + """Returns the string representation of a recursive object.""" + # This is copied over from the stdlib `pprint` module: + return f'' + + def __repr_str__(self, join_str: str) -> str: + return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) + + def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any]: + """Used by devtools (https://python-devtools.helpmanual.io/) to pretty print objects.""" + yield self.__repr_name__() + '(' + yield 1 + for name, value in self.__repr_args__(): + if name is not None: + yield name + '=' + yield fmt(value) + yield ',' + yield 0 + yield -1 + yield ')' + + def __rich_repr__(self) -> RichReprResult: + """Used by Rich (https://rich.readthedocs.io/en/stable/pretty.html) to pretty print objects.""" + for name, field_repr in self.__repr_args__(): + if name is None: + yield field_repr + else: + yield name, field_repr + + def __str__(self) -> str: + return self.__repr_str__(' ') + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + +def display_as_type(obj: Any) -> str: + """Pretty representation of a type, should be as close as possible to the original type definition string. + + Takes some logic from `typing._type_repr`. + """ + if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)): + return obj.__name__ + elif obj is ...: + return '...' + elif isinstance(obj, Representation): + return repr(obj) + elif isinstance(obj, ForwardRef) or typing_objects.is_typealiastype(obj): + return str(obj) + + if not isinstance(obj, (_typing_extra.typing_base, _typing_extra.WithArgsTypes, type)): + obj = obj.__class__ + + if is_union_origin(typing_extensions.get_origin(obj)): + args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) + return f'Union[{args}]' + elif isinstance(obj, _typing_extra.WithArgsTypes): + if typing_objects.is_literal(typing_extensions.get_origin(obj)): + args = ', '.join(map(repr, typing_extensions.get_args(obj))) + else: + args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) + try: + return f'{obj.__qualname__}[{args}]' + except AttributeError: + return str(obj).replace('typing.', '').replace('typing_extensions.', '') # handles TypeAliasType in 3.12 + elif isinstance(obj, type): + return obj.__qualname__ + else: + return repr(obj).replace('typing.', '').replace('typing_extensions.', '') diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_schema_gather.py b/backend/venv/Lib/site-packages/pydantic/_internal/_schema_gather.py new file mode 100644 index 0000000..fc2d806 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_schema_gather.py @@ -0,0 +1,209 @@ +# pyright: reportTypedDictNotRequiredAccess=false, reportGeneralTypeIssues=false, reportArgumentType=false, reportAttributeAccessIssue=false +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TypedDict + +from pydantic_core.core_schema import ComputedField, CoreSchema, DefinitionReferenceSchema, SerSchema +from typing_extensions import TypeAlias + +AllSchemas: TypeAlias = 'CoreSchema | SerSchema | ComputedField' + + +class GatherResult(TypedDict): + """Schema traversing result.""" + + collected_references: dict[str, DefinitionReferenceSchema | None] + """The collected definition references. + + If a definition reference schema can be inlined, it means that there is + only one in the whole core schema. As such, it is stored as the value. + Otherwise, the value is set to `None`. + """ + + deferred_discriminator_schemas: list[CoreSchema] + """The list of core schemas having the discriminator application deferred.""" + + +class MissingDefinitionError(LookupError): + """A reference was pointing to a non-existing core schema.""" + + def __init__(self, schema_reference: str, /) -> None: + self.schema_reference = schema_reference + + +@dataclass +class GatherContext: + """The current context used during core schema traversing. + + Context instances should only be used during schema traversing. + """ + + definitions: dict[str, CoreSchema] + """The available definitions.""" + + deferred_discriminator_schemas: list[CoreSchema] = field(init=False, default_factory=list) + """The list of core schemas having the discriminator application deferred. + + Internally, these core schemas have a specific key set in the core metadata dict. + """ + + collected_references: dict[str, DefinitionReferenceSchema | None] = field(init=False, default_factory=dict) + """The collected definition references. + + If a definition reference schema can be inlined, it means that there is + only one in the whole core schema. As such, it is stored as the value. + Otherwise, the value is set to `None`. + + During schema traversing, definition reference schemas can be added as candidates, or removed + (by setting the value to `None`). + """ + + +def traverse_metadata(schema: AllSchemas, ctx: GatherContext) -> None: + meta = schema.get('metadata') + if meta is not None and 'pydantic_internal_union_discriminator' in meta: + ctx.deferred_discriminator_schemas.append(schema) # pyright: ignore[reportArgumentType] + + +def traverse_definition_ref(def_ref_schema: DefinitionReferenceSchema, ctx: GatherContext) -> None: + schema_ref = def_ref_schema['schema_ref'] + + if schema_ref not in ctx.collected_references: + definition = ctx.definitions.get(schema_ref) + if definition is None: + raise MissingDefinitionError(schema_ref) + + # The `'definition-ref'` schema was only encountered once, make it + # a candidate to be inlined: + ctx.collected_references[schema_ref] = def_ref_schema + traverse_schema(definition, ctx) + if 'serialization' in def_ref_schema: + traverse_schema(def_ref_schema['serialization'], ctx) + traverse_metadata(def_ref_schema, ctx) + else: + # The `'definition-ref'` schema was already encountered, meaning + # the previously encountered schema (and this one) can't be inlined: + ctx.collected_references[schema_ref] = None + + +def traverse_schema(schema: AllSchemas, context: GatherContext) -> None: + # TODO When we drop 3.9, use a match statement to get better type checking and remove + # file-level type ignore. + # (the `'type'` could also be fetched in every `if/elif` statement, but this alters performance). + schema_type = schema['type'] + + if schema_type == 'definition-ref': + traverse_definition_ref(schema, context) + # `traverse_definition_ref` handles the possible serialization and metadata schemas: + return + elif schema_type == 'definitions': + traverse_schema(schema['schema'], context) + for definition in schema['definitions']: + traverse_schema(definition, context) + elif schema_type in {'list', 'set', 'frozenset', 'generator'}: + if 'items_schema' in schema: + traverse_schema(schema['items_schema'], context) + elif schema_type == 'tuple': + if 'items_schema' in schema: + for s in schema['items_schema']: + traverse_schema(s, context) + elif schema_type == 'dict': + if 'keys_schema' in schema: + traverse_schema(schema['keys_schema'], context) + if 'values_schema' in schema: + traverse_schema(schema['values_schema'], context) + elif schema_type == 'union': + for choice in schema['choices']: + if isinstance(choice, tuple): + traverse_schema(choice[0], context) + else: + traverse_schema(choice, context) + elif schema_type == 'tagged-union': + for v in schema['choices'].values(): + traverse_schema(v, context) + elif schema_type == 'chain': + for step in schema['steps']: + traverse_schema(step, context) + elif schema_type == 'lax-or-strict': + traverse_schema(schema['lax_schema'], context) + traverse_schema(schema['strict_schema'], context) + elif schema_type == 'json-or-python': + traverse_schema(schema['json_schema'], context) + traverse_schema(schema['python_schema'], context) + elif schema_type in {'model-fields', 'typed-dict'}: + if 'extras_schema' in schema: + traverse_schema(schema['extras_schema'], context) + if 'computed_fields' in schema: + for s in schema['computed_fields']: + traverse_schema(s, context) + for s in schema['fields'].values(): + traverse_schema(s, context) + elif schema_type == 'dataclass-args': + if 'computed_fields' in schema: + for s in schema['computed_fields']: + traverse_schema(s, context) + for s in schema['fields']: + traverse_schema(s, context) + elif schema_type == 'arguments': + for s in schema['arguments_schema']: + traverse_schema(s['schema'], context) + if 'var_args_schema' in schema: + traverse_schema(schema['var_args_schema'], context) + if 'var_kwargs_schema' in schema: + traverse_schema(schema['var_kwargs_schema'], context) + elif schema_type == 'arguments-v3': + for s in schema['arguments_schema']: + traverse_schema(s['schema'], context) + elif schema_type == 'call': + traverse_schema(schema['arguments_schema'], context) + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + elif schema_type == 'computed-field': + traverse_schema(schema['return_schema'], context) + elif schema_type == 'function-before': + if 'schema' in schema: + traverse_schema(schema['schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + elif schema_type == 'function-plain': + # TODO duplicate schema types for serializers and validators, needs to be deduplicated. + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + elif schema_type == 'function-wrap': + # TODO duplicate schema types for serializers and validators, needs to be deduplicated. + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + if 'schema' in schema: + traverse_schema(schema['schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + else: + if 'schema' in schema: + traverse_schema(schema['schema'], context) + + if 'serialization' in schema: + traverse_schema(schema['serialization'], context) + traverse_metadata(schema, context) + + +def gather_schemas_for_cleaning(schema: CoreSchema, definitions: dict[str, CoreSchema]) -> GatherResult: + """Traverse the core schema and definitions and return the necessary information for schema cleaning. + + During the core schema traversing, any `'definition-ref'` schema is: + + - Validated: the reference must point to an existing definition. If this is not the case, a + `MissingDefinitionError` exception is raised. + - Stored in the context: the actual reference is stored in the context. Depending on whether + the `'definition-ref'` schema is encountered more that once, the schema itself is also + saved in the context to be inlined (i.e. replaced by the definition it points to). + """ + context = GatherContext(definitions) + traverse_schema(schema, context) + + return { + 'collected_references': context.collected_references, + 'deferred_discriminator_schemas': context.deferred_discriminator_schemas, + } diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_schema_generation_shared.py b/backend/venv/Lib/site-packages/pydantic/_internal/_schema_generation_shared.py new file mode 100644 index 0000000..b231a82 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_schema_generation_shared.py @@ -0,0 +1,125 @@ +"""Types and utility functions used by various other internal tools.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Callable, Literal + +from pydantic_core import core_schema + +from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler + +if TYPE_CHECKING: + from ..json_schema import GenerateJsonSchema, JsonSchemaValue + from ._core_utils import CoreSchemaOrField + from ._generate_schema import GenerateSchema + from ._namespace_utils import NamespacesTuple + + GetJsonSchemaFunction = Callable[[CoreSchemaOrField, GetJsonSchemaHandler], JsonSchemaValue] + HandlerOverride = Callable[[CoreSchemaOrField], JsonSchemaValue] + + +class GenerateJsonSchemaHandler(GetJsonSchemaHandler): + """JsonSchemaHandler implementation that doesn't do ref unwrapping by default. + + This is used for any Annotated metadata so that we don't end up with conflicting + modifications to the definition schema. + + Used internally by Pydantic, please do not rely on this implementation. + See `GetJsonSchemaHandler` for the handler API. + """ + + def __init__(self, generate_json_schema: GenerateJsonSchema, handler_override: HandlerOverride | None) -> None: + self.generate_json_schema = generate_json_schema + self.handler = handler_override or generate_json_schema.generate_inner + self.mode = generate_json_schema.mode + + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: + return self.handler(core_schema) + + def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Resolves `$ref` in the json schema. + + This returns the input json schema if there is no `$ref` in json schema. + + Args: + maybe_ref_json_schema: The input json schema that may contains `$ref`. + + Returns: + Resolved json schema. + + Raises: + LookupError: If it can't find the definition for `$ref`. + """ + if '$ref' not in maybe_ref_json_schema: + return maybe_ref_json_schema + ref = maybe_ref_json_schema['$ref'] + json_schema = self.generate_json_schema.get_schema_from_definitions(ref) + if json_schema is None: + raise LookupError( + f'Could not find a ref for {ref}.' + ' Maybe you tried to call resolve_ref_schema from within a recursive model?' + ) + return json_schema + + +class CallbackGetCoreSchemaHandler(GetCoreSchemaHandler): + """Wrapper to use an arbitrary function as a `GetCoreSchemaHandler`. + + Used internally by Pydantic, please do not rely on this implementation. + See `GetCoreSchemaHandler` for the handler API. + """ + + def __init__( + self, + handler: Callable[[Any], core_schema.CoreSchema], + generate_schema: GenerateSchema, + ref_mode: Literal['to-def', 'unpack'] = 'to-def', + ) -> None: + self._handler = handler + self._generate_schema = generate_schema + self._ref_mode = ref_mode + + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: + schema = self._handler(source_type) + if self._ref_mode == 'to-def': + ref = schema.get('ref') + if ref is not None: + return self._generate_schema.defs.create_definition_reference_schema(schema) + return schema + else: # ref_mode = 'unpack' + return self.resolve_ref_schema(schema) + + def _get_types_namespace(self) -> NamespacesTuple: + return self._generate_schema._types_namespace + + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: + return self._generate_schema.generate_schema(source_type) + + @property + def field_name(self) -> str | None: + return self._generate_schema.field_name_stack.get() + + def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Resolves reference in the core schema. + + Args: + maybe_ref_schema: The input core schema that may contains reference. + + Returns: + Resolved core schema. + + Raises: + LookupError: If it can't find the definition for reference. + """ + if maybe_ref_schema['type'] == 'definition-ref': + ref = maybe_ref_schema['schema_ref'] + definition = self._generate_schema.defs.get_schema_from_ref(ref) + if definition is None: + raise LookupError( + f'Could not find a ref for {ref}.' + ' Maybe you tried to call resolve_ref_schema from within a recursive model?' + ) + return definition + elif maybe_ref_schema['type'] == 'definitions': + return self.resolve_ref_schema(maybe_ref_schema['schema']) + return maybe_ref_schema diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_serializers.py b/backend/venv/Lib/site-packages/pydantic/_internal/_serializers.py new file mode 100644 index 0000000..a4058e0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_serializers.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import collections +import collections.abc +import typing +from typing import Any + +from pydantic_core import PydanticOmit, core_schema + +SEQUENCE_ORIGIN_MAP: dict[Any, Any] = { + typing.Deque: collections.deque, # noqa: UP006 + collections.deque: collections.deque, + list: list, + typing.List: list, # noqa: UP006 + tuple: tuple, + typing.Tuple: tuple, # noqa: UP006 + set: set, + typing.AbstractSet: set, + typing.Set: set, # noqa: UP006 + frozenset: frozenset, + typing.FrozenSet: frozenset, # noqa: UP006 + typing.Sequence: list, + typing.MutableSequence: list, + typing.MutableSet: set, + # this doesn't handle subclasses of these + # parametrized typing.Set creates one of these + collections.abc.MutableSet: set, + collections.abc.Set: frozenset, +} + + +def serialize_sequence_via_list( + v: Any, handler: core_schema.SerializerFunctionWrapHandler, info: core_schema.SerializationInfo +) -> Any: + items: list[Any] = [] + + mapped_origin = SEQUENCE_ORIGIN_MAP.get(type(v), None) + if mapped_origin is None: + # we shouldn't hit this branch, should probably add a serialization error or something + return v + + for index, item in enumerate(v): + try: + v = handler(item, index) + except PydanticOmit: # noqa: PERF203 + pass + else: + items.append(v) + + if info.mode_is_json(): + return items + else: + return mapped_origin(items) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_signature.py b/backend/venv/Lib/site-packages/pydantic/_internal/_signature.py new file mode 100644 index 0000000..977e5d2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_signature.py @@ -0,0 +1,188 @@ +from __future__ import annotations + +import dataclasses +from inspect import Parameter, Signature, signature +from typing import TYPE_CHECKING, Any, Callable + +from pydantic_core import PydanticUndefined + +from ._utils import is_valid_identifier + +if TYPE_CHECKING: + from ..config import ExtraValues + from ..fields import FieldInfo + + +# Copied over from stdlib dataclasses +class _HAS_DEFAULT_FACTORY_CLASS: + def __repr__(self): + return '' + + +_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS() + + +def _field_name_for_signature(field_name: str, field_info: FieldInfo) -> str: + """Extract the correct name to use for the field when generating a signature. + + Assuming the field has a valid alias, this will return the alias. Otherwise, it will return the field name. + First priority is given to the alias, then the validation_alias, then the field name. + + Args: + field_name: The name of the field + field_info: The corresponding FieldInfo object. + + Returns: + The correct name to use when generating a signature. + """ + if isinstance(field_info.alias, str) and is_valid_identifier(field_info.alias): + return field_info.alias + if isinstance(field_info.validation_alias, str) and is_valid_identifier(field_info.validation_alias): + return field_info.validation_alias + + return field_name + + +def _process_param_defaults(param: Parameter) -> Parameter: + """Modify the signature for a parameter in a dataclass where the default value is a FieldInfo instance. + + Args: + param (Parameter): The parameter + + Returns: + Parameter: The custom processed parameter + """ + from ..fields import FieldInfo + + param_default = param.default + if isinstance(param_default, FieldInfo): + annotation = param.annotation + # Replace the annotation if appropriate + # inspect does "clever" things to show annotations as strings because we have + # `from __future__ import annotations` in main, we don't want that + if annotation == 'Any': + annotation = Any + + # Replace the field default + default = param_default.default + if default is PydanticUndefined: + if param_default.default_factory is PydanticUndefined: + default = Signature.empty + else: + # this is used by dataclasses to indicate a factory exists: + default = dataclasses._HAS_DEFAULT_FACTORY # type: ignore + return param.replace( + annotation=annotation, name=_field_name_for_signature(param.name, param_default), default=default + ) + return param + + +def _generate_signature_parameters( # noqa: C901 (ignore complexity, could use a refactor) + init: Callable[..., None], + fields: dict[str, FieldInfo], + validate_by_name: bool, + extra: ExtraValues | None, +) -> dict[str, Parameter]: + """Generate a mapping of parameter names to Parameter objects for a pydantic BaseModel or dataclass.""" + from itertools import islice + + present_params = signature(init).parameters.values() + merged_params: dict[str, Parameter] = {} + var_kw = None + use_var_kw = False + + for param in islice(present_params, 1, None): # skip self arg + # inspect does "clever" things to show annotations as strings because we have + # `from __future__ import annotations` in main, we don't want that + if fields.get(param.name): + # exclude params with init=False + if getattr(fields[param.name], 'init', True) is False: + continue + param = param.replace(name=_field_name_for_signature(param.name, fields[param.name])) + if param.annotation == 'Any': + param = param.replace(annotation=Any) + if param.kind is param.VAR_KEYWORD: + var_kw = param + continue + merged_params[param.name] = param + + if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through + allow_names = validate_by_name + for field_name, field in fields.items(): + # when alias is a str it should be used for signature generation + param_name = _field_name_for_signature(field_name, field) + + if field_name in merged_params or param_name in merged_params: + continue + + if not is_valid_identifier(param_name): + if allow_names: + param_name = field_name + else: + use_var_kw = True + continue + + if field.is_required(): + default = Parameter.empty + elif field.default_factory is not None: + # Mimics stdlib dataclasses: + default = _HAS_DEFAULT_FACTORY + else: + default = field.default + merged_params[param_name] = Parameter( + param_name, + Parameter.KEYWORD_ONLY, + annotation=field.rebuild_annotation(), + default=default, + ) + + if extra == 'allow': + use_var_kw = True + + if var_kw and use_var_kw: + # Make sure the parameter for extra kwargs + # does not have the same name as a field + default_model_signature = [ + ('self', Parameter.POSITIONAL_ONLY), + ('data', Parameter.VAR_KEYWORD), + ] + if [(p.name, p.kind) for p in present_params] == default_model_signature: + # if this is the standard model signature, use extra_data as the extra args name + var_kw_name = 'extra_data' + else: + # else start from var_kw + var_kw_name = var_kw.name + + # generate a name that's definitely unique + while var_kw_name in fields: + var_kw_name += '_' + merged_params[var_kw_name] = var_kw.replace(name=var_kw_name) + + return merged_params + + +def generate_pydantic_signature( + init: Callable[..., None], + fields: dict[str, FieldInfo], + validate_by_name: bool, + extra: ExtraValues | None, + is_dataclass: bool = False, +) -> Signature: + """Generate signature for a pydantic BaseModel or dataclass. + + Args: + init: The class init. + fields: The model fields. + validate_by_name: The `validate_by_name` value of the config. + extra: The `extra` value of the config. + is_dataclass: Whether the model is a dataclass. + + Returns: + The dataclass/BaseModel subclass signature. + """ + merged_params = _generate_signature_parameters(init, fields, validate_by_name, extra) + + if is_dataclass: + merged_params = {k: _process_param_defaults(v) for k, v in merged_params.items()} + + return Signature(parameters=list(merged_params.values()), return_annotation=None) diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_typing_extra.py b/backend/venv/Lib/site-packages/pydantic/_internal/_typing_extra.py new file mode 100644 index 0000000..986ee42 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_typing_extra.py @@ -0,0 +1,760 @@ +"""Logic for interacting with type annotations, mostly extensions, shims and hacks to wrap Python's typing module.""" + +from __future__ import annotations + +import collections.abc +import re +import sys +import types +import typing +from functools import partial +from typing import TYPE_CHECKING, Any, Callable, cast + +import typing_extensions +from typing_extensions import deprecated, get_args, get_origin +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from pydantic.version import version_short + +from ._namespace_utils import GlobalsNamespace, MappingNamespace, NsResolver, get_module_ns_of + +if sys.version_info < (3, 10): + NoneType = type(None) + EllipsisType = type(Ellipsis) +else: + from types import EllipsisType as EllipsisType + from types import NoneType as NoneType + +if sys.version_info >= (3, 14): + import annotationlib + +if TYPE_CHECKING: + from pydantic import BaseModel + +# As per https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types, +# always check for both `typing` and `typing_extensions` variants of a typing construct. +# (this is implemented differently than the suggested approach in the `typing_extensions` +# docs for performance). + + +_t_annotated = typing.Annotated +_te_annotated = typing_extensions.Annotated + + +def is_annotated(tp: Any, /) -> bool: + """Return whether the provided argument is a `Annotated` special form. + + ```python {test="skip" lint="skip"} + is_annotated(Annotated[int, ...]) + #> True + ``` + """ + origin = get_origin(tp) + return origin is _t_annotated or origin is _te_annotated + + +def annotated_type(tp: Any, /) -> Any | None: + """Return the type of the `Annotated` special form, or `None`.""" + return tp.__origin__ if typing_objects.is_annotated(get_origin(tp)) else None + + +def unpack_type(tp: Any, /) -> Any | None: + """Return the type wrapped by the `Unpack` special form, or `None`.""" + return get_args(tp)[0] if typing_objects.is_unpack(get_origin(tp)) else None + + +def is_hashable(tp: Any, /) -> bool: + """Return whether the provided argument is the `Hashable` class. + + ```python {test="skip" lint="skip"} + is_hashable(Hashable) + #> True + ``` + """ + # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, + # hence the second check: + return tp is collections.abc.Hashable or get_origin(tp) is collections.abc.Hashable + + +def is_callable(tp: Any, /) -> bool: + """Return whether the provided argument is a `Callable`, parametrized or not. + + ```python {test="skip" lint="skip"} + is_callable(Callable[[int], str]) + #> True + is_callable(typing.Callable) + #> True + is_callable(collections.abc.Callable) + #> True + ``` + """ + # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, + # hence the second check: + return tp is collections.abc.Callable or get_origin(tp) is collections.abc.Callable + + +_classvar_re = re.compile(r'((\w+\.)?Annotated\[)?(\w+\.)?ClassVar\[') + + +def is_classvar_annotation(tp: Any, /) -> bool: + """Return whether the provided argument represents a class variable annotation. + + Although not explicitly stated by the typing specification, `ClassVar` can be used + inside `Annotated` and as such, this function checks for this specific scenario. + + Because this function is used to detect class variables before evaluating forward references + (or because evaluation failed), we also implement a naive regex match implementation. This is + required because class variables are inspected before fields are collected, so we try to be + as accurate as possible. + """ + if typing_objects.is_classvar(tp): + return True + + origin = get_origin(tp) + + if typing_objects.is_classvar(origin): + return True + + if typing_objects.is_annotated(origin): + annotated_type = tp.__origin__ + if typing_objects.is_classvar(annotated_type) or typing_objects.is_classvar(get_origin(annotated_type)): + return True + + str_ann: str | None = None + if isinstance(tp, typing.ForwardRef): + str_ann = tp.__forward_arg__ + if isinstance(tp, str): + str_ann = tp + + if str_ann is not None and _classvar_re.match(str_ann): + # stdlib dataclasses do something similar, although a bit more advanced + # (see `dataclass._is_type`). + return True + + return False + + +_t_final = typing.Final +_te_final = typing_extensions.Final + + +# TODO implement `is_finalvar_annotation` as Final can be wrapped with other special forms: +def is_finalvar(tp: Any, /) -> bool: + """Return whether the provided argument is a `Final` special form, parametrized or not. + + ```python {test="skip" lint="skip"} + is_finalvar(Final[int]) + #> True + is_finalvar(Final) + #> True + """ + # Final is not necessarily parametrized: + if tp is _t_final or tp is _te_final: + return True + origin = get_origin(tp) + return origin is _t_final or origin is _te_final + + +_NONE_TYPES: tuple[Any, ...] = (None, NoneType, typing.Literal[None], typing_extensions.Literal[None]) + + +def is_none_type(tp: Any, /) -> bool: + """Return whether the argument represents the `None` type as part of an annotation. + + ```python {test="skip" lint="skip"} + is_none_type(None) + #> True + is_none_type(NoneType) + #> True + is_none_type(Literal[None]) + #> True + is_none_type(type[None]) + #> False + """ + return tp in _NONE_TYPES + + +def is_namedtuple(tp: Any, /) -> bool: + """Return whether the provided argument is a named tuple class. + + The class can be created using `typing.NamedTuple` or `collections.namedtuple`. + Parametrized generic classes are *not* assumed to be named tuples. + """ + from ._utils import lenient_issubclass # circ. import + + return lenient_issubclass(tp, tuple) and hasattr(tp, '_fields') + + +# TODO In 2.12, delete this export. It is currently defined only to not break +# pydantic-settings which relies on it: +origin_is_union = is_union_origin + + +def is_generic_alias(tp: Any, /) -> bool: + return isinstance(tp, (types.GenericAlias, typing._GenericAlias)) # pyright: ignore[reportAttributeAccessIssue] + + +# TODO: Ideally, we should avoid relying on the private `typing` constructs: + +if sys.version_info < (3, 10): + WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # pyright: ignore[reportAttributeAccessIssue] +else: + WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias, types.UnionType) # pyright: ignore[reportAttributeAccessIssue] + + +# Similarly, we shouldn't rely on this `_Final` class, which is even more private than `_GenericAlias`: +typing_base: Any = typing._Final # pyright: ignore[reportAttributeAccessIssue] + + +### Annotation evaluations functions: + + +def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> dict[str, Any] | None: + """Fetch the local namespace of the parent frame where this function is called. + + Using this function is mostly useful to resolve forward annotations pointing to members defined in a local namespace, + such as assignments inside a function. Using the standard library tools, it is currently not possible to resolve + such annotations: + + ```python {lint="skip" test="skip"} + from typing import get_type_hints + + def func() -> None: + Alias = int + + class C: + a: 'Alias' + + # Raises a `NameError: 'Alias' is not defined` + get_type_hints(C) + ``` + + Pydantic uses this function when a Pydantic model is being defined to fetch the parent frame locals. However, + this only allows us to fetch the parent frame namespace and not other parents (e.g. a model defined in a function, + itself defined in another function). Inspecting the next outer frames (using `f_back`) is not reliable enough + (see https://discuss.python.org/t/20659). + + Because this function is mostly used to better resolve forward annotations, nothing is returned if the parent frame's + code object is defined at the module level. In this case, the locals of the frame will be the same as the module + globals where the class is defined (see `_namespace_utils.get_module_ns_of`). However, if you still want to fetch + the module globals (e.g. when rebuilding a model, where the frame where the rebuild call is performed might contain + members that you want to use for forward annotations evaluation), you can use the `force` parameter. + + Args: + parent_depth: The depth at which to get the frame. Defaults to 2, meaning the parent frame where this function + is called will be used. + force: Whether to always return the frame locals, even if the frame's code object is defined at the module level. + + Returns: + The locals of the namespace, or `None` if it was skipped as per the described logic. + """ + frame = sys._getframe(parent_depth) + + if frame.f_code.co_name.startswith('`, + # and we need to skip this frame as it is irrelevant. + frame = cast(types.FrameType, frame.f_back) # guaranteed to not be `None` + + # note, we don't copy frame.f_locals here (or during the last return call), because we don't expect the namespace to be + # modified down the line if this becomes a problem, we could implement some sort of frozen mapping structure to enforce this. + if force: + return frame.f_locals + + # If either of the following conditions are true, the class is defined at the top module level. + # To better understand why we need both of these checks, see + # https://github.com/pydantic/pydantic/pull/10113#discussion_r1714981531. + if frame.f_back is None or frame.f_code.co_name == '': + return None + + return frame.f_locals + + +def _type_convert(arg: Any) -> Any: + """Convert `None` to `NoneType` and strings to `ForwardRef` instances. + + This is a backport of the private `typing._type_convert` function. When + evaluating a type, `ForwardRef._evaluate` ends up being called, and is + responsible for making this conversion. However, we still have to apply + it for the first argument passed to our type evaluation functions, similarly + to the `typing.get_type_hints` function. + """ + if arg is None: + return NoneType + if isinstance(arg, str): + # Like `typing.get_type_hints`, assume the arg can be in any context, + # hence the proper `is_argument` and `is_class` args: + return _make_forward_ref(arg, is_argument=False, is_class=True) + return arg + + +def safe_get_annotations(cls: type[Any]) -> dict[str, Any]: + """Get the annotations for the provided class, accounting for potential deferred forward references. + + Starting with Python 3.14, accessing the `__annotations__` attribute might raise a `NameError` if + a referenced symbol isn't defined yet. In this case, we return the annotation in the *forward ref* + format. + """ + if sys.version_info >= (3, 14): + return annotationlib.get_annotations(cls, format=annotationlib.Format.FORWARDREF) + else: + return cls.__dict__.get('__annotations__', {}) + + +def get_model_type_hints( + obj: type[BaseModel], + *, + ns_resolver: NsResolver | None = None, +) -> dict[str, tuple[Any, bool]]: + """Collect annotations from a Pydantic model class, including those from parent classes. + + Args: + obj: The Pydantic model to inspect. + ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. + + Returns: + A dictionary mapping annotation names to a two-tuple: the first element is the evaluated + type or the original annotation if a `NameError` occurred, the second element is a boolean + indicating if whether the evaluation succeeded. + """ + hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {} + ns_resolver = ns_resolver or NsResolver() + + for base in reversed(obj.__mro__): + # For Python 3.14, we could also use `Format.VALUE` and pass the globals/locals + # from the ns_resolver, but we want to be able to know which specific field failed + # to evaluate: + ann = safe_get_annotations(base) + + if not ann: + continue + + with ns_resolver.push(base): + globalns, localns = ns_resolver.types_namespace + for name, value in ann.items(): + if name.startswith('_'): + # For private attributes, we only need the annotation to detect the `ClassVar` special form. + # For this reason, we still try to evaluate it, but we also catch any possible exception (on + # top of the `NameError`s caught in `try_eval_type`) that could happen so that users are free + # to use any kind of forward annotation for private fields (e.g. circular imports, new typing + # syntax, etc). + try: + hints[name] = try_eval_type(value, globalns, localns) + except Exception: + hints[name] = (value, False) + else: + hints[name] = try_eval_type(value, globalns, localns) + return hints + + +def get_cls_type_hints( + obj: type[Any], + *, + ns_resolver: NsResolver | None = None, +) -> dict[str, Any]: + """Collect annotations from a class, including those from parent classes. + + Args: + obj: The class to inspect. + ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. + """ + hints: dict[str, Any] = {} + ns_resolver = ns_resolver or NsResolver() + + for base in reversed(obj.__mro__): + # For Python 3.14, we could also use `Format.VALUE` and pass the globals/locals + # from the ns_resolver, but we want to be able to know which specific field failed + # to evaluate: + ann = safe_get_annotations(base) + + if not ann: + continue + + with ns_resolver.push(base): + globalns, localns = ns_resolver.types_namespace + for name, value in ann.items(): + hints[name] = eval_type(value, globalns, localns) + return hints + + +def try_eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> tuple[Any, bool]: + """Try evaluating the annotation using the provided namespaces. + + Args: + value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance + of `str`, it will be converted to a `ForwardRef`. + localns: The global namespace to use during annotation evaluation. + globalns: The local namespace to use during annotation evaluation. + + Returns: + A two-tuple containing the possibly evaluated type and a boolean indicating + whether the evaluation succeeded or not. + """ + value = _type_convert(value) + + try: + return eval_type_backport(value, globalns, localns), True + except NameError: + return value, False + + +def eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any: + """Evaluate the annotation using the provided namespaces. + + Args: + value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance + of `str`, it will be converted to a `ForwardRef`. + localns: The global namespace to use during annotation evaluation. + globalns: The local namespace to use during annotation evaluation. + """ + value = _type_convert(value) + return eval_type_backport(value, globalns, localns) + + +@deprecated( + '`eval_type_lenient` is deprecated, use `try_eval_type` instead.', + category=None, +) +def eval_type_lenient( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any: + ev, _ = try_eval_type(value, globalns, localns) + return ev + + +def eval_type_backport( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + """An enhanced version of `typing._eval_type` which will fall back to using the `eval_type_backport` + package if it's installed to let older Python versions use newer typing constructs. + + Specifically, this transforms `X | Y` into `typing.Union[X, Y]` and `list[X]` into `typing.List[X]` + (as well as all the types made generic in PEP 585) if the original syntax is not supported in the + current Python version. + + This function will also display a helpful error if the value passed fails to evaluate. + """ + try: + return _eval_type_backport(value, globalns, localns, type_params) + except TypeError as e: + if 'Unable to evaluate type annotation' in str(e): + raise + + # If it is a `TypeError` and value isn't a `ForwardRef`, it would have failed during annotation definition. + # Thus we assert here for type checking purposes: + assert isinstance(value, typing.ForwardRef) + + message = f'Unable to evaluate type annotation {value.__forward_arg__!r}.' + if sys.version_info >= (3, 11): + e.add_note(message) + raise + else: + raise TypeError(message) from e + except RecursionError as e: + # TODO ideally recursion errors should be checked in `eval_type` above, but `eval_type_backport` + # is used directly in some places. + message = ( + "If you made use of an implicit recursive type alias (e.g. `MyType = list['MyType']), " + 'consider using PEP 695 type aliases instead. For more details, refer to the documentation: ' + f'https://docs.pydantic.dev/{version_short()}/concepts/types/#named-recursive-types' + ) + if sys.version_info >= (3, 11): + e.add_note(message) + raise + else: + raise RecursionError(f'{e.args[0]}\n{message}') + + +def _eval_type_backport( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + try: + return _eval_type(value, globalns, localns, type_params) + except TypeError as e: + if not (isinstance(value, typing.ForwardRef) and is_backport_fixable_error(e)): + raise + + try: + from eval_type_backport import eval_type_backport + except ImportError: + raise TypeError( + f'Unable to evaluate type annotation {value.__forward_arg__!r}. If you are making use ' + 'of the new typing syntax (unions using `|` since Python 3.10 or builtins subscripting ' + 'since Python 3.9), you should either replace the use of new syntax with the existing ' + '`typing` constructs or install the `eval_type_backport` package.' + ) from e + + return eval_type_backport( + value, + globalns, + localns, # pyright: ignore[reportArgumentType], waiting on a new `eval_type_backport` release. + try_default=False, + ) + + +def _eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + if sys.version_info >= (3, 14): + # Starting in 3.14, `_eval_type()` does *not* apply `_type_convert()` + # anymore. This means the `None` -> `type(None)` conversion does not apply: + evaluated = typing._eval_type( # type: ignore + value, + globalns, + localns, + type_params=type_params, + # This is relevant when evaluating types from `TypedDict` classes, where string annotations + # are automatically converted to `ForwardRef` instances with a module set. In this case, + # Our `globalns` is irrelevant and we need to indicate `typing._eval_type()` that it should + # infer it from the `ForwardRef.__forward_module__` attribute instead (`typing.get_type_hints()` + # does the same). Note that this would probably be unnecessary if we properly iterated over the + # `__orig_bases__` for TypedDicts in `get_cls_type_hints()`: + prefer_fwd_module=True, + ) + if evaluated is None: + evaluated = type(None) + return evaluated + elif sys.version_info >= (3, 13): + return typing._eval_type( # type: ignore + value, globalns, localns, type_params=type_params + ) + else: + return typing._eval_type( # type: ignore + value, globalns, localns + ) + + +def is_backport_fixable_error(e: TypeError) -> bool: + msg = str(e) + + return sys.version_info < (3, 10) and msg.startswith('unsupported operand type(s) for |: ') + + +def get_function_type_hints( + function: Callable[..., Any], + *, + include_keys: set[str] | None = None, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> dict[str, Any]: + """Return type hints for a function. + + This is similar to the `typing.get_type_hints` function, with a few differences: + - Support `functools.partial` by using the underlying `func` attribute. + - Do not wrap type annotation of a parameter with `Optional` if it has a default value of `None` + (related bug: https://github.com/python/cpython/issues/90353, only fixed in 3.11+). + """ + try: + if isinstance(function, partial): + annotations = function.func.__annotations__ + else: + annotations = function.__annotations__ + except AttributeError: + # Some functions (e.g. builtins) don't have annotations: + return {} + + if globalns is None: + globalns = get_module_ns_of(function) + type_params: tuple[Any, ...] | None = None + if localns is None: + # If localns was specified, it is assumed to already contain type params. This is because + # Pydantic has more advanced logic to do so (see `_namespace_utils.ns_for_function`). + type_params = getattr(function, '__type_params__', ()) + + type_hints = {} + for name, value in annotations.items(): + if include_keys is not None and name not in include_keys: + continue + if value is None: + value = NoneType + elif isinstance(value, str): + value = _make_forward_ref(value) + + type_hints[name] = eval_type_backport(value, globalns, localns, type_params) + + return type_hints + + +# TODO use typing.ForwardRef directly when we stop supporting 3.9: +if sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): + + def _make_forward_ref( + arg: Any, + is_argument: bool = True, + *, + is_class: bool = False, + ) -> typing.ForwardRef: + """Wrapper for ForwardRef that accounts for the `is_class` argument missing in older versions. + The `module` argument is omitted as it breaks <3.9.8, =3.10.0 and isn't used in the calls below. + + See https://github.com/python/cpython/pull/28560 for some background. + The backport happened on 3.9.8, see: + https://github.com/pydantic/pydantic/discussions/6244#discussioncomment-6275458, + and on 3.10.1 for the 3.10 branch, see: + https://github.com/pydantic/pydantic/issues/6912 + + Implemented as EAFP with memory. + """ + return typing.ForwardRef(arg, is_argument) # pyright: ignore[reportCallIssue] + +else: + _make_forward_ref = typing.ForwardRef # pyright: ignore[reportAssignmentType] + + +if sys.version_info >= (3, 10): + get_type_hints = typing.get_type_hints + +else: + """ + For older versions of python, we have a custom implementation of `get_type_hints` which is a close as possible to + the implementation in CPython 3.10.8. + """ + + @typing.no_type_check + def get_type_hints( # noqa: C901 + obj: Any, + globalns: dict[str, Any] | None = None, + localns: dict[str, Any] | None = None, + include_extras: bool = False, + ) -> dict[str, Any]: # pragma: no cover + """Taken verbatim from python 3.10.8 unchanged, except: + * type annotations of the function definition above. + * prefixing `typing.` where appropriate + * Use `_make_forward_ref` instead of `typing.ForwardRef` to handle the `is_class` argument. + + https://github.com/python/cpython/blob/aaaf5174241496afca7ce4d4584570190ff972fe/Lib/typing.py#L1773-L1875 + + DO NOT CHANGE THIS METHOD UNLESS ABSOLUTELY NECESSARY. + ====================================================== + + Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. For classes, the search + order is globals first then locals. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if getattr(obj, '__no_type_check__', None): + return {} + # Classes require a special treatment. + if isinstance(obj, type): + hints = {} + for base in reversed(obj.__mro__): + if globalns is None: + base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {}) + else: + base_globals = globalns + ann = base.__dict__.get('__annotations__', {}) + if isinstance(ann, types.GetSetDescriptorType): + ann = {} + base_locals = dict(vars(base)) if localns is None else localns + if localns is None and globalns is None: + # This is surprising, but required. Before Python 3.10, + # get_type_hints only evaluated the globalns of + # a class. To maintain backwards compatibility, we reverse + # the globalns and localns order so that eval() looks into + # *base_globals* first rather than *base_locals*. + # This only affects ForwardRefs. + base_globals, base_locals = base_locals, base_globals + for name, value in ann.items(): + if value is None: + value = type(None) + if isinstance(value, str): + value = _make_forward_ref(value, is_argument=False, is_class=True) + + value = eval_type_backport(value, base_globals, base_locals) + hints[name] = value + if not include_extras and hasattr(typing, '_strip_annotations'): + return { + k: typing._strip_annotations(t) # type: ignore + for k, t in hints.items() + } + else: + return hints + + if globalns is None: + if isinstance(obj, types.ModuleType): + globalns = obj.__dict__ + else: + nsobj = obj + # Find globalns for the unwrapped object. + while hasattr(nsobj, '__wrapped__'): + nsobj = nsobj.__wrapped__ + globalns = getattr(nsobj, '__globals__', {}) + if localns is None: + localns = globalns + elif localns is None: + localns = globalns + hints = getattr(obj, '__annotations__', None) + if hints is None: + # Return empty annotations for something that _could_ have them. + if isinstance(obj, typing._allowed_types): # type: ignore + return {} + else: + raise TypeError(f'{obj!r} is not a module, class, method, or function.') + defaults = typing._get_defaults(obj) # type: ignore + hints = dict(hints) + for name, value in hints.items(): + if value is None: + value = type(None) + if isinstance(value, str): + # class-level forward refs were handled above, this must be either + # a module-level annotation or a function argument annotation + + value = _make_forward_ref( + value, + is_argument=not isinstance(obj, types.ModuleType), + is_class=False, + ) + value = eval_type_backport(value, globalns, localns) + if name in defaults and defaults[name] is None: + value = typing.Optional[value] + hints[name] = value + return hints if include_extras else {k: typing._strip_annotations(t) for k, t in hints.items()} # type: ignore diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_utils.py b/backend/venv/Lib/site-packages/pydantic/_internal/_utils.py new file mode 100644 index 0000000..7eae1b7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_utils.py @@ -0,0 +1,446 @@ +"""Bucket of reusable internal utilities. + +This should be reduced as much as possible with functions only used in one place, moved to that place. +""" + +from __future__ import annotations as _annotations + +import dataclasses +import keyword +import sys +import warnings +import weakref +from collections import OrderedDict, defaultdict, deque +from collections.abc import Callable, Iterable, Mapping +from collections.abc import Set as AbstractSet +from copy import deepcopy +from functools import cached_property +from inspect import Parameter +from itertools import zip_longest +from types import BuiltinFunctionType, CodeType, FunctionType, GeneratorType, LambdaType, ModuleType +from typing import TYPE_CHECKING, Any, Generic, TypeVar, overload + +from pydantic_core import MISSING +from typing_extensions import TypeAlias, TypeGuard, deprecated + +from pydantic import PydanticDeprecatedSince211 + +from . import _repr, _typing_extra +from ._import_utils import import_cached_base_model + +if TYPE_CHECKING: + # TODO remove type error comments when we drop support for Python 3.9 + MappingIntStrAny: TypeAlias = Mapping[int, Any] | Mapping[str, Any] # pyright: ignore[reportGeneralTypeIssues] + AbstractSetIntStr: TypeAlias = AbstractSet[int] | AbstractSet[str] # pyright: ignore[reportGeneralTypeIssues] + from ..main import BaseModel + + +# these are types that are returned unchanged by deepcopy +IMMUTABLE_NON_COLLECTIONS_TYPES: set[type[Any]] = { + int, + float, + complex, + str, + bool, + bytes, + type, + _typing_extra.NoneType, + FunctionType, + BuiltinFunctionType, + LambdaType, + weakref.ref, + CodeType, + # note: including ModuleType will differ from behaviour of deepcopy by not producing error. + # It might be not a good idea in general, but considering that this function used only internally + # against default values of fields, this will allow to actually have a field with module as default value + ModuleType, + NotImplemented.__class__, + Ellipsis.__class__, +} + +# these are types that if empty, might be copied with simple copy() instead of deepcopy() +BUILTIN_COLLECTIONS: set[type[Any]] = { + list, + set, + tuple, + frozenset, + dict, + OrderedDict, + defaultdict, + deque, +} + + +def can_be_positional(param: Parameter) -> bool: + """Return whether the parameter accepts a positional argument. + + ```python {test="skip" lint="skip"} + def func(a, /, b, *, c): + pass + + params = inspect.signature(func).parameters + can_be_positional(params['a']) + #> True + can_be_positional(params['b']) + #> True + can_be_positional(params['c']) + #> False + ``` + """ + return param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD) + + +def sequence_like(v: Any) -> bool: + return isinstance(v, (list, tuple, set, frozenset, GeneratorType, deque)) + + +def lenient_isinstance(o: Any, class_or_tuple: type[Any] | tuple[type[Any], ...] | None) -> bool: # pragma: no cover + try: + return isinstance(o, class_or_tuple) # type: ignore[arg-type] + except TypeError: + return False + + +def lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool: # pragma: no cover + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) + except TypeError: + if isinstance(cls, _typing_extra.WithArgsTypes): + return False + raise # pragma: no cover + + +def is_model_class(cls: Any) -> TypeGuard[type[BaseModel]]: + """Returns true if cls is a _proper_ subclass of BaseModel, and provides proper type-checking, + unlike raw calls to lenient_issubclass. + """ + BaseModel = import_cached_base_model() + + return lenient_issubclass(cls, BaseModel) and cls is not BaseModel + + +def is_valid_identifier(identifier: str) -> bool: + """Checks that a string is a valid identifier and not a Python keyword. + :param identifier: The identifier to test. + :return: True if the identifier is valid. + """ + return identifier.isidentifier() and not keyword.iskeyword(identifier) + + +KeyType = TypeVar('KeyType') + + +def deep_update(mapping: dict[KeyType, Any], *updating_mappings: dict[KeyType, Any]) -> dict[KeyType, Any]: + updated_mapping = mapping.copy() + for updating_mapping in updating_mappings: + for k, v in updating_mapping.items(): + if k in updated_mapping and isinstance(updated_mapping[k], dict) and isinstance(v, dict): + updated_mapping[k] = deep_update(updated_mapping[k], v) + else: + updated_mapping[k] = v + return updated_mapping + + +def update_not_none(mapping: dict[Any, Any], **update: Any) -> None: + mapping.update({k: v for k, v in update.items() if v is not None}) + + +T = TypeVar('T') + + +def unique_list( + input_list: list[T] | tuple[T, ...], + *, + name_factory: Callable[[T], str] = str, +) -> list[T]: + """Make a list unique while maintaining order. + We update the list if another one with the same name is set + (e.g. model validator overridden in subclass). + """ + result: list[T] = [] + result_names: list[str] = [] + for v in input_list: + v_name = name_factory(v) + if v_name not in result_names: + result_names.append(v_name) + result.append(v) + else: + result[result_names.index(v_name)] = v + + return result + + +class ValueItems(_repr.Representation): + """Class for more convenient calculation of excluded or included fields on values.""" + + __slots__ = ('_items', '_type') + + def __init__(self, value: Any, items: AbstractSetIntStr | MappingIntStrAny) -> None: + items = self._coerce_items(items) + + if isinstance(value, (list, tuple)): + items = self._normalize_indexes(items, len(value)) # type: ignore + + self._items: MappingIntStrAny = items # type: ignore + + def is_excluded(self, item: Any) -> bool: + """Check if item is fully excluded. + + :param item: key or index of a value + """ + return self.is_true(self._items.get(item)) + + def is_included(self, item: Any) -> bool: + """Check if value is contained in self._items. + + :param item: key or index of value + """ + return item in self._items + + def for_element(self, e: int | str) -> AbstractSetIntStr | MappingIntStrAny | None: + """:param e: key or index of element on value + :return: raw values for element if self._items is dict and contain needed element + """ + item = self._items.get(e) # type: ignore + return item if not self.is_true(item) else None + + def _normalize_indexes(self, items: MappingIntStrAny, v_length: int) -> dict[int | str, Any]: + """:param items: dict or set of indexes which will be normalized + :param v_length: length of sequence indexes of which will be + + >>> self._normalize_indexes({0: True, -2: True, -1: True}, 4) + {0: True, 2: True, 3: True} + >>> self._normalize_indexes({'__all__': True}, 4) + {0: True, 1: True, 2: True, 3: True} + """ + normalized_items: dict[int | str, Any] = {} + all_items = None + for i, v in items.items(): + if not (isinstance(v, Mapping) or isinstance(v, AbstractSet) or self.is_true(v)): + raise TypeError(f'Unexpected type of exclude value for index "{i}" {v.__class__}') + if i == '__all__': + all_items = self._coerce_value(v) + continue + if not isinstance(i, int): + raise TypeError( + 'Excluding fields from a sequence of sub-models or dicts must be performed index-wise: ' + 'expected integer keys or keyword "__all__"' + ) + normalized_i = v_length + i if i < 0 else i + normalized_items[normalized_i] = self.merge(v, normalized_items.get(normalized_i)) + + if not all_items: + return normalized_items + if self.is_true(all_items): + for i in range(v_length): + normalized_items.setdefault(i, ...) + return normalized_items + for i in range(v_length): + normalized_item = normalized_items.setdefault(i, {}) + if not self.is_true(normalized_item): + normalized_items[i] = self.merge(all_items, normalized_item) + return normalized_items + + @classmethod + def merge(cls, base: Any, override: Any, intersect: bool = False) -> Any: + """Merge a `base` item with an `override` item. + + Both `base` and `override` are converted to dictionaries if possible. + Sets are converted to dictionaries with the sets entries as keys and + Ellipsis as values. + + Each key-value pair existing in `base` is merged with `override`, + while the rest of the key-value pairs are updated recursively with this function. + + Merging takes place based on the "union" of keys if `intersect` is + set to `False` (default) and on the intersection of keys if + `intersect` is set to `True`. + """ + override = cls._coerce_value(override) + base = cls._coerce_value(base) + if override is None: + return base + if cls.is_true(base) or base is None: + return override + if cls.is_true(override): + return base if intersect else override + + # intersection or union of keys while preserving ordering: + if intersect: + merge_keys = [k for k in base if k in override] + [k for k in override if k in base] + else: + merge_keys = list(base) + [k for k in override if k not in base] + + merged: dict[int | str, Any] = {} + for k in merge_keys: + merged_item = cls.merge(base.get(k), override.get(k), intersect=intersect) + if merged_item is not None: + merged[k] = merged_item + + return merged + + @staticmethod + def _coerce_items(items: AbstractSetIntStr | MappingIntStrAny) -> MappingIntStrAny: + if isinstance(items, Mapping): + pass + elif isinstance(items, AbstractSet): + items = dict.fromkeys(items, ...) # type: ignore + else: + class_name = getattr(items, '__class__', '???') + raise TypeError(f'Unexpected type of exclude value {class_name}') + return items # type: ignore + + @classmethod + def _coerce_value(cls, value: Any) -> Any: + if value is None or cls.is_true(value): + return value + return cls._coerce_items(value) + + @staticmethod + def is_true(v: Any) -> bool: + return v is True or v is ... + + def __repr_args__(self) -> _repr.ReprArgs: + return [(None, self._items)] + + +if TYPE_CHECKING: + + def LazyClassAttribute(name: str, get_value: Callable[[], T]) -> T: ... + +else: + + class LazyClassAttribute: + """A descriptor exposing an attribute only accessible on a class (hidden from instances). + + The attribute is lazily computed and cached during the first access. + """ + + def __init__(self, name: str, get_value: Callable[[], Any]) -> None: + self.name = name + self.get_value = get_value + + @cached_property + def value(self) -> Any: + return self.get_value() + + def __get__(self, instance: Any, owner: type[Any]) -> None: + if instance is None: + return self.value + raise AttributeError(f'{self.name!r} attribute of {owner.__name__!r} is class-only') + + +Obj = TypeVar('Obj') + + +def smart_deepcopy(obj: Obj) -> Obj: + """Return type as is for immutable built-in types + Use obj.copy() for built-in empty collections + Use copy.deepcopy() for non-empty collections and unknown objects. + """ + if obj is MISSING: + return obj # pyright: ignore[reportReturnType] + obj_type = obj.__class__ + if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES: + return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway + try: + if not obj and obj_type in BUILTIN_COLLECTIONS: + # faster way for empty collections, no need to copy its members + return obj if obj_type is tuple else obj.copy() # tuple doesn't have copy method # type: ignore + except (TypeError, ValueError, RuntimeError): + # do we really dare to catch ALL errors? Seems a bit risky + pass + + return deepcopy(obj) # slowest way when we actually might need a deepcopy + + +_SENTINEL = object() + + +def all_identical(left: Iterable[Any], right: Iterable[Any]) -> bool: + """Check that the items of `left` are the same objects as those in `right`. + + >>> a, b = object(), object() + >>> all_identical([a, b, a], [a, b, a]) + True + >>> all_identical([a, b, [a]], [a, b, [a]]) # new list object, while "equal" is not "identical" + False + """ + for left_item, right_item in zip_longest(left, right, fillvalue=_SENTINEL): + if left_item is not right_item: + return False + return True + + +def get_first_not_none(a: Any, b: Any) -> Any: + """Return the first argument if it is not `None`, otherwise return the second argument.""" + return a if a is not None else b + + +@dataclasses.dataclass(frozen=True) +class SafeGetItemProxy: + """Wrapper redirecting `__getitem__` to `get` with a sentinel value as default + + This makes is safe to use in `operator.itemgetter` when some keys may be missing + """ + + # Define __slots__manually for performances + # @dataclasses.dataclass() only support slots=True in python>=3.10 + __slots__ = ('wrapped',) + + wrapped: Mapping[str, Any] + + def __getitem__(self, key: str, /) -> Any: + return self.wrapped.get(key, _SENTINEL) + + # required to pass the object to operator.itemgetter() instances due to a quirk of typeshed + # https://github.com/python/mypy/issues/13713 + # https://github.com/python/typeshed/pull/8785 + # Since this is typing-only, hide it in a typing.TYPE_CHECKING block + if TYPE_CHECKING: + + def __contains__(self, key: str, /) -> bool: + return self.wrapped.__contains__(key) + + +_ModelT = TypeVar('_ModelT', bound='BaseModel') +_RT = TypeVar('_RT') + + +class deprecated_instance_property(Generic[_ModelT, _RT]): + """A decorator exposing the decorated class method as a property, with a warning on instance access. + + This decorator takes a class method defined on the `BaseModel` class and transforms it into + an attribute. The attribute can be accessed on both the class and instances of the class. If accessed + via an instance, a deprecation warning is emitted stating that instance access will be removed in V3. + """ + + def __init__(self, fget: Callable[[type[_ModelT]], _RT], /) -> None: + # Note: fget should be a classmethod: + self.fget = fget + + @overload + def __get__(self, instance: None, objtype: type[_ModelT]) -> _RT: ... + @overload + @deprecated( + 'Accessing this attribute on the instance is deprecated, and will be removed in Pydantic V3. ' + 'Instead, you should access this attribute from the model class.', + category=None, + ) + def __get__(self, instance: _ModelT, objtype: type[_ModelT]) -> _RT: ... + def __get__(self, instance: _ModelT | None, objtype: type[_ModelT]) -> _RT: + if instance is not None: + # fmt: off + attr_name = ( + self.fget.__name__ + if sys.version_info >= (3, 10) + else self.fget.__func__.__name__ # pyright: ignore[reportFunctionMemberAccess] + ) + # fmt: on + warnings.warn( + f'Accessing the {attr_name!r} attribute on the instance is deprecated. ' + 'Instead, you should access this attribute from the model class.', + category=PydanticDeprecatedSince211, + stacklevel=2, + ) + return self.fget.__get__(instance, objtype)() diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_validate_call.py b/backend/venv/Lib/site-packages/pydantic/_internal/_validate_call.py new file mode 100644 index 0000000..ab82832 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_validate_call.py @@ -0,0 +1,140 @@ +from __future__ import annotations as _annotations + +import functools +import inspect +from collections.abc import Awaitable +from functools import partial +from typing import Any, Callable + +import pydantic_core + +from ..config import ConfigDict +from ..plugin._schema_validator import create_schema_validator +from ._config import ConfigWrapper +from ._generate_schema import GenerateSchema, ValidateCallSupportedTypes +from ._namespace_utils import MappingNamespace, NsResolver, ns_for_function + + +def extract_function_name(func: ValidateCallSupportedTypes) -> str: + """Extract the name of a `ValidateCallSupportedTypes` object.""" + return f'partial({func.func.__name__})' if isinstance(func, functools.partial) else func.__name__ + + +def extract_function_qualname(func: ValidateCallSupportedTypes) -> str: + """Extract the qualname of a `ValidateCallSupportedTypes` object.""" + return f'partial({func.func.__qualname__})' if isinstance(func, functools.partial) else func.__qualname__ + + +def update_wrapper_attributes(wrapped: ValidateCallSupportedTypes, wrapper: Callable[..., Any]): + """Update the `wrapper` function with the attributes of the `wrapped` function. Return the updated function.""" + if inspect.iscoroutinefunction(wrapped): + + @functools.wraps(wrapped) + async def wrapper_function(*args, **kwargs): # type: ignore + return await wrapper(*args, **kwargs) + else: + + @functools.wraps(wrapped) + def wrapper_function(*args, **kwargs): + return wrapper(*args, **kwargs) + + # We need to manually update this because `partial` object has no `__name__` and `__qualname__`. + wrapper_function.__name__ = extract_function_name(wrapped) + wrapper_function.__qualname__ = extract_function_qualname(wrapped) + wrapper_function.raw_function = wrapped # type: ignore + + return wrapper_function + + +class ValidateCallWrapper: + """This is a wrapper around a function that validates the arguments passed to it, and optionally the return value.""" + + __slots__ = ( + 'function', + 'validate_return', + 'schema_type', + 'module', + 'qualname', + 'ns_resolver', + 'config_wrapper', + '__pydantic_complete__', + '__pydantic_validator__', + '__return_pydantic_validator__', + ) + + def __init__( + self, + function: ValidateCallSupportedTypes, + config: ConfigDict | None, + validate_return: bool, + parent_namespace: MappingNamespace | None, + ) -> None: + self.function = function + self.validate_return = validate_return + if isinstance(function, partial): + self.schema_type = function.func + self.module = function.func.__module__ + else: + self.schema_type = function + self.module = function.__module__ + self.qualname = extract_function_qualname(function) + + self.ns_resolver = NsResolver( + namespaces_tuple=ns_for_function(self.schema_type, parent_namespace=parent_namespace) + ) + self.config_wrapper = ConfigWrapper(config) + if not self.config_wrapper.defer_build: + self._create_validators() + else: + self.__pydantic_complete__ = False + + def _create_validators(self) -> None: + gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) + schema = gen_schema.clean_schema(gen_schema.generate_schema(self.function)) + core_config = self.config_wrapper.core_config(title=self.qualname) + + self.__pydantic_validator__ = create_schema_validator( + schema, + self.schema_type, + self.module, + self.qualname, + 'validate_call', + core_config, + self.config_wrapper.plugin_settings, + ) + if self.validate_return: + signature = inspect.signature(self.function) + return_type = signature.return_annotation if signature.return_annotation is not signature.empty else Any + gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) + schema = gen_schema.clean_schema(gen_schema.generate_schema(return_type)) + validator = create_schema_validator( + schema, + self.schema_type, + self.module, + self.qualname, + 'validate_call', + core_config, + self.config_wrapper.plugin_settings, + ) + if inspect.iscoroutinefunction(self.function): + + async def return_val_wrapper(aw: Awaitable[Any]) -> None: + return validator.validate_python(await aw) + + self.__return_pydantic_validator__ = return_val_wrapper + else: + self.__return_pydantic_validator__ = validator.validate_python + else: + self.__return_pydantic_validator__ = None + + self.__pydantic_complete__ = True + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + if not self.__pydantic_complete__: + self._create_validators() + + res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) + if self.__return_pydantic_validator__: + return self.__return_pydantic_validator__(res) + else: + return res diff --git a/backend/venv/Lib/site-packages/pydantic/_internal/_validators.py b/backend/venv/Lib/site-packages/pydantic/_internal/_validators.py new file mode 100644 index 0000000..2c7fab6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_internal/_validators.py @@ -0,0 +1,533 @@ +"""Validator functions for standard library types. + +Import of this module is deferred since it contains imports of many standard library modules. +""" + +from __future__ import annotations as _annotations + +import collections.abc +import math +import re +import typing +from collections.abc import Sequence +from decimal import Decimal +from fractions import Fraction +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from typing import Any, Callable, TypeVar, Union, cast +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError + +import typing_extensions +from pydantic_core import PydanticCustomError, PydanticKnownError, core_schema +from typing_extensions import get_args, get_origin +from typing_inspection import typing_objects + +from pydantic._internal._import_utils import import_cached_field_info +from pydantic.errors import PydanticSchemaGenerationError + + +def sequence_validator( + input_value: Sequence[Any], + /, + validator: core_schema.ValidatorFunctionWrapHandler, +) -> Sequence[Any]: + """Validator for `Sequence` types, isinstance(v, Sequence) has already been called.""" + value_type = type(input_value) + + # We don't accept any plain string as a sequence + # Relevant issue: https://github.com/pydantic/pydantic/issues/5595 + if issubclass(value_type, (str, bytes)): + raise PydanticCustomError( + 'sequence_str', + "'{type_name}' instances are not allowed as a Sequence value", + {'type_name': value_type.__name__}, + ) + + # TODO: refactor sequence validation to validate with either a list or a tuple + # schema, depending on the type of the value. + # Additionally, we should be able to remove one of either this validator or the + # SequenceValidator in _std_types_schema.py (preferably this one, while porting over some logic). + # Effectively, a refactor for sequence validation is needed. + if value_type is tuple: + input_value = list(input_value) + + v_list = validator(input_value) + + # the rest of the logic is just re-creating the original type from `v_list` + if value_type is list: + return v_list + elif issubclass(value_type, range): + # return the list as we probably can't re-create the range + return v_list + elif value_type is tuple: + return tuple(v_list) + else: + # best guess at how to re-create the original type, more custom construction logic might be required + return value_type(v_list) # type: ignore[call-arg] + + +def import_string(value: Any) -> Any: + if isinstance(value, str): + try: + return _import_string_logic(value) + except ImportError as e: + raise PydanticCustomError('import_error', 'Invalid python path: {error}', {'error': str(e)}) from e + else: + # otherwise we just return the value and let the next validator do the rest of the work + return value + + +def _import_string_logic(dotted_path: str) -> Any: + """Inspired by uvicorn — dotted paths should include a colon before the final item if that item is not a module. + (This is necessary to distinguish between a submodule and an attribute when there is a conflict.). + + If the dotted path does not include a colon and the final item is not a valid module, importing as an attribute + rather than a submodule will be attempted automatically. + + So, for example, the following values of `dotted_path` result in the following returned values: + * 'collections': + * 'collections.abc': + * 'collections.abc:Mapping': + * `collections.abc.Mapping`: (though this is a bit slower than the previous line) + + An error will be raised under any of the following scenarios: + * `dotted_path` contains more than one colon (e.g., 'collections:abc:Mapping') + * the substring of `dotted_path` before the colon is not a valid module in the environment (e.g., '123:Mapping') + * the substring of `dotted_path` after the colon is not an attribute of the module (e.g., 'collections:abc123') + """ + from importlib import import_module + + components = dotted_path.strip().split(':') + if len(components) > 2: + raise ImportError(f"Import strings should have at most one ':'; received {dotted_path!r}") + + module_path = components[0] + if not module_path: + raise ImportError(f'Import strings should have a nonempty module name; received {dotted_path!r}') + + try: + module = import_module(module_path) + except ModuleNotFoundError as e: + if '.' in module_path: + # Check if it would be valid if the final item was separated from its module with a `:` + maybe_module_path, maybe_attribute = dotted_path.strip().rsplit('.', 1) + try: + return _import_string_logic(f'{maybe_module_path}:{maybe_attribute}') + except ImportError: + pass + raise ImportError(f'No module named {module_path!r}') from e + raise e + + if len(components) > 1: + attribute = components[1] + try: + return getattr(module, attribute) + except AttributeError as e: + raise ImportError(f'cannot import name {attribute!r} from {module_path!r}') from e + else: + return module + + +def pattern_either_validator(input_value: Any, /) -> re.Pattern[Any]: + if isinstance(input_value, re.Pattern): + return input_value + elif isinstance(input_value, (str, bytes)): + # todo strict mode + return compile_pattern(input_value) # type: ignore + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +def pattern_str_validator(input_value: Any, /) -> re.Pattern[str]: + if isinstance(input_value, re.Pattern): + if isinstance(input_value.pattern, str): + return input_value + else: + raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') + elif isinstance(input_value, str): + return compile_pattern(input_value) + elif isinstance(input_value, bytes): + raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +def pattern_bytes_validator(input_value: Any, /) -> re.Pattern[bytes]: + if isinstance(input_value, re.Pattern): + if isinstance(input_value.pattern, bytes): + return input_value + else: + raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') + elif isinstance(input_value, bytes): + return compile_pattern(input_value) + elif isinstance(input_value, str): + raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +PatternType = TypeVar('PatternType', str, bytes) + + +def compile_pattern(pattern: PatternType) -> re.Pattern[PatternType]: + try: + return re.compile(pattern) + except re.error: + raise PydanticCustomError('pattern_regex', 'Input should be a valid regular expression') + + +def ip_v4_address_validator(input_value: Any, /) -> IPv4Address: + if isinstance(input_value, IPv4Address): + return input_value + + try: + return IPv4Address(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_address', 'Input is not a valid IPv4 address') + + +def ip_v6_address_validator(input_value: Any, /) -> IPv6Address: + if isinstance(input_value, IPv6Address): + return input_value + + try: + return IPv6Address(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_address', 'Input is not a valid IPv6 address') + + +def ip_v4_network_validator(input_value: Any, /) -> IPv4Network: + """Assume IPv4Network initialised with a default `strict` argument. + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network + """ + if isinstance(input_value, IPv4Network): + return input_value + + try: + return IPv4Network(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_network', 'Input is not a valid IPv4 network') + + +def ip_v6_network_validator(input_value: Any, /) -> IPv6Network: + """Assume IPv6Network initialised with a default `strict` argument. + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network + """ + if isinstance(input_value, IPv6Network): + return input_value + + try: + return IPv6Network(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_network', 'Input is not a valid IPv6 network') + + +def ip_v4_interface_validator(input_value: Any, /) -> IPv4Interface: + if isinstance(input_value, IPv4Interface): + return input_value + + try: + return IPv4Interface(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_interface', 'Input is not a valid IPv4 interface') + + +def ip_v6_interface_validator(input_value: Any, /) -> IPv6Interface: + if isinstance(input_value, IPv6Interface): + return input_value + + try: + return IPv6Interface(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_interface', 'Input is not a valid IPv6 interface') + + +def fraction_validator(input_value: Any, /) -> Fraction: + if isinstance(input_value, Fraction): + return input_value + + try: + return Fraction(input_value) + except ValueError: + raise PydanticCustomError('fraction_parsing', 'Input is not a valid fraction') + + +def forbid_inf_nan_check(x: Any) -> Any: + if not math.isfinite(x): + raise PydanticKnownError('finite_number') + return x + + +def _safe_repr(v: Any) -> int | float | str: + """The context argument for `PydanticKnownError` requires a number or str type, so we do a simple repr() coercion for types like timedelta. + + See tests/test_types.py::test_annotated_metadata_any_order for some context. + """ + if isinstance(v, (int, float, str)): + return v + return repr(v) + + +def greater_than_validator(x: Any, gt: Any) -> Any: + try: + if not (x > gt): + raise PydanticKnownError('greater_than', {'gt': _safe_repr(gt)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'gt' to supplied value {x}") + + +def greater_than_or_equal_validator(x: Any, ge: Any) -> Any: + try: + if not (x >= ge): + raise PydanticKnownError('greater_than_equal', {'ge': _safe_repr(ge)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'ge' to supplied value {x}") + + +def less_than_validator(x: Any, lt: Any) -> Any: + try: + if not (x < lt): + raise PydanticKnownError('less_than', {'lt': _safe_repr(lt)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'lt' to supplied value {x}") + + +def less_than_or_equal_validator(x: Any, le: Any) -> Any: + try: + if not (x <= le): + raise PydanticKnownError('less_than_equal', {'le': _safe_repr(le)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'le' to supplied value {x}") + + +def multiple_of_validator(x: Any, multiple_of: Any) -> Any: + try: + if x % multiple_of: + raise PydanticKnownError('multiple_of', {'multiple_of': _safe_repr(multiple_of)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'multiple_of' to supplied value {x}") + + +def min_length_validator(x: Any, min_length: Any) -> Any: + try: + if not (len(x) >= min_length): + raise PydanticKnownError( + 'too_short', {'field_type': 'Value', 'min_length': min_length, 'actual_length': len(x)} + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'min_length' to supplied value {x}") + + +def max_length_validator(x: Any, max_length: Any) -> Any: + try: + if len(x) > max_length: + raise PydanticKnownError( + 'too_long', + {'field_type': 'Value', 'max_length': max_length, 'actual_length': len(x)}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'max_length' to supplied value {x}") + + +def _extract_decimal_digits_info(decimal: Decimal) -> tuple[int, int]: + """Compute the total number of digits and decimal places for a given [`Decimal`][decimal.Decimal] instance. + + This function handles both normalized and non-normalized Decimal instances. + Example: Decimal('1.230') -> 4 digits, 3 decimal places + + Args: + decimal (Decimal): The decimal number to analyze. + + Returns: + tuple[int, int]: A tuple containing the number of decimal places and total digits. + + Though this could be divided into two separate functions, the logic is easier to follow if we couple the computation + of the number of decimals and digits together. + """ + try: + decimal_tuple = decimal.as_tuple() + + assert isinstance(decimal_tuple.exponent, int) + + exponent = decimal_tuple.exponent + num_digits = len(decimal_tuple.digits) + + if exponent >= 0: + # A positive exponent adds that many trailing zeros + # Ex: digit_tuple=(1, 2, 3), exponent=2 -> 12300 -> 0 decimal places, 5 digits + num_digits += exponent + decimal_places = 0 + else: + # If the absolute value of the negative exponent is larger than the + # number of digits, then it's the same as the number of digits, + # because it'll consume all the digits in digit_tuple and then + # add abs(exponent) - len(digit_tuple) leading zeros after the decimal point. + # Ex: digit_tuple=(1, 2, 3), exponent=-2 -> 1.23 -> 2 decimal places, 3 digits + # Ex: digit_tuple=(1, 2, 3), exponent=-4 -> 0.0123 -> 4 decimal places, 4 digits + decimal_places = abs(exponent) + num_digits = max(num_digits, decimal_places) + + return decimal_places, num_digits + except (AssertionError, AttributeError): + raise TypeError(f'Unable to extract decimal digits info from supplied value {decimal}') + + +def max_digits_validator(x: Any, max_digits: Any) -> Any: + try: + _, num_digits = _extract_decimal_digits_info(x) + _, normalized_num_digits = _extract_decimal_digits_info(x.normalize()) + if (num_digits > max_digits) and (normalized_num_digits > max_digits): + raise PydanticKnownError( + 'decimal_max_digits', + {'max_digits': max_digits}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'max_digits' to supplied value {x}") + + +def decimal_places_validator(x: Any, decimal_places: Any) -> Any: + try: + decimal_places_, _ = _extract_decimal_digits_info(x) + if decimal_places_ > decimal_places: + normalized_decimal_places, _ = _extract_decimal_digits_info(x.normalize()) + if normalized_decimal_places > decimal_places: + raise PydanticKnownError( + 'decimal_max_places', + {'decimal_places': decimal_places}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'decimal_places' to supplied value {x}") + + +def deque_validator(input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> collections.deque[Any]: + return collections.deque(handler(input_value), maxlen=getattr(input_value, 'maxlen', None)) + + +def defaultdict_validator( + input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler, default_default_factory: Callable[[], Any] +) -> collections.defaultdict[Any, Any]: + if isinstance(input_value, collections.defaultdict): + default_factory = input_value.default_factory + return collections.defaultdict(default_factory, handler(input_value)) + else: + return collections.defaultdict(default_default_factory, handler(input_value)) + + +def get_defaultdict_default_default_factory(values_source_type: Any) -> Callable[[], Any]: + FieldInfo = import_cached_field_info() + + values_type_origin = get_origin(values_source_type) + + def infer_default() -> Callable[[], Any]: + allowed_default_types: dict[Any, Any] = { + tuple: tuple, + collections.abc.Sequence: tuple, + collections.abc.MutableSequence: list, + list: list, + typing.Sequence: list, + set: set, + typing.MutableSet: set, + collections.abc.MutableSet: set, + collections.abc.Set: frozenset, + typing.MutableMapping: dict, + typing.Mapping: dict, + collections.abc.Mapping: dict, + collections.abc.MutableMapping: dict, + float: float, + int: int, + str: str, + bool: bool, + } + values_type = values_type_origin or values_source_type + instructions = 'set using `DefaultDict[..., Annotated[..., Field(default_factory=...)]]`' + if typing_objects.is_typevar(values_type): + + def type_var_default_factory() -> None: + raise RuntimeError( + 'Generic defaultdict cannot be used without a concrete value type or an' + ' explicit default factory, ' + instructions + ) + + return type_var_default_factory + elif values_type not in allowed_default_types: + # a somewhat subjective set of types that have reasonable default values + allowed_msg = ', '.join([t.__name__ for t in set(allowed_default_types.values())]) + raise PydanticSchemaGenerationError( + f'Unable to infer a default factory for keys of type {values_source_type}.' + f' Only {allowed_msg} are supported, other types require an explicit default factory' + ' ' + instructions + ) + return allowed_default_types[values_type] + + # Assume Annotated[..., Field(...)] + if typing_objects.is_annotated(values_type_origin): + field_info = next((v for v in get_args(values_source_type) if isinstance(v, FieldInfo)), None) + else: + field_info = None + if field_info and field_info.default_factory: + # Assume the default factory does not take any argument: + default_default_factory = cast(Callable[[], Any], field_info.default_factory) + else: + default_default_factory = infer_default() + return default_default_factory + + +def validate_str_is_valid_iana_tz(value: Any, /) -> ZoneInfo: + if isinstance(value, ZoneInfo): + return value + try: + return ZoneInfo(value) + except (ZoneInfoNotFoundError, ValueError, TypeError): + raise PydanticCustomError('zoneinfo_str', 'invalid timezone: {value}', {'value': value}) + + +NUMERIC_VALIDATOR_LOOKUP: dict[str, Callable] = { + 'gt': greater_than_validator, + 'ge': greater_than_or_equal_validator, + 'lt': less_than_validator, + 'le': less_than_or_equal_validator, + 'multiple_of': multiple_of_validator, + 'min_length': min_length_validator, + 'max_length': max_length_validator, + 'max_digits': max_digits_validator, + 'decimal_places': decimal_places_validator, +} + +IpType = Union[IPv4Address, IPv6Address, IPv4Network, IPv6Network, IPv4Interface, IPv6Interface] + +IP_VALIDATOR_LOOKUP: dict[type[IpType], Callable] = { + IPv4Address: ip_v4_address_validator, + IPv6Address: ip_v6_address_validator, + IPv4Network: ip_v4_network_validator, + IPv6Network: ip_v6_network_validator, + IPv4Interface: ip_v4_interface_validator, + IPv6Interface: ip_v6_interface_validator, +} + +MAPPING_ORIGIN_MAP: dict[Any, Any] = { + typing.DefaultDict: collections.defaultdict, # noqa: UP006 + collections.defaultdict: collections.defaultdict, + typing.OrderedDict: collections.OrderedDict, # noqa: UP006 + collections.OrderedDict: collections.OrderedDict, + typing_extensions.OrderedDict: collections.OrderedDict, + typing.Counter: collections.Counter, + collections.Counter: collections.Counter, + # this doesn't handle subclasses of these + typing.Mapping: dict, + typing.MutableMapping: dict, + # parametrized typing.{Mutable}Mapping creates one of these + collections.abc.Mapping: dict, + collections.abc.MutableMapping: dict, +} diff --git a/backend/venv/Lib/site-packages/pydantic/_migration.py b/backend/venv/Lib/site-packages/pydantic/_migration.py new file mode 100644 index 0000000..b4ecd28 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/_migration.py @@ -0,0 +1,316 @@ +import sys +from typing import Any, Callable + +from pydantic.warnings import PydanticDeprecatedSince20 + +from .version import version_short + +MOVED_IN_V2 = { + 'pydantic.utils:version_info': 'pydantic.version:version_info', + 'pydantic.error_wrappers:ValidationError': 'pydantic:ValidationError', + 'pydantic.utils:to_camel': 'pydantic.alias_generators:to_pascal', + 'pydantic.utils:to_lower_camel': 'pydantic.alias_generators:to_camel', + 'pydantic:PyObject': 'pydantic.types:ImportString', + 'pydantic.types:PyObject': 'pydantic.types:ImportString', + 'pydantic.generics:GenericModel': 'pydantic.BaseModel', +} + +DEPRECATED_MOVED_IN_V2 = { + 'pydantic.tools:schema_of': 'pydantic.deprecated.tools:schema_of', + 'pydantic.tools:parse_obj_as': 'pydantic.deprecated.tools:parse_obj_as', + 'pydantic.tools:schema_json_of': 'pydantic.deprecated.tools:schema_json_of', + 'pydantic.json:pydantic_encoder': 'pydantic.deprecated.json:pydantic_encoder', + 'pydantic:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments', + 'pydantic.json:custom_pydantic_encoder': 'pydantic.deprecated.json:custom_pydantic_encoder', + 'pydantic.json:timedelta_isoformat': 'pydantic.deprecated.json:timedelta_isoformat', + 'pydantic.decorator:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments', + 'pydantic.class_validators:validator': 'pydantic.deprecated.class_validators:validator', + 'pydantic.class_validators:root_validator': 'pydantic.deprecated.class_validators:root_validator', + 'pydantic.config:BaseConfig': 'pydantic.deprecated.config:BaseConfig', + 'pydantic.config:Extra': 'pydantic.deprecated.config:Extra', +} + +REDIRECT_TO_V1 = { + f'pydantic.utils:{obj}': f'pydantic.v1.utils:{obj}' + for obj in ( + 'deep_update', + 'GetterDict', + 'lenient_issubclass', + 'lenient_isinstance', + 'is_valid_field', + 'update_not_none', + 'import_string', + 'Representation', + 'ROOT_KEY', + 'smart_deepcopy', + 'sequence_like', + ) +} + + +REMOVED_IN_V2 = { + 'pydantic:ConstrainedBytes', + 'pydantic:ConstrainedDate', + 'pydantic:ConstrainedDecimal', + 'pydantic:ConstrainedFloat', + 'pydantic:ConstrainedFrozenSet', + 'pydantic:ConstrainedInt', + 'pydantic:ConstrainedList', + 'pydantic:ConstrainedSet', + 'pydantic:ConstrainedStr', + 'pydantic:JsonWrapper', + 'pydantic:NoneBytes', + 'pydantic:NoneStr', + 'pydantic:NoneStrBytes', + 'pydantic:Protocol', + 'pydantic:Required', + 'pydantic:StrBytes', + 'pydantic:compiled', + 'pydantic.config:get_config', + 'pydantic.config:inherit_config', + 'pydantic.config:prepare_config', + 'pydantic:create_model_from_namedtuple', + 'pydantic:create_model_from_typeddict', + 'pydantic.dataclasses:create_pydantic_model_from_dataclass', + 'pydantic.dataclasses:make_dataclass_validator', + 'pydantic.dataclasses:set_validation', + 'pydantic.datetime_parse:parse_date', + 'pydantic.datetime_parse:parse_time', + 'pydantic.datetime_parse:parse_datetime', + 'pydantic.datetime_parse:parse_duration', + 'pydantic.error_wrappers:ErrorWrapper', + 'pydantic.errors:AnyStrMaxLengthError', + 'pydantic.errors:AnyStrMinLengthError', + 'pydantic.errors:ArbitraryTypeError', + 'pydantic.errors:BoolError', + 'pydantic.errors:BytesError', + 'pydantic.errors:CallableError', + 'pydantic.errors:ClassError', + 'pydantic.errors:ColorError', + 'pydantic.errors:ConfigError', + 'pydantic.errors:DataclassTypeError', + 'pydantic.errors:DateError', + 'pydantic.errors:DateNotInTheFutureError', + 'pydantic.errors:DateNotInThePastError', + 'pydantic.errors:DateTimeError', + 'pydantic.errors:DecimalError', + 'pydantic.errors:DecimalIsNotFiniteError', + 'pydantic.errors:DecimalMaxDigitsError', + 'pydantic.errors:DecimalMaxPlacesError', + 'pydantic.errors:DecimalWholeDigitsError', + 'pydantic.errors:DictError', + 'pydantic.errors:DurationError', + 'pydantic.errors:EmailError', + 'pydantic.errors:EnumError', + 'pydantic.errors:EnumMemberError', + 'pydantic.errors:ExtraError', + 'pydantic.errors:FloatError', + 'pydantic.errors:FrozenSetError', + 'pydantic.errors:FrozenSetMaxLengthError', + 'pydantic.errors:FrozenSetMinLengthError', + 'pydantic.errors:HashableError', + 'pydantic.errors:IPv4AddressError', + 'pydantic.errors:IPv4InterfaceError', + 'pydantic.errors:IPv4NetworkError', + 'pydantic.errors:IPv6AddressError', + 'pydantic.errors:IPv6InterfaceError', + 'pydantic.errors:IPv6NetworkError', + 'pydantic.errors:IPvAnyAddressError', + 'pydantic.errors:IPvAnyInterfaceError', + 'pydantic.errors:IPvAnyNetworkError', + 'pydantic.errors:IntEnumError', + 'pydantic.errors:IntegerError', + 'pydantic.errors:InvalidByteSize', + 'pydantic.errors:InvalidByteSizeUnit', + 'pydantic.errors:InvalidDiscriminator', + 'pydantic.errors:InvalidLengthForBrand', + 'pydantic.errors:JsonError', + 'pydantic.errors:JsonTypeError', + 'pydantic.errors:ListError', + 'pydantic.errors:ListMaxLengthError', + 'pydantic.errors:ListMinLengthError', + 'pydantic.errors:ListUniqueItemsError', + 'pydantic.errors:LuhnValidationError', + 'pydantic.errors:MissingDiscriminator', + 'pydantic.errors:MissingError', + 'pydantic.errors:NoneIsAllowedError', + 'pydantic.errors:NoneIsNotAllowedError', + 'pydantic.errors:NotDigitError', + 'pydantic.errors:NotNoneError', + 'pydantic.errors:NumberNotGeError', + 'pydantic.errors:NumberNotGtError', + 'pydantic.errors:NumberNotLeError', + 'pydantic.errors:NumberNotLtError', + 'pydantic.errors:NumberNotMultipleError', + 'pydantic.errors:PathError', + 'pydantic.errors:PathNotADirectoryError', + 'pydantic.errors:PathNotAFileError', + 'pydantic.errors:PathNotExistsError', + 'pydantic.errors:PatternError', + 'pydantic.errors:PyObjectError', + 'pydantic.errors:PydanticTypeError', + 'pydantic.errors:PydanticValueError', + 'pydantic.errors:SequenceError', + 'pydantic.errors:SetError', + 'pydantic.errors:SetMaxLengthError', + 'pydantic.errors:SetMinLengthError', + 'pydantic.errors:StrError', + 'pydantic.errors:StrRegexError', + 'pydantic.errors:StrictBoolError', + 'pydantic.errors:SubclassError', + 'pydantic.errors:TimeError', + 'pydantic.errors:TupleError', + 'pydantic.errors:TupleLengthError', + 'pydantic.errors:UUIDError', + 'pydantic.errors:UUIDVersionError', + 'pydantic.errors:UrlError', + 'pydantic.errors:UrlExtraError', + 'pydantic.errors:UrlHostError', + 'pydantic.errors:UrlHostTldError', + 'pydantic.errors:UrlPortError', + 'pydantic.errors:UrlSchemeError', + 'pydantic.errors:UrlSchemePermittedError', + 'pydantic.errors:UrlUserInfoError', + 'pydantic.errors:WrongConstantError', + 'pydantic.main:validate_model', + 'pydantic.networks:stricturl', + 'pydantic:parse_file_as', + 'pydantic:parse_raw_as', + 'pydantic:stricturl', + 'pydantic.tools:parse_file_as', + 'pydantic.tools:parse_raw_as', + 'pydantic.types:ConstrainedBytes', + 'pydantic.types:ConstrainedDate', + 'pydantic.types:ConstrainedDecimal', + 'pydantic.types:ConstrainedFloat', + 'pydantic.types:ConstrainedFrozenSet', + 'pydantic.types:ConstrainedInt', + 'pydantic.types:ConstrainedList', + 'pydantic.types:ConstrainedSet', + 'pydantic.types:ConstrainedStr', + 'pydantic.types:JsonWrapper', + 'pydantic.types:NoneBytes', + 'pydantic.types:NoneStr', + 'pydantic.types:NoneStrBytes', + 'pydantic.types:StrBytes', + 'pydantic.typing:evaluate_forwardref', + 'pydantic.typing:AbstractSetIntStr', + 'pydantic.typing:AnyCallable', + 'pydantic.typing:AnyClassMethod', + 'pydantic.typing:CallableGenerator', + 'pydantic.typing:DictAny', + 'pydantic.typing:DictIntStrAny', + 'pydantic.typing:DictStrAny', + 'pydantic.typing:IntStr', + 'pydantic.typing:ListStr', + 'pydantic.typing:MappingIntStrAny', + 'pydantic.typing:NoArgAnyCallable', + 'pydantic.typing:NoneType', + 'pydantic.typing:ReprArgs', + 'pydantic.typing:SetStr', + 'pydantic.typing:StrPath', + 'pydantic.typing:TupleGenerator', + 'pydantic.typing:WithArgsTypes', + 'pydantic.typing:all_literal_values', + 'pydantic.typing:display_as_type', + 'pydantic.typing:get_all_type_hints', + 'pydantic.typing:get_args', + 'pydantic.typing:get_origin', + 'pydantic.typing:get_sub_types', + 'pydantic.typing:is_callable_type', + 'pydantic.typing:is_classvar', + 'pydantic.typing:is_finalvar', + 'pydantic.typing:is_literal_type', + 'pydantic.typing:is_namedtuple', + 'pydantic.typing:is_new_type', + 'pydantic.typing:is_none_type', + 'pydantic.typing:is_typeddict', + 'pydantic.typing:is_typeddict_special', + 'pydantic.typing:is_union', + 'pydantic.typing:new_type_supertype', + 'pydantic.typing:resolve_annotations', + 'pydantic.typing:typing_base', + 'pydantic.typing:update_field_forward_refs', + 'pydantic.typing:update_model_forward_refs', + 'pydantic.utils:ClassAttribute', + 'pydantic.utils:DUNDER_ATTRIBUTES', + 'pydantic.utils:PyObjectStr', + 'pydantic.utils:ValueItems', + 'pydantic.utils:almost_equal_floats', + 'pydantic.utils:get_discriminator_alias_and_values', + 'pydantic.utils:get_model', + 'pydantic.utils:get_unique_discriminator_alias', + 'pydantic.utils:in_ipython', + 'pydantic.utils:is_valid_identifier', + 'pydantic.utils:path_type', + 'pydantic.utils:validate_field_name', + 'pydantic:validate_model', +} + + +def getattr_migration(module: str) -> Callable[[str], Any]: + """Implement PEP 562 for objects that were either moved or removed on the migration + to V2. + + Args: + module: The module name. + + Returns: + A callable that will raise an error if the object is not found. + """ + # This avoids circular import with errors.py. + from .errors import PydanticImportError + + def wrapper(name: str) -> object: + """Raise an error if the object is not found, or warn if it was moved. + + In case it was moved, it still returns the object. + + Args: + name: The object name. + + Returns: + The object. + """ + if name == '__path__': + raise AttributeError(f'module {module!r} has no attribute {name!r}') + + import warnings + + from ._internal._validators import import_string + + import_path = f'{module}:{name}' + if import_path in MOVED_IN_V2.keys(): + new_location = MOVED_IN_V2[import_path] + warnings.warn( + f'`{import_path}` has been moved to `{new_location}`.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return import_string(MOVED_IN_V2[import_path]) + if import_path in DEPRECATED_MOVED_IN_V2: + # skip the warning here because a deprecation warning will be raised elsewhere + return import_string(DEPRECATED_MOVED_IN_V2[import_path]) + if import_path in REDIRECT_TO_V1: + new_location = REDIRECT_TO_V1[import_path] + warnings.warn( + f'`{import_path}` has been removed. We are importing from `{new_location}` instead.' + 'See the migration guide for more details: https://docs.pydantic.dev/latest/migration/', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return import_string(REDIRECT_TO_V1[import_path]) + if import_path == 'pydantic:BaseSettings': + raise PydanticImportError( + '`BaseSettings` has been moved to the `pydantic-settings` package. ' + f'See https://docs.pydantic.dev/{version_short()}/migration/#basesettings-has-moved-to-pydantic-settings ' + 'for more details.' + ) + if import_path in REMOVED_IN_V2: + raise PydanticImportError(f'`{import_path}` has been removed in V2.') + globals: dict[str, Any] = sys.modules[module].__dict__ + if name in globals: + return globals[name] + raise AttributeError(f'module {module!r} has no attribute {name!r}') + + return wrapper diff --git a/backend/venv/Lib/site-packages/pydantic/alias_generators.py b/backend/venv/Lib/site-packages/pydantic/alias_generators.py new file mode 100644 index 0000000..0b7653f --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/alias_generators.py @@ -0,0 +1,62 @@ +"""Alias generators for converting between different capitalization conventions.""" + +import re + +__all__ = ('to_pascal', 'to_camel', 'to_snake') + +# TODO: in V3, change the argument names to be more descriptive +# Generally, don't only convert from snake_case, or name the functions +# more specifically like snake_to_camel. + + +def to_pascal(snake: str) -> str: + """Convert a snake_case string to PascalCase. + + Args: + snake: The string to convert. + + Returns: + The PascalCase string. + """ + camel = snake.title() + return re.sub('([0-9A-Za-z])_(?=[0-9A-Z])', lambda m: m.group(1), camel) + + +def to_camel(snake: str) -> str: + """Convert a snake_case string to camelCase. + + Args: + snake: The string to convert. + + Returns: + The converted camelCase string. + """ + # If the string is already in camelCase and does not contain a digit followed + # by a lowercase letter, return it as it is + if re.match('^[a-z]+[A-Za-z0-9]*$', snake) and not re.search(r'\d[a-z]', snake): + return snake + + camel = to_pascal(snake) + return re.sub('(^_*[A-Z])', lambda m: m.group(1).lower(), camel) + + +def to_snake(camel: str) -> str: + """Convert a PascalCase, camelCase, or kebab-case string to snake_case. + + Args: + camel: The string to convert. + + Returns: + The converted string in snake_case. + """ + # Handle the sequence of uppercase letters followed by a lowercase letter + snake = re.sub(r'([A-Z]+)([A-Z][a-z])', lambda m: f'{m.group(1)}_{m.group(2)}', camel) + # Insert an underscore between a lowercase letter and an uppercase letter + snake = re.sub(r'([a-z])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a digit and an uppercase letter + snake = re.sub(r'([0-9])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a lowercase letter and a digit + snake = re.sub(r'([a-z])([0-9])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Replace hyphens with underscores to handle kebab-case + snake = snake.replace('-', '_') + return snake.lower() diff --git a/backend/venv/Lib/site-packages/pydantic/aliases.py b/backend/venv/Lib/site-packages/pydantic/aliases.py new file mode 100644 index 0000000..ac22737 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/aliases.py @@ -0,0 +1,135 @@ +"""Support for alias configurations.""" + +from __future__ import annotations + +import dataclasses +from typing import Any, Callable, Literal + +from pydantic_core import PydanticUndefined + +from ._internal import _internal_dataclass + +__all__ = ('AliasGenerator', 'AliasPath', 'AliasChoices') + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasPath: + """!!! abstract "Usage Documentation" + [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices) + + A data class used by `validation_alias` as a convenience to create aliases. + + Attributes: + path: A list of string or integer aliases. + """ + + path: list[int | str] + + def __init__(self, first_arg: str, *args: str | int) -> None: + self.path = [first_arg] + list(args) + + def convert_to_aliases(self) -> list[str | int]: + """Converts arguments to a list of string or integer aliases. + + Returns: + The list of aliases. + """ + return self.path + + def search_dict_for_path(self, d: dict) -> Any: + """Searches a dictionary for the path specified by the alias. + + Returns: + The value at the specified path, or `PydanticUndefined` if the path is not found. + """ + v = d + for k in self.path: + if isinstance(v, str): + # disallow indexing into a str, like for AliasPath('x', 0) and x='abc' + return PydanticUndefined + try: + v = v[k] + except (KeyError, IndexError, TypeError): + return PydanticUndefined + return v + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasChoices: + """!!! abstract "Usage Documentation" + [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices) + + A data class used by `validation_alias` as a convenience to create aliases. + + Attributes: + choices: A list containing a string or `AliasPath`. + """ + + choices: list[str | AliasPath] + + def __init__(self, first_choice: str | AliasPath, *choices: str | AliasPath) -> None: + self.choices = [first_choice] + list(choices) + + def convert_to_aliases(self) -> list[list[str | int]]: + """Converts arguments to a list of lists containing string or integer aliases. + + Returns: + The list of aliases. + """ + aliases: list[list[str | int]] = [] + for c in self.choices: + if isinstance(c, AliasPath): + aliases.append(c.convert_to_aliases()) + else: + aliases.append([c]) + return aliases + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasGenerator: + """!!! abstract "Usage Documentation" + [Using an `AliasGenerator`](../concepts/alias.md#using-an-aliasgenerator) + + A data class used by `alias_generator` as a convenience to create various aliases. + + Attributes: + alias: A callable that takes a field name and returns an alias for it. + validation_alias: A callable that takes a field name and returns a validation alias for it. + serialization_alias: A callable that takes a field name and returns a serialization alias for it. + """ + + alias: Callable[[str], str] | None = None + validation_alias: Callable[[str], str | AliasPath | AliasChoices] | None = None + serialization_alias: Callable[[str], str] | None = None + + def _generate_alias( + self, + alias_kind: Literal['alias', 'validation_alias', 'serialization_alias'], + allowed_types: tuple[type[str] | type[AliasPath] | type[AliasChoices], ...], + field_name: str, + ) -> str | AliasPath | AliasChoices | None: + """Generate an alias of the specified kind. Returns None if the alias generator is None. + + Raises: + TypeError: If the alias generator produces an invalid type. + """ + alias = None + if alias_generator := getattr(self, alias_kind): + alias = alias_generator(field_name) + if alias and not isinstance(alias, allowed_types): + raise TypeError( + f'Invalid `{alias_kind}` type. `{alias_kind}` generator must produce one of `{allowed_types}`' + ) + return alias + + def generate_aliases(self, field_name: str) -> tuple[str | None, str | AliasPath | AliasChoices | None, str | None]: + """Generate `alias`, `validation_alias`, and `serialization_alias` for a field. + + Returns: + A tuple of three aliases - validation, alias, and serialization. + """ + alias = self._generate_alias('alias', (str,), field_name) + validation_alias = self._generate_alias('validation_alias', (str, AliasChoices, AliasPath), field_name) + serialization_alias = self._generate_alias('serialization_alias', (str,), field_name) + + return alias, validation_alias, serialization_alias # type: ignore diff --git a/backend/venv/Lib/site-packages/pydantic/annotated_handlers.py b/backend/venv/Lib/site-packages/pydantic/annotated_handlers.py new file mode 100644 index 0000000..d0cb5d3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/annotated_handlers.py @@ -0,0 +1,122 @@ +"""Type annotations to use with `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__`.""" + +from __future__ import annotations as _annotations + +from typing import TYPE_CHECKING, Any, Union + +from pydantic_core import core_schema + +if TYPE_CHECKING: + from ._internal._namespace_utils import NamespacesTuple + from .json_schema import JsonSchemaMode, JsonSchemaValue + + CoreSchemaOrField = Union[ + core_schema.CoreSchema, + core_schema.ModelField, + core_schema.DataclassField, + core_schema.TypedDictField, + core_schema.ComputedField, + ] + +__all__ = 'GetJsonSchemaHandler', 'GetCoreSchemaHandler' + + +class GetJsonSchemaHandler: + """Handler to call into the next JSON schema generation function. + + Attributes: + mode: Json schema mode, can be `validation` or `serialization`. + """ + + mode: JsonSchemaMode + + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: + """Call the inner handler and get the JsonSchemaValue it returns. + This will call the next JSON schema modifying function up until it calls + into `pydantic.json_schema.GenerateJsonSchema`, which will raise a + `pydantic.errors.PydanticInvalidForJsonSchema` error if it cannot generate + a JSON schema. + + Args: + core_schema: A `pydantic_core.core_schema.CoreSchema`. + + Returns: + JsonSchemaValue: The JSON schema generated by the inner JSON schema modify + functions. + """ + raise NotImplementedError + + def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue, /) -> JsonSchemaValue: + """Get the real schema for a `{"$ref": ...}` schema. + If the schema given is not a `$ref` schema, it will be returned as is. + This means you don't have to check before calling this function. + + Args: + maybe_ref_json_schema: A JsonSchemaValue which may be a `$ref` schema. + + Raises: + LookupError: If the ref is not found. + + Returns: + JsonSchemaValue: A JsonSchemaValue that has no `$ref`. + """ + raise NotImplementedError + + +class GetCoreSchemaHandler: + """Handler to call into the next CoreSchema schema generation function.""" + + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: + """Call the inner handler and get the CoreSchema it returns. + This will call the next CoreSchema modifying function up until it calls + into Pydantic's internal schema generation machinery, which will raise a + `pydantic.errors.PydanticSchemaGenerationError` error if it cannot generate + a CoreSchema for the given source type. + + Args: + source_type: The input type. + + Returns: + CoreSchema: The `pydantic-core` CoreSchema generated. + """ + raise NotImplementedError + + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: + """Generate a schema unrelated to the current context. + Use this function if e.g. you are handling schema generation for a sequence + and want to generate a schema for its items. + Otherwise, you may end up doing something like applying a `min_length` constraint + that was intended for the sequence itself to its items! + + Args: + source_type: The input type. + + Returns: + CoreSchema: The `pydantic-core` CoreSchema generated. + """ + raise NotImplementedError + + def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema, /) -> core_schema.CoreSchema: + """Get the real schema for a `definition-ref` schema. + If the schema given is not a `definition-ref` schema, it will be returned as is. + This means you don't have to check before calling this function. + + Args: + maybe_ref_schema: A `CoreSchema`, `ref`-based or not. + + Raises: + LookupError: If the `ref` is not found. + + Returns: + A concrete `CoreSchema`. + """ + raise NotImplementedError + + @property + def field_name(self) -> str | None: + """Get the name of the closest field to this validator.""" + raise NotImplementedError + + def _get_types_namespace(self) -> NamespacesTuple: + """Internal method used during type resolution for serializer annotations.""" + raise NotImplementedError diff --git a/backend/venv/Lib/site-packages/pydantic/class_validators.py b/backend/venv/Lib/site-packages/pydantic/class_validators.py new file mode 100644 index 0000000..9977150 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/class_validators.py @@ -0,0 +1,5 @@ +"""`class_validators` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/color.py b/backend/venv/Lib/site-packages/pydantic/color.py new file mode 100644 index 0000000..9a42d58 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/color.py @@ -0,0 +1,604 @@ +"""Color definitions are used as per the CSS3 +[CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#svg-color) specification. + +A few colors have multiple names referring to the sames colors, eg. `grey` and `gray` or `aqua` and `cyan`. + +In these cases the _last_ color when sorted alphabetically takes preferences, +eg. `Color((0, 255, 255)).as_named() == 'cyan'` because "cyan" comes after "aqua". + +Warning: Deprecated + The `Color` class is deprecated, use `pydantic_extra_types` instead. + See [`pydantic-extra-types.Color`](../usage/types/extra_types/color_types.md) + for more information. +""" + +import math +import re +from colorsys import hls_to_rgb, rgb_to_hls +from typing import Any, Callable, Optional, Union, cast + +from pydantic_core import CoreSchema, PydanticCustomError, core_schema +from typing_extensions import deprecated + +from ._internal import _repr +from ._internal._schema_generation_shared import GetJsonSchemaHandler as _GetJsonSchemaHandler +from .json_schema import JsonSchemaValue +from .warnings import PydanticDeprecatedSince20 + +ColorTuple = Union[tuple[int, int, int], tuple[int, int, int, float]] +ColorType = Union[ColorTuple, str] +HslColorTuple = Union[tuple[float, float, float], tuple[float, float, float, float]] + + +class RGBA: + """Internal use only as a representation of a color.""" + + __slots__ = 'r', 'g', 'b', 'alpha', '_tuple' + + def __init__(self, r: float, g: float, b: float, alpha: Optional[float]): + self.r = r + self.g = g + self.b = b + self.alpha = alpha + + self._tuple: tuple[float, float, float, Optional[float]] = (r, g, b, alpha) + + def __getitem__(self, item: Any) -> Any: + return self._tuple[item] + + +# these are not compiled here to avoid import slowdown, they'll be compiled the first time they're used, then cached +_r_255 = r'(\d{1,3}(?:\.\d+)?)' +_r_comma = r'\s*,\s*' +_r_alpha = r'(\d(?:\.\d+)?|\.\d+|\d{1,2}%)' +_r_h = r'(-?\d+(?:\.\d+)?|-?\.\d+)(deg|rad|turn)?' +_r_sl = r'(\d{1,3}(?:\.\d+)?)%' +r_hex_short = r'\s*(?:#|0x)?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?\s*' +r_hex_long = r'\s*(?:#|0x)?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?\s*' +# CSS3 RGB examples: rgb(0, 0, 0), rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 50%) +r_rgb = rf'\s*rgba?\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}(?:{_r_comma}{_r_alpha})?\s*\)\s*' +# CSS3 HSL examples: hsl(270, 60%, 50%), hsla(270, 60%, 50%, 0.5), hsla(270, 60%, 50%, 50%) +r_hsl = rf'\s*hsla?\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}(?:{_r_comma}{_r_alpha})?\s*\)\s*' +# CSS4 RGB examples: rgb(0 0 0), rgb(0 0 0 / 0.5), rgb(0 0 0 / 50%), rgba(0 0 0 / 50%) +r_rgb_v4_style = rf'\s*rgba?\(\s*{_r_255}\s+{_r_255}\s+{_r_255}(?:\s*/\s*{_r_alpha})?\s*\)\s*' +# CSS4 HSL examples: hsl(270 60% 50%), hsl(270 60% 50% / 0.5), hsl(270 60% 50% / 50%), hsla(270 60% 50% / 50%) +r_hsl_v4_style = rf'\s*hsla?\(\s*{_r_h}\s+{_r_sl}\s+{_r_sl}(?:\s*/\s*{_r_alpha})?\s*\)\s*' + +# colors where the two hex characters are the same, if all colors match this the short version of hex colors can be used +repeat_colors = {int(c * 2, 16) for c in '0123456789abcdef'} +rads = 2 * math.pi + + +@deprecated( + 'The `Color` class is deprecated, use `pydantic_extra_types` instead. ' + 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_color/.', + category=PydanticDeprecatedSince20, +) +class Color(_repr.Representation): + """Represents a color.""" + + __slots__ = '_original', '_rgba' + + def __init__(self, value: ColorType) -> None: + self._rgba: RGBA + self._original: ColorType + if isinstance(value, (tuple, list)): + self._rgba = parse_tuple(value) + elif isinstance(value, str): + self._rgba = parse_str(value) + elif isinstance(value, Color): + self._rgba = value._rgba + value = value._original + else: + raise PydanticCustomError( + 'color_error', 'value is not a valid color: value must be a tuple, list or string' + ) + + # if we've got here value must be a valid color + self._original = value + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='color') + return field_schema + + def original(self) -> ColorType: + """Original value passed to `Color`.""" + return self._original + + def as_named(self, *, fallback: bool = False) -> str: + """Returns the name of the color if it can be found in `COLORS_BY_VALUE` dictionary, + otherwise returns the hexadecimal representation of the color or raises `ValueError`. + + Args: + fallback: If True, falls back to returning the hexadecimal representation of + the color instead of raising a ValueError when no named color is found. + + Returns: + The name of the color, or the hexadecimal representation of the color. + + Raises: + ValueError: When no named color is found and fallback is `False`. + """ + if self._rgba.alpha is None: + rgb = cast(tuple[int, int, int], self.as_rgb_tuple()) + try: + return COLORS_BY_VALUE[rgb] + except KeyError as e: + if fallback: + return self.as_hex() + else: + raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()') from e + else: + return self.as_hex() + + def as_hex(self) -> str: + """Returns the hexadecimal representation of the color. + + Hex string representing the color can be 3, 4, 6, or 8 characters depending on whether the string + a "short" representation of the color is possible and whether there's an alpha channel. + + Returns: + The hexadecimal representation of the color. + """ + values = [float_to_255(c) for c in self._rgba[:3]] + if self._rgba.alpha is not None: + values.append(float_to_255(self._rgba.alpha)) + + as_hex = ''.join(f'{v:02x}' for v in values) + if all(c in repeat_colors for c in values): + as_hex = ''.join(as_hex[c] for c in range(0, len(as_hex), 2)) + return '#' + as_hex + + def as_rgb(self) -> str: + """Color as an `rgb(, , )` or `rgba(, , ,
        )` string.""" + if self._rgba.alpha is None: + return f'rgb({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)})' + else: + return ( + f'rgba({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)}, ' + f'{round(self._alpha_float(), 2)})' + ) + + def as_rgb_tuple(self, *, alpha: Optional[bool] = None) -> ColorTuple: + """Returns the color as an RGB or RGBA tuple. + + Args: + alpha: Whether to include the alpha channel. There are three options for this input: + + - `None` (default): Include alpha only if it's set. (e.g. not `None`) + - `True`: Always include alpha. + - `False`: Always omit alpha. + + Returns: + A tuple that contains the values of the red, green, and blue channels in the range 0 to 255. + If alpha is included, it is in the range 0 to 1. + """ + r, g, b = (float_to_255(c) for c in self._rgba[:3]) + if alpha is None: + if self._rgba.alpha is None: + return r, g, b + else: + return r, g, b, self._alpha_float() + elif alpha: + return r, g, b, self._alpha_float() + else: + # alpha is False + return r, g, b + + def as_hsl(self) -> str: + """Color as an `hsl(, , )` or `hsl(, , , )` string.""" + if self._rgba.alpha is None: + h, s, li = self.as_hsl_tuple(alpha=False) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%})' + else: + h, s, li, a = self.as_hsl_tuple(alpha=True) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%}, {round(a, 2)})' + + def as_hsl_tuple(self, *, alpha: Optional[bool] = None) -> HslColorTuple: + """Returns the color as an HSL or HSLA tuple. + + Args: + alpha: Whether to include the alpha channel. + + - `None` (default): Include the alpha channel only if it's set (e.g. not `None`). + - `True`: Always include alpha. + - `False`: Always omit alpha. + + Returns: + The color as a tuple of hue, saturation, lightness, and alpha (if included). + All elements are in the range 0 to 1. + + Note: + This is HSL as used in HTML and most other places, not HLS as used in Python's `colorsys`. + """ + h, l, s = rgb_to_hls(self._rgba.r, self._rgba.g, self._rgba.b) # noqa: E741 + if alpha is None: + if self._rgba.alpha is None: + return h, s, l + else: + return h, s, l, self._alpha_float() + if alpha: + return h, s, l, self._alpha_float() + else: + # alpha is False + return h, s, l + + def _alpha_float(self) -> float: + return 1 if self._rgba.alpha is None else self._rgba.alpha + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: Callable[[Any], CoreSchema] + ) -> core_schema.CoreSchema: + return core_schema.with_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, __input_value: Any, _: Any) -> 'Color': + return cls(__input_value) + + def __str__(self) -> str: + return self.as_named(fallback=True) + + def __repr_args__(self) -> '_repr.ReprArgs': + return [(None, self.as_named(fallback=True))] + [('rgb', self.as_rgb_tuple())] + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Color) and self.as_rgb_tuple() == other.as_rgb_tuple() + + def __hash__(self) -> int: + return hash(self.as_rgb_tuple()) + + +def parse_tuple(value: tuple[Any, ...]) -> RGBA: + """Parse a tuple or list to get RGBA values. + + Args: + value: A tuple or list. + + Returns: + An `RGBA` tuple parsed from the input tuple. + + Raises: + PydanticCustomError: If tuple is not valid. + """ + if len(value) == 3: + r, g, b = (parse_color_value(v) for v in value) + return RGBA(r, g, b, None) + elif len(value) == 4: + r, g, b = (parse_color_value(v) for v in value[:3]) + return RGBA(r, g, b, parse_float_alpha(value[3])) + else: + raise PydanticCustomError('color_error', 'value is not a valid color: tuples must have length 3 or 4') + + +def parse_str(value: str) -> RGBA: + """Parse a string representing a color to an RGBA tuple. + + Possible formats for the input string include: + + * named color, see `COLORS_BY_NAME` + * hex short eg. `fff` (prefix can be `#`, `0x` or nothing) + * hex long eg. `ffffff` (prefix can be `#`, `0x` or nothing) + * `rgb(, , )` + * `rgba(, , , )` + + Args: + value: A string representing a color. + + Returns: + An `RGBA` tuple parsed from the input string. + + Raises: + ValueError: If the input string cannot be parsed to an RGBA tuple. + """ + value_lower = value.lower() + try: + r, g, b = COLORS_BY_NAME[value_lower] + except KeyError: + pass + else: + return ints_to_rgba(r, g, b, None) + + m = re.fullmatch(r_hex_short, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v * 2, 16) for v in rgb) + if a: + alpha: Optional[float] = int(a * 2, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_hex_long, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v, 16) for v in rgb) + if a: + alpha = int(a, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_rgb, value_lower) or re.fullmatch(r_rgb_v4_style, value_lower) + if m: + return ints_to_rgba(*m.groups()) # type: ignore + + m = re.fullmatch(r_hsl, value_lower) or re.fullmatch(r_hsl_v4_style, value_lower) + if m: + return parse_hsl(*m.groups()) # type: ignore + + raise PydanticCustomError('color_error', 'value is not a valid color: string not recognised as a valid color') + + +def ints_to_rgba(r: Union[int, str], g: Union[int, str], b: Union[int, str], alpha: Optional[float] = None) -> RGBA: + """Converts integer or string values for RGB color and an optional alpha value to an `RGBA` object. + + Args: + r: An integer or string representing the red color value. + g: An integer or string representing the green color value. + b: An integer or string representing the blue color value. + alpha: A float representing the alpha value. Defaults to None. + + Returns: + An instance of the `RGBA` class with the corresponding color and alpha values. + """ + return RGBA(parse_color_value(r), parse_color_value(g), parse_color_value(b), parse_float_alpha(alpha)) + + +def parse_color_value(value: Union[int, str], max_val: int = 255) -> float: + """Parse the color value provided and return a number between 0 and 1. + + Args: + value: An integer or string color value. + max_val: Maximum range value. Defaults to 255. + + Raises: + PydanticCustomError: If the value is not a valid color. + + Returns: + A number between 0 and 1. + """ + try: + color = float(value) + except ValueError: + raise PydanticCustomError('color_error', 'value is not a valid color: color values must be a valid number') + if 0 <= color <= max_val: + return color / max_val + else: + raise PydanticCustomError( + 'color_error', + 'value is not a valid color: color values must be in the range 0 to {max_val}', + {'max_val': max_val}, + ) + + +def parse_float_alpha(value: Union[None, str, float, int]) -> Optional[float]: + """Parse an alpha value checking it's a valid float in the range 0 to 1. + + Args: + value: The input value to parse. + + Returns: + The parsed value as a float, or `None` if the value was None or equal 1. + + Raises: + PydanticCustomError: If the input value cannot be successfully parsed as a float in the expected range. + """ + if value is None: + return None + try: + if isinstance(value, str) and value.endswith('%'): + alpha = float(value[:-1]) / 100 + else: + alpha = float(value) + except ValueError: + raise PydanticCustomError('color_error', 'value is not a valid color: alpha values must be a valid float') + + if math.isclose(alpha, 1): + return None + elif 0 <= alpha <= 1: + return alpha + else: + raise PydanticCustomError('color_error', 'value is not a valid color: alpha values must be in the range 0 to 1') + + +def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: Optional[float] = None) -> RGBA: + """Parse raw hue, saturation, lightness, and alpha values and convert to RGBA. + + Args: + h: The hue value. + h_units: The unit for hue value. + sat: The saturation value. + light: The lightness value. + alpha: Alpha value. + + Returns: + An instance of `RGBA`. + """ + s_value, l_value = parse_color_value(sat, 100), parse_color_value(light, 100) + + h_value = float(h) + if h_units in {None, 'deg'}: + h_value = h_value % 360 / 360 + elif h_units == 'rad': + h_value = h_value % rads / rads + else: + # turns + h_value = h_value % 1 + + r, g, b = hls_to_rgb(h_value, l_value, s_value) + return RGBA(r, g, b, parse_float_alpha(alpha)) + + +def float_to_255(c: float) -> int: + """Converts a float value between 0 and 1 (inclusive) to an integer between 0 and 255 (inclusive). + + Args: + c: The float value to be converted. Must be between 0 and 1 (inclusive). + + Returns: + The integer equivalent of the given float value rounded to the nearest whole number. + + Raises: + ValueError: If the given float value is outside the acceptable range of 0 to 1 (inclusive). + """ + return int(round(c * 255)) + + +COLORS_BY_NAME = { + 'aliceblue': (240, 248, 255), + 'antiquewhite': (250, 235, 215), + 'aqua': (0, 255, 255), + 'aquamarine': (127, 255, 212), + 'azure': (240, 255, 255), + 'beige': (245, 245, 220), + 'bisque': (255, 228, 196), + 'black': (0, 0, 0), + 'blanchedalmond': (255, 235, 205), + 'blue': (0, 0, 255), + 'blueviolet': (138, 43, 226), + 'brown': (165, 42, 42), + 'burlywood': (222, 184, 135), + 'cadetblue': (95, 158, 160), + 'chartreuse': (127, 255, 0), + 'chocolate': (210, 105, 30), + 'coral': (255, 127, 80), + 'cornflowerblue': (100, 149, 237), + 'cornsilk': (255, 248, 220), + 'crimson': (220, 20, 60), + 'cyan': (0, 255, 255), + 'darkblue': (0, 0, 139), + 'darkcyan': (0, 139, 139), + 'darkgoldenrod': (184, 134, 11), + 'darkgray': (169, 169, 169), + 'darkgreen': (0, 100, 0), + 'darkgrey': (169, 169, 169), + 'darkkhaki': (189, 183, 107), + 'darkmagenta': (139, 0, 139), + 'darkolivegreen': (85, 107, 47), + 'darkorange': (255, 140, 0), + 'darkorchid': (153, 50, 204), + 'darkred': (139, 0, 0), + 'darksalmon': (233, 150, 122), + 'darkseagreen': (143, 188, 143), + 'darkslateblue': (72, 61, 139), + 'darkslategray': (47, 79, 79), + 'darkslategrey': (47, 79, 79), + 'darkturquoise': (0, 206, 209), + 'darkviolet': (148, 0, 211), + 'deeppink': (255, 20, 147), + 'deepskyblue': (0, 191, 255), + 'dimgray': (105, 105, 105), + 'dimgrey': (105, 105, 105), + 'dodgerblue': (30, 144, 255), + 'firebrick': (178, 34, 34), + 'floralwhite': (255, 250, 240), + 'forestgreen': (34, 139, 34), + 'fuchsia': (255, 0, 255), + 'gainsboro': (220, 220, 220), + 'ghostwhite': (248, 248, 255), + 'gold': (255, 215, 0), + 'goldenrod': (218, 165, 32), + 'gray': (128, 128, 128), + 'green': (0, 128, 0), + 'greenyellow': (173, 255, 47), + 'grey': (128, 128, 128), + 'honeydew': (240, 255, 240), + 'hotpink': (255, 105, 180), + 'indianred': (205, 92, 92), + 'indigo': (75, 0, 130), + 'ivory': (255, 255, 240), + 'khaki': (240, 230, 140), + 'lavender': (230, 230, 250), + 'lavenderblush': (255, 240, 245), + 'lawngreen': (124, 252, 0), + 'lemonchiffon': (255, 250, 205), + 'lightblue': (173, 216, 230), + 'lightcoral': (240, 128, 128), + 'lightcyan': (224, 255, 255), + 'lightgoldenrodyellow': (250, 250, 210), + 'lightgray': (211, 211, 211), + 'lightgreen': (144, 238, 144), + 'lightgrey': (211, 211, 211), + 'lightpink': (255, 182, 193), + 'lightsalmon': (255, 160, 122), + 'lightseagreen': (32, 178, 170), + 'lightskyblue': (135, 206, 250), + 'lightslategray': (119, 136, 153), + 'lightslategrey': (119, 136, 153), + 'lightsteelblue': (176, 196, 222), + 'lightyellow': (255, 255, 224), + 'lime': (0, 255, 0), + 'limegreen': (50, 205, 50), + 'linen': (250, 240, 230), + 'magenta': (255, 0, 255), + 'maroon': (128, 0, 0), + 'mediumaquamarine': (102, 205, 170), + 'mediumblue': (0, 0, 205), + 'mediumorchid': (186, 85, 211), + 'mediumpurple': (147, 112, 219), + 'mediumseagreen': (60, 179, 113), + 'mediumslateblue': (123, 104, 238), + 'mediumspringgreen': (0, 250, 154), + 'mediumturquoise': (72, 209, 204), + 'mediumvioletred': (199, 21, 133), + 'midnightblue': (25, 25, 112), + 'mintcream': (245, 255, 250), + 'mistyrose': (255, 228, 225), + 'moccasin': (255, 228, 181), + 'navajowhite': (255, 222, 173), + 'navy': (0, 0, 128), + 'oldlace': (253, 245, 230), + 'olive': (128, 128, 0), + 'olivedrab': (107, 142, 35), + 'orange': (255, 165, 0), + 'orangered': (255, 69, 0), + 'orchid': (218, 112, 214), + 'palegoldenrod': (238, 232, 170), + 'palegreen': (152, 251, 152), + 'paleturquoise': (175, 238, 238), + 'palevioletred': (219, 112, 147), + 'papayawhip': (255, 239, 213), + 'peachpuff': (255, 218, 185), + 'peru': (205, 133, 63), + 'pink': (255, 192, 203), + 'plum': (221, 160, 221), + 'powderblue': (176, 224, 230), + 'purple': (128, 0, 128), + 'red': (255, 0, 0), + 'rosybrown': (188, 143, 143), + 'royalblue': (65, 105, 225), + 'saddlebrown': (139, 69, 19), + 'salmon': (250, 128, 114), + 'sandybrown': (244, 164, 96), + 'seagreen': (46, 139, 87), + 'seashell': (255, 245, 238), + 'sienna': (160, 82, 45), + 'silver': (192, 192, 192), + 'skyblue': (135, 206, 235), + 'slateblue': (106, 90, 205), + 'slategray': (112, 128, 144), + 'slategrey': (112, 128, 144), + 'snow': (255, 250, 250), + 'springgreen': (0, 255, 127), + 'steelblue': (70, 130, 180), + 'tan': (210, 180, 140), + 'teal': (0, 128, 128), + 'thistle': (216, 191, 216), + 'tomato': (255, 99, 71), + 'turquoise': (64, 224, 208), + 'violet': (238, 130, 238), + 'wheat': (245, 222, 179), + 'white': (255, 255, 255), + 'whitesmoke': (245, 245, 245), + 'yellow': (255, 255, 0), + 'yellowgreen': (154, 205, 50), +} + +COLORS_BY_VALUE = {v: k for k, v in COLORS_BY_NAME.items()} diff --git a/backend/venv/Lib/site-packages/pydantic/config.py b/backend/venv/Lib/site-packages/pydantic/config.py new file mode 100644 index 0000000..bbf57aa --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/config.py @@ -0,0 +1,1288 @@ +"""Configuration for Pydantic models.""" + +from __future__ import annotations as _annotations + +import warnings +from re import Pattern +from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar, Union, cast, overload + +from typing_extensions import TypeAlias, TypedDict, Unpack, deprecated + +from ._migration import getattr_migration +from .aliases import AliasGenerator +from .errors import PydanticUserError +from .warnings import PydanticDeprecatedSince211 + +if TYPE_CHECKING: + from ._internal._generate_schema import GenerateSchema as _GenerateSchema + from .fields import ComputedFieldInfo, FieldInfo + +__all__ = ('ConfigDict', 'with_config') + + +JsonValue: TypeAlias = Union[int, float, str, bool, None, list['JsonValue'], 'JsonDict'] +JsonDict: TypeAlias = dict[str, JsonValue] + +JsonEncoder = Callable[[Any], Any] + +JsonSchemaExtraCallable: TypeAlias = Union[ + Callable[[JsonDict], None], + Callable[[JsonDict, type[Any]], None], +] + +ExtraValues = Literal['allow', 'ignore', 'forbid'] + + +class ConfigDict(TypedDict, total=False): + """A TypedDict for configuring Pydantic behaviour.""" + + title: str | None + """The title for the generated JSON schema, defaults to the model's name""" + + model_title_generator: Callable[[type], str] | None + """A callable that takes a model class and returns the title for it. Defaults to `None`.""" + + field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None + """A callable that takes a field's name and info and returns title for it. Defaults to `None`.""" + + str_to_lower: bool + """Whether to convert all characters to lowercase for str types. Defaults to `False`.""" + + str_to_upper: bool + """Whether to convert all characters to uppercase for str types. Defaults to `False`.""" + + str_strip_whitespace: bool + """Whether to strip leading and trailing whitespace for str types.""" + + str_min_length: int + """The minimum length for str types. Defaults to `None`.""" + + str_max_length: int | None + """The maximum length for str types. Defaults to `None`.""" + + extra: ExtraValues | None + ''' + Whether to ignore, allow, or forbid extra data during model initialization. Defaults to `'ignore'`. + + Three configuration values are available: + + - `'ignore'`: Providing extra data is ignored (the default): + ```python + from pydantic import BaseModel, ConfigDict + + class User(BaseModel): + model_config = ConfigDict(extra='ignore') # (1)! + + name: str + + user = User(name='John Doe', age=20) # (2)! + print(user) + #> name='John Doe' + ``` + + 1. This is the default behaviour. + 2. The `age` argument is ignored. + + - `'forbid'`: Providing extra data is not permitted, and a [`ValidationError`][pydantic_core.ValidationError] + will be raised if this is the case: + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + + class Model(BaseModel): + x: int + + model_config = ConfigDict(extra='forbid') + + + try: + Model(x=1, y='a') + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Extra inputs are not permitted [type=extra_forbidden, input_value='a', input_type=str] + """ + ``` + + - `'allow'`: Providing extra data is allowed and stored in the `__pydantic_extra__` dictionary attribute: + ```python + from pydantic import BaseModel, ConfigDict + + + class Model(BaseModel): + x: int + + model_config = ConfigDict(extra='allow') + + + m = Model(x=1, y='a') + assert m.__pydantic_extra__ == {'y': 'a'} + ``` + By default, no validation will be applied to these extra items, but you can set a type for the values by overriding + the type annotation for `__pydantic_extra__`: + ```python + from pydantic import BaseModel, ConfigDict, Field, ValidationError + + + class Model(BaseModel): + __pydantic_extra__: dict[str, int] = Field(init=False) # (1)! + + x: int + + model_config = ConfigDict(extra='allow') + + + try: + Model(x=1, y='a') + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + """ + + m = Model(x=1, y='2') + assert m.x == 1 + assert m.y == 2 + assert m.model_dump() == {'x': 1, 'y': 2} + assert m.__pydantic_extra__ == {'y': 2} + ``` + + 1. The `= Field(init=False)` does not have any effect at runtime, but prevents the `__pydantic_extra__` field from + being included as a parameter to the model's `__init__` method by type checkers. + + As well as specifying an `extra` configuration value on the model, you can also provide it as an argument to the validation methods. + This will override any `extra` configuration value set on the model: + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + x: int + model_config = ConfigDict(extra="allow") + + try: + # Override model config and forbid extra fields just this time + Model.model_validate({"x": 1, "y": 2}, extra="forbid") + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Extra inputs are not permitted [type=extra_forbidden, input_value=2, input_type=int] + """ + ``` + ''' + + frozen: bool + """ + Whether models are faux-immutable, i.e. whether `__setattr__` is allowed, and also generates + a `__hash__()` method for the model. This makes instances of the model potentially hashable if all the + attributes are hashable. Defaults to `False`. + + Note: + On V1, the inverse of this setting was called `allow_mutation`, and was `True` by default. + """ + + populate_by_name: bool + """ + Whether an aliased field may be populated by its name as given by the model + attribute, as well as the alias. Defaults to `False`. + + !!! warning + `populate_by_name` usage is not recommended in v2.11+ and will be deprecated in v3. + Instead, you should use the [`validate_by_name`][pydantic.config.ConfigDict.validate_by_name] configuration setting. + + When `validate_by_name=True` and `validate_by_alias=True`, this is strictly equivalent to the + previous behavior of `populate_by_name=True`. + + In v2.11, we also introduced a [`validate_by_alias`][pydantic.config.ConfigDict.validate_by_alias] setting that introduces more fine grained + control for validation behavior. + + Here's how you might go about using the new settings to achieve the same behavior: + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + my_field: str = Field(alias='my_alias') # (1)! + + m = Model(my_alias='foo') # (2)! + print(m) + #> my_field='foo' + + m = Model(my_field='foo') # (3)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is populated by the alias `'my_alias'`. + 3. The model is populated by the attribute name `'my_field'`. + """ + + use_enum_values: bool + """ + Whether to populate models with the `value` property of enums, rather than the raw enum. + This may be useful if you want to serialize `model.model_dump()` later. Defaults to `False`. + + !!! note + If you have an `Optional[Enum]` value that you set a default for, you need to use `validate_default=True` + for said Field to ensure that the `use_enum_values` flag takes effect on the default, as extracting an + enum's value occurs during validation, not serialization. + + ```python + from enum import Enum + from typing import Optional + + from pydantic import BaseModel, ConfigDict, Field + + class SomeEnum(Enum): + FOO = 'foo' + BAR = 'bar' + BAZ = 'baz' + + class SomeModel(BaseModel): + model_config = ConfigDict(use_enum_values=True) + + some_enum: SomeEnum + another_enum: Optional[SomeEnum] = Field( + default=SomeEnum.FOO, validate_default=True + ) + + model1 = SomeModel(some_enum=SomeEnum.BAR) + print(model1.model_dump()) + #> {'some_enum': 'bar', 'another_enum': 'foo'} + + model2 = SomeModel(some_enum=SomeEnum.BAR, another_enum=SomeEnum.BAZ) + print(model2.model_dump()) + #> {'some_enum': 'bar', 'another_enum': 'baz'} + ``` + """ + + validate_assignment: bool + """ + Whether to validate the data when the model is changed. Defaults to `False`. + + The default behavior of Pydantic is to validate the data when the model is created. + + In case the user changes the data after the model is created, the model is _not_ revalidated. + + ```python + from pydantic import BaseModel + + class User(BaseModel): + name: str + + user = User(name='John Doe') # (1)! + print(user) + #> name='John Doe' + user.name = 123 # (1)! + print(user) + #> name=123 + ``` + + 1. The validation happens only when the model is created. + 2. The validation does not happen when the data is changed. + + In case you want to revalidate the model when the data is changed, you can use `validate_assignment=True`: + + ```python + from pydantic import BaseModel, ValidationError + + class User(BaseModel, validate_assignment=True): # (1)! + name: str + + user = User(name='John Doe') # (2)! + print(user) + #> name='John Doe' + try: + user.name = 123 # (3)! + except ValidationError as e: + print(e) + ''' + 1 validation error for User + name + Input should be a valid string [type=string_type, input_value=123, input_type=int] + ''' + ``` + + 1. You can either use class keyword arguments, or `model_config` to set `validate_assignment=True`. + 2. The validation happens when the model is created. + 3. The validation _also_ happens when the data is changed. + """ + + arbitrary_types_allowed: bool + """ + Whether arbitrary types are allowed for field types. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + # This is not a pydantic model, it's an arbitrary class + class Pet: + def __init__(self, name: str): + self.name = name + + class Model(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) + + pet: Pet + owner: str + + pet = Pet(name='Hedwig') + # A simple check of instance type is used to validate the data + model = Model(owner='Harry', pet=pet) + print(model) + #> pet=<__main__.Pet object at 0x0123456789ab> owner='Harry' + print(model.pet) + #> <__main__.Pet object at 0x0123456789ab> + print(model.pet.name) + #> Hedwig + print(type(model.pet)) + #> + try: + # If the value is not an instance of the type, it's invalid + Model(owner='Harry', pet='Hedwig') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + pet + Input should be an instance of Pet [type=is_instance_of, input_value='Hedwig', input_type=str] + ''' + + # Nothing in the instance of the arbitrary type is checked + # Here name probably should have been a str, but it's not validated + pet2 = Pet(name=42) + model2 = Model(owner='Harry', pet=pet2) + print(model2) + #> pet=<__main__.Pet object at 0x0123456789ab> owner='Harry' + print(model2.pet) + #> <__main__.Pet object at 0x0123456789ab> + print(model2.pet.name) + #> 42 + print(type(model2.pet)) + #> + ``` + """ + + from_attributes: bool + """ + Whether to build models and look up discriminators of tagged unions using python object attributes. + """ + + loc_by_alias: bool + """Whether to use the actual key provided in the data (e.g. alias) for error `loc`s rather than the field's name. Defaults to `True`.""" + + alias_generator: Callable[[str], str] | AliasGenerator | None + """ + A callable that takes a field name and returns an alias for it + or an instance of [`AliasGenerator`][pydantic.aliases.AliasGenerator]. Defaults to `None`. + + When using a callable, the alias generator is used for both validation and serialization. + If you want to use different alias generators for validation and serialization, you can use + [`AliasGenerator`][pydantic.aliases.AliasGenerator] instead. + + If data source field names do not match your code style (e.g. CamelCase fields), + you can automatically generate aliases using `alias_generator`. Here's an example with + a basic callable: + + ```python + from pydantic import BaseModel, ConfigDict + from pydantic.alias_generators import to_pascal + + class Voice(BaseModel): + model_config = ConfigDict(alias_generator=to_pascal) + + name: str + language_code: str + + voice = Voice(Name='Filiz', LanguageCode='tr-TR') + print(voice.language_code) + #> tr-TR + print(voice.model_dump(by_alias=True)) + #> {'Name': 'Filiz', 'LanguageCode': 'tr-TR'} + ``` + + If you want to use different alias generators for validation and serialization, you can use + [`AliasGenerator`][pydantic.aliases.AliasGenerator]. + + ```python + from pydantic import AliasGenerator, BaseModel, ConfigDict + from pydantic.alias_generators import to_camel, to_pascal + + class Athlete(BaseModel): + first_name: str + last_name: str + sport: str + + model_config = ConfigDict( + alias_generator=AliasGenerator( + validation_alias=to_camel, + serialization_alias=to_pascal, + ) + ) + + athlete = Athlete(firstName='John', lastName='Doe', sport='track') + print(athlete.model_dump(by_alias=True)) + #> {'FirstName': 'John', 'LastName': 'Doe', 'Sport': 'track'} + ``` + + Note: + Pydantic offers three built-in alias generators: [`to_pascal`][pydantic.alias_generators.to_pascal], + [`to_camel`][pydantic.alias_generators.to_camel], and [`to_snake`][pydantic.alias_generators.to_snake]. + """ + + ignored_types: tuple[type, ...] + """A tuple of types that may occur as values of class attributes without annotations. This is + typically used for custom descriptors (classes that behave like `property`). If an attribute is set on a + class without an annotation and has a type that is not in this tuple (or otherwise recognized by + _pydantic_), an error will be raised. Defaults to `()`. + """ + + allow_inf_nan: bool + """Whether to allow infinity (`+inf` an `-inf`) and NaN values to float and decimal fields. Defaults to `True`.""" + + json_schema_extra: JsonDict | JsonSchemaExtraCallable | None + """A dict or callable to provide extra JSON schema properties. Defaults to `None`.""" + + json_encoders: dict[type[object], JsonEncoder] | None + """ + A `dict` of custom JSON encoders for specific types. Defaults to `None`. + + /// version-deprecated | v2 + This configuration option is a carryover from v1. We originally planned to remove it in v2 but didn't have a 1:1 replacement + so we are keeping it for now. It is still deprecated and will likely be removed in the future. + /// + """ + + # new in V2 + strict: bool + """ + Whether strict validation is applied to all fields on the model. + + By default, Pydantic attempts to coerce values to the correct type, when possible. + + There are situations in which you may want to disable this behavior, and instead raise an error if a value's type + does not match the field's type annotation. + + To configure strict mode for all fields on a model, you can set `strict=True` on the model. + + ```python + from pydantic import BaseModel, ConfigDict + + class Model(BaseModel): + model_config = ConfigDict(strict=True) + + name: str + age: int + ``` + + See [Strict Mode](../concepts/strict_mode.md) for more details. + + See the [Conversion Table](../concepts/conversion_table.md) for more details on how Pydantic converts data in both + strict and lax modes. + + /// version-added | v2 + /// + """ + # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' + revalidate_instances: Literal['always', 'never', 'subclass-instances'] + """ + When and how to revalidate models and dataclasses during validation. Can be one of: + + - `'never'`: will *not* revalidate models and dataclasses during validation + - `'always'`: will revalidate models and dataclasses during validation + - `'subclass-instances'`: will revalidate models and dataclasses during validation if the instance is a + subclass of the model or dataclass + + The default is `'never'` (no revalidation). + + This configuration only affects *the current model* it is applied on, and does *not* populate to the models + referenced in fields. + + ```python + from pydantic import BaseModel + + class User(BaseModel, revalidate_instances='never'): # (1)! + name: str + + class Transaction(BaseModel): + user: User + + my_user = User(name='John') + t = Transaction(user=my_user) + + my_user.name = 1 # (2)! + t = Transaction(user=my_user) # (3)! + print(t) + #> user=User(name=1) + ``` + + 1. This is the default behavior. + 2. The assignment is *not* validated, unless you set [`validate_assignment`][pydantic.ConfigDict.validate_assignment] in the configuration. + 3. Since `revalidate_instances` is set to `'never'`, the user instance is not revalidated. + + Here is an example demonstrating the behavior of `'subclass-instances'`: + + ```python + from pydantic import BaseModel + + class User(BaseModel, revalidate_instances='subclass-instances'): + name: str + + class SubUser(User): + age: int + + class Transaction(BaseModel): + user: User + + my_user = User(name='John') + my_user.name = 1 # (1)! + t = Transaction(user=my_user) # (2)! + print(t) + #> user=User(name=1) + + my_sub_user = SubUser(name='John', age=20) + t = Transaction(user=my_sub_user) + print(t) # (3)! + #> user=User(name='John') + ``` + + 1. The assignment is *not* validated, unless you set [`validate_assignment`][pydantic.ConfigDict.validate_assignment] in the configuration. + 2. Because `my_user` is a "direct" instance of `User`, it is *not* being revalidated. It would have been the case if + `revalidate_instances` was set to `'always'`. + 3. Because `my_sub_user` is an instance of a `User` subclass, it is being revalidated. In this case, Pydantic coerces `my_sub_user` to the defined + `User` class defined on `Transaction`. If one of its fields had an invalid value, a validation error would have been raised. + + /// version-added | v2 + /// + """ + + ser_json_timedelta: Literal['iso8601', 'float'] + """ + The format of JSON serialized timedeltas. Accepts the string values of `'iso8601'` and + `'float'`. Defaults to `'iso8601'`. + + - `'iso8601'` will serialize timedeltas to [ISO 8601 text format](https://en.wikipedia.org/wiki/ISO_8601#Durations). + - `'float'` will serialize timedeltas to the total number of seconds. + + /// version-changed | v2.12 + It is now recommended to use the [`ser_json_temporal`][pydantic.config.ConfigDict.ser_json_temporal] + setting. `ser_json_timedelta` will be deprecated in v3. + /// + """ + + ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] + """ + The format of JSON serialized temporal types from the [`datetime`][] module. This includes: + + - [`datetime.datetime`][] + - [`datetime.date`][] + - [`datetime.time`][] + - [`datetime.timedelta`][] + + Can be one of: + + - `'iso8601'` will serialize date-like types to [ISO 8601 text format](https://en.wikipedia.org/wiki/ISO_8601#Durations). + - `'milliseconds'` will serialize date-like types to a floating point number of milliseconds since the epoch. + - `'seconds'` will serialize date-like types to a floating point number of seconds since the epoch. + + Defaults to `'iso8601'`. + + /// version-added | v2.12 + This setting replaces [`ser_json_timedelta`][pydantic.config.ConfigDict.ser_json_timedelta], + which will be deprecated in v3. `ser_json_temporal` adds more configurability for the other temporal types. + /// + """ + + val_temporal_unit: Literal['seconds', 'milliseconds', 'infer'] + """ + The unit to assume for validating numeric input for datetime-like types ([`datetime.datetime`][] and [`datetime.date`][]). Can be one of: + + - `'seconds'` will validate date or time numeric inputs as seconds since the [epoch]. + - `'milliseconds'` will validate date or time numeric inputs as milliseconds since the [epoch]. + - `'infer'` will infer the unit from the string numeric input on unix time as: + + * seconds since the [epoch] if $-2^{10} <= v <= 2^{10}$ + * milliseconds since the [epoch] (if $v < -2^{10}$ or $v > 2^{10}$). + + Defaults to `'infer'`. + + /// version-added | v2.12 + /// + + [epoch]: https://en.wikipedia.org/wiki/Unix_time + """ + + ser_json_bytes: Literal['utf8', 'base64', 'hex'] + """ + The encoding of JSON serialized bytes. Defaults to `'utf8'`. + Set equal to `val_json_bytes` to get back an equal value after serialization round trip. + + - `'utf8'` will serialize bytes to UTF-8 strings. + - `'base64'` will serialize bytes to URL safe base64 strings. + - `'hex'` will serialize bytes to hexadecimal strings. + """ + + val_json_bytes: Literal['utf8', 'base64', 'hex'] + """ + The encoding of JSON serialized bytes to decode. Defaults to `'utf8'`. + Set equal to `ser_json_bytes` to get back an equal value after serialization round trip. + + - `'utf8'` will deserialize UTF-8 strings to bytes. + - `'base64'` will deserialize URL safe base64 strings to bytes. + - `'hex'` will deserialize hexadecimal strings to bytes. + """ + + ser_json_inf_nan: Literal['null', 'constants', 'strings'] + """ + The encoding of JSON serialized infinity and NaN float values. Defaults to `'null'`. + + - `'null'` will serialize infinity and NaN values as `null`. + - `'constants'` will serialize infinity and NaN values as `Infinity` and `NaN`. + - `'strings'` will serialize infinity as string `"Infinity"` and NaN as string `"NaN"`. + """ + + # whether to validate default values during validation, default False + validate_default: bool + """Whether to validate default values during validation. Defaults to `False`.""" + + validate_return: bool + """Whether to validate the return value from call validators. Defaults to `False`.""" + + protected_namespaces: tuple[str | Pattern[str], ...] + """ + A tuple of strings and/or regex patterns that prevent models from having fields with names that conflict with its existing members/methods. + + Strings are matched on a prefix basis. For instance, with `'dog'`, having a field named `'dog_name'` will be disallowed. + + Regex patterns are matched on the entire field name. For instance, with the pattern `'^dog$'`, having a field named `'dog'` will be disallowed, + but `'dog_name'` will be accepted. + + Defaults to `('model_validate', 'model_dump')`. This default is used to prevent collisions with the existing (and possibly future) + [validation](../concepts/models.md#validating-data) and [serialization](../concepts/serialization.md#serializing-data) methods. + + ```python + import warnings + + from pydantic import BaseModel + + warnings.filterwarnings('error') # Raise warnings as errors + + try: + + class Model(BaseModel): + model_dump_something: str + + except UserWarning as e: + print(e) + ''' + Field 'model_dump_something' in 'Model' conflicts with protected namespace 'model_dump'. + + You may be able to solve this by setting the 'protected_namespaces' configuration to ('model_validate',). + ''' + ``` + + You can customize this behavior using the `protected_namespaces` setting: + + ```python {test="skip"} + import re + import warnings + + from pydantic import BaseModel, ConfigDict + + with warnings.catch_warnings(record=True) as caught_warnings: + warnings.simplefilter('always') # Catch all warnings + + class Model(BaseModel): + safe_field: str + also_protect_field: str + protect_this: str + + model_config = ConfigDict( + protected_namespaces=( + 'protect_me_', + 'also_protect_', + re.compile('^protect_this$'), + ) + ) + + for warning in caught_warnings: + print(f'{warning.message}') + ''' + Field 'also_protect_field' in 'Model' conflicts with protected namespace 'also_protect_'. + You may be able to solve this by setting the 'protected_namespaces' configuration to ('protect_me_', re.compile('^protect_this$'))`. + + Field 'protect_this' in 'Model' conflicts with protected namespace 're.compile('^protect_this$')'. + You may be able to solve this by setting the 'protected_namespaces' configuration to ('protect_me_', 'also_protect_')`. + ''' + ``` + + While Pydantic will only emit a warning when an item is in a protected namespace but does not actually have a collision, + an error _is_ raised if there is an actual collision with an existing attribute: + + ```python + from pydantic import BaseModel, ConfigDict + + try: + + class Model(BaseModel): + model_validate: str + + model_config = ConfigDict(protected_namespaces=('model_',)) + + except ValueError as e: + print(e) + ''' + Field 'model_validate' conflicts with member > of protected namespace 'model_'. + ''' + ``` + + /// version-changed | v2.10 + The default protected namespaces was changed from `('model_',)` to `('model_validate', 'model_dump')`, to allow + for fields like `model_id`, `model_name` to be used. + /// + """ + + hide_input_in_errors: bool + """ + Whether to hide inputs when printing errors. Defaults to `False`. + + Pydantic shows the input value and type when it raises `ValidationError` during the validation. + + ```python + from pydantic import BaseModel, ValidationError + + class Model(BaseModel): + a: str + + try: + Model(a=123) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + a + Input should be a valid string [type=string_type, input_value=123, input_type=int] + ''' + ``` + + You can hide the input value and type by setting the `hide_input_in_errors` config to `True`. + + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + a: str + model_config = ConfigDict(hide_input_in_errors=True) + + try: + Model(a=123) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + a + Input should be a valid string [type=string_type] + ''' + ``` + """ + + defer_build: bool + """ + Whether to defer model validator and serializer construction until the first model validation. Defaults to False. + + This can be useful to avoid the overhead of building models which are only + used nested within other models, or when you want to manually define type namespace via + [`Model.model_rebuild(_types_namespace=...)`][pydantic.BaseModel.model_rebuild]. + + /// version-changed | v2.10 + The setting also applies to [Pydantic dataclasses](../concepts/dataclasses.md) and [type adapters](../concepts/type_adapter.md). + /// + """ + + plugin_settings: dict[str, object] | None + """A `dict` of settings for plugins. Defaults to `None`.""" + + schema_generator: type[_GenerateSchema] | None + """ + The `GenerateSchema` class to use during core schema generation. + + /// version-deprecated | v2.10 + The `GenerateSchema` class is private and highly subject to change. + /// + """ + + json_schema_serialization_defaults_required: bool + """ + Whether fields with default values should be marked as required in the serialization schema. Defaults to `False`. + + This ensures that the serialization schema will reflect the fact a field with a default will always be present + when serializing the model, even though it is not required for validation. + + However, there are scenarios where this may be undesirable — in particular, if you want to share the schema + between validation and serialization, and don't mind fields with defaults being marked as not required during + serialization. See [#7209](https://github.com/pydantic/pydantic/issues/7209) for more details. + + ```python + from pydantic import BaseModel, ConfigDict + + class Model(BaseModel): + a: str = 'a' + + model_config = ConfigDict(json_schema_serialization_defaults_required=True) + + print(Model.model_json_schema(mode='validation')) + ''' + { + 'properties': {'a': {'default': 'a', 'title': 'A', 'type': 'string'}}, + 'title': 'Model', + 'type': 'object', + } + ''' + print(Model.model_json_schema(mode='serialization')) + ''' + { + 'properties': {'a': {'default': 'a', 'title': 'A', 'type': 'string'}}, + 'required': ['a'], + 'title': 'Model', + 'type': 'object', + } + ''' + ``` + + /// version-added | v2.4 + /// + """ + + json_schema_mode_override: Literal['validation', 'serialization', None] + """ + If not `None`, the specified mode will be used to generate the JSON schema regardless of what `mode` was passed to + the function call. Defaults to `None`. + + This provides a way to force the JSON schema generation to reflect a specific mode, e.g., to always use the + validation schema. + + It can be useful when using frameworks (such as FastAPI) that may generate different schemas for validation + and serialization that must both be referenced from the same schema; when this happens, we automatically append + `-Input` to the definition reference for the validation schema and `-Output` to the definition reference for the + serialization schema. By specifying a `json_schema_mode_override` though, this prevents the conflict between + the validation and serialization schemas (since both will use the specified schema), and so prevents the suffixes + from being added to the definition references. + + ```python + from pydantic import BaseModel, ConfigDict, Json + + class Model(BaseModel): + a: Json[int] # requires a string to validate, but will dump an int + + print(Model.model_json_schema(mode='serialization')) + ''' + { + 'properties': {'a': {'title': 'A', 'type': 'integer'}}, + 'required': ['a'], + 'title': 'Model', + 'type': 'object', + } + ''' + + class ForceInputModel(Model): + # the following ensures that even with mode='serialization', we + # will get the schema that would be generated for validation. + model_config = ConfigDict(json_schema_mode_override='validation') + + print(ForceInputModel.model_json_schema(mode='serialization')) + ''' + { + 'properties': { + 'a': { + 'contentMediaType': 'application/json', + 'contentSchema': {'type': 'integer'}, + 'title': 'A', + 'type': 'string', + } + }, + 'required': ['a'], + 'title': 'ForceInputModel', + 'type': 'object', + } + ''' + ``` + + /// version-added | v2.4 + /// + """ + + coerce_numbers_to_str: bool + """ + If `True`, enables automatic coercion of any `Number` type to `str` in "lax" (non-strict) mode. Defaults to `False`. + + Pydantic doesn't allow number types (`int`, `float`, `Decimal`) to be coerced as type `str` by default. + + ```python + from decimal import Decimal + + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + value: str + + try: + print(Model(value=42)) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + value + Input should be a valid string [type=string_type, input_value=42, input_type=int] + ''' + + class Model(BaseModel): + model_config = ConfigDict(coerce_numbers_to_str=True) + + value: str + + repr(Model(value=42).value) + #> "42" + repr(Model(value=42.13).value) + #> "42.13" + repr(Model(value=Decimal('42.13')).value) + #> "42.13" + ``` + """ + + regex_engine: Literal['rust-regex', 'python-re'] + """ + The regex engine to be used for pattern validation. + Defaults to `'rust-regex'`. + + - `'rust-regex'` uses the [`regex`](https://docs.rs/regex) Rust crate, + which is non-backtracking and therefore more DDoS resistant, but does not support all regex features. + - `'python-re'` use the [`re`][] module, which supports all regex features, but may be slower. + + !!! note + If you use a compiled regex pattern, the `'python-re'` engine will be used regardless of this setting. + This is so that flags such as [`re.IGNORECASE`][] are respected. + + ```python + from pydantic import BaseModel, ConfigDict, Field, ValidationError + + class Model(BaseModel): + model_config = ConfigDict(regex_engine='python-re') + + value: str = Field(pattern=r'^abc(?=def)') + + print(Model(value='abcdef').value) + #> abcdef + + try: + print(Model(value='abxyzcdef')) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + value + String should match pattern '^abc(?=def)' [type=string_pattern_mismatch, input_value='abxyzcdef', input_type=str] + ''' + ``` + + /// version-added | v2.5 + /// + """ + + validation_error_cause: bool + """ + If `True`, Python exceptions that were part of a validation failure will be shown as an exception group as a cause. Can be useful for debugging. Defaults to `False`. + + Note: + Python 3.10 and older don't support exception groups natively. <=3.10, backport must be installed: `pip install exceptiongroup`. + + Note: + The structure of validation errors are likely to change in future Pydantic versions. Pydantic offers no guarantees about their structure. Should be used for visual traceback debugging only. + + /// version-added | v2.5 + /// + """ + + use_attribute_docstrings: bool + ''' + Whether docstrings of attributes (bare string literals immediately following the attribute declaration) + should be used for field descriptions. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + + class Model(BaseModel): + model_config = ConfigDict(use_attribute_docstrings=True) + + x: str + """ + Example of an attribute docstring + """ + + y: int = Field(description="Description in Field") + """ + Description in Field overrides attribute docstring + """ + + + print(Model.model_fields["x"].description) + # > Example of an attribute docstring + print(Model.model_fields["y"].description) + # > Description in Field + ``` + This requires the source code of the class to be available at runtime. + + !!! warning "Usage with `TypedDict` and stdlib dataclasses" + Due to current limitations, attribute docstrings detection may not work as expected when using + [`TypedDict`][typing.TypedDict] and stdlib dataclasses, in particular when: + + - inheritance is being used. + - multiple classes have the same name in the same source file (unless Python 3.13 or greater is used). + + /// version-added | v2.7 + /// + ''' + + cache_strings: bool | Literal['all', 'keys', 'none'] + """ + Whether to cache strings to avoid constructing new Python objects. Defaults to True. + + Enabling this setting should significantly improve validation performance while increasing memory usage slightly. + + - `True` or `'all'` (the default): cache all strings + - `'keys'`: cache only dictionary keys + - `False` or `'none'`: no caching + + !!! note + `True` or `'all'` is required to cache strings during general validation because + validators don't know if they're in a key or a value. + + !!! tip + If repeated strings are rare, it's recommended to use `'keys'` or `'none'` to reduce memory usage, + as the performance difference is minimal if repeated strings are rare. + + /// version-added | v2.7 + /// + """ + + validate_by_alias: bool + """ + Whether an aliased field may be populated by its alias. Defaults to `True`. + + Here's an example of disabling validation by alias: + + ```py + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=False) + + my_field: str = Field(validation_alias='my_alias') # (1)! + + m = Model(my_field='foo') # (2)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model can only be populated by the attribute name `'my_field'`. + + !!! warning + You cannot set both `validate_by_alias` and `validate_by_name` to `False`. + This would make it impossible to populate an attribute. + + See [usage errors](../errors/usage_errors.md#validate-by-alias-and-name-false) for an example. + + If you set `validate_by_alias` to `False`, under the hood, Pydantic dynamically sets + `validate_by_name` to `True` to ensure that validation can still occur. + + /// version-added | v2.11 + This setting was introduced in conjunction with [`validate_by_name`][pydantic.ConfigDict.validate_by_name] + to empower users with more fine grained validation control. + /// + """ + + validate_by_name: bool + """ + Whether an aliased field may be populated by its name as given by the model + attribute. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + my_field: str = Field(validation_alias='my_alias') # (1)! + + m = Model(my_alias='foo') # (2)! + print(m) + #> my_field='foo' + + m = Model(my_field='foo') # (3)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is populated by the alias `'my_alias'`. + 3. The model is populated by the attribute name `'my_field'`. + + !!! warning + You cannot set both `validate_by_alias` and `validate_by_name` to `False`. + This would make it impossible to populate an attribute. + + See [usage errors](../errors/usage_errors.md#validate-by-alias-and-name-false) for an example. + + /// version-added | v2.11 + This setting was introduced in conjunction with [`validate_by_alias`][pydantic.ConfigDict.validate_by_alias] + to empower users with more fine grained validation control. It is an alternative to [`populate_by_name`][pydantic.ConfigDict.populate_by_name], + that enables validation by name **and** by alias. + /// + """ + + serialize_by_alias: bool + """ + Whether an aliased field should be serialized by its alias. Defaults to `False`. + + Note: In v2.11, `serialize_by_alias` was introduced to address the + [popular request](https://github.com/pydantic/pydantic/issues/8379) + for consistency with alias behavior for validation and serialization settings. + In v3, the default value is expected to change to `True` for consistency with the validation default. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(serialize_by_alias=True) + + my_field: str = Field(serialization_alias='my_alias') # (1)! + + m = Model(my_field='foo') + print(m.model_dump()) # (2)! + #> {'my_alias': 'foo'} + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is serialized using the alias `'my_alias'` for the `'my_field'` attribute. + + + /// version-added | v2.11 + This setting was introduced to address the [popular request](https://github.com/pydantic/pydantic/issues/8379) + for consistency with alias behavior for validation and serialization. + + In v3, the default value is expected to change to `True` for consistency with the validation default. + /// + """ + + url_preserve_empty_path: bool + """ + Whether to preserve empty URL paths when validating values for a URL type. Defaults to `False`. + + ```python + from pydantic import AnyUrl, BaseModel, ConfigDict + + class Model(BaseModel): + model_config = ConfigDict(url_preserve_empty_path=True) + + url: AnyUrl + + m = Model(url='http://example.com') + print(m.url) + #> http://example.com + ``` + + /// version-added | v2.12 + /// + """ + + +_TypeT = TypeVar('_TypeT', bound=type) + + +@overload +@deprecated('Passing `config` as a keyword argument is deprecated. Pass `config` as a positional argument instead.') +def with_config(*, config: ConfigDict) -> Callable[[_TypeT], _TypeT]: ... + + +@overload +def with_config(config: ConfigDict, /) -> Callable[[_TypeT], _TypeT]: ... + + +@overload +def with_config(**config: Unpack[ConfigDict]) -> Callable[[_TypeT], _TypeT]: ... + + +def with_config(config: ConfigDict | None = None, /, **kwargs: Any) -> Callable[[_TypeT], _TypeT]: + """!!! abstract "Usage Documentation" + [Configuration with other types](../concepts/config.md#configuration-on-other-supported-types) + + A convenience decorator to set a [Pydantic configuration](config.md) on a `TypedDict` or a `dataclass` from the standard library. + + Although the configuration can be set using the `__pydantic_config__` attribute, it does not play well with type checkers, + especially with `TypedDict`. + + !!! example "Usage" + + ```python + from typing_extensions import TypedDict + + from pydantic import ConfigDict, TypeAdapter, with_config + + @with_config(ConfigDict(str_to_lower=True)) + class TD(TypedDict): + x: str + + ta = TypeAdapter(TD) + + print(ta.validate_python({'x': 'ABC'})) + #> {'x': 'abc'} + ``` + + /// deprecated-removed | v2.11 v3 + Passing `config` as a keyword argument. + /// + + /// version-changed | v2.11 + Keyword arguments can be provided directly instead of a config dictionary. + /// + """ + if config is not None and kwargs: + raise ValueError('Cannot specify both `config` and keyword arguments') + + if len(kwargs) == 1 and (kwargs_conf := kwargs.get('config')) is not None: + warnings.warn( + 'Passing `config` as a keyword argument is deprecated. Pass `config` as a positional argument instead', + category=PydanticDeprecatedSince211, + stacklevel=2, + ) + final_config = cast(ConfigDict, kwargs_conf) + else: + final_config = config if config is not None else cast(ConfigDict, kwargs) + + def inner(class_: _TypeT, /) -> _TypeT: + # Ideally, we would check for `class_` to either be a `TypedDict` or a stdlib dataclass. + # However, the `@with_config` decorator can be applied *after* `@dataclass`. To avoid + # common mistakes, we at least check for `class_` to not be a Pydantic model. + from ._internal._utils import is_model_class + + if is_model_class(class_): + raise PydanticUserError( + f'Cannot use `with_config` on {class_.__name__} as it is a Pydantic model', + code='with-config-on-model', + ) + class_.__pydantic_config__ = final_config + return class_ + + return inner + + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/dataclasses.py b/backend/venv/Lib/site-packages/pydantic/dataclasses.py new file mode 100644 index 0000000..cecd540 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/dataclasses.py @@ -0,0 +1,413 @@ +"""Provide an enhanced dataclass that performs validation.""" + +from __future__ import annotations as _annotations + +import dataclasses +import functools +import sys +import types +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, overload +from warnings import warn + +from typing_extensions import TypeGuard, dataclass_transform + +from ._internal import _config, _decorators, _mock_val_ser, _namespace_utils, _typing_extra +from ._internal import _dataclasses as _pydantic_dataclasses +from ._migration import getattr_migration +from .config import ConfigDict +from .errors import PydanticUserError +from .fields import Field, FieldInfo, PrivateAttr + +if TYPE_CHECKING: + from ._internal._dataclasses import PydanticDataclass + from ._internal._namespace_utils import MappingNamespace + +__all__ = 'dataclass', 'rebuild_dataclass' + +_T = TypeVar('_T') + +if sys.version_info >= (3, 10): + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = ..., + slots: bool = ..., + ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + _cls: type[_T], # type: ignore + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = ..., + slots: bool = ..., + ) -> type[PydanticDataclass]: ... + +else: + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + _cls: type[_T], # type: ignore + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + ) -> type[PydanticDataclass]: ... + + +@dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) +def dataclass( + _cls: type[_T] | None = None, + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = False, + slots: bool = False, +) -> Callable[[type[_T]], type[PydanticDataclass]] | type[PydanticDataclass]: + """!!! abstract "Usage Documentation" + [`dataclasses`](../concepts/dataclasses.md) + + A decorator used to create a Pydantic-enhanced dataclass, similar to the standard Python `dataclass`, + but with added validation. + + This function should be used similarly to `dataclasses.dataclass`. + + Args: + _cls: The target `dataclass`. + init: Included for signature compatibility with `dataclasses.dataclass`, and is passed through to + `dataclasses.dataclass` when appropriate. If specified, must be set to `False`, as pydantic inserts its + own `__init__` function. + repr: A boolean indicating whether to include the field in the `__repr__` output. + eq: Determines if a `__eq__` method should be generated for the class. + order: Determines if comparison magic methods should be generated, such as `__lt__`, but not `__eq__`. + unsafe_hash: Determines if a `__hash__` method should be included in the class, as in `dataclasses.dataclass`. + frozen: Determines if the generated class should be a 'frozen' `dataclass`, which does not allow its + attributes to be modified after it has been initialized. If not set, the value from the provided `config` argument will be used (and will default to `False` otherwise). + config: The Pydantic config to use for the `dataclass`. + validate_on_init: A deprecated parameter included for backwards compatibility; in V2, all Pydantic dataclasses + are validated on init. + kw_only: Determines if `__init__` method parameters must be specified by keyword only. Defaults to `False`. + slots: Determines if the generated class should be a 'slots' `dataclass`, which does not allow the addition of + new attributes after instantiation. + + Returns: + A decorator that accepts a class as its argument and returns a Pydantic `dataclass`. + + Raises: + AssertionError: Raised if `init` is not `False` or `validate_on_init` is `False`. + """ + assert init is False, 'pydantic.dataclasses.dataclass only supports init=False' + assert validate_on_init is not False, 'validate_on_init=False is no longer supported' + + if sys.version_info >= (3, 10): + kwargs = {'kw_only': kw_only, 'slots': slots} + else: + kwargs = {} + + def create_dataclass(cls: type[Any]) -> type[PydanticDataclass]: + """Create a Pydantic dataclass from a regular dataclass. + + Args: + cls: The class to create the Pydantic dataclass from. + + Returns: + A Pydantic dataclass. + """ + from ._internal._utils import is_model_class + + if is_model_class(cls): + raise PydanticUserError( + f'Cannot create a Pydantic dataclass from {cls.__name__} as it is already a Pydantic model', + code='dataclass-on-model', + ) + + original_cls = cls + + # we warn on conflicting config specifications, but only if the class doesn't have a dataclass base + # because a dataclass base might provide a __pydantic_config__ attribute that we don't want to warn about + has_dataclass_base = any(dataclasses.is_dataclass(base) for base in cls.__bases__) + if not has_dataclass_base and config is not None and hasattr(cls, '__pydantic_config__'): + warn( + f'`config` is set via both the `dataclass` decorator and `__pydantic_config__` for dataclass {cls.__name__}. ' + f'The `config` specification from `dataclass` decorator will take priority.', + category=UserWarning, + stacklevel=2, + ) + + # if config is not explicitly provided, try to read it from the type + config_dict = config if config is not None else getattr(cls, '__pydantic_config__', None) + config_wrapper = _config.ConfigWrapper(config_dict) + decorators = _decorators.DecoratorInfos.build(cls) + decorators.update_from_config(config_wrapper) + + # Keep track of the original __doc__ so that we can restore it after applying the dataclasses decorator + # Otherwise, classes with no __doc__ will have their signature added into the JSON schema description, + # since dataclasses.dataclass will set this as the __doc__ + original_doc = cls.__doc__ + + if _pydantic_dataclasses.is_stdlib_dataclass(cls): + # Vanilla dataclasses include a default docstring (representing the class signature), + # which we don't want to preserve. + original_doc = None + + # We don't want to add validation to the existing std lib dataclass, so we will subclass it + # If the class is generic, we need to make sure the subclass also inherits from Generic + # with all the same parameters. + bases = (cls,) + if issubclass(cls, Generic): + generic_base = Generic[cls.__parameters__] # type: ignore + bases = bases + (generic_base,) + cls = types.new_class(cls.__name__, bases) + + # Respect frozen setting from dataclass constructor and fallback to config setting if not provided + if frozen is not None: + frozen_ = frozen + if config_wrapper.frozen: + # It's not recommended to define both, as the setting from the dataclass decorator will take priority. + warn( + f'`frozen` is set via both the `dataclass` decorator and `config` for dataclass {cls.__name__!r}.' + 'This is not recommended. The `frozen` specification on `dataclass` will take priority.', + category=UserWarning, + stacklevel=2, + ) + else: + frozen_ = config_wrapper.frozen or False + + # Make Pydantic's `Field()` function compatible with stdlib dataclasses. As we'll decorate + # `cls` with the stdlib `@dataclass` decorator first, there are two attributes, `kw_only` and + # `repr` that need to be understood *during* the stdlib creation. We do so in two steps: + + # 1. On the decorated class, wrap `Field()` assignment with `dataclass.field()`, with the + # two attributes set (done in `as_dataclass_field()`) + cls_anns = _typing_extra.safe_get_annotations(cls) + for field_name in cls_anns: + # We should look for assignments in `__dict__` instead, but for now we follow + # the same behavior as stdlib dataclasses (see https://github.com/python/cpython/issues/88609) + field_value = getattr(cls, field_name, None) + if isinstance(field_value, FieldInfo): + setattr(cls, field_name, _pydantic_dataclasses.as_dataclass_field(field_value)) + + # 2. For bases of `cls` that are stdlib dataclasses, we temporarily patch their fields + # (see the docstring of the context manager): + with _pydantic_dataclasses.patch_base_fields(cls): + cls = dataclasses.dataclass( # pyright: ignore[reportCallIssue] + cls, + # the value of init here doesn't affect anything except that it makes it easier to generate a signature + init=True, + repr=repr, + eq=eq, + order=order, + unsafe_hash=unsafe_hash, + frozen=frozen_, + **kwargs, + ) + + if config_wrapper.validate_assignment: + original_setattr = cls.__setattr__ + + @functools.wraps(cls.__setattr__) + def validated_setattr(instance: PydanticDataclass, name: str, value: Any, /) -> None: + if frozen_: + return original_setattr(instance, name, value) # pyright: ignore[reportCallIssue] + inst_cls = type(instance) + attr = getattr(inst_cls, name, None) + + if isinstance(attr, property): + attr.__set__(instance, value) + elif isinstance(attr, functools.cached_property): + instance.__dict__.__setitem__(name, value) + else: + inst_cls.__pydantic_validator__.validate_assignment(instance, name, value) + + cls.__setattr__ = validated_setattr.__get__(None, cls) # type: ignore + + if slots and not hasattr(cls, '__setstate__'): + # If slots is set, `pickle` (relied on by `copy.copy()`) will use + # `__setattr__()` to reconstruct the dataclass. However, the custom + # `__setattr__()` set above relies on `validate_assignment()`, which + # in turn expects all the field values to be already present on the + # instance, resulting in attribute errors. + # As such, we make use of `object.__setattr__()` instead. + # Note that we do so only if `__setstate__()` isn't already set (this is the + # case if on top of `slots`, `frozen` is used). + + # Taken from `dataclasses._dataclass_get/setstate()`: + def _dataclass_getstate(self: Any) -> list[Any]: + return [getattr(self, f.name) for f in dataclasses.fields(self)] + + def _dataclass_setstate(self: Any, state: list[Any]) -> None: + for field, value in zip(dataclasses.fields(self), state): + object.__setattr__(self, field.name, value) + + cls.__getstate__ = _dataclass_getstate # pyright: ignore[reportAttributeAccessIssue] + cls.__setstate__ = _dataclass_setstate # pyright: ignore[reportAttributeAccessIssue] + + # This is an undocumented attribute to distinguish stdlib/Pydantic dataclasses. + # It should be set as early as possible: + cls.__is_pydantic_dataclass__ = True + cls.__pydantic_decorators__ = decorators # type: ignore + cls.__doc__ = original_doc + # Can be non-existent for dynamically created classes: + firstlineno = getattr(original_cls, '__firstlineno__', None) + cls.__module__ = original_cls.__module__ + if sys.version_info >= (3, 13) and firstlineno is not None: + # As per https://docs.python.org/3/reference/datamodel.html#type.__firstlineno__: + # Setting the `__module__` attribute removes the `__firstlineno__` item from the type’s dictionary. + original_cls.__firstlineno__ = firstlineno + cls.__firstlineno__ = firstlineno + cls.__qualname__ = original_cls.__qualname__ + cls.__pydantic_fields_complete__ = classmethod(_pydantic_fields_complete) + cls.__pydantic_complete__ = False # `complete_dataclass` will set it to `True` if successful. + # TODO `parent_namespace` is currently None, but we could do the same thing as Pydantic models: + # fetch the parent ns using `parent_frame_namespace` (if the dataclass was defined in a function), + # and possibly cache it (see the `__pydantic_parent_namespace__` logic for models). + _pydantic_dataclasses.complete_dataclass(cls, config_wrapper, raise_errors=False) + return cls + + return create_dataclass if _cls is None else create_dataclass(_cls) + + +def _pydantic_fields_complete(cls: type[PydanticDataclass]) -> bool: + """Return whether the fields where successfully collected (i.e. type hints were successfully resolves). + + This is a private property, not meant to be used outside Pydantic. + """ + return all(field_info._complete for field_info in cls.__pydantic_fields__.values()) + + +__getattr__ = getattr_migration(__name__) + +if sys.version_info < (3, 11): + # Monkeypatch dataclasses.InitVar so that typing doesn't error if it occurs as a type when evaluating type hints + # Starting in 3.11, typing.get_type_hints will not raise an error if the retrieved type hints are not callable. + + def _call_initvar(*args: Any, **kwargs: Any) -> NoReturn: + """This function does nothing but raise an error that is as similar as possible to what you'd get + if you were to try calling `InitVar[int]()` without this monkeypatch. The whole purpose is just + to ensure typing._type_check does not error if the type hint evaluates to `InitVar[]`. + """ + raise TypeError("'InitVar' object is not callable") + + dataclasses.InitVar.__call__ = _call_initvar + + +def rebuild_dataclass( + cls: type[PydanticDataclass], + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: MappingNamespace | None = None, +) -> bool | None: + """Try to rebuild the pydantic-core schema for the dataclass. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + This is analogous to `BaseModel.model_rebuild`. + + Args: + cls: The class to rebuild the pydantic-core schema for. + force: Whether to force the rebuilding of the schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: The depth level of the parent namespace, defaults to 2. + _types_namespace: The types namespace, defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + if not force and cls.__pydantic_complete__: + return None + + for attr in ('__pydantic_core_schema__', '__pydantic_validator__', '__pydantic_serializer__'): + if attr in cls.__dict__ and not isinstance(getattr(cls, attr), _mock_val_ser.MockValSer): + # Deleting the validator/serializer is necessary as otherwise they can get reused in + # pydantic-core. Same applies for the core schema that can be reused in schema generation. + delattr(cls, attr) + + cls.__pydantic_complete__ = False + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + ns_resolver = _namespace_utils.NsResolver( + parent_namespace=rebuild_ns, + ) + + return _pydantic_dataclasses.complete_dataclass( + cls, + _config.ConfigWrapper(cls.__pydantic_config__, check=False), + raise_errors=raise_errors, + ns_resolver=ns_resolver, + # We could provide a different config instead (with `'defer_build'` set to `True`) + # of this explicit `_force_build` argument, but because config can come from the + # decorator parameter or the `__pydantic_config__` attribute, `complete_dataclass` + # will overwrite `__pydantic_config__` with the provided config above: + _force_build=True, + ) + + +def is_pydantic_dataclass(class_: type[Any], /) -> TypeGuard[type[PydanticDataclass]]: + """Whether a class is a pydantic dataclass. + + Args: + class_: The class. + + Returns: + `True` if the class is a pydantic dataclass, `False` otherwise. + """ + try: + return '__is_pydantic_dataclass__' in class_.__dict__ and dataclasses.is_dataclass(class_) + except AttributeError: + return False diff --git a/backend/venv/Lib/site-packages/pydantic/datetime_parse.py b/backend/venv/Lib/site-packages/pydantic/datetime_parse.py new file mode 100644 index 0000000..53d5264 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/datetime_parse.py @@ -0,0 +1,5 @@ +"""The `datetime_parse` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/decorator.py b/backend/venv/Lib/site-packages/pydantic/decorator.py new file mode 100644 index 0000000..0d97560 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/decorator.py @@ -0,0 +1,5 @@ +"""The `decorator` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__init__.py b/backend/venv/Lib/site-packages/pydantic/deprecated/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c22a3b32a4a8764089b1ce22c4355988e84b26d7 GIT binary patch literal 196 zcmX@j%ge<81flDKGC}lX5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!N_Mu2DJaTMFG|eK z&CE-WDbLSO&d<$FElN&}&&(@J%`3?-s*FiWOwLZtONjyU%VK;olVXZ9OHy?UfTD@% zsl_n`l_`mNC7H?kDX9fTsmX~YsVVyLK<$|&@$q^EmA5!-a`RJ4b5iY!Sb=sj0&y{j O@sXL4k+Fyw$N~V4r#Bq{ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/class_validators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/class_validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9763ae73f3339845b58c1d162b744e0524479770 GIT binary patch literal 11754 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/config.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38ad34e29014545b3315bfd3fab1ea5c9846d072 GIT binary patch literal 4073 zcmb7HU2GKB6~1?V_RqU`y*B1QjKQhBO}ZG91UDri#u!QhF2Yb?F&f4@*JhpBS@+J^ z#w$~yl&J8~hDxn?AeACD4w^* zOw8z2V#ZkGUD_xHVbWZ3hTL|J(3>l0Hwwf~aKja=o+#G|qYbfpElHwhzIYLcvE$|k+4WMzn1@shf~{upzOoMkvpuChva z2!n*(r7H`QUd1{?H-UCpa@C4~j8*Uu^zm8eBT{eobyr{u_23LCnUMy` zPU6Oc+3ke4U6$R(pl{L{GL{T_wdXBB+>CsS{93t7ed~<;fn<`)@{i>yIz=wYXUP;z z%LAo^J3Y>{;_w*Dxmri5xkI~XIGSD54AXZyQ|Z}M`gZ$lYS*>C#dym{$F3jyxZ~mG z*Jn4sKELHrb2o`i~|I%inUo4TkTK6_A8)MX@dr&7e4l*{ft#3aL5D+k>If zJGETY@{U&9$c%Q%VVZl9X%~WR&iFZZFrRZTXnEUlnPFxi*(1mTqi|kNrE!Jc=t>v7 z?5FjKOo2?5Yh;9)($#oYF;$_)wSQVXQ?ujoxuPfFL78S*nYN3+M@9$=(SVE& zT$Uk|UVlL_I;g3}enDh{wnf(P+eq3{n}ir>jnI< z?GaIN-G;8eCc7RlHn%+@QljS{t?i!<-fsTQnYq@?{l0Q? z?~)4Ee=mh$=@X{|Uj37vedLeP17Z0=sHInv9&DzlYukJGs}J_e2PFB=k_whw<;s8+ zgy1Ja9?=yJ3Zl-fj;?hPx=7EWt$6`fF&AJ0&KI^{MlE#>Z}4 z^9l$!wZ%yCqr~;ZFGnA??w)PkJ-?@aK5}TWvE};IY-8taWB2VhK$IihJ~h4si-2*F zxdi)i4Kz;~DB29Z1&Nrqq1b`uu&$fM9AFd?#4#){Q9)UbS(dKfp?>(d_wV>%!)+4` zhie>k`1mSWRunbzbv&l_e6vwf_bd|-empoGh&EcNmOEgmwkp$VV0wyaCBdu|m{k_c zs=%4ZaEFMZOVm#FVvR#8Jhm4mID0?rgN4@OKmtC|Y* zWYJTzAu|L$6?@a+bcAD3&A$txl&t(GIafK~^Za{gZmODnICY%oZ$54J;ns0};JK6* zj=e@*ulq{``Hg;s6G3YJMr}o#2nNLg_&Io4d`OleWc#^a@f_Y88SqGRi+rj^D z9RC5qU6;2ZEo{T`FHNiz#HERp1<3$!LU!~EMZrh{8{%tr;(#a<@e94kKELXGn;(KM zqRF`d0t#A6KO@~=kjB4}%q+=#NjkqI+dm^+e-F1Tg~;YTWu^7=*!C;o)lit`=nZ$3 z;B&c!Nbz!fpnR6kQ)g9LPxq9!ys}E*xgrzErAug9?TXT_8!f8@9?KhH#e#CQe0qFU YmLzF4B-8Ybu~h<(l`t5V(I6uJ4{{*4l>h($ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/copy_internals.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/copy_internals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eec6695efba04195aaf69c4627eaf15107ce1389 GIT binary patch literal 8660 zcmb6;TWlLwc6WwD&hY(|sE1`s*25k-mY-`ou^n5IEx%&LiJiEX?a&lwq)_HVxkFi& zGeneauqF$mmNw~10RpUo_CtZ)t{3P>ivBpsqRFNo6LSK`HQ5YSdmj9DNXa>E61SC)~ z6sHDgiokTtG+=_KDaORj17@v{iCN<80IR{~m?_Q;a3x&pfK{*vY|Iw757^_50Y}_9 z;G~df8d+mZSb5^3fXl_)anFDU=q-XZ=8gLXd~yGPA7}z1NB)LP^*}OE13aFp&>D~! z6zc$oCO85u&?W48n#{S=z^Xh2n_$1~xJBzd1C4@nV2$7sn*{eh=o0NCZ|Q>s0jNF-C?R5Y28`k~DUqBt5!j!po~98QeI;c4nlO#FeI z8gEklp?FddW1$G(r|?*W5US2lYGO2+7!HY7Q#hLQ~N%j!PBw0^(OxV=N@CU?^sF-1{?zPJvd z3ouifOIu~@i1rpgPB}^4@XK8FvA5|PEewj7($+L5GltBk8QJva!Jod96gd;EjJOS` z@~pm3fih;5O#*eBzGc!W(x#Nxpp}tqk{Q{2+jOg>i_$jPHhEsAq;oPYot4efOR_~e zEwj=KFpJNit2}?~G!KIgdmU!|6+J`$!fb|{1RjA3tpVZn)%$-M?+GF$wJFe~dZ{KQ zu;21sBq#x;?QkDYrZE{OsnIy9uXeKWr=L*TnK+UP8Y}+k^tVd8eT+wy6aKN2GIcj-#ul zb7-9UThlnjoBPjz>9B&<7O^BoQeZpSXd)6D6GW92uj+ua1cb&Cpx1d;WmCxzQR^x< zI1vgH4ULI7;TlraLZx~P5M(i|pzV1-CYn;Uy&R5>iN{i69CUnK#KR(( zuF&X&5Kg3`ksFYIeQ7MGQ*T$k)6jZjfNR>MwP8`NKiB+?k?Qedz(lk$kzbX%tWsB0M>rNsj*Ei6P^ZQi%yH?M z^=9e#F%eGHsvQAASIrs-rXLPoqbK^gd3E_N+WX9fQJfsc;dmTu_J#3eGLnqL*+#@r zG;sx%ox~Ft2E&odVnVn8?JF0aiw<6p;Dk4iLT`9jlr9)Iutg9@u^54)6}Av}12}-7 zB*HPNYZO)#0wRoe!8*WaMbaB!2mb^8X%ZFd5a-UZ4flO@d0(sIYt8$3#m5&qI`bXR zDjm<}I}RxwhZZ~f79E$Aj=pz=+3=kAvzCA1f6pt&Lzx$*s2S_DHG3h~(Ra^rDK{8h zHqm}thAnbc`QC2(&E^j_f5_zboKp6j%DwpVLg(4sxl6g&XwJtk_+HDf5B%%rcHRlz z-HTA`a-ZVAM8?sUHRZnCAf1TxGV42m2>PWaIU322XcE(ywjHtv@3!3Ibr_DVqj

        HUg{Mc{O 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/decorator.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/decorator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f349502b3f32ac7a0c3ad87a01b4670eff60dfff GIT binary patch literal 14024 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�*j9~t>3Azk`NtM%$j(v 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/json.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/json.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6625e1f925766c84b7e46d9a816c9b483339b185 GIT binary patch literal 6172 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/parse.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/parse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c3cc8554fd879862d80d4e769f2633eb91fc964 GIT binary patch literal 3402 zcmb_e-ESMm5#RgZ@yI)pBK2YG!xF8wiJ90^5Xp%x*9H`QSV?QevFxO!WzZ+y$)R+- zWA{#yNt^&BFi;D5umu>9f~G(V6sQdutsnD0^r5t+AoN8>Q^a`)`a;)!(o<*mc%tlD zEl_j`&d$y5&g{<4Z+89?iG&ff3x7J7`)dfH@5qPWf*!*>9b*t$MJiGm9p#xc!w{a; z*)&UgF3r)NPxH`odLS>P1v-b-J}yN(xR%QvUlZm)|08M8i9XQV`pCRH(&47 z*cX8i+Uut_stwnK_1g4w6V)F7ziDq$6T7rG7ui(v55!iAaV5ntOk1&YreTf4H$P&` zMn!O$3|u6e=8Ig4cg3^Vw9Txk zyZnr08m>^tWoLD5JQZ-oOvX_1S|;O$Gnu@p&gq1gGnrq_DY`d;qo5hbfZRb(fuilp zLj#iqY+k`iKA$tLOfHz9JfGKaR?Fm!dCjm*T%4Rzva_0@PQv&6z`oY<~>R)Iu4?cbdxBwV+1;x4YartR#&= z4!1PwFnHKuW@;eyMm(zW>ovWYG2V1|+`Y%Vz|Oq5E&3W}XhQJ6ync~0qBe0YZK~if zzd^rc{nei`4tJHY8W^-o3kiT1+9Kz0|9QsjA-JQI9rqVH$WHjY4|W`P&`h&0t@qB( zeijjnoPdM;{Y`+scG-Q&`KaAthqokqpRZ93`s+Vs{>zS72N^NgRja?Y-usDVQLrUn zI@9KJ_1+PDYZGXfr$vW*-qWejIBtPun4IDci^+D~uw?^6bZuVKQ!IrZ1fVjnSXrDa z*c67PmJ7zLVJ;ZSS{NT8VLXs5^`FN@2;-z}0t6tWwd6w1{y6EyvB&R@?31I4ZfT{2 zuZ;#jWQl=fD(Z?03N}EQIvhLwr?S5!d!_G<07dd>Ct8JNVgR zS?s8UqPGsM_OA3k2pxPFYu`$Amb)%&Bt9(5A8sW&);{<{U^DT`@&~sE|2%eQZ2i6K z>{hJ#hO_Lfy|WSPDvMo@qx;Hjhi_lFeY(8Aem$yiE zpm{3+ndN`aTlP-2s-tre0dk=9c(K)y<1kC7V9rZ$tMc;*$8D19X`6Xz)-k&FSRJ6a zZ`ifI!Pivp7dgAp|8fL}a~OwpcqedISQk9`1WEwi7ocd^ z6AJh+X#008geVrs<>P*saDq%K0(lMwJ)6hRl{1&W;*~8ac9Z{X03K9Pz7boFZHTQ) zgOy-oIoMv2VmD4KpD4Gzc3*mppy15PndOm6B!1)K^2N2$2a)a?G_H?4mRc)f=w|cp zCchjjPh`sa{4XIv9&7OlyMdA|d_CZ&wSs_)J=g^}d^%Bfm zgriyJZNky(J4QH?Z}4$K1_+_*T1a^`JqP-sJi_Gdu2)6$wq0I>iVu@F-VKub({oea zy$g_>A&+7bU{o0<0CeM?IHO&KLc}6JXo&+t#S;*JVM>yA?X_w`3A)vq2@Vl0U9AwN(xrth9DkUVZ(K zrQesH#5$R`D#1jRgC3ML9;gNhC!$!Q8X{a6$?a8%a58G#SB(%ZisC=1l9km4B!vDM z2kt3{*i%&&xF_#0)as#o{hQ3OJ*+k{LM7Z(<)E)wC7frKaGq7dc~%MMStXoj6*yw` L_!Aa5>d1cqL3j2$ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/tools.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/deprecated/__pycache__/tools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf6dfd753618cdc9eebdae61053b3ac3dfab6ffc GIT binary patch literal 3538 zcmb_e-ESMm5#Rgdk$3#kw`|!xxpitbv7AUQiW-Jfmyy$|lA>5tg3vNfC*De?a=at< zPD&`SfZPUXi~_OV5}*J zC_pdRVnr%S6}c!^V#QcRDJqqCF&^5AcA}ydRnR3%wzW#Kn5?9Vsc;;#)0Ipy6Y7dB zRIBJXr+qX=`>8w(39WLpZ-qxKlEnd@P{m5zg&eUJ2VtyQs>R>a z?()$ytIz7UlJ7}(qai5{g*K@tY+C=QsZ+&pJQe@E>KO!aedP-yN)-TlY(U7t+`1f|C7o5&we`lY9L&6YJrkBZQES7 zX%H*as`L$$1=4~8D`0)XqE$vqrcbTU@#S-T(D%yZrHc#G1>^GMC8IDoGdF#)Fd6i` zN*&6;Zpw3=`O-C7F)=(kyl9zKpE4K@&($o`@yn%GI$r0?PKl1cm=gl6YBG-+?(&*p zdO_R^eHiXakZP%G;2FnU;o$Y9ZsR4r?CFPzj_C^?)t9QRSYur|jBS{9*@7&MYR$jq zI-_ke!0Bx$3f7Nobubb`tzy%qi~JtJ{*tXm=&tSenJPw^z>eKZ?x{Xy6rlvU{zuicFWU!TB*9sWHr6w zTGaOLaBL7l<>Wwl$7D{~S@i-DHI~8*dfF!s@Om?vXHX_ckbdf901#4`T_6A=f_NuW z54Tj;^@FASxy34TS0V2TgjsyYbxUrgLRpC#WoLsrJ{;xZGQ2Q#tVI}aEKZk~7rnAi zPgmioxk|moHb~AK!sm?dy0$k~t+6yj3dIpnyjc)ikrgppQ@+ttEX?59;o9x;`lyz zBnMMV9jJc|Actg#79N7Qa7Tn)EBioYWw~Ym)`3YHqbmj;lMM$JWLm*iBf7e*)CM#H zw*&Tn!Qh*N-H+j$Ve0~H2gK1#ILp_?x^PcyL;dGcox6U)??AiG`C8k$U3*!q&ebJL zI*;C^`L80R>?7{N2BeC$BXNW$;HN{UZjU)-bG}{8bW@+2e{EKec1=HJLZK;_{G7hx zGTjFTRZY*MRs?<>o>?`ZQ@I2cwWhcB7^Yo^jaACSnNYad5ID{$4DUFGP!6dW(N68cQIIG@ zWGE3(kpsc=89Ry#Wp)hLV0KZ)VX~NZATa8AShRqT(3p-knYK6$iuY>}z?vf+))cx} z1H@1Vw&{b!$ft=@_Ymfo6roFvKqn=?0N8X0RhbE0u{1ZbB`?Ip;_=&kEjE-aWw~#5o|C+y4b9{|^qWDd6a-*2NLTF<%$zBJc?L3vGof12=xheZav* zAblyC5#8Si&3L+pXlCDrAwcCxj0GZYa3ERhm8us47 z_a;FAtVTMpdh1D8X_=enZk*dyvfC#=TEG47AMG8w{)w`&CkUGSC^4`nLEj{TB!_^= zakIb=g!yI+FPbZbtL!+8815(g7KnqMS-2iAnI*hb^twI^j1FW*{dKt6dcYv3MKlRl zgj^ZNwI@LY;xgPQ5yzj$hsd3Sp)gRp&P;W_ny#`5nBGibnYjWad_jkAw5z$)Gu^YZ z=rbf`$2s|awq`wgkil7G<-M1jK2HALKBr7tS3RtfQ!k7;FwP!qG_OZ z?QXc8(cK%C5>KHrttdmE`w|e9LGH*Cq5(UUr73|%Zl=iS z$wvQhW9Ws(OZmOzF)j_Yrzt=W324WgG1L^2?rp|VOOW1yriz+I2G2Cn9$d(MU!*~6 zg#m5vM{sFD8Vk>g)5FPO9OzqdP>bTA7R5m=ii28;^ba-DsAY&8{~`-o7;#SlE!^{e E1K{~v!T Any: ... + + class _V1ValidatorWithValuesClsMethod(Protocol): + def __call__(self, __cls: Any, __value: Any, values: dict[str, Any]) -> Any: ... + + class _V1ValidatorWithValuesKwOnlyClsMethod(Protocol): + def __call__(self, __cls: Any, __value: Any, *, values: dict[str, Any]) -> Any: ... + + class _V1ValidatorWithKwargsClsMethod(Protocol): + def __call__(self, __cls: Any, **kwargs: Any) -> Any: ... + + class _V1ValidatorWithValuesAndKwargsClsMethod(Protocol): + def __call__(self, __cls: Any, values: dict[str, Any], **kwargs: Any) -> Any: ... + + class _V1RootValidatorClsMethod(Protocol): + def __call__( + self, __cls: Any, __values: _decorators_v1.RootValidatorValues + ) -> _decorators_v1.RootValidatorValues: ... + + V1Validator = Union[ + _OnlyValueValidatorClsMethod, + _V1ValidatorWithValuesClsMethod, + _V1ValidatorWithValuesKwOnlyClsMethod, + _V1ValidatorWithKwargsClsMethod, + _V1ValidatorWithValuesAndKwargsClsMethod, + _decorators_v1.V1ValidatorWithValues, + _decorators_v1.V1ValidatorWithValuesKwOnly, + _decorators_v1.V1ValidatorWithKwargs, + _decorators_v1.V1ValidatorWithValuesAndKwargs, + ] + + V1RootValidator = Union[ + _V1RootValidatorClsMethod, + _decorators_v1.V1RootValidatorFunction, + ] + + _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] + + # Allow both a V1 (assumed pre=False) or V2 (assumed mode='after') validator + # We lie to type checkers and say we return the same thing we get + # but in reality we return a proxy object that _mostly_ behaves like the wrapped thing + _V1ValidatorType = TypeVar('_V1ValidatorType', V1Validator, _PartialClsOrStaticMethod) + _V1RootValidatorFunctionType = TypeVar( + '_V1RootValidatorFunctionType', + _decorators_v1.V1RootValidatorFunction, + _V1RootValidatorClsMethod, + _PartialClsOrStaticMethod, + ) +else: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + + +@deprecated( + 'Pydantic V1 style `@validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@field_validator` validators,' + ' see the migration guide for more details', + category=None, +) +def validator( + __field: str, + *fields: str, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool | None = None, + allow_reuse: bool = False, +) -> Callable[[_V1ValidatorType], _V1ValidatorType]: + """Decorate methods on the class indicating that they should be used to validate fields. + + Args: + __field (str): The first field the validator should be called on; this is separate + from `fields` to ensure an error is raised if you don't pass at least one. + *fields (str): Additional field(s) the validator should be called on. + pre (bool, optional): Whether this validator should be called before the standard + validators (else after). Defaults to False. + each_item (bool, optional): For complex objects (sets, lists etc.) whether to validate + individual elements rather than the whole object. Defaults to False. + always (bool, optional): Whether this method and other validators should be called even if + the value is missing. Defaults to False. + check_fields (bool | None, optional): Whether to check that the fields actually exist on the model. + Defaults to None. + allow_reuse (bool, optional): Whether to track and raise an error if another validator refers to + the decorated function. Defaults to False. + + Returns: + Callable: A decorator that can be used to decorate a + function to be used as a validator. + """ + warn( + 'Pydantic V1 style `@validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@field_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) + + if allow_reuse is True: # pragma: no cover + warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2) + fields = __field, *fields + if isinstance(fields[0], FunctionType): + raise PydanticUserError( + '`@validator` should be used with fields and keyword arguments, not bare. ' + "E.g. usage should be `@validator('', ...)`", + code='validator-no-fields', + ) + elif not all(isinstance(field, str) for field in fields): + raise PydanticUserError( + '`@validator` fields should be passed as separate string args. ' + "E.g. usage should be `@validator('', '', ...)`", + code='validator-invalid-fields', + ) + + mode: Literal['before', 'after'] = 'before' if pre is True else 'after' + + def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: + if _decorators.is_instance_method_from_sig(f): + raise PydanticUserError( + '`@validator` cannot be applied to instance methods', code='validator-instance-method' + ) + # auto apply the @classmethod decorator + f = _decorators.ensure_classmethod_based_on_signature(f) + wrap = _decorators_v1.make_generic_v1_field_validator + validator_wrapper_info = _decorators.ValidatorDecoratorInfo( + fields=fields, + mode=mode, + each_item=each_item, + always=always, + check_fields=check_fields, + ) + return _decorators.PydanticDescriptorProxy(f, validator_wrapper_info, shim=wrap) + + return dec # type: ignore[return-value] + + +@overload +def root_validator( + *, + # if you don't specify `pre` the default is `pre=False` + # which means you need to specify `skip_on_failure=True` + skip_on_failure: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@overload +def root_validator( + *, + # if you specify `pre=True` then you don't need to specify + # `skip_on_failure`, in fact it is not allowed as an argument! + pre: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@overload +def root_validator( + *, + # if you explicitly specify `pre=False` then you + # MUST specify `skip_on_failure=True` + pre: Literal[False], + skip_on_failure: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@deprecated( + 'Pydantic V1 style `@root_validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@model_validator` validators,' + ' see the migration guide for more details', + category=None, +) +def root_validator( + *__args, + pre: bool = False, + skip_on_failure: bool = False, + allow_reuse: bool = False, +) -> Any: + """Decorate methods on a model indicating that they should be used to validate (and perhaps + modify) data either before or after standard model parsing/validation is performed. + + Args: + pre (bool, optional): Whether this validator should be called before the standard + validators (else after). Defaults to False. + skip_on_failure (bool, optional): Whether to stop validation and return as soon as a + failure is encountered. Defaults to False. + allow_reuse (bool, optional): Whether to track and raise an error if another validator + refers to the decorated function. Defaults to False. + + Returns: + Any: A decorator that can be used to decorate a function to be used as a root_validator. + """ + warn( + 'Pydantic V1 style `@root_validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@model_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) + + if __args: + # Ensure a nice error is raised if someone attempts to use the bare decorator + return root_validator()(*__args) # type: ignore + + if allow_reuse is True: # pragma: no cover + warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2) + mode: Literal['before', 'after'] = 'before' if pre is True else 'after' + if pre is False and skip_on_failure is not True: + raise PydanticUserError( + 'If you use `@root_validator` with pre=False (the default) you MUST specify `skip_on_failure=True`.' + ' Note that `@root_validator` is deprecated and should be replaced with `@model_validator`.', + code='root-validator-pre-skip', + ) + + wrap = partial(_decorators_v1.make_v1_generic_root_validator, pre=pre) + + def dec(f: Callable[..., Any] | classmethod[Any, Any, Any] | staticmethod[Any, Any]) -> Any: + if _decorators.is_instance_method_from_sig(f): + raise TypeError('`@root_validator` cannot be applied to instance methods') + # auto apply the @classmethod decorator + res = _decorators.ensure_classmethod_based_on_signature(f) + dec_info = _decorators.RootValidatorDecoratorInfo(mode=mode) + return _decorators.PydanticDescriptorProxy(res, dec_info, shim=wrap) + + return dec diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/config.py b/backend/venv/Lib/site-packages/pydantic/deprecated/config.py new file mode 100644 index 0000000..bd4692a --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/config.py @@ -0,0 +1,72 @@ +from __future__ import annotations as _annotations + +import warnings +from typing import TYPE_CHECKING, Any, Literal + +from typing_extensions import deprecated + +from .._internal import _config +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'BaseConfig', 'Extra' + + +class _ConfigMetaclass(type): + def __getattr__(self, item: str) -> Any: + try: + obj = _config.config_defaults[item] + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return obj + except KeyError as exc: + raise AttributeError(f"type object '{self.__name__}' has no attribute {exc}") from exc + + +@deprecated('BaseConfig is deprecated. Use the `pydantic.ConfigDict` instead.', category=PydanticDeprecatedSince20) +class BaseConfig(metaclass=_ConfigMetaclass): + """This class is only retained for backwards compatibility. + + !!! Warning "Deprecated" + BaseConfig is deprecated. Use the [`pydantic.ConfigDict`][pydantic.ConfigDict] instead. + """ + + def __getattr__(self, item: str) -> Any: + try: + obj = super().__getattribute__(item) + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return obj + except AttributeError as exc: + try: + return getattr(type(self), item) + except AttributeError: + # re-raising changes the displayed text to reflect that `self` is not a type + raise AttributeError(str(exc)) from exc + + def __init_subclass__(cls, **kwargs: Any) -> None: + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return super().__init_subclass__(**kwargs) + + +class _ExtraMeta(type): + def __getattribute__(self, __name: str) -> Any: + # The @deprecated decorator accesses other attributes, so we only emit a warning for the expected ones + if __name in {'allow', 'ignore', 'forbid'}: + warnings.warn( + "`pydantic.config.Extra` is deprecated, use literal values instead (e.g. `extra='allow'`)", + DeprecationWarning, + stacklevel=2, + ) + return super().__getattribute__(__name) + + +@deprecated( + "Extra is deprecated. Use literal values instead (e.g. `extra='allow'`)", category=PydanticDeprecatedSince20 +) +class Extra(metaclass=_ExtraMeta): + allow: Literal['allow'] = 'allow' + ignore: Literal['ignore'] = 'ignore' + forbid: Literal['forbid'] = 'forbid' diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/copy_internals.py b/backend/venv/Lib/site-packages/pydantic/deprecated/copy_internals.py new file mode 100644 index 0000000..0170dc0 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/copy_internals.py @@ -0,0 +1,224 @@ +from __future__ import annotations as _annotations + +import typing +from copy import deepcopy +from enum import Enum +from typing import Any + +import typing_extensions + +from .._internal import ( + _model_construction, + _typing_extra, + _utils, +) + +if typing.TYPE_CHECKING: + from .. import BaseModel + from .._internal._utils import AbstractSetIntStr, MappingIntStrAny + + AnyClassMethod = classmethod[Any, Any, Any] + TupleGenerator = typing.Generator[tuple[str, Any], None, None] + Model = typing.TypeVar('Model', bound='BaseModel') + # should be `set[int] | set[str] | dict[int, IncEx] | dict[str, IncEx] | None`, but mypy can't cope + IncEx: typing_extensions.TypeAlias = 'set[int] | set[str] | dict[int, Any] | dict[str, Any] | None' + +_object_setattr = _model_construction.object_setattr + + +def _iter( + self: BaseModel, + to_dict: bool = False, + by_alias: bool = False, + include: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, +) -> TupleGenerator: + # Merge field set excludes with explicit exclude parameter with explicit overriding field set options. + # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case. + if exclude is not None: + exclude = _utils.ValueItems.merge( + {k: v.exclude for k, v in self.__pydantic_fields__.items() if v.exclude is not None}, exclude + ) + + if include is not None: + include = _utils.ValueItems.merge(dict.fromkeys(self.__pydantic_fields__, True), include, intersect=True) + + allowed_keys = _calculate_keys(self, include=include, exclude=exclude, exclude_unset=exclude_unset) # type: ignore + if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): + # huge boost for plain _iter() + yield from self.__dict__.items() + if self.__pydantic_extra__: + yield from self.__pydantic_extra__.items() + return + + value_exclude = _utils.ValueItems(self, exclude) if exclude is not None else None + value_include = _utils.ValueItems(self, include) if include is not None else None + + if self.__pydantic_extra__ is None: + items = self.__dict__.items() + else: + items = list(self.__dict__.items()) + list(self.__pydantic_extra__.items()) + + for field_key, v in items: + if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): + continue + + if exclude_defaults: + try: + field = self.__pydantic_fields__[field_key] + except KeyError: + pass + else: + if not field.is_required() and field.default == v: + continue + + if by_alias and field_key in self.__pydantic_fields__: + dict_key = self.__pydantic_fields__[field_key].alias or field_key + else: + dict_key = field_key + + if to_dict or value_include or value_exclude: + v = _get_value( + type(self), + v, + to_dict=to_dict, + by_alias=by_alias, + include=value_include and value_include.for_element(field_key), + exclude=value_exclude and value_exclude.for_element(field_key), + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + yield dict_key, v + + +def _copy_and_set_values( + self: Model, + values: dict[str, Any], + fields_set: set[str], + extra: dict[str, Any] | None = None, + private: dict[str, Any] | None = None, + *, + deep: bool, # UP006 +) -> Model: + if deep: + # chances of having empty dict here are quite low for using smart_deepcopy + values = deepcopy(values) + extra = deepcopy(extra) + private = deepcopy(private) + + cls = self.__class__ + m = cls.__new__(cls) + _object_setattr(m, '__dict__', values) + _object_setattr(m, '__pydantic_extra__', extra) + _object_setattr(m, '__pydantic_fields_set__', fields_set) + _object_setattr(m, '__pydantic_private__', private) + + return m + + +@typing.no_type_check +def _get_value( + cls: type[BaseModel], + v: Any, + to_dict: bool, + by_alias: bool, + include: AbstractSetIntStr | MappingIntStrAny | None, + exclude: AbstractSetIntStr | MappingIntStrAny | None, + exclude_unset: bool, + exclude_defaults: bool, + exclude_none: bool, +) -> Any: + from .. import BaseModel + + if isinstance(v, BaseModel): + if to_dict: + return v.model_dump( + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=include, # type: ignore + exclude=exclude, # type: ignore + exclude_none=exclude_none, + ) + else: + return v.copy(include=include, exclude=exclude) + + value_exclude = _utils.ValueItems(v, exclude) if exclude else None + value_include = _utils.ValueItems(v, include) if include else None + + if isinstance(v, dict): + return { + k_: _get_value( + cls, + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(k_), + exclude=value_exclude and value_exclude.for_element(k_), + exclude_none=exclude_none, + ) + for k_, v_ in v.items() + if (not value_exclude or not value_exclude.is_excluded(k_)) + and (not value_include or value_include.is_included(k_)) + } + + elif _utils.sequence_like(v): + seq_args = ( + _get_value( + cls, + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(i), + exclude=value_exclude and value_exclude.for_element(i), + exclude_none=exclude_none, + ) + for i, v_ in enumerate(v) + if (not value_exclude or not value_exclude.is_excluded(i)) + and (not value_include or value_include.is_included(i)) + ) + + return v.__class__(*seq_args) if _typing_extra.is_namedtuple(v.__class__) else v.__class__(seq_args) + + elif isinstance(v, Enum) and getattr(cls.model_config, 'use_enum_values', False): + return v.value + + else: + return v + + +def _calculate_keys( + self: BaseModel, + include: MappingIntStrAny | None, + exclude: MappingIntStrAny | None, + exclude_unset: bool, + update: dict[str, Any] | None = None, # noqa UP006 +) -> typing.AbstractSet[str] | None: + if include is None and exclude is None and exclude_unset is False: + return None + + keys: typing.AbstractSet[str] + if exclude_unset: + keys = self.__pydantic_fields_set__.copy() + else: + keys = set(self.__dict__.keys()) + keys = keys | (self.__pydantic_extra__ or {}).keys() + + if include is not None: + keys &= include.keys() + + if update: + keys -= update.keys() + + if exclude: + keys -= {k for k, v in exclude.items() if _utils.ValueItems.is_true(v)} + + return keys diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/decorator.py b/backend/venv/Lib/site-packages/pydantic/deprecated/decorator.py new file mode 100644 index 0000000..e73ad20 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/decorator.py @@ -0,0 +1,284 @@ +import warnings +from collections.abc import Mapping +from functools import wraps +from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, overload + +from typing_extensions import deprecated + +from .._internal import _config, _typing_extra +from ..alias_generators import to_pascal +from ..errors import PydanticUserError +from ..functional_validators import field_validator +from ..main import BaseModel, create_model +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = ('validate_arguments',) + +if TYPE_CHECKING: + AnyCallable = Callable[..., Any] + + AnyCallableT = TypeVar('AnyCallableT', bound=AnyCallable) + ConfigType = Union[None, type[Any], dict[str, Any]] + + +@overload +def validate_arguments( + func: None = None, *, config: 'ConfigType' = None +) -> Callable[['AnyCallableT'], 'AnyCallableT']: ... + + +@overload +def validate_arguments(func: 'AnyCallableT') -> 'AnyCallableT': ... + + +@deprecated( + 'The `validate_arguments` method is deprecated; use `validate_call` instead.', + category=None, +) +def validate_arguments(func: Optional['AnyCallableT'] = None, *, config: 'ConfigType' = None) -> Any: + """Decorator to validate the arguments passed to a function.""" + warnings.warn( + 'The `validate_arguments` method is deprecated; use `validate_call` instead.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + def validate(_func: 'AnyCallable') -> 'AnyCallable': + vd = ValidatedFunction(_func, config) + + @wraps(_func) + def wrapper_function(*args: Any, **kwargs: Any) -> Any: + return vd.call(*args, **kwargs) + + wrapper_function.vd = vd # type: ignore + wrapper_function.validate = vd.init_model_instance # type: ignore + wrapper_function.raw_function = vd.raw_function # type: ignore + wrapper_function.model = vd.model # type: ignore + return wrapper_function + + if func: + return validate(func) + else: + return validate + + +ALT_V_ARGS = 'v__args' +ALT_V_KWARGS = 'v__kwargs' +V_POSITIONAL_ONLY_NAME = 'v__positional_only' +V_DUPLICATE_KWARGS = 'v__duplicate_kwargs' + + +class ValidatedFunction: + def __init__(self, function: 'AnyCallable', config: 'ConfigType'): + from inspect import Parameter, signature + + parameters: Mapping[str, Parameter] = signature(function).parameters + + if parameters.keys() & {ALT_V_ARGS, ALT_V_KWARGS, V_POSITIONAL_ONLY_NAME, V_DUPLICATE_KWARGS}: + raise PydanticUserError( + f'"{ALT_V_ARGS}", "{ALT_V_KWARGS}", "{V_POSITIONAL_ONLY_NAME}" and "{V_DUPLICATE_KWARGS}" ' + f'are not permitted as argument names when using the "{validate_arguments.__name__}" decorator', + code=None, + ) + + self.raw_function = function + self.arg_mapping: dict[int, str] = {} + self.positional_only_args: set[str] = set() + self.v_args_name = 'args' + self.v_kwargs_name = 'kwargs' + + type_hints = _typing_extra.get_type_hints(function, include_extras=True) + takes_args = False + takes_kwargs = False + fields: dict[str, tuple[Any, Any]] = {} + for i, (name, p) in enumerate(parameters.items()): + if p.annotation is p.empty: + annotation = Any + else: + annotation = type_hints[name] + + default = ... if p.default is p.empty else p.default + if p.kind == Parameter.POSITIONAL_ONLY: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_POSITIONAL_ONLY_NAME] = list[str], None + self.positional_only_args.add(name) + elif p.kind == Parameter.POSITIONAL_OR_KEYWORD: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_DUPLICATE_KWARGS] = list[str], None + elif p.kind == Parameter.KEYWORD_ONLY: + fields[name] = annotation, default + elif p.kind == Parameter.VAR_POSITIONAL: + self.v_args_name = name + fields[name] = tuple[annotation, ...], None + takes_args = True + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + self.v_kwargs_name = name + fields[name] = dict[str, annotation], None + takes_kwargs = True + + # these checks avoid a clash between "args" and a field with that name + if not takes_args and self.v_args_name in fields: + self.v_args_name = ALT_V_ARGS + + # same with "kwargs" + if not takes_kwargs and self.v_kwargs_name in fields: + self.v_kwargs_name = ALT_V_KWARGS + + if not takes_args: + # we add the field so validation below can raise the correct exception + fields[self.v_args_name] = list[Any], None + + if not takes_kwargs: + # same with kwargs + fields[self.v_kwargs_name] = dict[Any, Any], None + + self.create_model(fields, takes_args, takes_kwargs, config) + + def init_model_instance(self, *args: Any, **kwargs: Any) -> BaseModel: + values = self.build_values(args, kwargs) + return self.model(**values) + + def call(self, *args: Any, **kwargs: Any) -> Any: + m = self.init_model_instance(*args, **kwargs) + return self.execute(m) + + def build_values(self, args: tuple[Any, ...], kwargs: dict[str, Any]) -> dict[str, Any]: + values: dict[str, Any] = {} + if args: + arg_iter = enumerate(args) + while True: + try: + i, a = next(arg_iter) + except StopIteration: + break + arg_name = self.arg_mapping.get(i) + if arg_name is not None: + values[arg_name] = a + else: + values[self.v_args_name] = [a] + [a for _, a in arg_iter] + break + + var_kwargs: dict[str, Any] = {} + wrong_positional_args = [] + duplicate_kwargs = [] + fields_alias = [ + field.alias + for name, field in self.model.__pydantic_fields__.items() + if name not in (self.v_args_name, self.v_kwargs_name) + ] + non_var_fields = set(self.model.__pydantic_fields__) - {self.v_args_name, self.v_kwargs_name} + for k, v in kwargs.items(): + if k in non_var_fields or k in fields_alias: + if k in self.positional_only_args: + wrong_positional_args.append(k) + if k in values: + duplicate_kwargs.append(k) + values[k] = v + else: + var_kwargs[k] = v + + if var_kwargs: + values[self.v_kwargs_name] = var_kwargs + if wrong_positional_args: + values[V_POSITIONAL_ONLY_NAME] = wrong_positional_args + if duplicate_kwargs: + values[V_DUPLICATE_KWARGS] = duplicate_kwargs + return values + + def execute(self, m: BaseModel) -> Any: + d = { + k: v + for k, v in m.__dict__.items() + if k in m.__pydantic_fields_set__ or m.__pydantic_fields__[k].default_factory + } + var_kwargs = d.pop(self.v_kwargs_name, {}) + + if self.v_args_name in d: + args_: list[Any] = [] + in_kwargs = False + kwargs = {} + for name, value in d.items(): + if in_kwargs: + kwargs[name] = value + elif name == self.v_args_name: + args_ += value + in_kwargs = True + else: + args_.append(value) + return self.raw_function(*args_, **kwargs, **var_kwargs) + elif self.positional_only_args: + args_ = [] + kwargs = {} + for name, value in d.items(): + if name in self.positional_only_args: + args_.append(value) + else: + kwargs[name] = value + return self.raw_function(*args_, **kwargs, **var_kwargs) + else: + return self.raw_function(**d, **var_kwargs) + + def create_model(self, fields: dict[str, Any], takes_args: bool, takes_kwargs: bool, config: 'ConfigType') -> None: + pos_args = len(self.arg_mapping) + + config_wrapper = _config.ConfigWrapper(config) + + if config_wrapper.alias_generator: + raise PydanticUserError( + 'Setting the "alias_generator" property on custom Config for ' + '@validate_arguments is not yet supported, please remove.', + code=None, + ) + if config_wrapper.extra is None: + config_wrapper.config_dict['extra'] = 'forbid' + + class DecoratorBaseModel(BaseModel): + @field_validator(self.v_args_name, check_fields=False) + @classmethod + def check_args(cls, v: Optional[list[Any]]) -> Optional[list[Any]]: + if takes_args or v is None: + return v + + raise TypeError(f'{pos_args} positional arguments expected but {pos_args + len(v)} given') + + @field_validator(self.v_kwargs_name, check_fields=False) + @classmethod + def check_kwargs(cls, v: Optional[dict[str, Any]]) -> Optional[dict[str, Any]]: + if takes_kwargs or v is None: + return v + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v.keys())) + raise TypeError(f'unexpected keyword argument{plural}: {keys}') + + @field_validator(V_POSITIONAL_ONLY_NAME, check_fields=False) + @classmethod + def check_positional_only(cls, v: Optional[list[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}') + + @field_validator(V_DUPLICATE_KWARGS, check_fields=False) + @classmethod + def check_duplicate_kwargs(cls, v: Optional[list[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'multiple values for argument{plural}: {keys}') + + model_config = config_wrapper.config_dict + + self.model = create_model(to_pascal(self.raw_function.__name__), __base__=DecoratorBaseModel, **fields) diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/json.py b/backend/venv/Lib/site-packages/pydantic/deprecated/json.py new file mode 100644 index 0000000..1e216a7 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/json.py @@ -0,0 +1,141 @@ +import datetime +import warnings +from collections import deque +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from re import Pattern +from types import GeneratorType +from typing import TYPE_CHECKING, Any, Callable, Union +from uuid import UUID + +from typing_extensions import deprecated + +from .._internal._import_utils import import_cached_base_model +from ..color import Color +from ..networks import NameEmail +from ..types import SecretBytes, SecretStr +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'pydantic_encoder', 'custom_pydantic_encoder', 'timedelta_isoformat' + + +def isoformat(o: Union[datetime.date, datetime.time]) -> str: + return o.isoformat() + + +def decimal_encoder(dec_value: Decimal) -> Union[int, float]: + """Encodes a Decimal as int of there's no exponent, otherwise float. + + This is useful when we use ConstrainedDecimal to represent Numeric(x,0) + where a 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 + """ + 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, + 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, +} + + +@deprecated( + '`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', + category=None, +) +def pydantic_encoder(obj: Any) -> Any: + warnings.warn( + '`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from dataclasses import asdict, is_dataclass + + BaseModel = import_cached_base_model() + + if isinstance(obj, BaseModel): + return obj.model_dump() + elif is_dataclass(obj): + return asdict(obj) # type: ignore + + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = ENCODERS_BY_TYPE[base] + except KeyError: + continue + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable") + + +# TODO: Add a suggested migration path once there is a way to use custom encoders +@deprecated( + '`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.', + category=None, +) +def custom_pydantic_encoder(type_encoders: dict[Any, Callable[[type[Any]], Any]], obj: Any) -> Any: + warnings.warn( + '`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = type_encoders[base] + except KeyError: + continue + + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + return pydantic_encoder(obj) + + +@deprecated('`timedelta_isoformat` is deprecated.', category=None) +def timedelta_isoformat(td: datetime.timedelta) -> str: + """ISO 8601 encoding for Python timedelta object.""" + warnings.warn('`timedelta_isoformat` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + minutes, seconds = divmod(td.seconds, 60) + hours, minutes = divmod(minutes, 60) + return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/parse.py b/backend/venv/Lib/site-packages/pydantic/deprecated/parse.py new file mode 100644 index 0000000..2a92e62 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/parse.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +import json +import pickle +import warnings +from enum import Enum +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable + +from typing_extensions import deprecated + +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + + +class Protocol(str, Enum): + json = 'json' + pickle = 'pickle' + + +@deprecated('`load_str_bytes` is deprecated.', category=None) +def load_str_bytes( + b: str | bytes, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: Protocol | None = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + warnings.warn('`load_str_bytes` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + if proto is None and content_type: + if content_type.endswith(('json', 'javascript')): + pass + elif allow_pickle and content_type.endswith('pickle'): + proto = Protocol.pickle + else: + raise TypeError(f'Unknown content-type: {content_type}') + + proto = proto or Protocol.json + + if proto == Protocol.json: + if isinstance(b, bytes): + b = b.decode(encoding) + return json_loads(b) # type: ignore + elif proto == Protocol.pickle: + if not allow_pickle: + raise RuntimeError('Trying to decode with pickle with allow_pickle=False') + bb = b if isinstance(b, bytes) else b.encode() # type: ignore + return pickle.loads(bb) + else: + raise TypeError(f'Unknown protocol: {proto}') + + +@deprecated('`load_file` is deprecated.', category=None) +def load_file( + path: str | Path, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: Protocol | None = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + warnings.warn('`load_file` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + path = Path(path) + b = path.read_bytes() + if content_type is None: + if path.suffix in ('.js', '.json'): + proto = Protocol.json + elif path.suffix == '.pkl': + proto = Protocol.pickle + + return load_str_bytes( + b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle, json_loads=json_loads + ) diff --git a/backend/venv/Lib/site-packages/pydantic/deprecated/tools.py b/backend/venv/Lib/site-packages/pydantic/deprecated/tools.py new file mode 100644 index 0000000..5ad7fae --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/deprecated/tools.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +import json +import warnings +from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union + +from typing_extensions import deprecated + +from ..json_schema import DEFAULT_REF_TEMPLATE, GenerateJsonSchema +from ..type_adapter import TypeAdapter +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'parse_obj_as', 'schema_of', 'schema_json_of' + +NameFactory = Union[str, Callable[[type[Any]], str]] + + +T = TypeVar('T') + + +@deprecated( + '`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', + category=None, +) +def parse_obj_as(type_: type[T], obj: Any, type_name: NameFactory | None = None) -> T: + warnings.warn( + '`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if type_name is not None: # pragma: no cover + warnings.warn( + 'The type_name parameter is deprecated. parse_obj_as no longer creates temporary models', + DeprecationWarning, + stacklevel=2, + ) + return TypeAdapter(type_).validate_python(obj) + + +@deprecated( + '`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=None, +) +def schema_of( + type_: Any, + *, + title: NameFactory | None = None, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, +) -> dict[str, Any]: + """Generate a JSON schema (as dict) for the passed model or dynamically generated one.""" + warnings.warn( + '`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + res = TypeAdapter(type_).json_schema( + by_alias=by_alias, + schema_generator=schema_generator, + ref_template=ref_template, + ) + if title is not None: + if isinstance(title, str): + res['title'] = title + else: + warnings.warn( + 'Passing a callable for the `title` parameter is deprecated and no longer supported', + DeprecationWarning, + stacklevel=2, + ) + res['title'] = title(type_) + return res + + +@deprecated( + '`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=None, +) +def schema_json_of( + type_: Any, + *, + title: NameFactory | None = None, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + **dumps_kwargs: Any, +) -> str: + """Generate a JSON schema (as JSON) for the passed model or dynamically generated one.""" + warnings.warn( + '`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return json.dumps( + schema_of(type_, title=title, by_alias=by_alias, ref_template=ref_template, schema_generator=schema_generator), + **dumps_kwargs, + ) diff --git a/backend/venv/Lib/site-packages/pydantic/env_settings.py b/backend/venv/Lib/site-packages/pydantic/env_settings.py new file mode 100644 index 0000000..cd0b04e --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/env_settings.py @@ -0,0 +1,5 @@ +"""The `env_settings` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/error_wrappers.py b/backend/venv/Lib/site-packages/pydantic/error_wrappers.py new file mode 100644 index 0000000..2985419 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/error_wrappers.py @@ -0,0 +1,5 @@ +"""The `error_wrappers` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/errors.py b/backend/venv/Lib/site-packages/pydantic/errors.py new file mode 100644 index 0000000..f227068 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/errors.py @@ -0,0 +1,189 @@ +"""Pydantic-specific errors.""" + +from __future__ import annotations as _annotations + +import re +from typing import Any, ClassVar, Literal + +from typing_extensions import Self +from typing_inspection.introspection import Qualifier + +from pydantic._internal import _repr + +from ._migration import getattr_migration +from .version import version_short + +__all__ = ( + 'PydanticUserError', + 'PydanticUndefinedAnnotation', + 'PydanticImportError', + 'PydanticSchemaGenerationError', + 'PydanticInvalidForJsonSchema', + 'PydanticForbiddenQualifier', + 'PydanticErrorCodes', +) + +# We use this URL to allow for future flexibility about how we host the docs, while allowing for Pydantic +# code in the while with "old" URLs to still work. +# 'u' refers to "user errors" - e.g. errors caused by developers using pydantic, as opposed to validation errors. +DEV_ERROR_DOCS_URL = f'https://errors.pydantic.dev/{version_short()}/u/' +PydanticErrorCodes = Literal[ + 'class-not-fully-defined', + 'custom-json-schema', + 'decorator-missing-field', + 'discriminator-no-field', + 'discriminator-alias-type', + 'discriminator-needs-literal', + 'discriminator-alias', + 'discriminator-validator', + 'callable-discriminator-no-tag', + 'typed-dict-version', + 'model-field-overridden', + 'model-field-missing-annotation', + 'config-both', + 'removed-kwargs', + 'circular-reference-schema', + 'invalid-for-json-schema', + 'json-schema-already-used', + 'base-model-instantiated', + 'undefined-annotation', + 'schema-for-unknown-type', + 'import-error', + 'create-model-field-definitions', + 'validator-no-fields', + 'validator-invalid-fields', + 'validator-instance-method', + 'validator-input-type', + 'root-validator-pre-skip', + 'model-serializer-instance-method', + 'validator-field-config-info', + 'validator-v1-signature', + 'validator-signature', + 'field-serializer-signature', + 'model-serializer-signature', + 'multiple-field-serializers', + 'invalid-annotated-type', + 'type-adapter-config-unused', + 'root-model-extra', + 'unevaluable-type-annotation', + 'dataclass-init-false-extra-allow', + 'clashing-init-and-init-var', + 'model-config-invalid-field-name', + 'with-config-on-model', + 'dataclass-on-model', + 'validate-call-type', + 'unpack-typed-dict', + 'overlapping-unpack-typed-dict', + 'invalid-self-type', + 'validate-by-alias-and-name-false', +] + + +class PydanticErrorMixin: + """A mixin class for common functionality shared by all Pydantic-specific errors. + + Attributes: + message: A message describing the error. + code: An optional error code from PydanticErrorCodes enum. + """ + + def __init__(self, message: str, *, code: PydanticErrorCodes | None) -> None: + self.message = message + self.code = code + + def __str__(self) -> str: + if self.code is None: + return self.message + else: + return f'{self.message}\n\nFor further information visit {DEV_ERROR_DOCS_URL}{self.code}' + + +class PydanticUserError(PydanticErrorMixin, TypeError): + """An error raised due to incorrect use of Pydantic.""" + + +class PydanticUndefinedAnnotation(PydanticErrorMixin, NameError): + """A subclass of `NameError` raised when handling undefined annotations during `CoreSchema` generation. + + Attributes: + name: Name of the error. + message: Description of the error. + """ + + def __init__(self, name: str, message: str) -> None: + self.name = name + super().__init__(message=message, code='undefined-annotation') + + @classmethod + def from_name_error(cls, name_error: NameError) -> Self: + """Convert a `NameError` to a `PydanticUndefinedAnnotation` error. + + Args: + name_error: `NameError` to be converted. + + Returns: + Converted `PydanticUndefinedAnnotation` error. + """ + try: + name = name_error.name # type: ignore # python > 3.10 + except AttributeError: + name = re.search(r".*'(.+?)'", str(name_error)).group(1) # type: ignore[union-attr] + return cls(name=name, message=str(name_error)) + + +class PydanticImportError(PydanticErrorMixin, ImportError): + """An error raised when an import fails due to module changes between V1 and V2. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='import-error') + + +class PydanticSchemaGenerationError(PydanticUserError): + """An error raised during failures to generate a `CoreSchema` for some type. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='schema-for-unknown-type') + + +class PydanticInvalidForJsonSchema(PydanticUserError): + """An error raised during failures to generate a JSON schema for some `CoreSchema`. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='invalid-for-json-schema') + + +class PydanticForbiddenQualifier(PydanticUserError): + """An error raised if a forbidden type qualifier is found in a type annotation.""" + + _qualifier_repr_map: ClassVar[dict[Qualifier, str]] = { + 'required': 'typing.Required', + 'not_required': 'typing.NotRequired', + 'read_only': 'typing.ReadOnly', + 'class_var': 'typing.ClassVar', + 'init_var': 'dataclasses.InitVar', + 'final': 'typing.Final', + } + + def __init__(self, qualifier: Qualifier, annotation: Any) -> None: + super().__init__( + message=( + f'The annotation {_repr.display_as_type(annotation)!r} contains the {self._qualifier_repr_map[qualifier]!r} ' + f'type qualifier, which is invalid in the context it is defined.' + ), + code=None, + ) + + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/__init__.py b/backend/venv/Lib/site-packages/pydantic/experimental/__init__.py new file mode 100644 index 0000000..5b5add1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/experimental/__init__.py @@ -0,0 +1 @@ +"""The "experimental" module of pydantic contains potential new features that are subject to change.""" diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e66c80e6abb499818ee893ff0ce83f8d688b985 GIT binary patch literal 310 zcmYjNJ5B>Z44nZ45mN48rAtB5BSb@sC=fJgq>*>l*&W#VXl9bIT!b^wa1m~>Ef+va zM}=1qiP!i&+p?eiF`b?Y#{K)PZ8?69Vh{O8b`vJAq81OLm-B-cylV+&^c*Q!N4{V; z0~hLbM-WyJ`xGKqxGBEjXu8V>RiPXnuN|-->7W}COAjQkhXrq8$#+;h31KTtypi=wXIaPh0Y>p rv7xN?=9d56FEtOaMe9ZEhsnk7DVOP(w~jB!4?P-h`3^; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/arguments_schema.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/arguments_schema.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe0d4f70aff9380c67c32dcc23e7d55d14933c84 GIT binary patch literal 2402 zcmai0&1)M+6rZ)E)t6;iwn-Y(B-7%es5o*-YG_O-2)6`6>ZDFei!8Gq?~dfP_N%ii zCkk%Kp@;U?Tl*ihC8gy5=*6l7c9uW_#fRPm$*HHlnboYMVCWjpy!m*)c{A_#-qW9j zLJqq!9Y+sL*TI2{ThyV91Qe!qmr?BNJJcpP*dYPl zBbI5vnvZp2S!5ef2y1mXu3!C!U%8@$dEz*3KscTc!_4YnYh@x#)SPaZzGVh*f(2{2 zRXE|UI3OB1O|$ihsRxxrnAUWc55s9qnxsXxz>Gs|>U%_|S|>0qe@#zD?=9L4wDA7Q zt9gaLeE@Cr?M_H(*as;o@2XN7_WOy)1MMIyXLp6yHl`Yp4n6Oq~!T`Q6))!0TXUWe+N6Uvzsmh zhmSZHyUh`rRC75DUyZf=6(R8v=g$jEWAyz>Fl{}YG8gTO7tBZYgdK25+OE;-^Sl@JC=b1 z(x&hdj8e?#*Bz4qPR#ff@kXX&&J*o%QH&!;W*~Ac2fGr}68WsLR{FLEc#tz_akoN+?!LG;S5#Fi`7YRDd!CPg& zZF=RcMeMr(1<^f*2YDdyAxG#|$Dqa-c$2xd*vzQku>zh#B4-U96oqc&&`9n;P8npF zj!y>+S{J5_kcitYqum%oh5RrbN4>8F9nYdLmv?*(%y6we%ED~yno5rGC=I71yYGr5 z!*~#fg;kMQzGTFMtjO|wF1O~dOPC^H0$DW4LAq><=rKq8mam`HE~*E{I9*b((stuf(WqT=^OW5S9fijGDwC% zbx6f7>o#~uP{(M%c&~BG+-~@gbT323Y?BuC8(!BSPGIUwPz2(_u=M6Ft6n!e7n}6v zD!TwiO~JpI=AyWl{l+Dy4}yA%PO0RU~$%hBmZXK3B`$2ulrN02gkX$`w8e@mX`Y|==&;~Usw8RE@n{Sg4hIF>h$Y8%!%Xw1IlE!tpET3 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/missing_sentinel.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/experimental/__pycache__/missing_sentinel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2e007ebf87abf076be9850c401df0f15aff2259 GIT binary patch literal 351 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/arguments_schema.py b/backend/venv/Lib/site-packages/pydantic/experimental/arguments_schema.py new file mode 100644 index 0000000..af4a8f3 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/experimental/arguments_schema.py @@ -0,0 +1,44 @@ +"""Experimental module exposing a function to generate a core schema that validates callable arguments.""" + +from __future__ import annotations + +from collections.abc import Callable +from typing import Any, Literal + +from pydantic_core import CoreSchema + +from pydantic import ConfigDict +from pydantic._internal import _config, _generate_schema, _namespace_utils + + +def generate_arguments_schema( + func: Callable[..., Any], + schema_type: Literal['arguments', 'arguments-v3'] = 'arguments-v3', + parameters_callback: Callable[[int, str, Any], Literal['skip'] | None] | None = None, + config: ConfigDict | None = None, +) -> CoreSchema: + """Generate the schema for the arguments of a function. + + Args: + func: The function to generate the schema for. + schema_type: The type of schema to generate. + parameters_callback: A callable that will be invoked for each parameter. The callback + should take three required arguments: the index, the name and the type annotation + (or [`Parameter.empty`][inspect.Parameter.empty] if not annotated) of the parameter. + The callback can optionally return `'skip'`, so that the parameter gets excluded + from the resulting schema. + config: The configuration to use. + + Returns: + The generated schema. + """ + generate_schema = _generate_schema.GenerateSchema( + _config.ConfigWrapper(config), + ns_resolver=_namespace_utils.NsResolver(namespaces_tuple=_namespace_utils.ns_for_function(func)), + ) + + if schema_type == 'arguments': + schema = generate_schema._arguments_schema(func, parameters_callback) # pyright: ignore[reportArgumentType] + else: + schema = generate_schema._arguments_v3_schema(func, parameters_callback) # pyright: ignore[reportArgumentType] + return generate_schema.clean_schema(schema) diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/missing_sentinel.py b/backend/venv/Lib/site-packages/pydantic/experimental/missing_sentinel.py new file mode 100644 index 0000000..3e7f820 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/experimental/missing_sentinel.py @@ -0,0 +1,5 @@ +"""Experimental module exposing a function a `MISSING` sentinel.""" + +from pydantic_core import MISSING + +__all__ = ('MISSING',) diff --git a/backend/venv/Lib/site-packages/pydantic/experimental/pipeline.py b/backend/venv/Lib/site-packages/pydantic/experimental/pipeline.py new file mode 100644 index 0000000..633fb00 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/experimental/pipeline.py @@ -0,0 +1,654 @@ +"""Experimental pipeline API functionality. Be careful with this API, it's subject to change.""" + +from __future__ import annotations + +import datetime +import operator +import re +import sys +from collections import deque +from collections.abc import Container +from dataclasses import dataclass +from decimal import Decimal +from functools import cached_property, partial +from re import Pattern +from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Protocol, TypeVar, Union, overload + +import annotated_types + +if TYPE_CHECKING: + from pydantic import GetCoreSchemaHandler + +from pydantic_core import PydanticCustomError +from pydantic_core import core_schema as cs + +from pydantic import Strict +from pydantic._internal._internal_dataclass import slots_true as _slots_true + +if sys.version_info < (3, 10): + EllipsisType = type(Ellipsis) +else: + from types import EllipsisType + +__all__ = ['validate_as', 'validate_as_deferred', 'transform'] + +_slots_frozen = {**_slots_true, 'frozen': True} + + +@dataclass(**_slots_frozen) +class _ValidateAs: + tp: type[Any] + strict: bool = False + + +@dataclass +class _ValidateAsDefer: + func: Callable[[], type[Any]] + + @cached_property + def tp(self) -> type[Any]: + return self.func() + + +@dataclass(**_slots_frozen) +class _Transform: + func: Callable[[Any], Any] + + +@dataclass(**_slots_frozen) +class _PipelineOr: + left: _Pipeline[Any, Any] + right: _Pipeline[Any, Any] + + +@dataclass(**_slots_frozen) +class _PipelineAnd: + left: _Pipeline[Any, Any] + right: _Pipeline[Any, Any] + + +@dataclass(**_slots_frozen) +class _Eq: + value: Any + + +@dataclass(**_slots_frozen) +class _NotEq: + value: Any + + +@dataclass(**_slots_frozen) +class _In: + values: Container[Any] + + +@dataclass(**_slots_frozen) +class _NotIn: + values: Container[Any] + + +_ConstraintAnnotation = Union[ + annotated_types.Le, + annotated_types.Ge, + annotated_types.Lt, + annotated_types.Gt, + annotated_types.Len, + annotated_types.MultipleOf, + annotated_types.Timezone, + annotated_types.Interval, + annotated_types.Predicate, + # common predicates not included in annotated_types + _Eq, + _NotEq, + _In, + _NotIn, + # regular expressions + Pattern[str], +] + + +@dataclass(**_slots_frozen) +class _Constraint: + constraint: _ConstraintAnnotation + + +_Step = Union[_ValidateAs, _ValidateAsDefer, _Transform, _PipelineOr, _PipelineAnd, _Constraint] + +_InT = TypeVar('_InT') +_OutT = TypeVar('_OutT') +_NewOutT = TypeVar('_NewOutT') + + +class _FieldTypeMarker: + pass + + +# TODO: ultimately, make this public, see https://github.com/pydantic/pydantic/pull/9459#discussion_r1628197626 +# Also, make this frozen eventually, but that doesn't work right now because of the generic base +# Which attempts to modify __orig_base__ and such. +# We could go with a manual freeze, but that seems overkill for now. +@dataclass(**_slots_true) +class _Pipeline(Generic[_InT, _OutT]): + """Abstract representation of a chain of validation, transformation, and parsing steps.""" + + _steps: tuple[_Step, ...] + + def transform( + self, + func: Callable[[_OutT], _NewOutT], + ) -> _Pipeline[_InT, _NewOutT]: + """Transform the output of the previous step. + + If used as the first step in a pipeline, the type of the field is used. + That is, the transformation is applied to after the value is parsed to the field's type. + """ + return _Pipeline[_InT, _NewOutT](self._steps + (_Transform(func),)) + + @overload + def validate_as(self, tp: type[_NewOutT], *, strict: bool = ...) -> _Pipeline[_InT, _NewOutT]: ... + + @overload + def validate_as(self, tp: EllipsisType, *, strict: bool = ...) -> _Pipeline[_InT, Any]: # type: ignore + ... + + def validate_as(self, tp: type[_NewOutT] | EllipsisType, *, strict: bool = False) -> _Pipeline[_InT, Any]: # type: ignore + """Validate / parse the input into a new type. + + If no type is provided, the type of the field is used. + + Types are parsed in Pydantic's `lax` mode by default, + but you can enable `strict` mode by passing `strict=True`. + """ + if isinstance(tp, EllipsisType): + return _Pipeline[_InT, Any](self._steps + (_ValidateAs(_FieldTypeMarker, strict=strict),)) + return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAs(tp, strict=strict),)) + + def validate_as_deferred(self, func: Callable[[], type[_NewOutT]]) -> _Pipeline[_InT, _NewOutT]: + """Parse the input into a new type, deferring resolution of the type until the current class + is fully defined. + + This is useful when you need to reference the class in it's own type annotations. + """ + return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAsDefer(func),)) + + # constraints + @overload + def constrain(self: _Pipeline[_InT, _NewOutGe], constraint: annotated_types.Ge) -> _Pipeline[_InT, _NewOutGe]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutGt], constraint: annotated_types.Gt) -> _Pipeline[_InT, _NewOutGt]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutLe], constraint: annotated_types.Le) -> _Pipeline[_InT, _NewOutLe]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutLt], constraint: annotated_types.Lt) -> _Pipeline[_InT, _NewOutLt]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutLen], constraint: annotated_types.Len + ) -> _Pipeline[_InT, _NewOutLen]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutT], constraint: annotated_types.MultipleOf + ) -> _Pipeline[_InT, _NewOutT]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutDatetime], constraint: annotated_types.Timezone + ) -> _Pipeline[_InT, _NewOutDatetime]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: annotated_types.Predicate) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutInterval], constraint: annotated_types.Interval + ) -> _Pipeline[_InT, _NewOutInterval]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _Eq) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotEq) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _In) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotIn) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutT], constraint: Pattern[str]) -> _Pipeline[_InT, _NewOutT]: ... + + def constrain(self, constraint: _ConstraintAnnotation) -> Any: + """Constrain a value to meet a certain condition. + + We support most conditions from `annotated_types`, as well as regular expressions. + + Most of the time you'll be calling a shortcut method like `gt`, `lt`, `len`, etc + so you don't need to call this directly. + """ + return _Pipeline[_InT, _OutT](self._steps + (_Constraint(constraint),)) + + def predicate(self: _Pipeline[_InT, _NewOutT], func: Callable[[_NewOutT], bool]) -> _Pipeline[_InT, _NewOutT]: + """Constrain a value to meet a certain predicate.""" + return self.constrain(annotated_types.Predicate(func)) + + def gt(self: _Pipeline[_InT, _NewOutGt], gt: _NewOutGt) -> _Pipeline[_InT, _NewOutGt]: + """Constrain a value to be greater than a certain value.""" + return self.constrain(annotated_types.Gt(gt)) + + def lt(self: _Pipeline[_InT, _NewOutLt], lt: _NewOutLt) -> _Pipeline[_InT, _NewOutLt]: + """Constrain a value to be less than a certain value.""" + return self.constrain(annotated_types.Lt(lt)) + + def ge(self: _Pipeline[_InT, _NewOutGe], ge: _NewOutGe) -> _Pipeline[_InT, _NewOutGe]: + """Constrain a value to be greater than or equal to a certain value.""" + return self.constrain(annotated_types.Ge(ge)) + + def le(self: _Pipeline[_InT, _NewOutLe], le: _NewOutLe) -> _Pipeline[_InT, _NewOutLe]: + """Constrain a value to be less than or equal to a certain value.""" + return self.constrain(annotated_types.Le(le)) + + def len(self: _Pipeline[_InT, _NewOutLen], min_len: int, max_len: int | None = None) -> _Pipeline[_InT, _NewOutLen]: + """Constrain a value to have a certain length.""" + return self.constrain(annotated_types.Len(min_len, max_len)) + + @overload + def multiple_of(self: _Pipeline[_InT, _NewOutDiv], multiple_of: _NewOutDiv) -> _Pipeline[_InT, _NewOutDiv]: ... + + @overload + def multiple_of(self: _Pipeline[_InT, _NewOutMod], multiple_of: _NewOutMod) -> _Pipeline[_InT, _NewOutMod]: ... + + def multiple_of(self: _Pipeline[_InT, Any], multiple_of: Any) -> _Pipeline[_InT, Any]: + """Constrain a value to be a multiple of a certain number.""" + return self.constrain(annotated_types.MultipleOf(multiple_of)) + + def eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: + """Constrain a value to be equal to a certain value.""" + return self.constrain(_Eq(value)) + + def not_eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: + """Constrain a value to not be equal to a certain value.""" + return self.constrain(_NotEq(value)) + + def in_(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: + """Constrain a value to be in a certain set.""" + return self.constrain(_In(values)) + + def not_in(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: + """Constrain a value to not be in a certain set.""" + return self.constrain(_NotIn(values)) + + # timezone methods + def datetime_tz_naive(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(None)) + + def datetime_tz_aware(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(...)) + + def datetime_tz( + self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo + ) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(tz)) # type: ignore + + def datetime_with_tz( + self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo | None + ) -> _Pipeline[_InT, datetime.datetime]: + return self.transform(partial(datetime.datetime.replace, tzinfo=tz)) + + # string methods + def str_lower(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.lower) + + def str_upper(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.upper) + + def str_title(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.title) + + def str_strip(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.strip) + + def str_pattern(self: _Pipeline[_InT, str], pattern: str) -> _Pipeline[_InT, str]: + return self.constrain(re.compile(pattern)) + + def str_contains(self: _Pipeline[_InT, str], substring: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: substring in v) + + def str_starts_with(self: _Pipeline[_InT, str], prefix: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: v.startswith(prefix)) + + def str_ends_with(self: _Pipeline[_InT, str], suffix: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: v.endswith(suffix)) + + # operators + def otherwise(self, other: _Pipeline[_OtherIn, _OtherOut]) -> _Pipeline[_InT | _OtherIn, _OutT | _OtherOut]: + """Combine two validation chains, returning the result of the first chain if it succeeds, and the second chain if it fails.""" + return _Pipeline((_PipelineOr(self, other),)) + + __or__ = otherwise + + def then(self, other: _Pipeline[_OutT, _OtherOut]) -> _Pipeline[_InT, _OtherOut]: + """Pipe the result of one validation chain into another.""" + return _Pipeline((_PipelineAnd(self, other),)) + + __and__ = then + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> cs.CoreSchema: + queue = deque(self._steps) + + s = None + + while queue: + step = queue.popleft() + s = _apply_step(step, s, handler, source_type) + + s = s or cs.any_schema() + return s + + def __supports_type__(self, _: _OutT) -> bool: + raise NotImplementedError + + +validate_as = _Pipeline[Any, Any](()).validate_as +validate_as_deferred = _Pipeline[Any, Any](()).validate_as_deferred +transform = _Pipeline[Any, Any]((_ValidateAs(_FieldTypeMarker),)).transform + + +def _check_func( + func: Callable[[Any], bool], predicate_err: str | Callable[[], str], s: cs.CoreSchema | None +) -> cs.CoreSchema: + def handler(v: Any) -> Any: + if func(v): + return v + raise ValueError(f'Expected {predicate_err if isinstance(predicate_err, str) else predicate_err()}') + + if s is None: + return cs.no_info_plain_validator_function(handler) + else: + return cs.no_info_after_validator_function(handler, s) + + +def _apply_step(step: _Step, s: cs.CoreSchema | None, handler: GetCoreSchemaHandler, source_type: Any) -> cs.CoreSchema: + if isinstance(step, _ValidateAs): + s = _apply_parse(s, step.tp, step.strict, handler, source_type) + elif isinstance(step, _ValidateAsDefer): + s = _apply_parse(s, step.tp, False, handler, source_type) + elif isinstance(step, _Transform): + s = _apply_transform(s, step.func, handler) + elif isinstance(step, _Constraint): + s = _apply_constraint(s, step.constraint) + elif isinstance(step, _PipelineOr): + s = cs.union_schema([handler(step.left), handler(step.right)]) + else: + assert isinstance(step, _PipelineAnd) + s = cs.chain_schema([handler(step.left), handler(step.right)]) + return s + + +def _apply_parse( + s: cs.CoreSchema | None, + tp: type[Any], + strict: bool, + handler: GetCoreSchemaHandler, + source_type: Any, +) -> cs.CoreSchema: + if tp is _FieldTypeMarker: + return cs.chain_schema([s, handler(source_type)]) if s else handler(source_type) + + if strict: + tp = Annotated[tp, Strict()] # type: ignore + + if s and s['type'] == 'any': + return handler(tp) + else: + return cs.chain_schema([s, handler(tp)]) if s else handler(tp) + + +def _apply_transform( + s: cs.CoreSchema | None, func: Callable[[Any], Any], handler: GetCoreSchemaHandler +) -> cs.CoreSchema: + if s is None: + return cs.no_info_plain_validator_function(func) + + if s['type'] == 'str': + if func is str.strip: + s = s.copy() + s['strip_whitespace'] = True + return s + elif func is str.lower: + s = s.copy() + s['to_lower'] = True + return s + elif func is str.upper: + s = s.copy() + s['to_upper'] = True + return s + + return cs.no_info_after_validator_function(func, s) + + +def _apply_constraint( # noqa: C901 + s: cs.CoreSchema | None, constraint: _ConstraintAnnotation +) -> cs.CoreSchema: + """Apply a single constraint to a schema.""" + if isinstance(constraint, annotated_types.Gt): + gt = constraint.gt + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(gt, int): + s['gt'] = gt + elif s['type'] == 'float' and isinstance(gt, float): + s['gt'] = gt + elif s['type'] == 'decimal' and isinstance(gt, Decimal): + s['gt'] = gt + else: + + def check_gt(v: Any) -> bool: + return v > gt + + s = _check_func(check_gt, f'> {gt}', s) + elif isinstance(constraint, annotated_types.Ge): + ge = constraint.ge + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(ge, int): + s['ge'] = ge + elif s['type'] == 'float' and isinstance(ge, float): + s['ge'] = ge + elif s['type'] == 'decimal' and isinstance(ge, Decimal): + s['ge'] = ge + + def check_ge(v: Any) -> bool: + return v >= ge + + s = _check_func(check_ge, f'>= {ge}', s) + elif isinstance(constraint, annotated_types.Lt): + lt = constraint.lt + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(lt, int): + s['lt'] = lt + elif s['type'] == 'float' and isinstance(lt, float): + s['lt'] = lt + elif s['type'] == 'decimal' and isinstance(lt, Decimal): + s['lt'] = lt + + def check_lt(v: Any) -> bool: + return v < lt + + s = _check_func(check_lt, f'< {lt}', s) + elif isinstance(constraint, annotated_types.Le): + le = constraint.le + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(le, int): + s['le'] = le + elif s['type'] == 'float' and isinstance(le, float): + s['le'] = le + elif s['type'] == 'decimal' and isinstance(le, Decimal): + s['le'] = le + + def check_le(v: Any) -> bool: + return v <= le + + s = _check_func(check_le, f'<= {le}', s) + elif isinstance(constraint, annotated_types.Len): + min_len = constraint.min_length + max_len = constraint.max_length + + if s and s['type'] in {'str', 'list', 'tuple', 'set', 'frozenset', 'dict'}: + assert ( + s['type'] == 'str' + or s['type'] == 'list' + or s['type'] == 'tuple' + or s['type'] == 'set' + or s['type'] == 'dict' + or s['type'] == 'frozenset' + ) + s = s.copy() + if min_len != 0: + s['min_length'] = min_len + if max_len is not None: + s['max_length'] = max_len + + def check_len(v: Any) -> bool: + if max_len is not None: + return (min_len <= len(v)) and (len(v) <= max_len) + return min_len <= len(v) + + s = _check_func(check_len, f'length >= {min_len} and length <= {max_len}', s) + elif isinstance(constraint, annotated_types.MultipleOf): + multiple_of = constraint.multiple_of + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(multiple_of, int): + s['multiple_of'] = multiple_of + elif s['type'] == 'float' and isinstance(multiple_of, float): + s['multiple_of'] = multiple_of + elif s['type'] == 'decimal' and isinstance(multiple_of, Decimal): + s['multiple_of'] = multiple_of + + def check_multiple_of(v: Any) -> bool: + return v % multiple_of == 0 + + s = _check_func(check_multiple_of, f'% {multiple_of} == 0', s) + elif isinstance(constraint, annotated_types.Timezone): + tz = constraint.tz + + if tz is ...: + if s and s['type'] == 'datetime': + s = s.copy() + s['tz_constraint'] = 'aware' + else: + + def check_tz_aware(v: object) -> bool: + assert isinstance(v, datetime.datetime) + return v.tzinfo is not None + + s = _check_func(check_tz_aware, 'timezone aware', s) + elif tz is None: + if s and s['type'] == 'datetime': + s = s.copy() + s['tz_constraint'] = 'naive' + else: + + def check_tz_naive(v: object) -> bool: + assert isinstance(v, datetime.datetime) + return v.tzinfo is None + + s = _check_func(check_tz_naive, 'timezone naive', s) + else: + raise NotImplementedError('Constraining to a specific timezone is not yet supported') + elif isinstance(constraint, annotated_types.Interval): + if constraint.ge: + s = _apply_constraint(s, annotated_types.Ge(constraint.ge)) + if constraint.gt: + s = _apply_constraint(s, annotated_types.Gt(constraint.gt)) + if constraint.le: + s = _apply_constraint(s, annotated_types.Le(constraint.le)) + if constraint.lt: + s = _apply_constraint(s, annotated_types.Lt(constraint.lt)) + assert s is not None + elif isinstance(constraint, annotated_types.Predicate): + func = constraint.func + # Same logic as in `_known_annotated_metadata.apply_known_metadata()`: + predicate_name = f'{func.__qualname__!r} ' if hasattr(func, '__qualname__') else '' + + def predicate_func(v: Any) -> Any: + if not func(v): + raise PydanticCustomError( + 'predicate_failed', + f'Predicate {predicate_name}failed', # pyright: ignore[reportArgumentType] + ) + return v + + if s is None: + s = cs.no_info_plain_validator_function(predicate_func) + else: + s = cs.no_info_after_validator_function(predicate_func, s) + elif isinstance(constraint, _NotEq): + value = constraint.value + + def check_not_eq(v: Any) -> bool: + return operator.__ne__(v, value) + + s = _check_func(check_not_eq, f'!= {value}', s) + elif isinstance(constraint, _Eq): + value = constraint.value + + def check_eq(v: Any) -> bool: + return operator.__eq__(v, value) + + s = _check_func(check_eq, f'== {value}', s) + elif isinstance(constraint, _In): + values = constraint.values + + def check_in(v: Any) -> bool: + return operator.__contains__(values, v) + + s = _check_func(check_in, f'in {values}', s) + elif isinstance(constraint, _NotIn): + values = constraint.values + + def check_not_in(v: Any) -> bool: + return operator.__not__(operator.__contains__(values, v)) + + s = _check_func(check_not_in, f'not in {values}', s) + else: + assert isinstance(constraint, Pattern) + if s and s['type'] == 'str': + s = s.copy() + s['pattern'] = constraint.pattern + else: + + def check_pattern(v: object) -> bool: + assert isinstance(v, str) + return constraint.match(v) is not None + + s = _check_func(check_pattern, f'~ {constraint.pattern}', s) + return s + + +class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): + pass + + +class _SupportsLen(Protocol): + def __len__(self) -> int: ... + + +_NewOutGt = TypeVar('_NewOutGt', bound=annotated_types.SupportsGt) +_NewOutGe = TypeVar('_NewOutGe', bound=annotated_types.SupportsGe) +_NewOutLt = TypeVar('_NewOutLt', bound=annotated_types.SupportsLt) +_NewOutLe = TypeVar('_NewOutLe', bound=annotated_types.SupportsLe) +_NewOutLen = TypeVar('_NewOutLen', bound=_SupportsLen) +_NewOutDiv = TypeVar('_NewOutDiv', bound=annotated_types.SupportsDiv) +_NewOutMod = TypeVar('_NewOutMod', bound=annotated_types.SupportsMod) +_NewOutDatetime = TypeVar('_NewOutDatetime', bound=datetime.datetime) +_NewOutInterval = TypeVar('_NewOutInterval', bound=_SupportsRange) +_OtherIn = TypeVar('_OtherIn') +_OtherOut = TypeVar('_OtherOut') diff --git a/backend/venv/Lib/site-packages/pydantic/fields.py b/backend/venv/Lib/site-packages/pydantic/fields.py new file mode 100644 index 0000000..b091710 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/fields.py @@ -0,0 +1,1834 @@ +"""Defining fields on models.""" + +from __future__ import annotations as _annotations + +import dataclasses +import inspect +import re +import sys +from collections.abc import Callable, Mapping +from copy import copy +from dataclasses import Field as DataclassField +from functools import cached_property +from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal, TypeVar, cast, final, overload +from warnings import warn + +import annotated_types +import typing_extensions +from pydantic_core import MISSING, PydanticUndefined +from typing_extensions import Self, TypeAlias, TypedDict, Unpack, deprecated +from typing_inspection import typing_objects +from typing_inspection.introspection import UNKNOWN, AnnotationSource, ForbiddenQualifier, Qualifier, inspect_annotation + +from . import types +from ._internal import _decorators, _fields, _generics, _internal_dataclass, _repr, _typing_extra, _utils +from ._internal._namespace_utils import GlobalsNamespace, MappingNamespace +from .aliases import AliasChoices, AliasGenerator, AliasPath +from .config import JsonDict +from .errors import PydanticForbiddenQualifier, PydanticUserError +from .json_schema import PydanticJsonSchemaWarning +from .warnings import PydanticDeprecatedSince20 + +if TYPE_CHECKING: + from ._internal._config import ConfigWrapper + from ._internal._repr import ReprArgs + + +__all__ = 'Field', 'FieldInfo', 'PrivateAttr', 'computed_field' + + +_Unset: Any = PydanticUndefined + +if sys.version_info >= (3, 13): + import warnings + + Deprecated: TypeAlias = warnings.deprecated | deprecated +else: + Deprecated: TypeAlias = deprecated + + +class _FromFieldInfoInputs(TypedDict, total=False): + """This class exists solely to add type checking for the `**kwargs` in `FieldInfo.from_field`.""" + + # TODO PEP 747: use TypeForm: + annotation: type[Any] | None + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None + alias: str | None + alias_priority: int | None + validation_alias: str | AliasPath | AliasChoices | None + serialization_alias: str | None + title: str | None + field_title_generator: Callable[[str, FieldInfo], str] | None + description: str | None + examples: list[Any] | None + exclude: bool | None + exclude_if: Callable[[Any], bool] | None + gt: annotated_types.SupportsGt | None + ge: annotated_types.SupportsGe | None + lt: annotated_types.SupportsLt | None + le: annotated_types.SupportsLe | None + multiple_of: float | None + strict: bool | None + min_length: int | None + max_length: int | None + pattern: str | re.Pattern[str] | None + allow_inf_nan: bool | None + max_digits: int | None + decimal_places: int | None + union_mode: Literal['smart', 'left_to_right'] | None + discriminator: str | types.Discriminator | None + deprecated: Deprecated | str | bool | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + frozen: bool | None + validate_default: bool | None + repr: bool + init: bool | None + init_var: bool | None + kw_only: bool | None + coerce_numbers_to_str: bool | None + fail_fast: bool | None + + +class _FieldInfoInputs(_FromFieldInfoInputs, total=False): + """This class exists solely to add type checking for the `**kwargs` in `FieldInfo.__init__`.""" + + default: Any + + +class _FieldInfoAsDict(TypedDict, closed=True): + # TODO PEP 747: use TypeForm: + annotation: Any + metadata: list[Any] + attributes: dict[str, Any] + + +@final +class FieldInfo(_repr.Representation): + """This class holds information about a field. + + `FieldInfo` is used for any field definition regardless of whether the [`Field()`][pydantic.fields.Field] + function is explicitly used. + + !!! warning + The `FieldInfo` class is meant to expose information about a field in a Pydantic model or dataclass. + `FieldInfo` instances shouldn't be instantiated directly, nor mutated. + + If you need to derive a new model from another one and are willing to alter `FieldInfo` instances, + refer to this [dynamic model example](../examples/dynamic_models.md). + + Attributes: + annotation: The type annotation of the field. + default: The default value of the field. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the already validated data. + alias: The alias name of the field. + alias_priority: The priority of the field's alias. + validation_alias: The validation alias of the field. + serialization_alias: The serialization alias of the field. + title: The title of the field. + field_title_generator: A callable that takes a field name and returns title for it. + description: The description of the field. + examples: List of examples of the field. + exclude: Whether to exclude the field from the model serialization. + exclude_if: A callable that determines whether to exclude a field during serialization based on its value. + discriminator: Field name or Discriminator for discriminating the type in a tagged union. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + frozen: Whether the field is frozen. + validate_default: Whether to validate the default value of the field. + repr: Whether to include the field in representation of the model. + init: Whether the field should be included in the constructor of the dataclass. + init_var: Whether the field should _only_ be included in the constructor of the dataclass, and not stored. + kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass. + metadata: The metadata list. Contains all the data that isn't expressed as direct `FieldInfo` attributes, including: + + * Type-specific constraints, such as `gt` or `min_length` (these are converted to metadata classes such as `annotated_types.Gt`). + * Any other arbitrary object used within [`Annotated`][typing.Annotated] metadata + (e.g. [custom types handlers](../concepts/types.md#as-an-annotation) or any object not recognized by Pydantic). + """ + + # TODO PEP 747: use TypeForm: + annotation: type[Any] | None + default: Any + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None + alias: str | None + alias_priority: int | None + validation_alias: str | AliasPath | AliasChoices | None + serialization_alias: str | None + title: str | None + field_title_generator: Callable[[str, FieldInfo], str] | None + description: str | None + examples: list[Any] | None + exclude: bool | None + exclude_if: Callable[[Any], bool] | None + discriminator: str | types.Discriminator | None + deprecated: Deprecated | str | bool | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + frozen: bool | None + validate_default: bool | None + repr: bool + init: bool | None + init_var: bool | None + kw_only: bool | None + metadata: list[Any] + + __slots__ = ( + 'annotation', + 'default', + 'default_factory', + 'alias', + 'alias_priority', + 'validation_alias', + 'serialization_alias', + 'title', + 'field_title_generator', + 'description', + 'examples', + 'exclude', + 'exclude_if', + 'discriminator', + 'deprecated', + 'json_schema_extra', + 'frozen', + 'validate_default', + 'repr', + 'init', + 'init_var', + 'kw_only', + 'metadata', + '_attributes_set', + '_qualifiers', + '_complete', + '_original_assignment', + '_original_annotation', + '_final', + ) + + # used to convert kwargs to metadata/constraints, + # None has a special meaning - these items are collected into a `PydanticGeneralMetadata` + metadata_lookup: ClassVar[dict[str, Callable[[Any], Any] | None]] = { + 'strict': types.Strict, + 'gt': annotated_types.Gt, + 'ge': annotated_types.Ge, + 'lt': annotated_types.Lt, + 'le': annotated_types.Le, + 'multiple_of': annotated_types.MultipleOf, + 'min_length': annotated_types.MinLen, + 'max_length': annotated_types.MaxLen, + 'pattern': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'union_mode': None, + 'coerce_numbers_to_str': None, + 'fail_fast': types.FailFast, + } + + def __init__(self, **kwargs: Unpack[_FieldInfoInputs]) -> None: + """This class should generally not be initialized directly; instead, use the `pydantic.fields.Field` function + or one of the constructor classmethods. + + See the signature of `pydantic.fields.Field` for more details about the expected arguments. + """ + # Tracking the explicitly set attributes is necessary to correctly merge `Field()` functions + # (e.g. with `Annotated[int, Field(alias='a'), Field(alias=None)]`, even though `None` is the default value, + # we need to track that `alias=None` was explicitly set): + self._attributes_set = {k: v for k, v in kwargs.items() if v is not _Unset and k not in self.metadata_lookup} + kwargs = {k: _DefaultValues.get(k) if v is _Unset else v for k, v in kwargs.items()} # type: ignore + self.annotation = kwargs.get('annotation') + + # Note: in theory, the second `pop()` arguments are not required below, as defaults are already set from `_DefaultsValues`. + default = kwargs.pop('default', PydanticUndefined) + if default is Ellipsis: + self.default = PydanticUndefined + self._attributes_set.pop('default', None) + else: + self.default = default + + self.default_factory = kwargs.pop('default_factory', None) + + if self.default is not PydanticUndefined and self.default_factory is not None: + raise TypeError('cannot specify both default and default_factory') + + self.alias = kwargs.pop('alias', None) + self.validation_alias = kwargs.pop('validation_alias', None) + self.serialization_alias = kwargs.pop('serialization_alias', None) + alias_is_set = any(alias is not None for alias in (self.alias, self.validation_alias, self.serialization_alias)) + self.alias_priority = kwargs.pop('alias_priority', None) or 2 if alias_is_set else None + self.title = kwargs.pop('title', None) + self.field_title_generator = kwargs.pop('field_title_generator', None) + self.description = kwargs.pop('description', None) + self.examples = kwargs.pop('examples', None) + self.exclude = kwargs.pop('exclude', None) + self.exclude_if = kwargs.pop('exclude_if', None) + self.discriminator = kwargs.pop('discriminator', None) + # For compatibility with FastAPI<=0.110.0, we preserve the existing value if it is not overridden + self.deprecated = kwargs.pop('deprecated', getattr(self, 'deprecated', None)) + self.repr = kwargs.pop('repr', True) + self.json_schema_extra = kwargs.pop('json_schema_extra', None) + self.validate_default = kwargs.pop('validate_default', None) + self.frozen = kwargs.pop('frozen', None) + # currently only used on dataclasses + self.init = kwargs.pop('init', None) + self.init_var = kwargs.pop('init_var', None) + self.kw_only = kwargs.pop('kw_only', None) + + self.metadata = self._collect_metadata(kwargs) # type: ignore + + # Private attributes: + self._qualifiers: set[Qualifier] = set() + # Used to rebuild FieldInfo instances: + self._complete = True + self._original_annotation: Any = PydanticUndefined + self._original_assignment: Any = PydanticUndefined + # Used to track whether the `FieldInfo` instance represents the data about a field (and is exposed in `model_fields`/`__pydantic_fields__`), + # or if it is the result of the `Field()` function being used as metadata in an `Annotated` type/as an assignment + # (not an ideal pattern, see https://github.com/pydantic/pydantic/issues/11122): + self._final = False + + @staticmethod + def from_field(default: Any = PydanticUndefined, **kwargs: Unpack[_FromFieldInfoInputs]) -> FieldInfo: + """Create a new `FieldInfo` object with the `Field` function. + + Args: + default: The default value for the field. Defaults to Undefined. + **kwargs: Additional arguments dictionary. + + Raises: + TypeError: If 'annotation' is passed as a keyword argument. + + Returns: + A new FieldInfo object with the given parameters. + + Example: + This is how you can create a field with default value like this: + + ```python + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int = pydantic.Field(4) + ``` + """ + if 'annotation' in kwargs: + raise TypeError('"annotation" is not permitted as a Field keyword argument') + return FieldInfo(default=default, **kwargs) + + @staticmethod + def from_annotation(annotation: type[Any], *, _source: AnnotationSource = AnnotationSource.ANY) -> FieldInfo: + """Creates a `FieldInfo` instance from a bare annotation. + + This function is used internally to create a `FieldInfo` from a bare annotation like this: + + ```python + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int # <-- like this + ``` + + We also account for the case where the annotation can be an instance of `Annotated` and where + one of the (not first) arguments in `Annotated` is an instance of `FieldInfo`, e.g.: + + ```python + from typing import Annotated + + import annotated_types + + import pydantic + + class MyModel(pydantic.BaseModel): + foo: Annotated[int, annotated_types.Gt(42)] + bar: Annotated[int, pydantic.Field(gt=42)] + ``` + + Args: + annotation: An annotation object. + + Returns: + An instance of the field metadata. + """ + try: + inspected_ann = inspect_annotation( + annotation, + annotation_source=_source, + unpack_type_aliases='skip', + ) + except ForbiddenQualifier as e: + raise PydanticForbiddenQualifier(e.qualifier, annotation) + + # TODO check for classvar and error? + + # No assigned value, this happens when using a bare `Final` qualifier (also for other + # qualifiers, but they shouldn't appear here). In this case we infer the type as `Any` + # because we don't have any assigned value. + type_expr: Any = Any if inspected_ann.type is UNKNOWN else inspected_ann.type + final = 'final' in inspected_ann.qualifiers + metadata = inspected_ann.metadata + + attr_overrides = {'annotation': type_expr} + if final: + attr_overrides['frozen'] = True + field_info = FieldInfo._construct(metadata, **attr_overrides) + field_info._qualifiers = inspected_ann.qualifiers + field_info._final = True + return field_info + + @staticmethod + def from_annotated_attribute( + annotation: type[Any], default: Any, *, _source: AnnotationSource = AnnotationSource.ANY + ) -> FieldInfo: + """Create `FieldInfo` from an annotation with a default value. + + This is used in cases like the following: + + ```python + from typing import Annotated + + import annotated_types + + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int = 4 # <-- like this + bar: Annotated[int, annotated_types.Gt(4)] = 4 # <-- or this + spam: Annotated[int, pydantic.Field(gt=4)] = 4 # <-- or this + ``` + + Args: + annotation: The type annotation of the field. + default: The default value of the field. + + Returns: + A field object with the passed values. + """ + if annotation is not MISSING and annotation is default: + raise PydanticUserError( + 'Error when building FieldInfo from annotated attribute. ' + "Make sure you don't have any field name clashing with a type annotation.", + code='unevaluable-type-annotation', + ) + + try: + inspected_ann = inspect_annotation( + annotation, + annotation_source=_source, + unpack_type_aliases='skip', + ) + except ForbiddenQualifier as e: + raise PydanticForbiddenQualifier(e.qualifier, annotation) + + # TODO check for classvar and error? + + # TODO infer from the default, this can be done in v3 once we treat final fields with + # a default as proper fields and not class variables: + type_expr: Any = Any if inspected_ann.type is UNKNOWN else inspected_ann.type + final = 'final' in inspected_ann.qualifiers + metadata = inspected_ann.metadata + + # HACK 1: the order in which the metadata is merged is inconsistent; we need to prepend + # metadata from the assignment at the beginning of the metadata. Changing this is only + # possible in v3 (at least). See https://github.com/pydantic/pydantic/issues/10507 + prepend_metadata: list[Any] | None = None + attr_overrides = {'annotation': type_expr} + if final: + attr_overrides['frozen'] = True + + # HACK 2: FastAPI is subclassing `FieldInfo` and historically expected the actual + # instance's type to be preserved when constructing new models with its subclasses as assignments. + # This code is never reached by Pydantic itself, and in an ideal world this shouldn't be necessary. + if not metadata and isinstance(default, FieldInfo) and type(default) is not FieldInfo: + field_info = default._copy() + field_info._attributes_set.update(attr_overrides) + for k, v in attr_overrides.items(): + setattr(field_info, k, v) + return field_info + + if isinstance(default, FieldInfo): + default_copy = default._copy() # Copy unnecessary when we remove HACK 1. + prepend_metadata = default_copy.metadata + default_copy.metadata = [] + metadata = metadata + [default_copy] + elif isinstance(default, dataclasses.Field): + from_field = FieldInfo._from_dataclass_field(default) + prepend_metadata = from_field.metadata # Unnecessary when we remove HACK 1. + from_field.metadata = [] + metadata = metadata + [from_field] + if 'init_var' in inspected_ann.qualifiers: + attr_overrides['init_var'] = True + if (init := getattr(default, 'init', None)) is not None: + attr_overrides['init'] = init + if (kw_only := getattr(default, 'kw_only', None)) is not None: + attr_overrides['kw_only'] = kw_only + else: + # `default` is the actual default value + attr_overrides['default'] = default + + field_info = FieldInfo._construct( + prepend_metadata + metadata if prepend_metadata is not None else metadata, **attr_overrides + ) + field_info._qualifiers = inspected_ann.qualifiers + field_info._final = True + return field_info + + @classmethod + def _construct(cls, metadata: list[Any], **attr_overrides: Any) -> Self: + """Construct the final `FieldInfo` instance, by merging the possibly existing `FieldInfo` instances from the metadata. + + With the following example: + + ```python {test="skip" lint="skip"} + class Model(BaseModel): + f: Annotated[int, Gt(1), Field(description='desc', lt=2)] + ``` + + `metadata` refers to the metadata elements of the `Annotated` form. This metadata is iterated over from left to right: + + - If the element is a `Field()` function (which is itself a `FieldInfo` instance), the field attributes (such as + `description`) are saved to be set on the final `FieldInfo` instance. + On the other hand, some kwargs (such as `lt`) are stored as `metadata` (see `FieldInfo.__init__()`, calling + `FieldInfo._collect_metadata()`). In this case, the final metadata list is extended with the one from this instance. + - Else, the element is considered as a single metadata object, and is appended to the final metadata list. + + Args: + metadata: The list of metadata elements to merge together. If the `FieldInfo` instance to be constructed is for + a field with an assigned `Field()`, this `Field()` assignment should be added as the last element of the + provided metadata. + **attr_overrides: Extra attributes that should be set on the final merged `FieldInfo` instance. + + Returns: + The final merged `FieldInfo` instance. + """ + merged_metadata: list[Any] = [] + merged_kwargs: dict[str, Any] = {} + + for meta in metadata: + if isinstance(meta, FieldInfo): + merged_metadata.extend(meta.metadata) + + new_js_extra: JsonDict | None = None + current_js_extra = meta.json_schema_extra + if current_js_extra is not None and 'json_schema_extra' in merged_kwargs: + # We need to merge `json_schema_extra`'s: + existing_js_extra = merged_kwargs['json_schema_extra'] + if isinstance(existing_js_extra, dict): + if isinstance(current_js_extra, dict): + new_js_extra = { + **existing_js_extra, + **current_js_extra, + } + elif callable(current_js_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported. ' + 'The `callable` type is being ignored. ' + "If you'd like support for this behavior, please open an issue on pydantic.", + UserWarning, + ) + elif callable(existing_js_extra) and isinstance(current_js_extra, dict): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported. ' + 'The `callable` type is being ignored. ' + "If you'd like support for this behavior, please open an issue on pydantic.", + UserWarning, + ) + + # HACK: It is common for users to define "make model partial" (or similar) utilities, that + # convert all model fields to be optional (i.e. have a default value). To do so, they mutate + # each `FieldInfo` instance from `model_fields` to set a `default`, and use `create_model()` + # with `Annotated[ | None, mutated_field_info]`` as an annotation. However, such + # mutations (by doing simple assignments) are only accidentally working, because we also + # need to track attributes explicitly set in `_attributes_set` (relying on default values for + # each attribute is *not* enough, for instance with `Annotated[int, Field(alias='a'), Field(alias=None)]` + # the resulting `FieldInfo` should have `alias=None`). + # To mitigate this, we add a special case when a "final" `FieldInfo` instance (that is an instance coming + # from `model_fields`) is used in annotated metadata (or assignment). In this case, we assume *all* attributes + # were explicitly set, and as such we use all of them (and this will correctly pick up the mutations). + # In theory, this shouldn't really be supported, you are only supposed to use the `Field()` function, not + # a `FieldInfo` instance directly (granted, `Field()` returns a `FieldInfo`, see + # https://github.com/pydantic/pydantic/issues/11122): + if meta._final: + merged_kwargs.update({attr: getattr(meta, attr) for attr in _Attrs}) + else: + merged_kwargs.update(meta._attributes_set) + + if new_js_extra is not None: + merged_kwargs['json_schema_extra'] = new_js_extra + elif typing_objects.is_deprecated(meta): + merged_kwargs['deprecated'] = meta + else: + merged_metadata.append(meta) + + merged_kwargs.update(attr_overrides) + merged_field_info = cls(**merged_kwargs) + merged_field_info.metadata = merged_metadata + return merged_field_info + + @staticmethod + @typing_extensions.deprecated( + "The 'merge_field_infos()' method is deprecated and will be removed in a future version. " + 'If you relied on this method, please open an issue in the Pydantic issue tracker.', + category=None, + ) + def merge_field_infos(*field_infos: FieldInfo, **overrides: Any) -> FieldInfo: + """Merge `FieldInfo` instances keeping only explicitly set attributes. + + Later `FieldInfo` instances override earlier ones. + + Returns: + FieldInfo: A merged FieldInfo instance. + """ + if len(field_infos) == 1: + # No merging necessary, but we still need to make a copy and apply the overrides + field_info = field_infos[0]._copy() + field_info._attributes_set.update(overrides) + + default_override = overrides.pop('default', PydanticUndefined) + if default_override is Ellipsis: + default_override = PydanticUndefined + if default_override is not PydanticUndefined: + field_info.default = default_override + + for k, v in overrides.items(): + setattr(field_info, k, v) + return field_info # type: ignore + + merged_field_info_kwargs: dict[str, Any] = {} + metadata = {} + for field_info in field_infos: + attributes_set = field_info._attributes_set.copy() + + try: + json_schema_extra = attributes_set.pop('json_schema_extra') + existing_json_schema_extra = merged_field_info_kwargs.get('json_schema_extra') + + if existing_json_schema_extra is None: + merged_field_info_kwargs['json_schema_extra'] = json_schema_extra + if isinstance(existing_json_schema_extra, dict): + if isinstance(json_schema_extra, dict): + merged_field_info_kwargs['json_schema_extra'] = { + **existing_json_schema_extra, + **json_schema_extra, + } + if callable(json_schema_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported.' + 'The `callable` type is being ignored.' + "If you'd like support for this behavior, please open an issue on pydantic.", + PydanticJsonSchemaWarning, + ) + elif callable(json_schema_extra): + # if ever there's a case of a callable, we'll just keep the last json schema extra spec + merged_field_info_kwargs['json_schema_extra'] = json_schema_extra + except KeyError: + pass + + # later FieldInfo instances override everything except json_schema_extra from earlier FieldInfo instances + merged_field_info_kwargs.update(attributes_set) + + for x in field_info.metadata: + if not isinstance(x, FieldInfo): + metadata[type(x)] = x + + merged_field_info_kwargs.update(overrides) + field_info = FieldInfo(**merged_field_info_kwargs) + field_info.metadata = list(metadata.values()) + return field_info + + @staticmethod + def _from_dataclass_field(dc_field: DataclassField[Any]) -> FieldInfo: + """Return a new `FieldInfo` instance from a `dataclasses.Field` instance. + + Args: + dc_field: The `dataclasses.Field` instance to convert. + + Returns: + The corresponding `FieldInfo` instance. + + Raises: + TypeError: If any of the `FieldInfo` kwargs does not match the `dataclass.Field` kwargs. + """ + default = dc_field.default + if default is dataclasses.MISSING: + default = _Unset + + if dc_field.default_factory is dataclasses.MISSING: + default_factory = _Unset + else: + default_factory = dc_field.default_factory + + # use the `Field` function so in correct kwargs raise the correct `TypeError` + dc_field_metadata = {k: v for k, v in dc_field.metadata.items() if k in _FIELD_ARG_NAMES} + if sys.version_info >= (3, 14) and dc_field.doc is not None: + dc_field_metadata['description'] = dc_field.doc + return Field(default=default, default_factory=default_factory, repr=dc_field.repr, **dc_field_metadata) # pyright: ignore[reportCallIssue] + + @staticmethod + def _collect_metadata(kwargs: dict[str, Any]) -> list[Any]: + """Collect annotations from kwargs. + + Args: + kwargs: Keyword arguments passed to the function. + + Returns: + A list of metadata objects - a combination of `annotated_types.BaseMetadata` and + `PydanticMetadata`. + """ + metadata: list[Any] = [] + general_metadata = {} + for key, value in list(kwargs.items()): + try: + marker = FieldInfo.metadata_lookup[key] + except KeyError: + continue + + del kwargs[key] + if value is not None: + if marker is None: + general_metadata[key] = value + else: + metadata.append(marker(value)) + if general_metadata: + metadata.append(_fields.pydantic_general_metadata(**general_metadata)) + return metadata + + @property + def deprecation_message(self) -> str | None: + """The deprecation message to be emitted, or `None` if not set.""" + if self.deprecated is None: + return None + if isinstance(self.deprecated, bool): + return 'deprecated' if self.deprecated else None + return self.deprecated if isinstance(self.deprecated, str) else self.deprecated.message + + @property + def default_factory_takes_validated_data(self) -> bool | None: + """Whether the provided default factory callable has a validated data parameter. + + Returns `None` if no default factory is set. + """ + if self.default_factory is not None: + return _fields.takes_validated_data_argument(self.default_factory) + + @overload + def get_default( + self, *, call_default_factory: Literal[True], validated_data: dict[str, Any] | None = None + ) -> Any: ... + + @overload + def get_default(self, *, call_default_factory: Literal[False] = ...) -> Any: ... + + def get_default(self, *, call_default_factory: bool = False, validated_data: dict[str, Any] | None = None) -> Any: + """Get the default value. + + We expose an option for whether to call the default_factory (if present), as calling it may + result in side effects that we want to avoid. However, there are times when it really should + be called (namely, when instantiating a model via `model_construct`). + + Args: + call_default_factory: Whether to call the default factory or not. + validated_data: The already validated data to be passed to the default factory. + + Returns: + The default value, calling the default factory if requested or `None` if not set. + """ + if self.default_factory is None: + return _utils.smart_deepcopy(self.default) + elif call_default_factory: + if self.default_factory_takes_validated_data: + fac = cast('Callable[[dict[str, Any]], Any]', self.default_factory) + if validated_data is None: + raise ValueError( + "The default factory requires the 'validated_data' argument, which was not provided when calling 'get_default'." + ) + return fac(validated_data) + else: + fac = cast('Callable[[], Any]', self.default_factory) + return fac() + else: + return None + + def is_required(self) -> bool: + """Check if the field is required (i.e., does not have a default value or factory). + + Returns: + `True` if the field is required, `False` otherwise. + """ + return self.default is PydanticUndefined and self.default_factory is None + + def rebuild_annotation(self) -> Any: + """Attempts to rebuild the original annotation for use in function signatures. + + If metadata is present, it adds it to the original annotation using + `Annotated`. Otherwise, it returns the original annotation as-is. + + Note that because the metadata has been flattened, the original annotation + may not be reconstructed exactly as originally provided, e.g. if the original + type had unrecognized annotations, or was annotated with a call to `pydantic.Field`. + + Returns: + The rebuilt annotation. + """ + if not self.metadata: + return self.annotation + else: + # Annotated arguments must be a tuple + return Annotated[(self.annotation, *self.metadata)] # type: ignore + + def apply_typevars_map( + self, + typevars_map: Mapping[TypeVar, Any] | None, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + ) -> None: + """Apply a `typevars_map` to the annotation. + + This method is used when analyzing parametrized generic types to replace typevars with their concrete types. + + This method applies the `typevars_map` to the annotation in place. + + Args: + typevars_map: A dictionary mapping type variables to their concrete types. + globalns: The globals namespace to use during type annotation evaluation. + localns: The locals namespace to use during type annotation evaluation. + + See Also: + pydantic._internal._generics.replace_types is used for replacing the typevars with + their concrete types. + """ + annotation = _generics.replace_types(self.annotation, typevars_map) + annotation, evaluated = _typing_extra.try_eval_type(annotation, globalns, localns) + self.annotation = annotation + if not evaluated: + self._complete = False + self._original_annotation = self.annotation + + def asdict(self) -> _FieldInfoAsDict: + """Return a dictionary representation of the `FieldInfo` instance. + + The returned value is a dictionary with three items: + + * `annotation`: The type annotation of the field. + * `metadata`: The metadata list. + * `attributes`: A mapping of the remaining `FieldInfo` attributes to their values (e.g. `alias`, `title`). + """ + return { + 'annotation': self.annotation, + 'metadata': self.metadata, + 'attributes': {attr: getattr(self, attr) for attr in _Attrs}, + } + + def _copy(self) -> Self: + """Return a copy of the `FieldInfo` instance.""" + # Note: we can't define a custom `__copy__()`, as `FieldInfo` is being subclassed + # by some third-party libraries with extra attributes defined (and as `FieldInfo` + # is slotted, we can't make a copy of the `__dict__`). + copied = copy(self) + for attr_name in ('metadata', '_attributes_set', '_qualifiers'): + # Apply "deep-copy" behavior on collections attributes: + value = getattr(copied, attr_name).copy() + setattr(copied, attr_name, value) + + return copied + + def __repr_args__(self) -> ReprArgs: + yield 'annotation', _repr.PlainRepr(_repr.display_as_type(self.annotation)) + yield 'required', self.is_required() + + for s in self.__slots__: + # TODO: properly make use of the protocol (https://rich.readthedocs.io/en/stable/pretty.html#rich-repr-protocol) + # By yielding a three-tuple: + if s in ( + 'annotation', + '_attributes_set', + '_qualifiers', + '_complete', + '_original_assignment', + '_original_annotation', + '_final', + ): + continue + elif s == 'metadata' and not self.metadata: + continue + elif s == 'repr' and self.repr is True: + continue + if s == 'frozen' and self.frozen is False: + continue + if s == 'validation_alias' and self.validation_alias == self.alias: + continue + if s == 'serialization_alias' and self.serialization_alias == self.alias: + continue + if s == 'default' and self.default is not PydanticUndefined: + yield 'default', self.default + elif s == 'default_factory' and self.default_factory is not None: + yield 'default_factory', _repr.PlainRepr(_repr.display_as_type(self.default_factory)) + else: + value = getattr(self, s) + if value is not None and value is not PydanticUndefined: + yield s, value + + +class _EmptyKwargs(TypedDict): + """This class exists solely to ensure that type checking warns about passing `**extra` in `Field`.""" + + +_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, +} + +_DefaultValues = { + **_Attrs, + 'kw_only': None, + 'pattern': None, + 'strict': None, + 'gt': None, + 'ge': None, + 'lt': None, + 'le': None, + 'multiple_of': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'min_length': None, + 'max_length': None, + 'coerce_numbers_to_str': None, +} + + +_T = TypeVar('_T') + + +# NOTE: Actual return type is 'FieldInfo', but we want to help type checkers +# to understand the magic that happens at runtime with the following overloads: +@overload # type hint the return value as `Any` to avoid type checking regressions when using `...`. +def Field( + default: ellipsis, # noqa: F821 # TODO: use `_typing_extra.EllipsisType` when we drop Py3.9 + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default` argument set, validate_default=True (no type checking on the default value) +def Field( + default: Any, + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[True], + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default` argument set, validate_default=False or unset +def Field( + default: _T, + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + # NOTE: to get proper type checking on `exclude_if`'s argument, we could use `_T` instead of `Any`. However, + # this requires (at least for pyright) adding an additional overload where `exclude_if` is required (otherwise + # `a: int = Field(default_factory=str)` results in a false negative). + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[False] = ..., + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> _T: ... +@overload # `default_factory` argument set, validate_default=True (no type checking on the default value) +def Field( # pyright: ignore[reportOverlappingOverload] + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any], + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[True], + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default_factory` argument set, validate_default=False or unset +def Field( + *, + default_factory: Callable[[], _T] | Callable[[dict[str, Any]], _T], + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + # NOTE: to get proper type checking on `exclude_if`'s argument, we could use `_T` instead of `Any`. However, + # this requires (at least for pyright) adding an additional overload where `exclude_if` is required (otherwise + # `a: int = Field(default_factory=str)` results in a false negative). + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[False] | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> _T: ... +@overload +def Field( # No default set + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +def Field( # noqa: C901 + default: Any = PydanticUndefined, + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = _Unset, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: + """!!! abstract "Usage Documentation" + [Fields](../concepts/fields.md) + + Create a field for objects that can be configured. + + Used to provide extra information about a field, either for the model schema or complex validation. Some arguments + apply only to number fields (`int`, `float`, `Decimal`) and some apply only to `str`. + + Note: + - Any `_Unset` objects will be replaced by the corresponding value defined in the `_DefaultValues` dictionary. If a key for the `_Unset` object is not found in the `_DefaultValues` dictionary, it will default to `None` + + Args: + default: Default value if the field is not set. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the already validated data. + alias: The name to use for the attribute when validating or serializing by alias. + This is often used for things like converting between snake and camel case. + alias_priority: Priority of the alias. This affects whether an alias generator is used. + validation_alias: Like `alias`, but only affects validation, not serialization. + serialization_alias: Like `alias`, but only affects serialization, not validation. + title: Human-readable title. + field_title_generator: A callable that takes a field name and returns title for it. + description: Human-readable description. + examples: Example values for this field. + exclude: Whether to exclude the field from the model serialization. + exclude_if: A callable that determines whether to exclude a field during serialization based on its value. + discriminator: Field name or Discriminator for discriminating the type in a tagged union. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. + validate_default: If `True`, apply validation to the default value every time you create an instance. + Otherwise, for performance reasons, the default value of the field is trusted and not validated. + repr: A boolean indicating whether to include the field in the `__repr__` output. + init: Whether the field should be included in the constructor of the dataclass. + (Only applies to dataclasses.) + init_var: Whether the field should _only_ be included in the constructor of the dataclass. + (Only applies to dataclasses.) + kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass. + (Only applies to dataclasses.) + coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). + strict: If `True`, strict validation is applied to the field. + See [Strict Mode](../concepts/strict_mode.md) for details. + gt: Greater than. If set, value must be greater than this. Only applicable to numbers. + ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. + lt: Less than. If set, value must be less than this. Only applicable to numbers. + le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. + multiple_of: Value must be a multiple of this. Only applicable to numbers. + min_length: Minimum length for iterables. + max_length: Maximum length for iterables. + pattern: Pattern for strings (a regular expression). + allow_inf_nan: Allow `inf`, `-inf`, `nan`. Only applicable to float and [`Decimal`][decimal.Decimal] numbers. + max_digits: Maximum number of allow digits for strings. + decimal_places: Maximum number of decimal places allowed for numbers. + union_mode: The strategy to apply when validating a union. Can be `smart` (the default), or `left_to_right`. + See [Union Mode](../concepts/unions.md#union-modes) for details. + fail_fast: If `True`, validation will stop on the first error. If `False`, all validation errors will be collected. + This option can be applied only to iterable types (list, tuple, set, and frozenset). + extra: (Deprecated) Extra fields that will be included in the JSON schema. + + !!! warning Deprecated + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + + Returns: + A new [`FieldInfo`][pydantic.fields.FieldInfo]. The return annotation is `Any` so `Field` can be used on + type-annotated fields without causing a type error. + """ + # Check deprecated and removed params from V1. This logic should eventually be removed. + const = extra.pop('const', None) # type: ignore + if const is not None: + raise PydanticUserError('`const` is removed, use `Literal` instead', code='removed-kwargs') + + min_items = extra.pop('min_items', None) # type: ignore + if min_items is not None: + warn( + '`min_items` is deprecated and will be removed, use `min_length` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if min_length in (None, _Unset): + min_length = min_items # type: ignore + + max_items = extra.pop('max_items', None) # type: ignore + if max_items is not None: + warn( + '`max_items` is deprecated and will be removed, use `max_length` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if max_length in (None, _Unset): + max_length = max_items # type: ignore + + unique_items = extra.pop('unique_items', None) # type: ignore + if unique_items is not None: + raise PydanticUserError( + ( + '`unique_items` is removed, use `Set` instead' + '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)' + ), + code='removed-kwargs', + ) + + allow_mutation = extra.pop('allow_mutation', None) # type: ignore + if allow_mutation is not None: + warn( + '`allow_mutation` is deprecated and will be removed. use `frozen` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if allow_mutation is False: + frozen = True + + regex = extra.pop('regex', None) # type: ignore + if regex is not None: + raise PydanticUserError('`regex` is removed. use `pattern` instead', code='removed-kwargs') + + if extra: + warn( + 'Using extra keyword arguments on `Field` is deprecated and will be removed.' + ' Use `json_schema_extra` instead.' + f' (Extra keys: {", ".join(k.__repr__() for k in extra.keys())})', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if not json_schema_extra or json_schema_extra is _Unset: + json_schema_extra = extra # type: ignore + + if ( + validation_alias + and validation_alias is not _Unset + and not isinstance(validation_alias, (str, AliasChoices, AliasPath)) + ): + raise TypeError('Invalid `validation_alias` type. it should be `str`, `AliasChoices`, or `AliasPath`') + + if serialization_alias in (_Unset, None) and isinstance(alias, str): + serialization_alias = alias + + if validation_alias in (_Unset, None): + validation_alias = alias + + include = extra.pop('include', None) # type: ignore + if include is not None: + warn( + '`include` is deprecated and does nothing. It will be removed, use `exclude` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + return FieldInfo.from_field( + default, + default_factory=default_factory, + alias=alias, + alias_priority=alias_priority, + validation_alias=validation_alias, + serialization_alias=serialization_alias, + title=title, + field_title_generator=field_title_generator, + description=description, + examples=examples, + exclude=exclude, + exclude_if=exclude_if, + discriminator=discriminator, + deprecated=deprecated, + json_schema_extra=json_schema_extra, + frozen=frozen, + pattern=pattern, + validate_default=validate_default, + repr=repr, + init=init, + init_var=init_var, + kw_only=kw_only, + coerce_numbers_to_str=coerce_numbers_to_str, + strict=strict, + gt=gt, + ge=ge, + lt=lt, + le=le, + multiple_of=multiple_of, + min_length=min_length, + max_length=max_length, + allow_inf_nan=allow_inf_nan, + max_digits=max_digits, + decimal_places=decimal_places, + union_mode=union_mode, + fail_fast=fail_fast, + ) + + +_FIELD_ARG_NAMES = set(inspect.signature(Field).parameters) +_FIELD_ARG_NAMES.remove('extra') # do not include the varkwargs parameter + + +class ModelPrivateAttr(_repr.Representation): + """A descriptor for private attributes in class models. + + !!! warning + You generally shouldn't be creating `ModelPrivateAttr` instances directly, instead use + `pydantic.fields.PrivateAttr`. (This is similar to `FieldInfo` vs. `Field`.) + + Attributes: + default: The default value of the attribute if not provided. + default_factory: A callable function that generates the default value of the + attribute if not provided. + """ + + __slots__ = ('default', 'default_factory') + + def __init__(self, default: Any = PydanticUndefined, *, default_factory: Callable[[], Any] | None = None) -> None: + if default is Ellipsis: + self.default = PydanticUndefined + else: + self.default = default + self.default_factory = default_factory + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """This function improves compatibility with custom descriptors by ensuring delegation happens + as expected when the default value of a private attribute is a descriptor. + """ + if item in {'__get__', '__set__', '__delete__'}: + if hasattr(self.default, item): + return getattr(self.default, item) + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + def __set_name__(self, cls: type[Any], name: str) -> None: + """Preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487.""" + default = self.default + if default is PydanticUndefined: + return + set_name = getattr(default, '__set_name__', None) + if callable(set_name): + set_name(cls, name) + + def get_default(self) -> Any: + """Retrieve the default value of the object. + + If `self.default_factory` is `None`, the method will return a deep copy of the `self.default` object. + + If `self.default_factory` is not `None`, it will call `self.default_factory` and return the value returned. + + Returns: + The default value of the object. + """ + return _utils.smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and (self.default, self.default_factory) == ( + other.default, + other.default_factory, + ) + + +# NOTE: Actual return type is 'ModelPrivateAttr', but we want to help type checkers +# to understand the magic that happens at runtime. +@overload # `default` argument set +def PrivateAttr( + default: _T, + *, + init: Literal[False] = False, +) -> _T: ... +@overload # `default_factory` argument set +def PrivateAttr( + *, + default_factory: Callable[[], _T], + init: Literal[False] = False, +) -> _T: ... +@overload # No default set +def PrivateAttr( + *, + init: Literal[False] = False, +) -> Any: ... +def PrivateAttr( + default: Any = PydanticUndefined, + *, + default_factory: Callable[[], Any] | None = None, + init: Literal[False] = False, +) -> Any: + """!!! abstract "Usage Documentation" + [Private Model Attributes](../concepts/models.md#private-model-attributes) + + Indicates that an attribute is intended for private use and not handled during normal validation/serialization. + + Private attributes are not validated by Pydantic, so it's up to you to ensure they are used in a type-safe manner. + + Private attributes are stored in `__private_attributes__` on the model. + + Args: + default: The attribute's default value. Defaults to Undefined. + default_factory: Callable that will be + called when a default value is needed for this attribute. + If both `default` and `default_factory` are set, an error will be raised. + init: Whether the attribute should be included in the constructor of the dataclass. Always `False`. + + Returns: + An instance of [`ModelPrivateAttr`][pydantic.fields.ModelPrivateAttr] class. + + Raises: + ValueError: If both `default` and `default_factory` are set. + """ + if default is not PydanticUndefined and default_factory is not None: + raise TypeError('cannot specify both default and default_factory') + + return ModelPrivateAttr( + default, + default_factory=default_factory, + ) + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class ComputedFieldInfo: + """A container for data from `@computed_field` so that we can access it while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@computed_field'. + wrapped_property: The wrapped computed field property. + return_type: The type of the computed field property's return value. + alias: The alias of the property to be used during serialization. + alias_priority: The priority of the alias. This affects whether an alias generator is used. + title: Title of the computed field to include in the serialization JSON schema. + field_title_generator: A callable that takes a field name and returns title for it. + description: Description of the computed field to include in the serialization JSON schema. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + examples: Example values of the computed field to include in the serialization JSON schema. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + repr: A boolean indicating whether to include the field in the __repr__ output. + """ + + decorator_repr: ClassVar[str] = '@computed_field' + wrapped_property: property + return_type: Any + alias: str | None + alias_priority: int | None + title: str | None + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None + description: str | None + deprecated: Deprecated | str | bool | None + examples: list[Any] | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + repr: bool + + @property + def deprecation_message(self) -> str | None: + """The deprecation message to be emitted, or `None` if not set.""" + if self.deprecated is None: + return None + if isinstance(self.deprecated, bool): + return 'deprecated' if self.deprecated else None + return self.deprecated if isinstance(self.deprecated, str) else self.deprecated.message + + def _update_from_config(self, config_wrapper: ConfigWrapper, name: str) -> None: + """Update the instance from the configuration set on the class this computed field belongs to.""" + title_generator = self.field_title_generator or config_wrapper.field_title_generator + if title_generator is not None and self.title is None: + self.title = title_generator(name, self) + if config_wrapper.alias_generator is not None: + self._apply_alias_generator(config_wrapper.alias_generator, name) + + def _apply_alias_generator(self, alias_generator: Callable[[str], str] | AliasGenerator, name: str) -> None: + """Apply an alias generator to aliases if appropriate. + + Args: + alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance. + name: The name of the computed field from which to generate the alias. + """ + # Apply an alias_generator if + # 1. An alias is not specified + # 2. An alias is specified, but the priority is <= 1 + + if self.alias_priority is None or self.alias_priority <= 1 or self.alias is None: + alias, _, serialization_alias = None, None, None + + if isinstance(alias_generator, AliasGenerator): + alias, _, serialization_alias = alias_generator.generate_aliases(name) + elif callable(alias_generator): + alias = alias_generator(name) + + # if priority is not set, we set to 1 + # which supports the case where the alias_generator from a child class is used + # to generate an alias for a field in a parent class + if self.alias_priority is None or self.alias_priority <= 1: + self.alias_priority = 1 + + # if the priority is 1, then we set the aliases to the generated alias + # note that we use the serialization_alias with priority over alias, as computed_field + # aliases are used for serialization only (not validation) + if self.alias_priority == 1: + self.alias = _utils.get_first_not_none(serialization_alias, alias) + + +def _wrapped_property_is_private(property_: cached_property | property) -> bool: # type: ignore + """Returns true if provided property is private, False otherwise.""" + wrapped_name: str = '' + + if isinstance(property_, property): + wrapped_name = getattr(property_.fget, '__name__', '') + elif isinstance(property_, cached_property): # type: ignore + wrapped_name = getattr(property_.func, '__name__', '') # type: ignore + + return wrapped_name.startswith('_') and not wrapped_name.startswith('__') + + +# this should really be `property[T], cached_property[T]` but property is not generic unlike cached_property +# See https://github.com/python/typing/issues/985 and linked issues +PropertyT = TypeVar('PropertyT') + + +@overload +def computed_field(func: PropertyT, /) -> PropertyT: ... + + +@overload +def computed_field( + *, + alias: str | None = None, + alias_priority: int | None = None, + title: str | None = None, + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None = None, + description: str | None = None, + deprecated: Deprecated | str | bool | None = None, + examples: list[Any] | None = None, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = None, + repr: bool = True, + return_type: Any = PydanticUndefined, +) -> Callable[[PropertyT], PropertyT]: ... + + +def computed_field( + func: PropertyT | None = None, + /, + *, + alias: str | None = None, + alias_priority: int | None = None, + title: str | None = None, + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None = None, + description: str | None = None, + deprecated: Deprecated | str | bool | None = None, + examples: list[Any] | None = None, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = None, + repr: bool | None = None, + return_type: Any = PydanticUndefined, +) -> PropertyT | Callable[[PropertyT], PropertyT]: + """!!! abstract "Usage Documentation" + [The `computed_field` decorator](../concepts/fields.md#the-computed_field-decorator) + + Decorator to include `property` and `cached_property` when serializing models or dataclasses. + + This is useful for fields that are computed from other fields, or for fields that are expensive to compute and should be cached. + + ```python + from pydantic import BaseModel, computed_field + + class Rectangle(BaseModel): + width: int + length: int + + @computed_field + @property + def area(self) -> int: + return self.width * self.length + + print(Rectangle(width=3, length=2).model_dump()) + #> {'width': 3, 'length': 2, 'area': 6} + ``` + + If applied to functions not yet decorated with `@property` or `@cached_property`, the function is + automatically wrapped with `property`. Although this is more concise, you will lose IntelliSense in your IDE, + and confuse static type checkers, thus explicit use of `@property` is recommended. + + !!! warning "Mypy Warning" + Even with the `@property` or `@cached_property` applied to your function before `@computed_field`, + mypy may throw a `Decorated property not supported` error. + See [mypy issue #1362](https://github.com/python/mypy/issues/1362), for more information. + To avoid this error message, add `# type: ignore[prop-decorator]` to the `@computed_field` line. + + [pyright](https://github.com/microsoft/pyright) supports `@computed_field` without error. + + ```python + import random + + from pydantic import BaseModel, computed_field + + class Square(BaseModel): + width: float + + @computed_field + def area(self) -> float: # converted to a `property` by `computed_field` + return round(self.width**2, 2) + + @area.setter + def area(self, new_area: float) -> None: + self.width = new_area**0.5 + + @computed_field(alias='the magic number', repr=False) + def random_number(self) -> int: + return random.randint(0, 1_000) + + square = Square(width=1.3) + + # `random_number` does not appear in representation + print(repr(square)) + #> Square(width=1.3, area=1.69) + + print(square.random_number) + #> 3 + + square.area = 4 + + print(square.model_dump_json(by_alias=True)) + #> {"width":2.0,"area":4.0,"the magic number":3} + ``` + + !!! warning "Overriding with `computed_field`" + You can't override a field from a parent class with a `computed_field` in the child class. + `mypy` complains about this behavior if allowed, and `dataclasses` doesn't allow this pattern either. + See the example below: + + ```python + from pydantic import BaseModel, computed_field + + class Parent(BaseModel): + a: str + + try: + + class Child(Parent): + @computed_field + @property + def a(self) -> str: + return 'new a' + + except TypeError as e: + print(e) + ''' + Field 'a' of class 'Child' overrides symbol of same name in a parent class. This override with a computed_field is incompatible. + ''' + ``` + + Private properties decorated with `@computed_field` have `repr=False` by default. + + ```python + from functools import cached_property + + from pydantic import BaseModel, computed_field + + class Model(BaseModel): + foo: int + + @computed_field + @cached_property + def _private_cached_property(self) -> int: + return -self.foo + + @computed_field + @property + def _private_property(self) -> int: + return -self.foo + + m = Model(foo=1) + print(repr(m)) + #> Model(foo=1) + ``` + + Args: + func: the function to wrap. + alias: alias to use when serializing this computed field, only used when `by_alias=True` + alias_priority: priority of the alias. This affects whether an alias generator is used + title: Title to use when including this computed field in JSON Schema + field_title_generator: A callable that takes a field name and returns title for it. + description: Description to use when including this computed field in JSON Schema, defaults to the function's + docstring + deprecated: A deprecation message (or an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport). + to be emitted when accessing the field. Or a boolean. This will automatically be set if the property is decorated with the + `deprecated` decorator. + examples: Example values to use when including this computed field in JSON Schema + json_schema_extra: A dict or callable to provide extra JSON schema properties. + repr: whether to include this computed field in model repr. + Default is `False` for private properties and `True` for public properties. + return_type: optional return for serialization logic to expect when serializing to JSON, if included + this must be correct, otherwise a `TypeError` is raised. + If you don't include a return type Any is used, which does runtime introspection to handle arbitrary + objects. + + Returns: + A proxy wrapper for the property. + """ + + def dec(f: Any) -> Any: + nonlocal description, deprecated, return_type, alias_priority + unwrapped = _decorators.unwrap_wrapped_function(f) + + if description is None and unwrapped.__doc__: + description = inspect.cleandoc(unwrapped.__doc__) + + if deprecated is None and hasattr(unwrapped, '__deprecated__'): + deprecated = unwrapped.__deprecated__ + + # if the function isn't already decorated with `@property` (or another descriptor), then we wrap it now + f = _decorators.ensure_property(f) + alias_priority = (alias_priority or 2) if alias is not None else None + + if repr is None: + repr_: bool = not _wrapped_property_is_private(property_=f) + else: + repr_ = repr + + dec_info = ComputedFieldInfo( + f, + return_type, + alias, + alias_priority, + title, + field_title_generator, + description, + deprecated, + examples, + json_schema_extra, + repr_, + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + if func is None: + return dec + else: + return dec(func) diff --git a/backend/venv/Lib/site-packages/pydantic/functional_serializers.py b/backend/venv/Lib/site-packages/pydantic/functional_serializers.py new file mode 100644 index 0000000..0c1522f --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/functional_serializers.py @@ -0,0 +1,451 @@ +"""This module contains related classes and functions for serialization.""" + +from __future__ import annotations + +import dataclasses +from functools import partial, partialmethod +from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, overload + +from pydantic_core import PydanticUndefined, core_schema +from pydantic_core.core_schema import SerializationInfo, SerializerFunctionWrapHandler, WhenUsed +from typing_extensions import TypeAlias + +from . import PydanticUndefinedAnnotation +from ._internal import _decorators, _internal_dataclass +from .annotated_handlers import GetCoreSchemaHandler + + +@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class PlainSerializer: + """Plain serializers use a function to modify the output of serialization. + + This is particularly helpful when you want to customize the serialization for annotated types. + Consider an input of `list`, which will be serialized into a space-delimited string. + + ```python + from typing import Annotated + + from pydantic import BaseModel, PlainSerializer + + CustomStr = Annotated[ + list, PlainSerializer(lambda x: ' '.join(x), return_type=str) + ] + + class StudentModel(BaseModel): + courses: CustomStr + + student = StudentModel(courses=['Math', 'Chemistry', 'English']) + print(student.model_dump()) + #> {'courses': 'Math Chemistry English'} + ``` + + Attributes: + func: The serializer function. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, + `'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. + """ + + func: core_schema.SerializerFunction + return_type: Any = PydanticUndefined + when_used: WhenUsed = 'always' + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + """Gets the Pydantic core schema. + + Args: + source_type: The source type. + handler: The `GetCoreSchemaHandler` instance. + + Returns: + The Pydantic core schema. + """ + schema = handler(source_type) + if self.return_type is not PydanticUndefined: + return_type = self.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + self.func, + localns=handler._get_types_namespace().locals, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) + schema['serialization'] = core_schema.plain_serializer_function_ser_schema( + function=self.func, + info_arg=_decorators.inspect_annotated_serializer(self.func, 'plain'), + return_schema=return_schema, + when_used=self.when_used, + ) + return schema + + +@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class WrapSerializer: + """Wrap serializers receive the raw inputs along with a handler function that applies the standard serialization + logic, and can modify the resulting value before returning it as the final output of serialization. + + For example, here's a scenario in which a wrap serializer transforms timezones to UTC **and** utilizes the existing `datetime` serialization logic. + + ```python + from datetime import datetime, timezone + from typing import Annotated, Any + + from pydantic import BaseModel, WrapSerializer + + class EventDatetime(BaseModel): + start: datetime + end: datetime + + def convert_to_utc(value: Any, handler, info) -> dict[str, datetime]: + # Note that `handler` can actually help serialize the `value` for + # further custom serialization in case it's a subclass. + partial_result = handler(value, info) + if info.mode == 'json': + return { + k: datetime.fromisoformat(v).astimezone(timezone.utc) + for k, v in partial_result.items() + } + return {k: v.astimezone(timezone.utc) for k, v in partial_result.items()} + + UTCEventDatetime = Annotated[EventDatetime, WrapSerializer(convert_to_utc)] + + class EventModel(BaseModel): + event_datetime: UTCEventDatetime + + dt = EventDatetime( + start='2024-01-01T07:00:00-08:00', end='2024-01-03T20:00:00+06:00' + ) + event = EventModel(event_datetime=dt) + print(event.model_dump()) + ''' + { + 'event_datetime': { + 'start': datetime.datetime( + 2024, 1, 1, 15, 0, tzinfo=datetime.timezone.utc + ), + 'end': datetime.datetime( + 2024, 1, 3, 14, 0, tzinfo=datetime.timezone.utc + ), + } + } + ''' + + print(event.model_dump_json()) + ''' + {"event_datetime":{"start":"2024-01-01T15:00:00Z","end":"2024-01-03T14:00:00Z"}} + ''' + ``` + + Attributes: + func: The serializer function to be wrapped. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, + `'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. + """ + + func: core_schema.WrapSerializerFunction + return_type: Any = PydanticUndefined + when_used: WhenUsed = 'always' + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + """This method is used to get the Pydantic core schema of the class. + + Args: + source_type: Source type. + handler: Core schema handler. + + Returns: + The generated core schema of the class. + """ + schema = handler(source_type) + if self.return_type is not PydanticUndefined: + return_type = self.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + self.func, + localns=handler._get_types_namespace().locals, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) + schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + function=self.func, + info_arg=_decorators.inspect_annotated_serializer(self.func, 'wrap'), + return_schema=return_schema, + when_used=self.when_used, + ) + return schema + + +if TYPE_CHECKING: + _Partial: TypeAlias = 'partial[Any] | partialmethod[Any]' + + FieldPlainSerializer: TypeAlias = 'core_schema.SerializerFunction | _Partial' + """A field serializer method or function in `plain` mode.""" + + FieldWrapSerializer: TypeAlias = 'core_schema.WrapSerializerFunction | _Partial' + """A field serializer method or function in `wrap` mode.""" + + FieldSerializer: TypeAlias = 'FieldPlainSerializer | FieldWrapSerializer' + """A field serializer method or function.""" + + _FieldPlainSerializerT = TypeVar('_FieldPlainSerializerT', bound=FieldPlainSerializer) + _FieldWrapSerializerT = TypeVar('_FieldWrapSerializerT', bound=FieldWrapSerializer) + + +@overload +def field_serializer( + field: str, + /, + *fields: str, + mode: Literal['wrap'], + return_type: Any = ..., + when_used: WhenUsed = ..., + check_fields: bool | None = ..., +) -> Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT]: ... + + +@overload +def field_serializer( + field: str, + /, + *fields: str, + mode: Literal['plain'] = ..., + return_type: Any = ..., + when_used: WhenUsed = ..., + check_fields: bool | None = ..., +) -> Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT]: ... + + +def field_serializer( + *fields: str, + mode: Literal['plain', 'wrap'] = 'plain', + # TODO PEP 747 (grep for 'return_type' on the whole code base): + return_type: Any = PydanticUndefined, + when_used: WhenUsed = 'always', + check_fields: bool | None = None, +) -> ( + Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT] + | Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT] +): + """Decorator that enables custom field serialization. + + In the below example, a field of type `set` is used to mitigate duplication. A `field_serializer` is used to serialize the data as a sorted list. + + ```python + from pydantic import BaseModel, field_serializer + + class StudentModel(BaseModel): + name: str = 'Jane' + courses: set[str] + + @field_serializer('courses', when_used='json') + def serialize_courses_in_order(self, courses: set[str]): + return sorted(courses) + + student = StudentModel(courses={'Math', 'Chemistry', 'English'}) + print(student.model_dump_json()) + #> {"name":"Jane","courses":["Chemistry","English","Math"]} + ``` + + See [the usage documentation](../concepts/serialization.md#serializers) for more information. + + Four signatures are supported: + + - `(self, value: Any, info: FieldSerializationInfo)` + - `(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo)` + - `(value: Any, info: SerializationInfo)` + - `(value: Any, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)` + + Args: + fields: Which field(s) the method should be called on. + mode: The serialization mode. + + - `plain` means the function will be called instead of the default serialization logic, + - `wrap` means the function will be called with an argument to optionally call the + default serialization logic. + return_type: Optional return type for the function, if omitted it will be inferred from the type annotation. + when_used: Determines the serializer will be used for serialization. + check_fields: Whether to check that the fields actually exist on the model. + + Returns: + The decorator function. + """ + + def dec(f: FieldSerializer) -> _decorators.PydanticDescriptorProxy[Any]: + dec_info = _decorators.FieldSerializerDecoratorInfo( + fields=fields, + mode=mode, + return_type=return_type, + when_used=when_used, + check_fields=check_fields, + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) # pyright: ignore[reportArgumentType] + + return dec # pyright: ignore[reportReturnType] + + +if TYPE_CHECKING: + # The first argument in the following callables represent the `self` type: + + ModelPlainSerializerWithInfo: TypeAlias = Callable[[Any, SerializationInfo[Any]], Any] + """A model serializer method with the `info` argument, in `plain` mode.""" + + ModelPlainSerializerWithoutInfo: TypeAlias = Callable[[Any], Any] + """A model serializer method without the `info` argument, in `plain` mode.""" + + ModelPlainSerializer: TypeAlias = 'ModelPlainSerializerWithInfo | ModelPlainSerializerWithoutInfo' + """A model serializer method in `plain` mode.""" + + ModelWrapSerializerWithInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler, SerializationInfo[Any]], Any] + """A model serializer method with the `info` argument, in `wrap` mode.""" + + ModelWrapSerializerWithoutInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler], Any] + """A model serializer method without the `info` argument, in `wrap` mode.""" + + ModelWrapSerializer: TypeAlias = 'ModelWrapSerializerWithInfo | ModelWrapSerializerWithoutInfo' + """A model serializer method in `wrap` mode.""" + + ModelSerializer: TypeAlias = 'ModelPlainSerializer | ModelWrapSerializer' + + _ModelPlainSerializerT = TypeVar('_ModelPlainSerializerT', bound=ModelPlainSerializer) + _ModelWrapSerializerT = TypeVar('_ModelWrapSerializerT', bound=ModelWrapSerializer) + + +@overload +def model_serializer(f: _ModelPlainSerializerT, /) -> _ModelPlainSerializerT: ... + + +@overload +def model_serializer( + *, mode: Literal['wrap'], when_used: WhenUsed = 'always', return_type: Any = ... +) -> Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT]: ... + + +@overload +def model_serializer( + *, + mode: Literal['plain'] = ..., + when_used: WhenUsed = 'always', + return_type: Any = ..., +) -> Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT]: ... + + +def model_serializer( + f: _ModelPlainSerializerT | _ModelWrapSerializerT | None = None, + /, + *, + mode: Literal['plain', 'wrap'] = 'plain', + when_used: WhenUsed = 'always', + return_type: Any = PydanticUndefined, +) -> ( + _ModelPlainSerializerT + | Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT] + | Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT] +): + """Decorator that enables custom model serialization. + + This is useful when a model need to be serialized in a customized manner, allowing for flexibility beyond just specific fields. + + An example would be to serialize temperature to the same temperature scale, such as degrees Celsius. + + ```python + from typing import Literal + + from pydantic import BaseModel, model_serializer + + class TemperatureModel(BaseModel): + unit: Literal['C', 'F'] + value: int + + @model_serializer() + def serialize_model(self): + if self.unit == 'F': + return {'unit': 'C', 'value': int((self.value - 32) / 1.8)} + return {'unit': self.unit, 'value': self.value} + + temperature = TemperatureModel(unit='F', value=212) + print(temperature.model_dump()) + #> {'unit': 'C', 'value': 100} + ``` + + Two signatures are supported for `mode='plain'`, which is the default: + + - `(self)` + - `(self, info: SerializationInfo)` + + And two other signatures for `mode='wrap'`: + + - `(self, nxt: SerializerFunctionWrapHandler)` + - `(self, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)` + + See [the usage documentation](../concepts/serialization.md#serializers) for more information. + + Args: + f: The function to be decorated. + mode: The serialization mode. + + - `'plain'` means the function will be called instead of the default serialization logic + - `'wrap'` means the function will be called with an argument to optionally call the default + serialization logic. + when_used: Determines when this serializer should be used. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + + Returns: + The decorator function. + """ + + def dec(f: ModelSerializer) -> _decorators.PydanticDescriptorProxy[Any]: + dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, return_type=return_type, when_used=when_used) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + if f is None: + return dec # pyright: ignore[reportReturnType] + else: + return dec(f) # pyright: ignore[reportReturnType] + + +AnyType = TypeVar('AnyType') + + +if TYPE_CHECKING: + SerializeAsAny = Annotated[AnyType, ...] # SerializeAsAny[list[str]] will be treated by type checkers as list[str] + """Annotation used to mark a type as having duck-typing serialization behavior. + + See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details. + """ +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SerializeAsAny: + """Annotation used to mark a type as having duck-typing serialization behavior. + + See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details. + """ + + def __class_getitem__(cls, item: Any) -> Any: + return Annotated[item, SerializeAsAny()] + + def __get_pydantic_core_schema__( + self, source_type: Any, handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + schema = handler(source_type) + schema_to_update = schema + while schema_to_update['type'] == 'definitions': + schema_to_update = schema_to_update.copy() + schema_to_update = schema_to_update['schema'] + schema_to_update['serialization'] = core_schema.simple_ser_schema('any') + return schema + + __hash__ = object.__hash__ diff --git a/backend/venv/Lib/site-packages/pydantic/functional_validators.py b/backend/venv/Lib/site-packages/pydantic/functional_validators.py new file mode 100644 index 0000000..fc4bbba --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/functional_validators.py @@ -0,0 +1,893 @@ +"""This module contains related classes and functions for validation.""" + +from __future__ import annotations as _annotations + +import dataclasses +import sys +import warnings +from functools import partialmethod +from types import FunctionType +from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload + +from pydantic_core import PydanticUndefined, core_schema +from typing_extensions import Self, TypeAlias + +from ._internal import _decorators, _generics, _internal_dataclass +from .annotated_handlers import GetCoreSchemaHandler +from .errors import PydanticUserError +from .version import version_short +from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince212 + +if sys.version_info < (3, 11): + from typing_extensions import Protocol +else: + from typing import Protocol + +_inspect_validator = _decorators.inspect_validator + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class AfterValidator: + """!!! abstract "Usage Documentation" + [field *after* validators](../concepts/validators.md#field-after-validator) + + A metadata class that indicates that a validation should be applied **after** the inner validation logic. + + Attributes: + func: The validator function. + + Example: + ```python + from typing import Annotated + + from pydantic import AfterValidator, BaseModel, ValidationError + + MyInt = Annotated[int, AfterValidator(lambda v: v + 1)] + + class Model(BaseModel): + a: MyInt + + print(Model(a=1).a) + #> 2 + + try: + Model(a='a') + except ValidationError as e: + print(e.json(indent=2)) + ''' + [ + { + "type": "int_parsing", + "loc": [ + "a" + ], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "input": "a", + "url": "https://errors.pydantic.dev/2/v/int_parsing" + } + ] + ''' + ``` + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + info_arg = _inspect_validator(self.func, mode='after', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_after_validator_function(func, schema=schema) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_after_validator_function(func, schema=schema) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls(func=decorator.func) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class BeforeValidator: + """!!! abstract "Usage Documentation" + [field *before* validators](../concepts/validators.md#field-before-validator) + + A metadata class that indicates that a validation should be applied **before** the inner validation logic. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + Example: + ```python + from typing import Annotated + + from pydantic import BaseModel, BeforeValidator + + MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)] + + class Model(BaseModel): + a: MyInt + + print(Model(a=1).a) + #> 2 + + try: + Model(a='a') + except TypeError as e: + print(e) + #> can only concatenate str (not "int") to str + ``` + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + json_schema_input_type: Any = PydanticUndefined + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + input_schema = ( + None + if self.json_schema_input_type is PydanticUndefined + else handler.generate_schema(self.json_schema_input_type) + ) + + info_arg = _inspect_validator(self.func, mode='before', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_before_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_before_validator_function( + func, schema=schema, json_schema_input_schema=input_schema + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class PlainValidator: + """!!! abstract "Usage Documentation" + [field *plain* validators](../concepts/validators.md#field-plain-validator) + + A metadata class that indicates that a validation should be applied **instead** of the inner validation logic. + + !!! note + Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`. + You can now use the `json_schema_input_type` argument to specify the input type of the function + to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + Example: + ```python + from typing import Annotated, Union + + from pydantic import BaseModel, PlainValidator + + def validate(v: object) -> int: + if not isinstance(v, (int, str)): + raise ValueError(f'Expected int or str, go {type(v)}') + + return int(v) + 1 + + MyInt = Annotated[ + int, + PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)! + ] + + class Model(BaseModel): + a: MyInt + + print(Model(a='1').a) + #> 2 + + print(Model(a=1).a) + #> 2 + ``` + + 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema + generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][]. + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + json_schema_input_type: Any = Any + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the + # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper + # serialization schema. To work around this for use cases that will not involve serialization, we simply + # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema + # and abort any attempts to handle special serialization. + from pydantic import PydanticSchemaGenerationError + + try: + schema = handler(source_type) + # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence', + # schema validation will fail. That's why we use 'type ignore' comments below. + serialization = schema.get( + 'serialization', + core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), + schema=schema, + return_schema=handler.generate_schema(source_type), + ), + ) + except PydanticSchemaGenerationError: + serialization = None + + input_schema = handler.generate_schema(self.json_schema_input_type) + + info_arg = _inspect_validator(self.func, mode='plain', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_plain_validator_function( + func, + serialization=serialization, # pyright: ignore[reportArgumentType] + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_plain_validator_function( + func, + serialization=serialization, # pyright: ignore[reportArgumentType] + json_schema_input_schema=input_schema, + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class WrapValidator: + """!!! abstract "Usage Documentation" + [field *wrap* validators](../concepts/validators.md#field-wrap-validator) + + A metadata class that indicates that a validation should be applied **around** the inner validation logic. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + ```python + from datetime import datetime + from typing import Annotated + + from pydantic import BaseModel, ValidationError, WrapValidator + + def validate_timestamp(v, handler): + if v == 'now': + # we don't want to bother with further validation, just return the new value + return datetime.now() + try: + return handler(v) + except ValidationError: + # validation failed, in this case we want to return a default value + return datetime(2000, 1, 1) + + MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)] + + class Model(BaseModel): + a: MyTimestamp + + print(Model(a='now').a) + #> 2032-01-02 03:04:05.000006 + print(Model(a='invalid').a) + #> 2000-01-01 00:00:00 + ``` + """ + + func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction + json_schema_input_type: Any = PydanticUndefined + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + input_schema = ( + None + if self.json_schema_input_type is PydanticUndefined + else handler.generate_schema(self.json_schema_input_type) + ) + + info_arg = _inspect_validator(self.func, mode='wrap', type='field') + if info_arg: + func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) + return core_schema.with_info_wrap_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) + return core_schema.no_info_wrap_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +if TYPE_CHECKING: + + class _OnlyValueValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, /) -> Any: ... + + class _V2ValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ... + + class _OnlyValueWrapValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ... + + class _V2WrapValidatorClsMethod(Protocol): + def __call__( + self, + cls: Any, + value: Any, + handler: core_schema.ValidatorFunctionWrapHandler, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + _V2Validator = Union[ + _V2ValidatorClsMethod, + core_schema.WithInfoValidatorFunction, + _OnlyValueValidatorClsMethod, + core_schema.NoInfoValidatorFunction, + ] + + _V2WrapValidator = Union[ + _V2WrapValidatorClsMethod, + core_schema.WithInfoWrapValidatorFunction, + _OnlyValueWrapValidatorClsMethod, + core_schema.NoInfoWrapValidatorFunction, + ] + + _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] + + _V2BeforeAfterOrPlainValidatorType = TypeVar( + '_V2BeforeAfterOrPlainValidatorType', + bound=Union[_V2Validator, _PartialClsOrStaticMethod], + ) + _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod]) + +FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['wrap'], + check_fields: bool | None = ..., + json_schema_input_type: Any = ..., +) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['before', 'plain'], + check_fields: bool | None = ..., + json_schema_input_type: Any = ..., +) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['after'] = ..., + check_fields: bool | None = ..., +) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... + + +def field_validator( + field: str, + /, + *fields: str, + mode: FieldValidatorModes = 'after', + check_fields: bool | None = None, + json_schema_input_type: Any = PydanticUndefined, +) -> Callable[[Any], Any]: + """!!! abstract "Usage Documentation" + [field validators](../concepts/validators.md#field-validators) + + Decorate methods on the class indicating that they should be used to validate fields. + + Example usage: + ```python + from typing import Any + + from pydantic import ( + BaseModel, + ValidationError, + field_validator, + ) + + class Model(BaseModel): + a: str + + @field_validator('a') + @classmethod + def ensure_foobar(cls, v: Any): + if 'foobar' not in v: + raise ValueError('"foobar" not found in a') + return v + + print(repr(Model(a='this is foobar good'))) + #> Model(a='this is foobar good') + + try: + Model(a='snap') + except ValidationError as exc_info: + print(exc_info) + ''' + 1 validation error for Model + a + Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str] + ''' + ``` + + For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators). + + Args: + field: The first field the `field_validator` should be called on; this is separate + from `fields` to ensure an error is raised if you don't pass at least one. + *fields: Additional field(s) the `field_validator` should be called on. + mode: Specifies whether to validate the fields before or after validation. + check_fields: Whether to check that the fields actually exist on the model. + json_schema_input_type: The input type of the function. This is only used to generate + the appropriate JSON Schema (in validation mode) and can only specified + when `mode` is either `'before'`, `'plain'` or `'wrap'`. + + Returns: + A decorator that can be used to decorate a function to be used as a field_validator. + + Raises: + PydanticUserError: + - If `@field_validator` is used bare (with no fields). + - If the args passed to `@field_validator` as fields are not strings. + - If `@field_validator` applied to instance methods. + """ + if isinstance(field, FunctionType): + raise PydanticUserError( + '`@field_validator` should be used with fields and keyword arguments, not bare. ' + "E.g. usage should be `@validator('', ...)`", + code='validator-no-fields', + ) + + if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: + raise PydanticUserError( + f"`json_schema_input_type` can't be used when mode is set to {mode!r}", + code='validator-input-type', + ) + + if json_schema_input_type is PydanticUndefined and mode == 'plain': + json_schema_input_type = Any + + fields = field, *fields + if not all(isinstance(field, str) for field in fields): + raise PydanticUserError( + '`@field_validator` fields should be passed as separate string args. ' + "E.g. usage should be `@validator('', '', ...)`", + code='validator-invalid-fields', + ) + + def dec( + f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any], + ) -> _decorators.PydanticDescriptorProxy[Any]: + if _decorators.is_instance_method_from_sig(f): + raise PydanticUserError( + '`@field_validator` cannot be applied to instance methods', code='validator-instance-method' + ) + + # auto apply the @classmethod decorator + f = _decorators.ensure_classmethod_based_on_signature(f) + + dec_info = _decorators.FieldValidatorDecoratorInfo( + fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + return dec + + +_ModelType = TypeVar('_ModelType') +_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) + + +class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): + """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`.""" + + def __call__( # noqa: D102 + self, + value: Any, + outer_location: str | int | None = None, + /, + ) -> _ModelTypeCo: # pragma: no cover + ... + + +class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): + """A `@model_validator` decorated function signature. + This is used when `mode='wrap'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + cls: type[_ModelType], + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + handler: ModelWrapValidatorHandler[_ModelType], + /, + ) -> _ModelType: ... + + +class ModelWrapValidator(Protocol[_ModelType]): + """A `@model_validator` decorated function signature. This is used when `mode='wrap'`.""" + + def __call__( # noqa: D102 + self, + cls: type[_ModelType], + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + handler: ModelWrapValidatorHandler[_ModelType], + info: core_schema.ValidationInfo, + /, + ) -> _ModelType: ... + + +class FreeModelBeforeValidatorWithoutInfo(Protocol): + """A `@model_validator` decorated function signature. + This is used when `mode='before'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + /, + ) -> Any: ... + + +class ModelBeforeValidatorWithoutInfo(Protocol): + """A `@model_validator` decorated function signature. + This is used when `mode='before'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + cls: Any, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + /, + ) -> Any: ... + + +class FreeModelBeforeValidator(Protocol): + """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" + + def __call__( # noqa: D102 + self, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + +class ModelBeforeValidator(Protocol): + """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" + + def __call__( # noqa: D102 + self, + cls: Any, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + +ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] +"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not +have info argument. +""" + +ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] +"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" + +_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] +_AnyModelBeforeValidator = Union[ + FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo +] +_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] + + +@overload +def model_validator( + *, + mode: Literal['wrap'], +) -> Callable[ + [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +@overload +def model_validator( + *, + mode: Literal['before'], +) -> Callable[ + [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +@overload +def model_validator( + *, + mode: Literal['after'], +) -> Callable[ + [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +def model_validator( + *, + mode: Literal['wrap', 'before', 'after'], +) -> Any: + """!!! abstract "Usage Documentation" + [Model Validators](../concepts/validators.md#model-validators) + + Decorate model methods for validation purposes. + + Example usage: + ```python + from typing_extensions import Self + + from pydantic import BaseModel, ValidationError, model_validator + + class Square(BaseModel): + width: float + height: float + + @model_validator(mode='after') + def verify_square(self) -> Self: + if self.width != self.height: + raise ValueError('width and height do not match') + return self + + s = Square(width=1, height=1) + print(repr(s)) + #> Square(width=1.0, height=1.0) + + try: + Square(width=1, height=2) + except ValidationError as e: + print(e) + ''' + 1 validation error for Square + Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict] + ''' + ``` + + For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators). + + Args: + mode: A required string literal that specifies the validation mode. + It can be one of the following: 'wrap', 'before', or 'after'. + + Returns: + A decorator that can be used to decorate a function to be used as a model validator. + """ + + def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: + # auto apply the @classmethod decorator. NOTE: in V3, do not apply the conversion for 'after' validators: + f = _decorators.ensure_classmethod_based_on_signature(f) + if mode == 'after' and isinstance(f, classmethod): + warnings.warn( + category=PydanticDeprecatedSince212, + message=( + "Using `@model_validator` with mode='after' on a classmethod is deprecated. Instead, use an instance method. " + f'See the documentation at https://docs.pydantic.dev/{version_short()}/concepts/validators/#model-after-validator.' + ), + stacklevel=2, + ) + + dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + return dec + + +AnyType = TypeVar('AnyType') + + +if TYPE_CHECKING: + # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this + InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence` + +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class InstanceOf: + '''Generic type for annotating a type that is an instance of a given class. + + Example: + ```python + from pydantic import BaseModel, InstanceOf + + class Foo: + ... + + class Bar(BaseModel): + foo: InstanceOf[Foo] + + Bar(foo=Foo()) + try: + Bar(foo=42) + except ValidationError as e: + print(e) + """ + [ + │ { + │ │ 'type': 'is_instance_of', + │ │ 'loc': ('foo',), + │ │ 'msg': 'Input should be an instance of Foo', + │ │ 'input': 42, + │ │ 'ctx': {'class': 'Foo'}, + │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of' + │ } + ] + """ + ``` + ''' + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + from pydantic import PydanticSchemaGenerationError + + # use the generic _origin_ as the second argument to isinstance when appropriate + instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) + + try: + # Try to generate the "standard" schema, which will be used when loading from JSON + original_schema = handler(source) + except PydanticSchemaGenerationError: + # If that fails, just produce a schema that can validate from python + return instance_of_schema + else: + # Use the "original" approach to serialization + instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), schema=original_schema + ) + return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) + + __hash__ = object.__hash__ + + +if TYPE_CHECKING: + SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str] +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SkipValidation: + """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be + skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`. + + This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes, + and know that it is safe to skip validation for one or more of the fields. + + Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations + may not have the expected effects. Therefore, when used, this annotation should generally be the final + annotation applied to a type. + """ + + def __class_getitem__(cls, item: Any) -> Any: + return Annotated[item, SkipValidation()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + with warnings.catch_warnings(): + warnings.simplefilter('ignore', ArbitraryTypeWarning) + original_schema = handler(source) + metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} + return core_schema.any_schema( + metadata=metadata, + serialization=core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), schema=original_schema + ), + ) + + __hash__ = object.__hash__ + + +_FromTypeT = TypeVar('_FromTypeT') + + +class ValidateAs: + """A helper class to validate a custom type from a type that is natively supported by Pydantic. + + Args: + from_type: The type natively supported by Pydantic to use to perform validation. + instantiation_hook: A callable taking the validated type as an argument, and returning + the populated custom type. + + Example: + ```python {lint="skip"} + from typing import Annotated + + from pydantic import BaseModel, TypeAdapter, ValidateAs + + class MyCls: + def __init__(self, a: int) -> None: + self.a = a + + def __repr__(self) -> str: + return f"MyCls(a={self.a})" + + class Model(BaseModel): + a: int + + + ta = TypeAdapter( + Annotated[MyCls, ValidateAs(Model, lambda v: MyCls(a=v.a))] + ) + + print(ta.validate_python({'a': 1})) + #> MyCls(a=1) + ``` + """ + + # TODO: make use of PEP 747 + def __init__(self, from_type: type[_FromTypeT], /, instantiation_hook: Callable[[_FromTypeT], Any]) -> None: + self.from_type = from_type + self.instantiation_hook = instantiation_hook + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(self.from_type) + return core_schema.no_info_after_validator_function( + self.instantiation_hook, + schema=schema, + ) diff --git a/backend/venv/Lib/site-packages/pydantic/generics.py b/backend/venv/Lib/site-packages/pydantic/generics.py new file mode 100644 index 0000000..3f1070d --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/generics.py @@ -0,0 +1,5 @@ +"""The `generics` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/json.py b/backend/venv/Lib/site-packages/pydantic/json.py new file mode 100644 index 0000000..bcaff9f --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/json.py @@ -0,0 +1,5 @@ +"""The `json` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/json_schema.py b/backend/venv/Lib/site-packages/pydantic/json_schema.py new file mode 100644 index 0000000..a16afb8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/json_schema.py @@ -0,0 +1,2854 @@ +"""!!! abstract "Usage Documentation" + [JSON Schema](../concepts/json_schema.md) + +The `json_schema` module contains classes and functions to allow the way [JSON Schema](https://json-schema.org/) +is generated to be customized. + +In general you shouldn't need to use this module directly; instead, you can use +[`BaseModel.model_json_schema`][pydantic.BaseModel.model_json_schema] and +[`TypeAdapter.json_schema`][pydantic.TypeAdapter.json_schema]. +""" + +from __future__ import annotations as _annotations + +import dataclasses +import inspect +import math +import os +import re +import warnings +from collections import Counter, defaultdict +from collections.abc import Hashable, Iterable, Sequence +from copy import deepcopy +from enum import Enum +from re import Pattern +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Callable, + Literal, + NewType, + TypeVar, + Union, + cast, + overload, +) + +import pydantic_core +from pydantic_core import MISSING, CoreSchema, PydanticOmit, core_schema, to_jsonable_python +from pydantic_core.core_schema import ComputedField +from typing_extensions import TypeAlias, assert_never, deprecated, final +from typing_inspection.introspection import get_literal_values + +from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 + +from ._internal import ( + _config, + _core_metadata, + _core_utils, + _decorators, + _internal_dataclass, + _mock_val_ser, + _schema_generation_shared, +) +from .annotated_handlers import GetJsonSchemaHandler +from .config import JsonDict, JsonValue +from .errors import PydanticInvalidForJsonSchema, PydanticSchemaGenerationError, PydanticUserError + +if TYPE_CHECKING: + from . import ConfigDict + from ._internal._core_utils import CoreSchemaField, CoreSchemaOrField + from ._internal._dataclasses import PydanticDataclass + from ._internal._schema_generation_shared import GetJsonSchemaFunction + from .main import BaseModel + + +CoreSchemaOrFieldType = Literal[core_schema.CoreSchemaType, core_schema.CoreSchemaFieldType] +""" +A type alias for defined schema types that represents a union of +`core_schema.CoreSchemaType` and +`core_schema.CoreSchemaFieldType`. +""" + +JsonSchemaValue = dict[str, Any] +""" +A type alias for a JSON schema value. This is a dictionary of string keys to arbitrary JSON values. +""" + +JsonSchemaMode = Literal['validation', 'serialization'] +""" +A type alias that represents the mode of a JSON schema; either 'validation' or 'serialization'. + +For some types, the inputs to validation differ from the outputs of serialization. For example, +computed fields will only be present when serializing, and should not be provided when +validating. This flag provides a way to indicate whether you want the JSON schema required +for validation inputs, or that will be matched by serialization outputs. +""" + +_MODE_TITLE_MAPPING: dict[JsonSchemaMode, str] = {'validation': 'Input', 'serialization': 'Output'} + + +JsonSchemaWarningKind = Literal['skipped-choice', 'non-serializable-default', 'skipped-discriminator'] +""" +A type alias representing the kinds of warnings that can be emitted during JSON schema generation. + +See [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] +for more details. +""" + + +class PydanticJsonSchemaWarning(UserWarning): + """This class is used to emit warnings produced during JSON schema generation. + See the [`GenerateJsonSchema.emit_warning`][pydantic.json_schema.GenerateJsonSchema.emit_warning] and + [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] + methods for more details; these can be overridden to control warning behavior. + """ + + +NoDefault = object() +"""A sentinel value used to indicate that no default value should be used when generating a JSON Schema +for a core schema with a default value. +""" + + +# ##### JSON Schema Generation ##### +DEFAULT_REF_TEMPLATE = '#/$defs/{model}' +"""The default format string used to generate reference names.""" + +# There are three types of references relevant to building JSON schemas: +# 1. core_schema "ref" values; these are not exposed as part of the JSON schema +# * these might look like the fully qualified path of a model, its id, or something similar +CoreRef = NewType('CoreRef', str) +# 2. keys of the "definitions" object that will eventually go into the JSON schema +# * by default, these look like "MyModel", though may change in the presence of collisions +# * eventually, we may want to make it easier to modify the way these names are generated +DefsRef = NewType('DefsRef', str) +# 3. the values corresponding to the "$ref" key in the schema +# * By default, these look like "#/$defs/MyModel", as in {"$ref": "#/$defs/MyModel"} +JsonRef = NewType('JsonRef', str) + +CoreModeRef = tuple[CoreRef, JsonSchemaMode] +JsonSchemaKeyT = TypeVar('JsonSchemaKeyT', bound=Hashable) + +_PRIMITIVE_JSON_SCHEMA_TYPES = ('string', 'boolean', 'null', 'integer', 'number') + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class _DefinitionsRemapping: + defs_remapping: dict[DefsRef, DefsRef] + json_remapping: dict[JsonRef, JsonRef] + + @staticmethod + def from_prioritized_choices( + prioritized_choices: dict[DefsRef, list[DefsRef]], + defs_to_json: dict[DefsRef, JsonRef], + definitions: dict[DefsRef, JsonSchemaValue], + ) -> _DefinitionsRemapping: + """ + This function should produce a remapping that replaces complex DefsRef with the simpler ones from the + prioritized_choices such that applying the name remapping would result in an equivalent JSON schema. + """ + # We need to iteratively simplify the definitions until we reach a fixed point. + # The reason for this is that outer definitions may reference inner definitions that get simplified + # into an equivalent reference, and the outer definitions won't be equivalent until we've simplified + # the inner definitions. + copied_definitions = deepcopy(definitions) + definitions_schema = {'$defs': copied_definitions} + for _iter in range(100): # prevent an infinite loop in the case of a bug, 100 iterations should be enough + # For every possible remapped DefsRef, collect all schemas that that DefsRef might be used for: + schemas_for_alternatives: dict[DefsRef, list[JsonSchemaValue]] = defaultdict(list) + for defs_ref in copied_definitions: + alternatives = prioritized_choices[defs_ref] + for alternative in alternatives: + schemas_for_alternatives[alternative].append(copied_definitions[defs_ref]) + + # Deduplicate the schemas for each alternative; the idea is that we only want to remap to a new DefsRef + # if it introduces no ambiguity, i.e., there is only one distinct schema for that DefsRef. + for defs_ref in schemas_for_alternatives: + schemas_for_alternatives[defs_ref] = _deduplicate_schemas(schemas_for_alternatives[defs_ref]) + + # Build the remapping + defs_remapping: dict[DefsRef, DefsRef] = {} + json_remapping: dict[JsonRef, JsonRef] = {} + for original_defs_ref in definitions: + alternatives = prioritized_choices[original_defs_ref] + # Pick the first alternative that has only one schema, since that means there is no collision + remapped_defs_ref = next(x for x in alternatives if len(schemas_for_alternatives[x]) == 1) + defs_remapping[original_defs_ref] = remapped_defs_ref + json_remapping[defs_to_json[original_defs_ref]] = defs_to_json[remapped_defs_ref] + remapping = _DefinitionsRemapping(defs_remapping, json_remapping) + new_definitions_schema = remapping.remap_json_schema({'$defs': copied_definitions}) + if definitions_schema == new_definitions_schema: + # We've reached the fixed point + return remapping + definitions_schema = new_definitions_schema + + raise PydanticInvalidForJsonSchema('Failed to simplify the JSON schema definitions') + + def remap_defs_ref(self, ref: DefsRef) -> DefsRef: + return self.defs_remapping.get(ref, ref) + + def remap_json_ref(self, ref: JsonRef) -> JsonRef: + return self.json_remapping.get(ref, ref) + + def remap_json_schema(self, schema: Any) -> Any: + """ + Recursively update the JSON schema replacing all $refs + """ + if isinstance(schema, str): + # Note: this may not really be a JsonRef; we rely on having no collisions between JsonRefs and other strings + return self.remap_json_ref(JsonRef(schema)) + elif isinstance(schema, list): + return [self.remap_json_schema(item) for item in schema] + elif isinstance(schema, dict): + for key, value in schema.items(): + if key == '$ref' and isinstance(value, str): + schema['$ref'] = self.remap_json_ref(JsonRef(value)) + elif key == '$defs': + schema['$defs'] = { + self.remap_defs_ref(DefsRef(key)): self.remap_json_schema(value) + for key, value in schema['$defs'].items() + } + else: + schema[key] = self.remap_json_schema(value) + return schema + + +class GenerateJsonSchema: + """!!! abstract "Usage Documentation" + [Customizing the JSON Schema Generation Process](../concepts/json_schema.md#customizing-the-json-schema-generation-process) + + A class for generating JSON schemas. + + This class generates JSON schemas based on configured parameters. The default schema dialect + is [https://json-schema.org/draft/2020-12/schema](https://json-schema.org/draft/2020-12/schema). + The class uses `by_alias` to configure how fields with + multiple names are handled and `ref_template` to format reference names. + + Attributes: + schema_dialect: The JSON schema dialect used to generate the schema. See + [Declaring a Dialect](https://json-schema.org/understanding-json-schema/reference/schema.html#id4) + in the JSON Schema documentation for more information about dialects. + ignored_warning_kinds: Warnings to ignore when generating the schema. `self.render_warning_message` will + do nothing if its argument `kind` is in `ignored_warning_kinds`; + this value can be modified on subclasses to easily control which warnings are emitted. + by_alias: Whether to use field aliases when generating the schema. + ref_template: The format string used when generating reference names. + core_to_json_refs: A mapping of core refs to JSON refs. + core_to_defs_refs: A mapping of core refs to definition refs. + defs_to_core_refs: A mapping of definition refs to core refs. + json_to_defs_refs: A mapping of JSON refs to definition refs. + definitions: Definitions in the schema. + + Args: + by_alias: Whether to use field aliases in the generated schemas. + ref_template: The format string to use when generating reference names. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + + Raises: + JsonSchemaError: If the instance of the class is inadvertently reused after generating a schema. + """ + + schema_dialect = 'https://json-schema.org/draft/2020-12/schema' + + # `self.render_warning_message` will do nothing if its argument `kind` is in `ignored_warning_kinds`; + # this value can be modified on subclasses to easily control which warnings are emitted + ignored_warning_kinds: set[JsonSchemaWarningKind] = {'skipped-choice'} + + def __init__( + self, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + ) -> None: + self.by_alias = by_alias + self.ref_template = ref_template + self.union_format: Literal['any_of', 'primitive_type_array'] = union_format + + self.core_to_json_refs: dict[CoreModeRef, JsonRef] = {} + self.core_to_defs_refs: dict[CoreModeRef, DefsRef] = {} + self.defs_to_core_refs: dict[DefsRef, CoreModeRef] = {} + self.json_to_defs_refs: dict[JsonRef, DefsRef] = {} + + self.definitions: dict[DefsRef, JsonSchemaValue] = {} + self._config_wrapper_stack = _config.ConfigWrapperStack(_config.ConfigWrapper({})) + + self._mode: JsonSchemaMode = 'validation' + + # The following includes a mapping of a fully-unique defs ref choice to a list of preferred + # alternatives, which are generally simpler, such as only including the class name. + # At the end of schema generation, we use these to produce a JSON schema with more human-readable + # definitions, which would also work better in a generated OpenAPI client, etc. + self._prioritized_defsref_choices: dict[DefsRef, list[DefsRef]] = {} + self._collision_counter: dict[str, int] = defaultdict(int) + self._collision_index: dict[str, int] = {} + + self._schema_type_to_method = self.build_schema_type_to_method() + + # When we encounter definitions we need to try to build them immediately + # so that they are available schemas that reference them + # But it's possible that CoreSchema was never going to be used + # (e.g. because the CoreSchema that references short circuits is JSON schema generation without needing + # the reference) so instead of failing altogether if we can't build a definition we + # store the error raised and re-throw it if we end up needing that def + self._core_defs_invalid_for_json_schema: dict[DefsRef, PydanticInvalidForJsonSchema] = {} + + # This changes to True after generating a schema, to prevent issues caused by accidental reuse + # of a single instance of a schema generator + self._used = False + + @property + def _config(self) -> _config.ConfigWrapper: + return self._config_wrapper_stack.tail + + @property + def mode(self) -> JsonSchemaMode: + if self._config.json_schema_mode_override is not None: + return self._config.json_schema_mode_override + else: + return self._mode + + def build_schema_type_to_method( + self, + ) -> dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]]: + """Builds a dictionary mapping fields to methods for generating JSON schemas. + + Returns: + A dictionary containing the mapping of `CoreSchemaOrFieldType` to a handler method. + + Raises: + TypeError: If no method has been defined for generating a JSON schema for a given pydantic core schema type. + """ + mapping: dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]] = {} + core_schema_types: list[CoreSchemaOrFieldType] = list(get_literal_values(CoreSchemaOrFieldType)) + for key in core_schema_types: + method_name = f'{key.replace("-", "_")}_schema' + try: + mapping[key] = getattr(self, method_name) + except AttributeError as e: # pragma: no cover + if os.getenv('PYDANTIC_PRIVATE_ALLOW_UNHANDLED_SCHEMA_TYPES'): + continue + raise TypeError( + f'No method for generating JsonSchema for core_schema.type={key!r} ' + f'(expected: {type(self).__name__}.{method_name})' + ) from e + return mapping + + def generate_definitions( + self, inputs: Sequence[tuple[JsonSchemaKeyT, JsonSchemaMode, core_schema.CoreSchema]] + ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], dict[DefsRef, JsonSchemaValue]]: + """Generates JSON schema definitions from a list of core schemas, pairing the generated definitions with a + mapping that links the input keys to the definition references. + + Args: + inputs: A sequence of tuples, where: + + - The first element is a JSON schema key type. + - The second element is the JSON mode: either 'validation' or 'serialization'. + - The third element is a core schema. + + Returns: + A tuple where: + + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a dictionary whose keys are definition references for the JSON schemas + from the first returned element, and whose values are the actual JSON schema definitions. + + Raises: + PydanticUserError: Raised if the JSON schema generator has already been used to generate a JSON schema. + """ + if self._used: + raise PydanticUserError( + 'This JSON schema generator has already been used to generate a JSON schema. ' + f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', + code='json-schema-already-used', + ) + + for _, mode, schema in inputs: + self._mode = mode + self.generate_inner(schema) + + definitions_remapping = self._build_definitions_remapping() + + json_schemas_map: dict[tuple[JsonSchemaKeyT, JsonSchemaMode], DefsRef] = {} + for key, mode, schema in inputs: + self._mode = mode + json_schema = self.generate_inner(schema) + json_schemas_map[(key, mode)] = definitions_remapping.remap_json_schema(json_schema) + + json_schema = {'$defs': self.definitions} + json_schema = definitions_remapping.remap_json_schema(json_schema) + self._used = True + return json_schemas_map, self.sort(json_schema['$defs']) # type: ignore + + def generate(self, schema: CoreSchema, mode: JsonSchemaMode = 'validation') -> JsonSchemaValue: + """Generates a JSON schema for a specified schema in a specified mode. + + Args: + schema: A Pydantic model. + mode: The mode in which to generate the schema. Defaults to 'validation'. + + Returns: + A JSON schema representing the specified schema. + + Raises: + PydanticUserError: If the JSON schema generator has already been used to generate a JSON schema. + """ + self._mode = mode + if self._used: + raise PydanticUserError( + 'This JSON schema generator has already been used to generate a JSON schema. ' + f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', + code='json-schema-already-used', + ) + + json_schema: JsonSchemaValue = self.generate_inner(schema) + json_ref_counts = self.get_json_ref_counts(json_schema) + + ref = cast(JsonRef, json_schema.get('$ref')) + while ref is not None: # may need to unpack multiple levels + ref_json_schema = self.get_schema_from_definitions(ref) + if json_ref_counts[ref] == 1 and ref_json_schema is not None and len(json_schema) == 1: + # "Unpack" the ref since this is the only reference and there are no sibling keys + json_schema = ref_json_schema.copy() # copy to prevent recursive dict reference + json_ref_counts[ref] -= 1 + ref = cast(JsonRef, json_schema.get('$ref')) + ref = None + + self._garbage_collect_definitions(json_schema) + definitions_remapping = self._build_definitions_remapping() + + if self.definitions: + json_schema['$defs'] = self.definitions + + json_schema = definitions_remapping.remap_json_schema(json_schema) + + # For now, we will not set the $schema key. However, if desired, this can be easily added by overriding + # this method and adding the following line after a call to super().generate(schema): + # json_schema['$schema'] = self.schema_dialect + + self._used = True + return self.sort(json_schema) + + def generate_inner(self, schema: CoreSchemaOrField) -> JsonSchemaValue: # noqa: C901 + """Generates a JSON schema for a given core schema. + + Args: + schema: The given core schema. + + Returns: + The generated JSON schema. + + TODO: the nested function definitions here seem like bad practice, I'd like to unpack these + in a future PR. It'd be great if we could shorten the call stack a bit for JSON schema generation, + and I think there's potential for that here. + """ + # If a schema with the same CoreRef has been handled, just return a reference to it + # Note that this assumes that it will _never_ be the case that the same CoreRef is used + # on types that should have different JSON schemas + if 'ref' in schema: + core_ref = CoreRef(schema['ref']) # type: ignore[typeddict-item] + core_mode_ref = (core_ref, self.mode) + if core_mode_ref in self.core_to_defs_refs and self.core_to_defs_refs[core_mode_ref] in self.definitions: + return {'$ref': self.core_to_json_refs[core_mode_ref]} + + def populate_defs(core_schema: CoreSchema, json_schema: JsonSchemaValue) -> JsonSchemaValue: + if 'ref' in core_schema: + core_ref = CoreRef(core_schema['ref']) # type: ignore[typeddict-item] + defs_ref, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) + json_ref = JsonRef(ref_json_schema['$ref']) + # Replace the schema if it's not a reference to itself + # What we want to avoid is having the def be just a ref to itself + # which is what would happen if we blindly assigned any + if json_schema.get('$ref', None) != json_ref: + self.definitions[defs_ref] = json_schema + self._core_defs_invalid_for_json_schema.pop(defs_ref, None) + json_schema = ref_json_schema + return json_schema + + def handler_func(schema_or_field: CoreSchemaOrField) -> JsonSchemaValue: + """Generate a JSON schema based on the input schema. + + Args: + schema_or_field: The core schema to generate a JSON schema from. + + Returns: + The generated JSON schema. + + Raises: + TypeError: If an unexpected schema type is encountered. + """ + # Generate the core-schema-type-specific bits of the schema generation: + json_schema: JsonSchemaValue | None = None + if self.mode == 'serialization' and 'serialization' in schema_or_field: + # In this case, we skip the JSON Schema generation of the schema + # and use the `'serialization'` schema instead (canonical example: + # `Annotated[int, PlainSerializer(str)]`). + ser_schema = schema_or_field['serialization'] # type: ignore + json_schema = self.ser_schema(ser_schema) + + # It might be that the 'serialization'` is skipped depending on `when_used`. + # This is only relevant for `nullable` schemas though, so we special case here. + if ( + json_schema is not None + and ser_schema.get('when_used') in ('unless-none', 'json-unless-none') + and schema_or_field['type'] == 'nullable' + ): + json_schema = self.get_union_of_schemas([{'type': 'null'}, json_schema]) + if json_schema is None: + if _core_utils.is_core_schema(schema_or_field) or _core_utils.is_core_schema_field(schema_or_field): + generate_for_schema_type = self._schema_type_to_method[schema_or_field['type']] + json_schema = generate_for_schema_type(schema_or_field) + else: + raise TypeError(f'Unexpected schema type: schema={schema_or_field}') + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, handler_func) + + metadata = cast(_core_metadata.CoreMetadata, schema.get('metadata', {})) + + # TODO: I dislike that we have to wrap these basic dict updates in callables, is there any way around this? + + if js_updates := metadata.get('pydantic_js_updates'): + + def js_updates_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + ) -> JsonSchemaValue: + json_schema = {**current_handler(schema_or_field), **js_updates} + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_updates_handler_func) + + if js_extra := metadata.get('pydantic_js_extra'): + + def js_extra_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + ) -> JsonSchemaValue: + json_schema = current_handler(schema_or_field) + if isinstance(js_extra, dict): + json_schema.update(to_jsonable_python(js_extra)) + elif callable(js_extra): + # similar to typing issue in _update_class_schema when we're working with callable js extra + js_extra(json_schema) # type: ignore + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_extra_handler_func) + + for js_modify_function in metadata.get('pydantic_js_functions', ()): + + def new_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + js_modify_function: GetJsonSchemaFunction = js_modify_function, + ) -> JsonSchemaValue: + json_schema = js_modify_function(schema_or_field, current_handler) + if _core_utils.is_core_schema(schema_or_field): + json_schema = populate_defs(schema_or_field, json_schema) + original_schema = current_handler.resolve_ref_schema(json_schema) + ref = json_schema.pop('$ref', None) + if ref and json_schema: + original_schema.update(json_schema) + return original_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) + + for js_modify_function in metadata.get('pydantic_js_annotation_functions', ()): + + def new_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + js_modify_function: GetJsonSchemaFunction = js_modify_function, + ) -> JsonSchemaValue: + return js_modify_function(schema_or_field, current_handler) + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) + + json_schema = current_handler(schema) + if _core_utils.is_core_schema(schema): + json_schema = populate_defs(schema, json_schema) + return json_schema + + def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue: + """Override this method to customize the sorting of the JSON schema (e.g., don't sort at all, sort all keys unconditionally, etc.) + + By default, alphabetically sort the keys in the JSON schema, skipping the 'properties' and 'default' keys to preserve field definition order. + This sort is recursive, so it will sort all nested dictionaries as well. + """ + sorted_dict: dict[str, JsonSchemaValue] = {} + keys = value.keys() + if parent_key not in ('properties', 'default'): + keys = sorted(keys) + for key in keys: + sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) + return sorted_dict + + def _sort_recursive(self, value: Any, parent_key: str | None = None) -> Any: + """Recursively sort a JSON schema value.""" + if isinstance(value, dict): + sorted_dict: dict[str, JsonSchemaValue] = {} + keys = value.keys() + if parent_key not in ('properties', 'default'): + keys = sorted(keys) + for key in keys: + sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) + return sorted_dict + elif isinstance(value, list): + sorted_list: list[JsonSchemaValue] = [self._sort_recursive(item, parent_key) for item in value] + return sorted_list + else: + return value + + # ### Schema generation methods + + def invalid_schema(self, schema: core_schema.InvalidSchema) -> JsonSchemaValue: + """Placeholder - should never be called.""" + + raise RuntimeError('Cannot generate schema for invalid_schema. This is a bug! Please report it.') + + def any_schema(self, schema: core_schema.AnySchema) -> JsonSchemaValue: + """Generates a JSON schema that matches any value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {} + + def none_schema(self, schema: core_schema.NoneSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches `None`. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'null'} + + def bool_schema(self, schema: core_schema.BoolSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a bool value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'boolean'} + + def int_schema(self, schema: core_schema.IntSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches an int value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: dict[str, Any] = {'type': 'integer'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) + json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} + return json_schema + + def float_schema(self, schema: core_schema.FloatSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a float value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: dict[str, Any] = {'type': 'number'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) + json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} + return json_schema + + def decimal_schema(self, schema: core_schema.DecimalSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a decimal value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + + def get_decimal_pattern(schema: core_schema.DecimalSchema) -> str: + max_digits = schema.get('max_digits') + decimal_places = schema.get('decimal_places') + + pattern = ( + r'^(?!^[-+.]*$)[+-]?0*' # check it is not empty string and not one or sequence of ".+-" characters. + ) + + # Case 1: Both max_digits and decimal_places are set + if max_digits is not None and decimal_places is not None: + integer_places = max(0, max_digits - decimal_places) + pattern += ( + rf'(?:' + rf'\d{{0,{integer_places}}}' + rf'|' + rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' + rf'\d{{0,{integer_places}}}\.\d{{0,{decimal_places}}}0*$' + rf')' + ) + + # Case 2: Only max_digits is set + elif max_digits is not None and decimal_places is None: + pattern += ( + rf'(?:' + rf'\d{{0,{max_digits}}}' + rf'|' + rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' + rf'\d*\.\d*0*$' + rf')' + ) + + # Case 3: Only decimal_places is set + elif max_digits is None and decimal_places is not None: + pattern += rf'\d*\.?\d{{0,{decimal_places}}}0*$' + + # Case 4: Both are None (no restrictions) + else: + pattern += r'\d*\.?\d*$' # look for arbitrary integer or decimal + + return pattern + + json_schema = self.str_schema(core_schema.str_schema(pattern=get_decimal_pattern(schema))) + if self.mode == 'validation': + multiple_of = schema.get('multiple_of') + le = schema.get('le') + ge = schema.get('ge') + lt = schema.get('lt') + gt = schema.get('gt') + json_schema = { + 'anyOf': [ + self.float_schema( + core_schema.float_schema( + allow_inf_nan=schema.get('allow_inf_nan'), + multiple_of=None if multiple_of is None else float(multiple_of), + le=None if le is None else float(le), + ge=None if ge is None else float(ge), + lt=None if lt is None else float(lt), + gt=None if gt is None else float(gt), + ) + ), + json_schema, + ], + } + return json_schema + + def str_schema(self, schema: core_schema.StringSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a string value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + if isinstance(json_schema.get('pattern'), Pattern): + # TODO: should we add regex flags to the pattern? + json_schema['pattern'] = json_schema.get('pattern').pattern # type: ignore + return json_schema + + def bytes_schema(self, schema: core_schema.BytesSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a bytes value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string', 'format': 'base64url' if self._config.ser_json_bytes == 'base64' else 'binary'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) + return json_schema + + def date_schema(self, schema: core_schema.DateSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a date value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'date'} + + def time_schema(self, schema: core_schema.TimeSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a time value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'time'} + + def datetime_schema(self, schema: core_schema.DatetimeSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a datetime value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'date-time'} + + def timedelta_schema(self, schema: core_schema.TimedeltaSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a timedelta value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self._config.ser_json_timedelta == 'float': + return {'type': 'number'} + return {'type': 'string', 'format': 'duration'} + + def literal_schema(self, schema: core_schema.LiteralSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a literal value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + expected = [to_jsonable_python(v.value if isinstance(v, Enum) else v) for v in schema['expected']] + + result: dict[str, Any] = {} + if len(expected) == 1: + result['const'] = expected[0] + else: + result['enum'] = expected + + types = {type(e) for e in expected} + if types == {str}: + result['type'] = 'string' + elif types == {int}: + result['type'] = 'integer' + elif types == {float}: + result['type'] = 'number' + elif types == {bool}: + result['type'] = 'boolean' + elif types == {list}: + result['type'] = 'array' + elif types == {type(None)}: + result['type'] = 'null' + return result + + def missing_sentinel_schema(self, schema: core_schema.MissingSentinelSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches the `MISSING` sentinel value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + raise PydanticOmit + + def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches an Enum value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + enum_type = schema['cls'] + description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) + if ( + description == 'An enumeration.' + ): # This is the default value provided by enum.EnumMeta.__new__; don't use it + description = None + result: dict[str, Any] = {'title': enum_type.__name__, 'description': description} + result = {k: v for k, v in result.items() if v is not None} + + expected = [to_jsonable_python(v.value) for v in schema['members']] + + result['enum'] = expected + + types = {type(e) for e in expected} + if isinstance(enum_type, str) or types == {str}: + result['type'] = 'string' + elif isinstance(enum_type, int) or types == {int}: + result['type'] = 'integer' + elif isinstance(enum_type, float) or types == {float}: + result['type'] = 'number' + elif types == {bool}: + result['type'] = 'boolean' + elif types == {list}: + result['type'] = 'array' + + return result + + def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: + """Handles JSON schema generation for a core schema that checks if a value is an instance of a class. + + Unless overridden in a subclass, this raises an error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.handle_invalid_for_json_schema(schema, f'core_schema.IsInstanceSchema ({schema["cls"]})') + + def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: + """Handles JSON schema generation for a core schema that checks if a value is a subclass of a class. + + For backwards compatibility with v1, this does not raise an error, but can be overridden to change this. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # Note: This is for compatibility with V1; you can override if you want different behavior. + return {} + + def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a callable value. + + Unless overridden in a subclass, this raises an error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') + + def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: + """Returns a schema that matches a list schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + @deprecated('`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', category=None) + @final + def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Replaced by `tuple_schema`.""" + warnings.warn( + '`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', + PydanticDeprecatedSince26, + stacklevel=2, + ) + return self.tuple_schema(schema) + + @deprecated('`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', category=None) + @final + def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Replaced by `tuple_schema`.""" + warnings.warn( + '`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', + PydanticDeprecatedSince26, + stacklevel=2, + ) + return self.tuple_schema(schema) + + def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a tuple schema e.g. `tuple[int, + str, bool]` or `tuple[int, ...]`. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: JsonSchemaValue = {'type': 'array'} + if 'variadic_item_index' in schema: + variadic_item_index = schema['variadic_item_index'] + if variadic_item_index > 0: + json_schema['minItems'] = variadic_item_index + json_schema['prefixItems'] = [ + self.generate_inner(item) for item in schema['items_schema'][:variadic_item_index] + ] + if variadic_item_index + 1 == len(schema['items_schema']): + # if the variadic item is the last item, then represent it faithfully + json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) + else: + # otherwise, 'items' represents the schema for the variadic + # item plus the suffix, so just allow anything for simplicity + # for now + json_schema['items'] = True + else: + prefixItems = [self.generate_inner(item) for item in schema['items_schema']] + if prefixItems: + json_schema['prefixItems'] = prefixItems + json_schema['minItems'] = len(prefixItems) + json_schema['maxItems'] = len(prefixItems) + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a set schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self._common_set_schema(schema) + + def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a frozenset schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self._common_set_schema(schema) + + def _common_set_schema(self, schema: core_schema.SetSchema | core_schema.FrozenSetSchema) -> JsonSchemaValue: + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: + """Returns a JSON schema that represents the provided GeneratorSchema. + + Args: + schema: The schema. + + Returns: + The generated JSON schema. + """ + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a dict schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: JsonSchemaValue = {'type': 'object'} + + keys_schema = self.generate_inner(schema['keys_schema']).copy() if 'keys_schema' in schema else {} + if '$ref' not in keys_schema: + keys_pattern = keys_schema.pop('pattern', None) + # Don't give a title to patternProperties/propertyNames: + keys_schema.pop('title', None) + else: + # Here, we assume that if the keys schema is a definition reference, + # it can't be a simple string core schema (and thus no pattern can exist). + # However, this is only in practice (in theory, a definition reference core + # schema could be generated for a simple string schema). + # Note that we avoid calling `self.resolve_ref_schema`, as it might not exist yet. + keys_pattern = None + + values_schema = self.generate_inner(schema['values_schema']).copy() if 'values_schema' in schema else {} + # don't give a title to additionalProperties: + values_schema.pop('title', None) + + if values_schema or keys_pattern is not None: + if keys_pattern is None: + json_schema['additionalProperties'] = values_schema + else: + json_schema['patternProperties'] = {keys_pattern: values_schema} + else: # for `dict[str, Any]`, we allow any key and any value, since `str` is the default key type + json_schema['additionalProperties'] = True + + if ( + # The len check indicates that constraints are probably present: + (keys_schema.get('type') == 'string' and len(keys_schema) > 1) + # If this is a definition reference schema, it most likely has constraints: + or '$ref' in keys_schema + ): + keys_schema.pop('type', None) + json_schema['propertyNames'] = keys_schema + + self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) + return json_schema + + def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-before schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.generate_inner(schema['schema']) + + def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-after schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-plain schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.handle_invalid_for_json_schema( + schema, f'core_schema.PlainValidatorFunctionSchema ({schema["function"]})' + ) + + def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-wrap schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.generate_inner(schema['schema']) + + def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema with a default value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = self.generate_inner(schema['schema']) + + default = self.get_default_value(schema) + if default is NoDefault or default is MISSING: + return json_schema + + # we reflect the application of custom plain, no-info serializers to defaults for + # JSON Schemas viewed in serialization mode: + # TODO: improvements along with https://github.com/pydantic/pydantic/issues/8208 + if self.mode == 'serialization': + # `_get_ser_schema_for_default_value()` is used to unpack potentially nested validator schemas: + ser_schema = _get_ser_schema_for_default_value(schema['schema']) + if ( + ser_schema is not None + and (ser_func := ser_schema.get('function')) + and not (default is None and ser_schema.get('when_used') in ('unless-none', 'json-unless-none')) + ): + try: + default = ser_func(default) # type: ignore + except Exception: + # It might be that the provided default needs to be validated (read: parsed) first + # (assuming `validate_default` is enabled). However, we can't perform + # such validation during JSON Schema generation so we don't support + # this pattern for now. + # (One example is when using `foo: ByteSize = '1MB'`, which validates and + # serializes as an int. In this case, `ser_func` is `int` and `int('1MB')` fails). + self.emit_warning( + 'non-serializable-default', + f'Unable to serialize value {default!r} with the plain serializer; excluding default from JSON schema', + ) + return json_schema + + try: + encoded_default = self.encode_default(default) + except pydantic_core.PydanticSerializationError: + self.emit_warning( + 'non-serializable-default', + f'Default value {default} is not JSON serializable; excluding default from JSON schema', + ) + # Return the inner schema, as though there was no default + return json_schema + + json_schema['default'] = encoded_default + return json_schema + + def get_default_value(self, schema: core_schema.WithDefaultSchema) -> Any: + """Get the default value to be used when generating a JSON Schema for a core schema with a default. + + The default implementation is to use the statically defined default value. This method can be overridden + if you want to make use of the default factory. + + Args: + schema: The `'with-default'` core schema. + + Returns: + The default value to use, or [`NoDefault`][pydantic.json_schema.NoDefault] if no default + value is available. + """ + return schema.get('default', NoDefault) + + def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows null values. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + null_schema = {'type': 'null'} + inner_json_schema = self.generate_inner(schema['schema']) + + if inner_json_schema == null_schema: + return null_schema + else: + return self.get_union_of_schemas([inner_json_schema, null_schema]) + + def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching any of the given schemas. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + generated: list[JsonSchemaValue] = [] + + choices = schema['choices'] + for choice in choices: + # choice will be a tuple if an explicit label was provided + choice_schema = choice[0] if isinstance(choice, tuple) else choice + try: + generated.append(self.generate_inner(choice_schema)) + except PydanticOmit: + continue + except PydanticInvalidForJsonSchema as exc: + self.emit_warning('skipped-choice', exc.message) + if len(generated) == 1: + return generated[0] + return self.get_union_of_schemas(generated) + + def get_union_of_schemas(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: + """Returns the JSON Schema representation for the union of the provided JSON Schemas. + + The result depends on the configured `'union_format'`. + + Args: + schemas: The list of JSON Schemas to be included in the union. + + Returns: + The JSON Schema representing the union of schemas. + """ + if self.union_format == 'primitive_type_array': + types: list[str] = [] + for schema in schemas: + schema_types: list[str] | str | None = schema.get('type') + if schema_types is None: + # No type, meaning it can be a ref or an empty schema. + break + if not isinstance(schema_types, list): + schema_types = [schema_types] + if not all(t in _PRIMITIVE_JSON_SCHEMA_TYPES for t in schema_types): + break + if len(schema) != 1: + # We only want to include types that don't have any constraints. For instance, + # if `schemas = [{'type': 'string', 'maxLength': 3}, {'type': 'string', 'minLength': 5}]`, + # we don't want to produce `{'type': 'string', 'maxLength': 3, 'minLength': 5}`. + # Same if we have some metadata (e.g. `title`) on a specific union member, we want to preserve it. + break + + types.extend(schema_types) + else: + # If we got there, all the schemas where valid to be used with the `'primitive_type_array` format + return {'type': list(dict.fromkeys(types))} + + return self.get_flattened_anyof(schemas) + + def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching any of the given schemas, where + the schemas are tagged with a discriminator field that indicates which schema should be used to validate + the value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + generated: dict[str, JsonSchemaValue] = {} + for k, v in schema['choices'].items(): + if isinstance(k, Enum): + k = k.value + try: + # Use str(k) since keys must be strings for json; while not technically correct, + # it's the closest that can be represented in valid JSON + generated[str(k)] = self.generate_inner(v).copy() + except PydanticOmit: + continue + except PydanticInvalidForJsonSchema as exc: + self.emit_warning('skipped-choice', exc.message) + + one_of_choices = _deduplicate_schemas(generated.values()) + json_schema: JsonSchemaValue = {'oneOf': one_of_choices} + + # This reflects the v1 behavior; TODO: we should make it possible to exclude OpenAPI stuff from the JSON schema + openapi_discriminator = self._extract_discriminator(schema, one_of_choices) + if openapi_discriminator is not None: + json_schema['discriminator'] = { + 'propertyName': openapi_discriminator, + 'mapping': {k: v.get('$ref', v) for k, v in generated.items()}, + } + + return json_schema + + def _extract_discriminator( + self, schema: core_schema.TaggedUnionSchema, one_of_choices: list[JsonDict] + ) -> str | None: + """Extract a compatible OpenAPI discriminator from the schema and one_of choices that end up in the final + schema.""" + openapi_discriminator: str | None = None + + if isinstance(schema['discriminator'], str): + return schema['discriminator'] + + if isinstance(schema['discriminator'], list): + # If the discriminator is a single item list containing a string, that is equivalent to the string case + if len(schema['discriminator']) == 1 and isinstance(schema['discriminator'][0], str): + return schema['discriminator'][0] + # When an alias is used that is different from the field name, the discriminator will be a list of single + # str lists, one for the attribute and one for the actual alias. The logic here will work even if there is + # more than one possible attribute, and looks for whether a single alias choice is present as a documented + # property on all choices. If so, that property will be used as the OpenAPI discriminator. + for alias_path in schema['discriminator']: + if not isinstance(alias_path, list): + break # this means that the discriminator is not a list of alias paths + if len(alias_path) != 1: + continue # this means that the "alias" does not represent a single field + alias = alias_path[0] + if not isinstance(alias, str): + continue # this means that the "alias" does not represent a field + alias_is_present_on_all_choices = True + for choice in one_of_choices: + try: + choice = self.resolve_ref_schema(choice) + except RuntimeError as exc: + # TODO: fixme - this is a workaround for the fact that we can't always resolve refs + # for tagged union choices at this point in the schema gen process, we might need to do + # another pass at the end like we do for core schemas + self.emit_warning('skipped-discriminator', str(exc)) + choice = {} + properties = choice.get('properties', {}) + if not isinstance(properties, dict) or alias not in properties: + alias_is_present_on_all_choices = False + break + if alias_is_present_on_all_choices: + openapi_discriminator = alias + break + return openapi_discriminator + + def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a core_schema.ChainSchema. + + When generating a schema for validation, we return the validation JSON schema for the first step in the chain. + For serialization, we return the serialization JSON schema for the last step in the chain. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + step_index = 0 if self.mode == 'validation' else -1 # use first step for validation, last for serialization + return self.generate_inner(schema['steps'][step_index]) + + def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching either the lax schema or the + strict schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # TODO: Need to read the default value off of model config or whatever + use_strict = schema.get('strict', False) # TODO: replace this default False + # If your JSON schema fails to generate it is probably + # because one of the following two branches failed. + if use_strict: + return self.generate_inner(schema['strict_schema']) + else: + return self.generate_inner(schema['lax_schema']) + + def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching either the JSON schema or the + Python schema. + + The JSON schema is used instead of the Python schema. If you want to use the Python schema, you should override + this method. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['json_schema']) + + def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a typed dict. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + total = schema.get('total', True) + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (name, self.field_is_required(field, total), field) + for name, field in schema['fields'].items() + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + cls = schema.get('cls') + config = _get_typed_dict_config(cls) + with self._config_wrapper_stack.push(config): + json_schema = self._named_required_fields_schema(named_required_fields) + + # There's some duplication between `extra_behavior` and + # the config's `extra`/core config's `extra_fields_behavior`. + # However, it is common to manually create TypedDictSchemas, + # where you don't necessarily have a class. + # At runtime, `extra_behavior` takes priority over the config + # for validation, so follow the same for the JSON Schema: + if schema.get('extra_behavior') == 'forbid': + json_schema['additionalProperties'] = False + elif schema.get('extra_behavior') == 'allow': + if 'extras_schema' in schema and schema['extras_schema'] != {'type': 'any'}: + json_schema['additionalProperties'] = self.generate_inner(schema['extras_schema']) + else: + json_schema['additionalProperties'] = True + + if cls is not None: + # `_update_class_schema()` will not override + # `additionalProperties` if already present: + self._update_class_schema(json_schema, cls, config) + elif 'additionalProperties' not in json_schema: + extra = schema.get('config', {}).get('extra_fields_behavior') + if extra == 'forbid': + json_schema['additionalProperties'] = False + elif extra == 'allow': + json_schema['additionalProperties'] = True + + return json_schema + + @staticmethod + def _name_required_computed_fields( + computed_fields: list[ComputedField], + ) -> list[tuple[str, bool, core_schema.ComputedField]]: + return [(field['property_name'], True, field) for field in computed_fields] + + def _named_required_fields_schema( + self, named_required_fields: Sequence[tuple[str, bool, CoreSchemaField]] + ) -> JsonSchemaValue: + properties: dict[str, JsonSchemaValue] = {} + required_fields: list[str] = [] + for name, required, field in named_required_fields: + if self.by_alias: + name = self._get_alias_name(field, name) + try: + field_json_schema = self.generate_inner(field).copy() + except PydanticOmit: + continue + if 'title' not in field_json_schema and self.field_title_should_be_set(field): + title = self.get_title_from_name(name) + field_json_schema['title'] = title + field_json_schema = self.handle_ref_overrides(field_json_schema) + properties[name] = field_json_schema + if required: + required_fields.append(name) + + json_schema = {'type': 'object', 'properties': properties} + if required_fields: + json_schema['required'] = required_fields + return json_schema + + def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: + if field['type'] == 'computed-field': + alias: Any = field.get('alias', name) + elif self.mode == 'validation': + alias = field.get('validation_alias', name) + else: + alias = field.get('serialization_alias', name) + if isinstance(alias, str): + name = alias + elif isinstance(alias, list): + alias = cast('list[str] | str', alias) + for path in alias: + if isinstance(path, list) and len(path) == 1 and isinstance(path[0], str): + # Use the first valid single-item string path; the code that constructs the alias array + # should ensure the first such item is what belongs in the JSON schema + name = path[0] + break + else: + assert_never(alias) + return name + + def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a typed dict field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a computed field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['return_schema']) + + def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # We do not use schema['model'].model_json_schema() here + # because it could lead to inconsistent refs handling, etc. + cls = cast('type[BaseModel]', schema['cls']) + config = cls.model_config + + with self._config_wrapper_stack.push(config): + json_schema = self.generate_inner(schema['schema']) + + self._update_class_schema(json_schema, cls, config) + + return json_schema + + def _update_class_schema(self, json_schema: JsonSchemaValue, cls: type[Any], config: ConfigDict) -> None: + """Update json_schema with the following, extracted from `config` and `cls`: + + * title + * description + * additional properties + * json_schema_extra + * deprecated + + Done in place, hence there's no return value as the original json_schema is mutated. + No ref resolving is involved here, as that's not appropriate for simple updates. + """ + from .main import BaseModel + from .root_model import RootModel + + if (config_title := config.get('title')) is not None: + json_schema.setdefault('title', config_title) + elif model_title_generator := config.get('model_title_generator'): + title = model_title_generator(cls) + if not isinstance(title, str): + raise TypeError(f'model_title_generator {model_title_generator} must return str, not {title.__class__}') + json_schema.setdefault('title', title) + if 'title' not in json_schema: + json_schema['title'] = cls.__name__ + + # BaseModel and dataclasses; don't use cls.__doc__ as it will contain the verbose class signature by default + docstring = None if cls is BaseModel or dataclasses.is_dataclass(cls) else cls.__doc__ + + if docstring: + json_schema.setdefault('description', inspect.cleandoc(docstring)) + elif issubclass(cls, RootModel) and (root_description := cls.__pydantic_fields__['root'].description): + json_schema.setdefault('description', root_description) + + extra = config.get('extra') + if 'additionalProperties' not in json_schema: # This check is particularly important for `typed_dict_schema()` + if extra == 'allow': + json_schema['additionalProperties'] = True + elif extra == 'forbid': + json_schema['additionalProperties'] = False + + json_schema_extra = config.get('json_schema_extra') + if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: + root_json_schema_extra = cls.model_fields['root'].json_schema_extra + if json_schema_extra and root_json_schema_extra: + raise ValueError( + '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"' + ' field must not be set simultaneously' + ) + if root_json_schema_extra: + json_schema_extra = root_json_schema_extra + + if isinstance(json_schema_extra, (staticmethod, classmethod)): + # In older versions of python, this is necessary to ensure staticmethod/classmethods are callable + json_schema_extra = json_schema_extra.__get__(cls) + + if isinstance(json_schema_extra, dict): + json_schema.update(json_schema_extra) + elif callable(json_schema_extra): + # FIXME: why are there type ignores here? We support two signatures for json_schema_extra callables... + if len(inspect.signature(json_schema_extra).parameters) > 1: + json_schema_extra(json_schema, cls) # type: ignore + else: + json_schema_extra(json_schema) # type: ignore + elif json_schema_extra is not None: + raise ValueError( + f"model_config['json_schema_extra']={json_schema_extra} should be a dict, callable, or None" + ) + + if hasattr(cls, '__deprecated__'): + json_schema['deprecated'] = True + + def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Resolve a JsonSchemaValue to the non-ref schema if it is a $ref schema. + + Args: + json_schema: The schema to resolve. + + Returns: + The resolved schema. + + Raises: + RuntimeError: If the schema reference can't be found in definitions. + """ + while '$ref' in json_schema: + ref = json_schema['$ref'] + schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) + if schema_to_update is None: + raise RuntimeError(f'Cannot update undefined schema for $ref={ref}') + json_schema = schema_to_update + return json_schema + + def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model's fields. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (name, self.field_is_required(field, total=True), field) + for name, field in schema['fields'].items() + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + json_schema = self._named_required_fields_schema(named_required_fields) + extras_schema = schema.get('extras_schema', None) + if extras_schema is not None: + schema_to_update = self.resolve_ref_schema(json_schema) + schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) + return json_schema + + def field_is_present(self, field: CoreSchemaField) -> bool: + """Whether the field should be included in the generated JSON schema. + + Args: + field: The schema for the field itself. + + Returns: + `True` if the field should be included in the generated JSON schema, `False` otherwise. + """ + if self.mode == 'serialization': + # If you still want to include the field in the generated JSON schema, + # override this method and return True + return not field.get('serialization_exclude') + elif self.mode == 'validation': + return True + else: + assert_never(self.mode) + + def field_is_required( + self, + field: core_schema.ModelField | core_schema.DataclassField | core_schema.TypedDictField, + total: bool, + ) -> bool: + """Whether the field should be marked as required in the generated JSON schema. + (Note that this is irrelevant if the field is not present in the JSON schema.). + + Args: + field: The schema for the field itself. + total: Only applies to `TypedDictField`s. + Indicates if the `TypedDict` this field belongs to is total, in which case any fields that don't + explicitly specify `required=False` are required. + + Returns: + `True` if the field should be marked as required in the generated JSON schema, `False` otherwise. + """ + if field['type'] == 'typed-dict-field': + required = field.get('required', total) + else: + required = field['schema']['type'] != 'default' + + if self.mode == 'serialization': + has_exclude_if = field.get('serialization_exclude_if') is not None + if self._config.json_schema_serialization_defaults_required: + return not has_exclude_if + else: + return required and not has_exclude_if + else: + return required + + def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass's constructor arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (field['name'], self.field_is_required(field, total=True), field) + for field in schema['fields'] + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + return self._named_required_fields_schema(named_required_fields) + + def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + from ._internal._dataclasses import is_stdlib_dataclass + + cls = schema['cls'] + config: ConfigDict = getattr(cls, '__pydantic_config__', cast('ConfigDict', {})) + + with self._config_wrapper_stack.push(config): + json_schema = self.generate_inner(schema['schema']).copy() + + self._update_class_schema(json_schema, cls, config) + + # Dataclass-specific handling of description + if is_stdlib_dataclass(cls): + # vanilla dataclass; don't use cls.__doc__ as it will contain the class signature by default + description = None + else: + description = None if cls.__doc__ is None else inspect.cleandoc(cls.__doc__) + if description: + json_schema['description'] = description + + return json_schema + + def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') + + arguments = schema['arguments_schema'] + kw_only_arguments = [a for a in arguments if a.get('mode') == 'keyword_only'] + kw_or_p_arguments = [a for a in arguments if a.get('mode') in {'positional_or_keyword', None}] + p_only_arguments = [a for a in arguments if a.get('mode') == 'positional_only'] + var_args_schema = schema.get('var_args_schema') + var_kwargs_schema = schema.get('var_kwargs_schema') + + if prefer_positional: + positional_possible = not kw_only_arguments and not var_kwargs_schema + if positional_possible: + return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) + + keyword_possible = not p_only_arguments and not var_args_schema + if keyword_possible: + return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) + + if not prefer_positional: + positional_possible = not kw_only_arguments and not var_kwargs_schema + if positional_possible: + return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) + + raise PydanticInvalidForJsonSchema( + 'Unable to generate JSON schema for arguments validator with positional-only and keyword-only arguments' + ) + + def kw_arguments_schema( + self, arguments: list[core_schema.ArgumentsParameter], var_kwargs_schema: CoreSchema | None + ) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's keyword arguments. + + Args: + arguments: The core schema. + + Returns: + The generated JSON schema. + """ + properties: dict[str, JsonSchemaValue] = {} + required: list[str] = [] + for argument in arguments: + name = self.get_argument_name(argument) + argument_schema = self.generate_inner(argument['schema']).copy() + if 'title' not in argument_schema and self.field_title_should_be_set(argument['schema']): + argument_schema['title'] = self.get_title_from_name(name) + properties[name] = argument_schema + + if argument['schema']['type'] != 'default': + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + required.append(name) + + json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} + if required: + json_schema['required'] = required + + if var_kwargs_schema: + additional_properties_schema = self.generate_inner(var_kwargs_schema) + if additional_properties_schema: + json_schema['additionalProperties'] = additional_properties_schema + else: + json_schema['additionalProperties'] = False + return json_schema + + def p_arguments_schema( + self, arguments: list[core_schema.ArgumentsParameter], var_args_schema: CoreSchema | None + ) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's positional arguments. + + Args: + arguments: The core schema. + + Returns: + The generated JSON schema. + """ + prefix_items: list[JsonSchemaValue] = [] + min_items = 0 + + for argument in arguments: + name = self.get_argument_name(argument) + + argument_schema = self.generate_inner(argument['schema']).copy() + if 'title' not in argument_schema and self.field_title_should_be_set(argument['schema']): + argument_schema['title'] = self.get_title_from_name(name) + prefix_items.append(argument_schema) + + if argument['schema']['type'] != 'default': + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + min_items += 1 + + json_schema: JsonSchemaValue = {'type': 'array'} + if prefix_items: + json_schema['prefixItems'] = prefix_items + if min_items: + json_schema['minItems'] = min_items + + if var_args_schema: + items_schema = self.generate_inner(var_args_schema) + if items_schema: + json_schema['items'] = items_schema + else: + json_schema['maxItems'] = len(prefix_items) + + return json_schema + + def get_argument_name(self, argument: core_schema.ArgumentsParameter | core_schema.ArgumentsV3Parameter) -> str: + """Retrieves the name of an argument. + + Args: + argument: The core schema. + + Returns: + The name of the argument. + """ + name = argument['name'] + if self.by_alias: + alias = argument.get('alias') + if isinstance(alias, str): + name = alias + else: + pass # might want to do something else? + return name + + def arguments_v3_schema(self, schema: core_schema.ArgumentsV3Schema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + arguments = schema['arguments_schema'] + properties: dict[str, JsonSchemaValue] = {} + required: list[str] = [] + for argument in arguments: + mode = argument.get('mode', 'positional_or_keyword') + name = self.get_argument_name(argument) + argument_schema = self.generate_inner(argument['schema']).copy() + if mode == 'var_args': + argument_schema = {'type': 'array', 'items': argument_schema} + elif mode == 'var_kwargs_uniform': + argument_schema = {'type': 'object', 'additionalProperties': argument_schema} + + argument_schema.setdefault('title', self.get_title_from_name(name)) + properties[name] = argument_schema + + if ( + (mode == 'var_kwargs_unpacked_typed_dict' and 'required' in argument_schema) + or mode not in {'var_args', 'var_kwargs_uniform', 'var_kwargs_unpacked_typed_dict'} + and argument['schema']['type'] != 'default' + ): + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + required.append(name) + + json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} + if required: + json_schema['required'] = required + return json_schema + + def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function call. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['arguments_schema']) + + def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a custom error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a JSON object. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + content_core_schema = schema.get('schema') or core_schema.any_schema() + content_json_schema = self.generate_inner(content_core_schema) + if self.mode == 'validation': + return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} + else: + # self.mode == 'serialization' + return content_json_schema + + def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a URL. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + return json_schema + + def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a URL that can be used with multiple hosts. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # Note: 'multi-host-uri' is a custom/pydantic-specific format, not part of the JSON Schema spec + json_schema = {'type': 'string', 'format': 'multi-host-uri', 'minLength': 1} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + return json_schema + + def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a UUID. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'uuid'} + + def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a JSON object with definitions. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + for definition in schema['definitions']: + try: + self.generate_inner(definition) + except PydanticInvalidForJsonSchema as e: # noqa: PERF203 + core_ref: CoreRef = CoreRef(definition['ref']) # type: ignore + self._core_defs_invalid_for_json_schema[self.get_defs_ref((core_ref, self.mode))] = e + continue + return self.generate_inner(schema['schema']) + + def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that references a definition. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + core_ref = CoreRef(schema['schema_ref']) + _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) + return ref_json_schema + + def ser_schema( + self, schema: core_schema.SerSchema | core_schema.IncExSeqSerSchema | core_schema.IncExDictSerSchema + ) -> JsonSchemaValue | None: + """Generates a JSON schema that matches a schema that defines a serialized object. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + schema_type = schema['type'] + if schema_type == 'function-plain' or schema_type == 'function-wrap': + # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema + return_schema = schema.get('return_schema') + if return_schema is not None: + return self.generate_inner(return_schema) + elif schema_type == 'format' or schema_type == 'to-string': + # FormatSerSchema or ToStringSerSchema + return self.str_schema(core_schema.str_schema()) + elif schema['type'] == 'model': + # ModelSerSchema + return self.generate_inner(schema['schema']) + return None + + def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a complex number. + + JSON has no standard way to represent complex numbers. Complex number is not a numeric + type. Here we represent complex number as strings following the rule defined by Python. + For instance, '1+2j' is an accepted complex string. Details can be found in + [Python's `complex` documentation][complex]. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string'} + + # ### Utility methods + + def get_title_from_name(self, name: str) -> str: + """Retrieves a title from a name. + + Args: + name: The name to retrieve a title from. + + Returns: + The title. + """ + return name.title().replace('_', ' ').strip() + + def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: + """Returns true if a field with the given schema should have a title set based on the field name. + + Intuitively, we want this to return true for schemas that wouldn't otherwise provide their own title + (e.g., int, float, str), and false for those that would (e.g., BaseModel subclasses). + + Args: + schema: The schema to check. + + Returns: + `True` if the field should have a title set, `False` otherwise. + """ + if _core_utils.is_core_schema_field(schema): + if schema['type'] == 'computed-field': + field_schema = schema['return_schema'] + else: + field_schema = schema['schema'] + return self.field_title_should_be_set(field_schema) + + elif _core_utils.is_core_schema(schema): + if schema.get('ref'): # things with refs, such as models and enums, should not have titles set + return False + if schema['type'] in {'default', 'nullable', 'definitions'}: + return self.field_title_should_be_set(schema['schema']) # type: ignore[typeddict-item] + if _core_utils.is_function_with_inner_schema(schema): + return self.field_title_should_be_set(schema['schema']) + if schema['type'] == 'definition-ref': + # Referenced schemas should not have titles set for the same reason + # schemas with refs should not + return False + return True # anything else should have title set + + else: + raise PydanticInvalidForJsonSchema(f'Unexpected schema type: schema={schema}') # pragma: no cover + + def normalize_name(self, name: str) -> str: + """Normalizes a name to be used as a key in a dictionary. + + Args: + name: The name to normalize. + + Returns: + The normalized name. + """ + return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name).replace('.', '__') + + def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: + """Override this method to change the way that definitions keys are generated from a core reference. + + Args: + core_mode_ref: The core reference. + + Returns: + The definitions key. + """ + # Split the core ref into "components"; generic origins and arguments are each separate components + core_ref, mode = core_mode_ref + components = re.split(r'([\][,])', core_ref) + # Remove IDs from each component + components = [x.rsplit(':', 1)[0] for x in components] + core_ref_no_id = ''.join(components) + # Remove everything before the last period from each "component" + components = [re.sub(r'(?:[^.[\]]+\.)+((?:[^.[\]]+))', r'\1', x) for x in components] + short_ref = ''.join(components) + + mode_title = _MODE_TITLE_MAPPING[mode] + + # It is important that the generated defs_ref values be such that at least one choice will not + # be generated for any other core_ref. Currently, this should be the case because we include + # the id of the source type in the core_ref + name = DefsRef(self.normalize_name(short_ref)) + name_mode = DefsRef(self.normalize_name(short_ref) + f'-{mode_title}') + module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) + module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') + module_qualname_id = DefsRef(self.normalize_name(core_ref)) + occurrence_index = self._collision_index.get(module_qualname_id) + if occurrence_index is None: + self._collision_counter[module_qualname] += 1 + occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] + + module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') + module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') + + self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ + name, + name_mode, + module_qualname, + module_qualname_mode, + module_qualname_occurrence, + module_qualname_occurrence_mode, + ] + + return module_qualname_occurrence_mode + + def get_cache_defs_ref_schema(self, core_ref: CoreRef) -> tuple[DefsRef, JsonSchemaValue]: + """This method wraps the get_defs_ref method with some cache-lookup/population logic, + and returns both the produced defs_ref and the JSON schema that will refer to the right definition. + + Args: + core_ref: The core reference to get the definitions reference for. + + Returns: + A tuple of the definitions reference and the JSON schema that will refer to it. + """ + core_mode_ref = (core_ref, self.mode) + maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) + if maybe_defs_ref is not None: + json_ref = self.core_to_json_refs[core_mode_ref] + return maybe_defs_ref, {'$ref': json_ref} + + defs_ref = self.get_defs_ref(core_mode_ref) + + # populate the ref translation mappings + self.core_to_defs_refs[core_mode_ref] = defs_ref + self.defs_to_core_refs[defs_ref] = core_mode_ref + + json_ref = JsonRef(self.ref_template.format(model=defs_ref)) + self.core_to_json_refs[core_mode_ref] = json_ref + self.json_to_defs_refs[json_ref] = defs_ref + ref_json_schema = {'$ref': json_ref} + return defs_ref, ref_json_schema + + def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Remove any sibling keys that are redundant with the referenced schema. + + Args: + json_schema: The schema to remove redundant sibling keys from. + + Returns: + The schema with redundant sibling keys removed. + """ + if '$ref' in json_schema: + # prevent modifications to the input; this copy may be safe to drop if there is significant overhead + json_schema = json_schema.copy() + + referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) + if referenced_json_schema is None: + # This can happen when building schemas for models with not-yet-defined references. + # It may be a good idea to do a recursive pass at the end of the generation to remove + # any redundant override keys. + return json_schema + for k, v in list(json_schema.items()): + if k == '$ref': + continue + if k in referenced_json_schema and referenced_json_schema[k] == v: + del json_schema[k] # redundant key + + return json_schema + + def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: + try: + def_ref = self.json_to_defs_refs[json_ref] + if def_ref in self._core_defs_invalid_for_json_schema: + raise self._core_defs_invalid_for_json_schema[def_ref] + return self.definitions.get(def_ref, None) + except KeyError: + if json_ref.startswith(('http://', 'https://')): + return None + raise + + def encode_default(self, dft: Any) -> Any: + """Encode a default value to a JSON-serializable value. + + This is used to encode default values for fields in the generated JSON schema. + + Args: + dft: The default value to encode. + + Returns: + The encoded default value. + """ + from .type_adapter import TypeAdapter, _type_has_config + + config = self._config + try: + default = ( + dft + if _type_has_config(type(dft)) + else TypeAdapter(type(dft), config=config.config_dict).dump_python( + dft, by_alias=self.by_alias, mode='json' + ) + ) + except PydanticSchemaGenerationError: + raise pydantic_core.PydanticSerializationError(f'Unable to encode default value {dft}') + + return pydantic_core.to_jsonable_python( + default, timedelta_mode=config.ser_json_timedelta, bytes_mode=config.ser_json_bytes, by_alias=self.by_alias + ) + + def update_with_validations( + self, json_schema: JsonSchemaValue, core_schema: CoreSchema, mapping: dict[str, str] + ) -> None: + """Update the json_schema with the corresponding validations specified in the core_schema, + using the provided mapping to translate keys in core_schema to the appropriate keys for a JSON schema. + + Args: + json_schema: The JSON schema to update. + core_schema: The core schema to get the validations from. + mapping: A mapping from core_schema attribute names to the corresponding JSON schema attribute names. + """ + for core_key, json_schema_key in mapping.items(): + if core_key in core_schema: + json_schema[json_schema_key] = core_schema[core_key] + + class ValidationsMapping: + """This class just contains mappings from core_schema attribute names to the corresponding + JSON schema attribute names. While I suspect it is unlikely to be necessary, you can in + principle override this class in a subclass of GenerateJsonSchema (by inheriting from + GenerateJsonSchema.ValidationsMapping) to change these mappings. + """ + + numeric = { + 'multiple_of': 'multipleOf', + 'le': 'maximum', + 'ge': 'minimum', + 'lt': 'exclusiveMaximum', + 'gt': 'exclusiveMinimum', + } + bytes = { + 'min_length': 'minLength', + 'max_length': 'maxLength', + } + string = { + 'min_length': 'minLength', + 'max_length': 'maxLength', + 'pattern': 'pattern', + } + array = { + 'min_length': 'minItems', + 'max_length': 'maxItems', + } + object = { + 'min_length': 'minProperties', + 'max_length': 'maxProperties', + } + + def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: + members = [] + for schema in schemas: + if len(schema) == 1 and 'anyOf' in schema: + members.extend(schema['anyOf']) + else: + members.append(schema) + members = _deduplicate_schemas(members) + if len(members) == 1: + return members[0] + return {'anyOf': members} + + def get_json_ref_counts(self, json_schema: JsonSchemaValue) -> dict[JsonRef, int]: + """Get all values corresponding to the key '$ref' anywhere in the json_schema.""" + json_refs: dict[JsonRef, int] = Counter() + + def _add_json_refs(schema: Any) -> None: + if isinstance(schema, dict): + if '$ref' in schema: + json_ref = JsonRef(schema['$ref']) + if not isinstance(json_ref, str): + return # in this case, '$ref' might have been the name of a property + already_visited = json_ref in json_refs + json_refs[json_ref] += 1 + if already_visited: + return # prevent recursion on a definition that was already visited + try: + defs_ref = self.json_to_defs_refs[json_ref] + if defs_ref in self._core_defs_invalid_for_json_schema: + raise self._core_defs_invalid_for_json_schema[defs_ref] + _add_json_refs(self.definitions[defs_ref]) + except KeyError: + if not json_ref.startswith(('http://', 'https://')): + raise + + for k, v in schema.items(): + if k == 'examples' and isinstance(v, list): + # Skip examples that may contain arbitrary values and references + # (see the comment in `_get_all_json_refs` for more details). + continue + _add_json_refs(v) + elif isinstance(schema, list): + for v in schema: + _add_json_refs(v) + + _add_json_refs(json_schema) + return json_refs + + def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: + raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') + + def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: + """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method.""" + message = self.render_warning_message(kind, detail) + if message is not None: + warnings.warn(message, PydanticJsonSchemaWarning) + + def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: + """This method is responsible for ignoring warnings as desired, and for formatting the warning messages. + + You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema + to modify what warnings are generated. If you want more control, you can override this method; + just return None in situations where you don't want warnings to be emitted. + + Args: + kind: The kind of warning to render. It can be one of the following: + + - 'skipped-choice': A choice field was skipped because it had no valid choices. + - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. + detail: A string with additional details about the warning. + + Returns: + The formatted warning message, or `None` if no warning should be emitted. + """ + if kind in self.ignored_warning_kinds: + return None + return f'{detail} [{kind}]' + + def _build_definitions_remapping(self) -> _DefinitionsRemapping: + defs_to_json: dict[DefsRef, JsonRef] = {} + for defs_refs in self._prioritized_defsref_choices.values(): + for defs_ref in defs_refs: + json_ref = JsonRef(self.ref_template.format(model=defs_ref)) + defs_to_json[defs_ref] = json_ref + + return _DefinitionsRemapping.from_prioritized_choices( + self._prioritized_defsref_choices, defs_to_json, self.definitions + ) + + def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: + visited_defs_refs: set[DefsRef] = set() + unvisited_json_refs = _get_all_json_refs(schema) + while unvisited_json_refs: + next_json_ref = unvisited_json_refs.pop() + try: + next_defs_ref = self.json_to_defs_refs[next_json_ref] + if next_defs_ref in visited_defs_refs: + continue + visited_defs_refs.add(next_defs_ref) + unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) + except KeyError: + if not next_json_ref.startswith(('http://', 'https://')): + raise + + self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} + + +# ##### Start JSON Schema Generation Functions ##### + + +def model_json_schema( + cls: type[BaseModel] | type[PydanticDataclass], + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', +) -> dict[str, Any]: + """Utility function to generate a JSON Schema for a model. + + Args: + cls: The model class to generate a JSON Schema for. + by_alias: If `True` (the default), fields will be serialized according to their alias. + If `False`, fields will be serialized according to their attribute name. + ref_template: The template to use for generating JSON Schema references. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The class to use for generating the JSON Schema. + mode: The mode to use for generating the JSON Schema. It can be one of the following: + + - 'validation': Generate a JSON Schema for validating data. + - 'serialization': Generate a JSON Schema for serializing data. + + Returns: + The generated JSON Schema. + """ + from .main import BaseModel + + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + + if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): + cls.__pydantic_core_schema__.rebuild() + + if cls is BaseModel: + raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') + + assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' + return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) + + +def models_json_schema( + models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], + *, + by_alias: bool = True, + title: str | None = None, + description: str | None = None, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, +) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: + """Utility function to generate a JSON Schema for multiple models. + + Args: + models: A sequence of tuples of the form (model, mode). + by_alias: Whether field aliases should be used as keys in the generated JSON Schema. + title: The title of the generated JSON Schema. + description: The description of the generated JSON Schema. + ref_template: The reference template to use for generating JSON Schema references. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The schema generator to use for generating the JSON Schema. + + Returns: + A tuple where: + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a JSON schema containing all definitions referenced in the first returned + element, along with the optional title and description keys. + """ + for cls, _ in models: + if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): + cls.__pydantic_core_schema__.rebuild() + + instance = schema_generator(by_alias=by_alias, ref_template=ref_template, union_format=union_format) + inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ + (m, mode, m.__pydantic_core_schema__) for m, mode in models + ] + json_schemas_map, definitions = instance.generate_definitions(inputs) + + json_schema: dict[str, Any] = {} + if definitions: + json_schema['$defs'] = definitions + if title: + json_schema['title'] = title + if description: + json_schema['description'] = description + + return json_schemas_map, json_schema + + +# ##### End JSON Schema Generation Functions ##### + + +_HashableJsonValue: TypeAlias = Union[ + int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] +] + + +def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: + return list({_make_json_hashable(schema): schema for schema in schemas}.values()) + + +def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: + if isinstance(value, dict): + return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) + elif isinstance(value, list): + return tuple(_make_json_hashable(v) for v in value) + else: + return value + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class WithJsonSchema: + """!!! abstract "Usage Documentation" + [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) + + Add this as an annotation on a field to override the (base) JSON schema that would be generated for that field. + This provides a way to set a JSON schema for types that would otherwise raise errors when producing a JSON schema, + such as Callable, or types that have an is-instance core schema, without needing to go so far as creating a + custom subclass of pydantic.json_schema.GenerateJsonSchema. + Note that any _modifications_ to the schema that would normally be made (such as setting the title for model fields) + will still be performed. + + If `mode` is set this will only apply to that schema generation mode, allowing you + to set different json schemas for validation and serialization. + """ + + json_schema: JsonSchemaValue | None + mode: Literal['validation', 'serialization'] | None = None + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + mode = self.mode or handler.mode + if mode != handler.mode: + return handler(core_schema) + if self.json_schema is None: + # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema + raise PydanticOmit + else: + return self.json_schema.copy() + + def __hash__(self) -> int: + return hash(type(self.mode)) + + +class Examples: + """Add examples to a JSON schema. + + If the JSON Schema already contains examples, the provided examples + will be appended. + + If `mode` is set this will only apply to that schema generation mode, + allowing you to add different examples for validation and serialization. + """ + + @overload + @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') + def __init__( + self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None + ) -> None: ... + + @overload + def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... + + def __init__( + self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None + ) -> None: + if isinstance(examples, dict): + warnings.warn( + 'Using a dict for `examples` is deprecated, use a list instead.', + PydanticDeprecatedSince29, + stacklevel=2, + ) + self.examples = examples + self.mode = mode + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + mode = self.mode or handler.mode + json_schema = handler(core_schema) + if mode != handler.mode: + return json_schema + examples = json_schema.get('examples') + if examples is None: + json_schema['examples'] = to_jsonable_python(self.examples) + if isinstance(examples, dict): + if isinstance(self.examples, list): + warnings.warn( + 'Updating existing JSON Schema examples of type dict with examples of type list. ' + 'Only the existing examples values will be retained. Note that dict support for ' + 'examples is deprecated and will be removed in v3.0.', + UserWarning, + ) + json_schema['examples'] = to_jsonable_python( + [ex for value in examples.values() for ex in value] + self.examples + ) + else: + json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) + if isinstance(examples, list): + if isinstance(self.examples, list): + json_schema['examples'] = to_jsonable_python(examples + self.examples) + elif isinstance(self.examples, dict): + warnings.warn( + 'Updating existing JSON Schema examples of type list with examples of type dict. ' + 'Only the examples values will be retained. Note that dict support for ' + 'examples is deprecated and will be removed in v3.0.', + UserWarning, + ) + json_schema['examples'] = to_jsonable_python( + examples + [ex for value in self.examples.values() for ex in value] + ) + + return json_schema + + def __hash__(self) -> int: + return hash(type(self.mode)) + + +def _get_all_json_refs(item: Any) -> set[JsonRef]: + """Get all the definitions references from a JSON schema.""" + refs: set[JsonRef] = set() + stack = [item] + + while stack: + current = stack.pop() + if isinstance(current, dict): + for key, value in current.items(): + if key == 'examples' and isinstance(value, list): + # Skip examples that may contain arbitrary values and references + # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value + # of type list is necessary to avoid skipping valid portions of the schema, + # for instance when "examples" is used as a property key. A more robust solution + # could be found, but would require more advanced JSON Schema parsing logic. + continue + if key == '$ref' and isinstance(value, str): + refs.add(JsonRef(value)) + elif isinstance(value, dict): + stack.append(value) + elif isinstance(value, list): + stack.extend(value) + elif isinstance(current, list): + stack.extend(current) + + return refs + + +AnyType = TypeVar('AnyType') + +if TYPE_CHECKING: + SkipJsonSchema = Annotated[AnyType, ...] +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SkipJsonSchema: + """!!! abstract "Usage Documentation" + [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) + + Add this as an annotation on a field to skip generating a JSON schema for that field. + + Example: + ```python + from pprint import pprint + from typing import Union + + from pydantic import BaseModel + from pydantic.json_schema import SkipJsonSchema + + class Model(BaseModel): + a: Union[int, None] = None # (1)! + b: Union[int, SkipJsonSchema[None]] = None # (2)! + c: SkipJsonSchema[Union[int, None]] = None # (3)! + + pprint(Model.model_json_schema()) + ''' + { + 'properties': { + 'a': { + 'anyOf': [ + {'type': 'integer'}, + {'type': 'null'} + ], + 'default': None, + 'title': 'A' + }, + 'b': { + 'default': None, + 'title': 'B', + 'type': 'integer' + } + }, + 'title': 'Model', + 'type': 'object' + } + ''' + ``` + + 1. The integer and null types are both included in the schema for `a`. + 2. The integer type is the only type included in the schema for `b`. + 3. The entirety of the `c` field is omitted from the schema. + """ + + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + def __get_pydantic_json_schema__( + self, core_schema: CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + raise PydanticOmit + + def __hash__(self) -> int: + return hash(type(self)) + + +def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: + if cls is not None: + try: + return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') + except AttributeError: + pass + return {} + + +def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: + """Get a `'function-plain'` serialization schema that can be used to serialize a default value. + + This takes into account having the serialization schema nested under validation schema(s). + """ + if ( + (ser_schema := schema.get('serialization')) + and ser_schema['type'] == 'function-plain' + and not ser_schema.get('info_arg') + ): + return ser_schema + if _core_utils.is_function_with_inner_schema(schema): + return _get_ser_schema_for_default_value(schema['schema']) diff --git a/backend/venv/Lib/site-packages/pydantic/main.py b/backend/venv/Lib/site-packages/pydantic/main.py new file mode 100644 index 0000000..2b3148e --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/main.py @@ -0,0 +1,1819 @@ +"""Logic for creating models.""" + +# Because `dict` is in the local namespace of the `BaseModel` class, we use `Dict` for annotations. +# TODO v3 fallback to `dict` when the deprecated `dict` method gets removed. +# ruff: noqa: UP035 + +from __future__ import annotations as _annotations + +import operator +import sys +import types +import warnings +from collections.abc import Generator, Mapping +from copy import copy, deepcopy +from functools import cached_property +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + Generic, + Literal, + TypeVar, + Union, + cast, + overload, +) + +import pydantic_core +import typing_extensions +from pydantic_core import PydanticUndefined, ValidationError +from typing_extensions import Self, TypeAlias, Unpack + +from . import PydanticDeprecatedSince20, PydanticDeprecatedSince211 +from ._internal import ( + _config, + _decorators, + _fields, + _forward_ref, + _generics, + _mock_val_ser, + _model_construction, + _namespace_utils, + _repr, + _typing_extra, + _utils, +) +from ._migration import getattr_migration +from .aliases import AliasChoices, AliasPath +from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from .config import ConfigDict, ExtraValues +from .errors import PydanticUndefinedAnnotation, PydanticUserError +from .json_schema import DEFAULT_REF_TEMPLATE, GenerateJsonSchema, JsonSchemaMode, JsonSchemaValue, model_json_schema +from .plugin._schema_validator import PluggableSchemaValidator + +if TYPE_CHECKING: + from inspect import Signature + from pathlib import Path + + from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator + + from ._internal._namespace_utils import MappingNamespace + from ._internal._utils import AbstractSetIntStr, MappingIntStrAny + from .deprecated.parse import Protocol as DeprecatedParseProtocol + from .fields import ComputedFieldInfo, FieldInfo, ModelPrivateAttr + + +__all__ = 'BaseModel', 'create_model' + +# Keep these type aliases available at runtime: +TupleGenerator: TypeAlias = Generator[tuple[str, Any], None, None] +# NOTE: In reality, `bool` should be replaced by `Literal[True]` but mypy fails to correctly apply bidirectional +# type inference (e.g. when using `{'a': {'b': True}}`): +# NOTE: Keep this type alias in sync with the stub definition in `pydantic-core`: +IncEx: TypeAlias = Union[set[int], set[str], Mapping[int, Union['IncEx', bool]], Mapping[str, Union['IncEx', bool]]] + +_object_setattr = _model_construction.object_setattr + + +def _check_frozen(model_cls: type[BaseModel], name: str, value: Any) -> None: + if model_cls.model_config.get('frozen'): + error_type = 'frozen_instance' + elif getattr(model_cls.__pydantic_fields__.get(name), 'frozen', False): + error_type = 'frozen_field' + else: + return + + raise ValidationError.from_exception_data( + model_cls.__name__, [{'type': error_type, 'loc': (name,), 'input': value}] + ) + + +def _model_field_setattr_handler(model: BaseModel, name: str, val: Any) -> None: + model.__dict__[name] = val + model.__pydantic_fields_set__.add(name) + + +def _private_setattr_handler(model: BaseModel, name: str, val: Any) -> None: + if getattr(model, '__pydantic_private__', None) is None: + # While the attribute should be present at this point, this may not be the case if + # users do unusual stuff with `model_post_init()` (which is where the `__pydantic_private__` + # is initialized, by wrapping the user-defined `model_post_init()`), e.g. if they mock + # the `model_post_init()` call. Ideally we should find a better way to init private attrs. + object.__setattr__(model, '__pydantic_private__', {}) + model.__pydantic_private__[name] = val # pyright: ignore[reportOptionalSubscript] + + +_SIMPLE_SETATTR_HANDLERS: Mapping[str, Callable[[BaseModel, str, Any], None]] = { + 'model_field': _model_field_setattr_handler, + 'validate_assignment': lambda model, name, val: model.__pydantic_validator__.validate_assignment(model, name, val), # pyright: ignore[reportAssignmentType] + 'private': _private_setattr_handler, + 'cached_property': lambda model, name, val: model.__dict__.__setitem__(name, val), + 'extra_known': lambda model, name, val: _object_setattr(model, name, val), +} + + +class BaseModel(metaclass=_model_construction.ModelMetaclass): + """!!! abstract "Usage Documentation" + [Models](../concepts/models.md) + + A base class for creating Pydantic models. + + Attributes: + __class_vars__: The names of the class variables defined on the model. + __private_attributes__: Metadata about the private attributes of the model. + __signature__: The synthesized `__init__` [`Signature`][inspect.Signature] of the model. + + __pydantic_complete__: Whether model building is completed, or if there are still undefined fields. + __pydantic_core_schema__: The core schema of the model. + __pydantic_custom_init__: Whether the model has a custom `__init__` function. + __pydantic_decorators__: Metadata containing the decorators defined on the model. + This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1. + __pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to + __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these. + __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models. + __pydantic_post_init__: The name of the post-init method for the model, if defined. + __pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel]. + __pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model. + __pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model. + + __pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects. + __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects. + + __pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] + is set to `'allow'`. + __pydantic_fields_set__: The names of fields explicitly set during instantiation. + __pydantic_private__: Values of private attributes set on the model instance. + """ + + # Note: Many of the below class vars are defined in the metaclass, but we define them here for type checking purposes. + + model_config: ClassVar[ConfigDict] = ConfigDict() + """ + Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict]. + """ + + __class_vars__: ClassVar[set[str]] + """The names of the class variables defined on the model.""" + + __private_attributes__: ClassVar[Dict[str, ModelPrivateAttr]] # noqa: UP006 + """Metadata about the private attributes of the model.""" + + __signature__: ClassVar[Signature] + """The synthesized `__init__` [`Signature`][inspect.Signature] of the model.""" + + __pydantic_complete__: ClassVar[bool] = False + """Whether model building is completed, or if there are still undefined fields.""" + + __pydantic_core_schema__: ClassVar[CoreSchema] + """The core schema of the model.""" + + __pydantic_custom_init__: ClassVar[bool] + """Whether the model has a custom `__init__` method.""" + + # Must be set for `GenerateSchema.model_schema` to work for a plain `BaseModel` annotation. + __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos] = _decorators.DecoratorInfos() + """Metadata containing the decorators defined on the model. + This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.""" + + __pydantic_generic_metadata__: ClassVar[_generics.PydanticGenericMetadata] + """Metadata for generic models; contains data used for a similar purpose to + __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.""" + + __pydantic_parent_namespace__: ClassVar[Dict[str, Any] | None] = None # noqa: UP006 + """Parent namespace of the model, used for automatic rebuilding of models.""" + + __pydantic_post_init__: ClassVar[None | Literal['model_post_init']] + """The name of the post-init method for the model, if defined.""" + + __pydantic_root_model__: ClassVar[bool] = False + """Whether the model is a [`RootModel`][pydantic.root_model.RootModel].""" + + __pydantic_serializer__: ClassVar[SchemaSerializer] + """The `pydantic-core` `SchemaSerializer` used to dump instances of the model.""" + + __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] + """The `pydantic-core` `SchemaValidator` used to validate instances of the model.""" + + __pydantic_fields__: ClassVar[Dict[str, FieldInfo]] # noqa: UP006 + """A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects. + This replaces `Model.__fields__` from Pydantic V1. + """ + + __pydantic_setattr_handlers__: ClassVar[Dict[str, Callable[[BaseModel, str, Any], None]]] # noqa: UP006 + """`__setattr__` handlers. Memoizing the handlers leads to a dramatic performance improvement in `__setattr__`""" + + __pydantic_computed_fields__: ClassVar[Dict[str, ComputedFieldInfo]] # noqa: UP006 + """A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.""" + + __pydantic_extra__: Dict[str, Any] | None = _model_construction.NoInitField(init=False) # noqa: UP006 + """A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] is set to `'allow'`.""" + + __pydantic_fields_set__: set[str] = _model_construction.NoInitField(init=False) + """The names of fields explicitly set during instantiation.""" + + __pydantic_private__: Dict[str, Any] | None = _model_construction.NoInitField(init=False) # noqa: UP006 + """Values of private attributes set on the model instance.""" + + if not TYPE_CHECKING: + # Prevent `BaseModel` from being instantiated directly + # (defined in an `if not TYPE_CHECKING` block for clarity and to avoid type checking errors): + __pydantic_core_schema__ = _mock_val_ser.MockCoreSchema( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + code='base-model-instantiated', + ) + __pydantic_validator__ = _mock_val_ser.MockValSer( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + val_or_ser='validator', + code='base-model-instantiated', + ) + __pydantic_serializer__ = _mock_val_ser.MockValSer( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + val_or_ser='serializer', + code='base-model-instantiated', + ) + + __slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__' + + def __init__(self, /, **data: Any) -> None: + """Create a new model by parsing and validating input data from keyword arguments. + + Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be + validated to form a valid model. + + `self` is explicitly positional-only to allow `self` as a field name. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self) + if self is not validated_self: + warnings.warn( + 'A custom validator is returning a value other than `self`.\n' + "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n" + 'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.', + stacklevel=2, + ) + + # The following line sets a flag that we use to determine when `__init__` gets overridden by the user + __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] + + @_utils.deprecated_instance_property + @classmethod + def model_fields(cls) -> dict[str, FieldInfo]: + """A mapping of field names to their respective [`FieldInfo`][pydantic.fields.FieldInfo] instances. + + !!! warning + Accessing this attribute from a model instance is deprecated, and will not work in Pydantic V3. + Instead, you should access this attribute from the model class. + """ + return getattr(cls, '__pydantic_fields__', {}) + + @_utils.deprecated_instance_property + @classmethod + def model_computed_fields(cls) -> dict[str, ComputedFieldInfo]: + """A mapping of computed field names to their respective [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] instances. + + !!! warning + Accessing this attribute from a model instance is deprecated, and will not work in Pydantic V3. + Instead, you should access this attribute from the model class. + """ + return getattr(cls, '__pydantic_computed_fields__', {}) + + @property + def model_extra(self) -> dict[str, Any] | None: + """Get extra fields set during validation. + + Returns: + A dictionary of extra fields, or `None` if `config.extra` is not set to `"allow"`. + """ + return self.__pydantic_extra__ + + @property + def model_fields_set(self) -> set[str]: + """Returns the set of fields that have been explicitly set on this model instance. + + Returns: + A set of strings representing the fields that have been set, + i.e. that were not filled from defaults. + """ + return self.__pydantic_fields_set__ + + @classmethod + def model_construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self: # noqa: C901 + """Creates a new instance of the `Model` class with validated data. + + Creates a new model setting `__dict__` and `__pydantic_fields_set__` from trusted or pre-validated data. + Default values are respected, but no other validation is performed. + + !!! note + `model_construct()` generally respects the `model_config.extra` setting on the provided model. + That is, if `model_config.extra == 'allow'`, then all extra passed values are added to the model instance's `__dict__` + and `__pydantic_extra__` fields. If `model_config.extra == 'ignore'` (the default), then all extra passed values are ignored. + Because no validation is performed with a call to `model_construct()`, having `model_config.extra == 'forbid'` does not result in + an error if extra values are passed, but they will be ignored. + + Args: + _fields_set: A set of field names that were originally explicitly set during instantiation. If provided, + this is directly used for the [`model_fields_set`][pydantic.BaseModel.model_fields_set] attribute. + Otherwise, the field names from the `values` argument will be used. + values: Trusted or pre-validated data dictionary. + + Returns: + A new instance of the `Model` class with validated data. + """ + m = cls.__new__(cls) + fields_values: dict[str, Any] = {} + fields_set = set() + + for name, field in cls.__pydantic_fields__.items(): + if field.alias is not None and field.alias in values: + fields_values[name] = values.pop(field.alias) + fields_set.add(name) + + if (name not in fields_set) and (field.validation_alias is not None): + validation_aliases: list[str | AliasPath] = ( + field.validation_alias.choices + if isinstance(field.validation_alias, AliasChoices) + else [field.validation_alias] + ) + + for alias in validation_aliases: + if isinstance(alias, str) and alias in values: + fields_values[name] = values.pop(alias) + fields_set.add(name) + break + elif isinstance(alias, AliasPath): + value = alias.search_dict_for_path(values) + if value is not PydanticUndefined: + fields_values[name] = value + fields_set.add(name) + break + + if name not in fields_set: + if name in values: + fields_values[name] = values.pop(name) + fields_set.add(name) + elif not field.is_required(): + fields_values[name] = field.get_default(call_default_factory=True, validated_data=fields_values) + if _fields_set is None: + _fields_set = fields_set + + _extra: dict[str, Any] | None = values if cls.model_config.get('extra') == 'allow' else None + _object_setattr(m, '__dict__', fields_values) + _object_setattr(m, '__pydantic_fields_set__', _fields_set) + if not cls.__pydantic_root_model__: + _object_setattr(m, '__pydantic_extra__', _extra) + + if cls.__pydantic_post_init__: + m.model_post_init(None) + # update private attributes with values set + if hasattr(m, '__pydantic_private__') and m.__pydantic_private__ is not None: + for k, v in values.items(): + if k in m.__private_attributes__: + m.__pydantic_private__[k] = v + + elif not cls.__pydantic_root_model__: + # Note: if there are any private attributes, cls.__pydantic_post_init__ would exist + # Since it doesn't, that means that `__pydantic_private__` should be set to None + _object_setattr(m, '__pydantic_private__', None) + + return m + + def model_copy(self, *, update: Mapping[str, Any] | None = None, deep: bool = False) -> Self: + """!!! abstract "Usage Documentation" + [`model_copy`](../concepts/models.md#model-copy) + + Returns a copy of the model. + + !!! note + The underlying instance's [`__dict__`][object.__dict__] attribute is copied. This + might have unexpected side effects if you store anything in it, on top of the model + fields (e.g. the value of [cached properties][functools.cached_property]). + + Args: + update: Values to change/add in the new model. Note: the data is not validated + before creating the new model. You should trust this data. + deep: Set to `True` to make a deep copy of the model. + + Returns: + New model instance. + """ + copied = self.__deepcopy__() if deep else self.__copy__() + if update: + if self.model_config.get('extra') == 'allow': + for k, v in update.items(): + if k in self.__pydantic_fields__: + copied.__dict__[k] = v + else: + if copied.__pydantic_extra__ is None: + copied.__pydantic_extra__ = {} + copied.__pydantic_extra__[k] = v + else: + copied.__dict__.update(update) + copied.__pydantic_fields_set__.update(update.keys()) + return copied + + def model_dump( + self, + *, + mode: Literal['json', 'python'] | str = 'python', + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> dict[str, Any]: + """!!! abstract "Usage Documentation" + [`model_dump`](../concepts/serialization.md#python-mode) + + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + Args: + mode: The mode in which `to_python` should run. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. + by_alias: Whether to use the field's alias in the dictionary key if defined. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + + Returns: + A dictionary representation of the model. + """ + return self.__pydantic_serializer__.to_python( + self, + mode=mode, + by_alias=by_alias, + include=include, + exclude=exclude, + context=context, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + ) + + def model_dump_json( + self, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> str: + """!!! abstract "Usage Documentation" + [`model_dump_json`](../concepts/serialization.md#json-mode) + + Generates a JSON representation of the model using Pydantic's `to_json` method. + + Args: + indent: Indentation to use in the JSON output. If None is passed, the output will be compact. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: Field(s) to include in the JSON output. + exclude: Field(s) to exclude from the JSON output. + context: Additional context to pass to the serializer. + by_alias: Whether to serialize using field aliases. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + + Returns: + A JSON string representation of the model. + """ + return self.__pydantic_serializer__.to_json( + self, + indent=indent, + ensure_ascii=ensure_ascii, + include=include, + exclude=exclude, + context=context, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + ).decode() + + @classmethod + def model_json_schema( + cls, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', + *, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + ) -> dict[str, Any]: + """Generates a JSON schema for a model class. + + Args: + by_alias: Whether to use attribute aliases or not. + ref_template: The reference template. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: To override the logic used to generate the JSON schema, as a subclass of + `GenerateJsonSchema` with your desired modifications + mode: The mode in which to generate the schema. + + Returns: + The JSON schema for the given model class. + """ + return model_json_schema( + cls, + by_alias=by_alias, + ref_template=ref_template, + union_format=union_format, + schema_generator=schema_generator, + mode=mode, + ) + + @classmethod + def model_parametrized_name(cls, params: tuple[type[Any], ...]) -> str: + """Compute the class name for parametrizations of generic classes. + + This method can be overridden to achieve a custom naming scheme for generic BaseModels. + + Args: + params: Tuple of types of the class. Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + + Returns: + String representing the new class where `params` are passed to `cls` as type variables. + + Raises: + TypeError: Raised when trying to generate concrete names for non-generic models. + """ + if not issubclass(cls, Generic): + raise TypeError('Concrete names should only be generated for generic models.') + + # Any strings received should represent forward references, so we handle them specially below. + # If we eventually move toward wrapping them in a ForwardRef in __class_getitem__ in the future, + # we may be able to remove this special case. + param_names = [param if isinstance(param, str) else _repr.display_as_type(param) for param in params] + params_component = ', '.join(param_names) + return f'{cls.__name__}[{params_component}]' + + def model_post_init(self, context: Any, /) -> None: + """Override this method to perform additional initialization after `__init__` and `model_construct`. + This is useful if you want to do some validation that requires the entire model to be initialized. + """ + + @classmethod + def model_rebuild( + cls, + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: MappingNamespace | None = None, + ) -> bool | None: + """Try to rebuild the pydantic-core schema for the model. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + Args: + force: Whether to force the rebuilding of the model schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: The depth level of the parent namespace, defaults to 2. + _types_namespace: The types namespace, defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + already_complete = cls.__pydantic_complete__ + if already_complete and not force: + return None + + cls.__pydantic_complete__ = False + + for attr in ('__pydantic_core_schema__', '__pydantic_validator__', '__pydantic_serializer__'): + if attr in cls.__dict__ and not isinstance(getattr(cls, attr), _mock_val_ser.MockValSer): + # Deleting the validator/serializer is necessary as otherwise they can get reused in + # pydantic-core. We do so only if they aren't mock instances, otherwise — as `model_rebuild()` + # isn't thread-safe — concurrent model instantiations can lead to the parent validator being used. + # Same applies for the core schema that can be reused in schema generation. + delattr(cls, attr) + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + parent_ns = _model_construction.unpack_lenient_weakvaluedict(cls.__pydantic_parent_namespace__) or {} + + ns_resolver = _namespace_utils.NsResolver( + parent_namespace={**rebuild_ns, **parent_ns}, + ) + + return _model_construction.complete_model_class( + cls, + _config.ConfigWrapper(cls.model_config, check=False), + ns_resolver, + raise_errors=raise_errors, + # If the model was already complete, we don't need to call the hook again. + call_on_complete_hook=not already_complete, + ) + + @classmethod + def model_validate( + cls, + obj: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """Validate a pydantic model instance. + + Args: + obj: The object to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + from_attributes: Whether to extract data from object attributes. + context: Additional context to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If the object could not be validated. + + Returns: + The validated model instance. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_python( + obj, + strict=strict, + extra=extra, + from_attributes=from_attributes, + context=context, + by_alias=by_alias, + by_name=by_name, + ) + + @classmethod + def model_validate_json( + cls, + json_data: str | bytes | bytearray, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """!!! abstract "Usage Documentation" + [JSON Parsing](../concepts/json.md#json-parsing) + + Validate the given JSON data against the Pydantic model. + + Args: + json_data: The JSON data to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Extra variables to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated Pydantic model. + + Raises: + ValidationError: If `json_data` is not a JSON string or the object could not be validated. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_json( + json_data, strict=strict, extra=extra, context=context, by_alias=by_alias, by_name=by_name + ) + + @classmethod + def model_validate_strings( + cls, + obj: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """Validate the given object with string data against the Pydantic model. + + Args: + obj: The object containing string data to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Extra variables to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated Pydantic model. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_strings( + obj, strict=strict, extra=extra, context=context, by_alias=by_alias, by_name=by_name + ) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[BaseModel], handler: GetCoreSchemaHandler, /) -> CoreSchema: + # This warning is only emitted when calling `super().__get_pydantic_core_schema__` from a model subclass. + # In the generate schema logic, this method (`BaseModel.__get_pydantic_core_schema__`) is special cased to + # *not* be called if not overridden. + warnings.warn( + 'The `__get_pydantic_core_schema__` method of the `BaseModel` class is deprecated. If you are calling ' + '`super().__get_pydantic_core_schema__` when overriding the method on a Pydantic model, consider using ' + '`handler(source)` instead. However, note that overriding this method on models can lead to unexpected ' + 'side effects.', + PydanticDeprecatedSince211, + stacklevel=2, + ) + # Logic copied over from `GenerateSchema._model_schema`: + schema = cls.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, _mock_val_ser.MockCoreSchema): + return cls.__pydantic_core_schema__ + + return handler(source) + + @classmethod + def __get_pydantic_json_schema__( + cls, + core_schema: CoreSchema, + handler: GetJsonSchemaHandler, + /, + ) -> JsonSchemaValue: + """Hook into generating the model's JSON schema. + + Args: + core_schema: A `pydantic-core` CoreSchema. + You can ignore this argument and call the handler with a new CoreSchema, + wrap this CoreSchema (`{'type': 'nullable', 'schema': current_schema}`), + or just call the handler with the original schema. + handler: Call into Pydantic's internal JSON schema generation. + This will raise a `pydantic.errors.PydanticInvalidForJsonSchema` if JSON schema + generation fails. + Since this gets called by `BaseModel.model_json_schema` you can override the + `schema_generator` argument to that function to change JSON schema generation globally + for a type. + + Returns: + A JSON schema, as a Python object. + """ + return handler(core_schema) + + @classmethod + def __pydantic_init_subclass__(cls, **kwargs: Any) -> None: + """This is intended to behave just like `__init_subclass__`, but is called by `ModelMetaclass` + only after basic class initialization is complete. In particular, attributes like `model_fields` will + be present when this is called, but forward annotations are not guaranteed to be resolved yet, + meaning that creating an instance of the class may fail. + + This is necessary because `__init_subclass__` will always be called by `type.__new__`, + and it would require a prohibitively large refactor to the `ModelMetaclass` to ensure that + `type.__new__` was called in such a manner that the class would already be sufficiently initialized. + + This will receive the same `kwargs` that would be passed to the standard `__init_subclass__`, namely, + any kwargs passed to the class definition that aren't used internally by Pydantic. + + Args: + **kwargs: Any keyword arguments passed to the class definition that aren't used internally + by Pydantic. + + Note: + You may want to override [`__pydantic_on_complete__()`][pydantic.main.BaseModel.__pydantic_on_complete__] + instead, which is called once the class and its fields are fully initialized and ready for validation. + """ + + @classmethod + def __pydantic_on_complete__(cls) -> None: + """This is called once the class and its fields are fully initialized and ready to be used. + + This typically happens when the class is created (just before + [`__pydantic_init_subclass__()`][pydantic.main.BaseModel.__pydantic_init_subclass__] is called on the superclass), + except when forward annotations are used that could not immediately be resolved. + In that case, it will be called later, when the model is rebuilt automatically or explicitly using + [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild]. + """ + + def __class_getitem__( + cls, typevar_values: type[Any] | tuple[type[Any], ...] + ) -> type[BaseModel] | _forward_ref.PydanticRecursiveRef: + cached = _generics.get_cached_generic_type_early(cls, typevar_values) + if cached is not None: + return cached + + if cls is BaseModel: + raise TypeError('Type parameters should be placed on typing.Generic, not BaseModel') + if not hasattr(cls, '__parameters__'): + raise TypeError(f'{cls} cannot be parametrized because it does not inherit from typing.Generic') + if not cls.__pydantic_generic_metadata__['parameters'] and Generic not in cls.__bases__: + raise TypeError(f'{cls} is not a generic class') + + if not isinstance(typevar_values, tuple): + typevar_values = (typevar_values,) + + # For a model `class Model[T, U, V = int](BaseModel): ...` parametrized with `(str, bool)`, + # this gives us `{T: str, U: bool, V: int}`: + typevars_map = _generics.map_generic_model_arguments(cls, typevar_values) + # We also update the provided args to use defaults values (`(str, bool)` becomes `(str, bool, int)`): + typevar_values = tuple(v for v in typevars_map.values()) + + if _utils.all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map: + submodel = cls # if arguments are equal to parameters it's the same object + _generics.set_cached_generic_type(cls, typevar_values, submodel) + else: + parent_args = cls.__pydantic_generic_metadata__['args'] + if not parent_args: + args = typevar_values + else: + args = tuple(_generics.replace_types(arg, typevars_map) for arg in parent_args) + + origin = cls.__pydantic_generic_metadata__['origin'] or cls + model_name = origin.model_parametrized_name(args) + params = tuple( + dict.fromkeys(_generics.iter_contained_typevars(typevars_map.values())) + ) # use dict as ordered set + + with _generics.generic_recursion_self_type(origin, args) as maybe_self_type: + cached = _generics.get_cached_generic_type_late(cls, typevar_values, origin, args) + if cached is not None: + return cached + + if maybe_self_type is not None: + return maybe_self_type + + # Attempt to rebuild the origin in case new types have been defined + try: + # depth 2 gets you above this __class_getitem__ call. + # Note that we explicitly provide the parent ns, otherwise + # `model_rebuild` will use the parent ns no matter if it is the ns of a module. + # We don't want this here, as this has unexpected effects when a model + # is being parametrized during a forward annotation evaluation. + parent_ns = _typing_extra.parent_frame_namespace(parent_depth=2) or {} + origin.model_rebuild(_types_namespace=parent_ns) + except PydanticUndefinedAnnotation: + # It's okay if it fails, it just means there are still undefined types + # that could be evaluated later. + pass + + submodel = _generics.create_generic_submodel(model_name, origin, args, params) + + _generics.set_cached_generic_type(cls, typevar_values, submodel, origin, args) + + return submodel + + def __copy__(self) -> Self: + """Returns a shallow copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', copy(self.__dict__)) + _object_setattr(m, '__pydantic_extra__', copy(self.__pydantic_extra__)) + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + + if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None: + _object_setattr(m, '__pydantic_private__', None) + else: + _object_setattr( + m, + '__pydantic_private__', + {k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined}, + ) + + return m + + def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: + """Returns a deep copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) + _object_setattr(m, '__pydantic_extra__', deepcopy(self.__pydantic_extra__, memo=memo)) + # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str], + # and attempting a deepcopy would be marginally slower. + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + + if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None: + _object_setattr(m, '__pydantic_private__', None) + else: + _object_setattr( + m, + '__pydantic_private__', + deepcopy({k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined}, memo=memo), + ) + + return m + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + # The same goes for __setattr__ and __delattr__, see: https://github.com/pydantic/pydantic/issues/8643 + + def __getattr__(self, item: str) -> Any: + private_attributes = object.__getattribute__(self, '__private_attributes__') + if item in private_attributes: + attribute = private_attributes[item] + if hasattr(attribute, '__get__'): + return attribute.__get__(self, type(self)) # type: ignore + + try: + # Note: self.__pydantic_private__ cannot be None if self.__private_attributes__ has items + return self.__pydantic_private__[item] # type: ignore + except KeyError as exc: + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') from exc + else: + # `__pydantic_extra__` can fail to be set if the model is not yet fully initialized. + # See `BaseModel.__repr_args__` for more details + try: + pydantic_extra = object.__getattribute__(self, '__pydantic_extra__') + except AttributeError: + pydantic_extra = None + + if pydantic_extra and item in pydantic_extra: + return pydantic_extra[item] + else: + if hasattr(self.__class__, item): + return super().__getattribute__(item) # Raises AttributeError if appropriate + else: + # this is the current error + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + def __setattr__(self, name: str, value: Any) -> None: + if (setattr_handler := self.__pydantic_setattr_handlers__.get(name)) is not None: + setattr_handler(self, name, value) + # if None is returned from _setattr_handler, the attribute was set directly + elif (setattr_handler := self._setattr_handler(name, value)) is not None: + setattr_handler(self, name, value) # call here to not memo on possibly unknown fields + self.__pydantic_setattr_handlers__[name] = setattr_handler # memoize the handler for faster access + + def _setattr_handler(self, name: str, value: Any) -> Callable[[BaseModel, str, Any], None] | None: + """Get a handler for setting an attribute on the model instance. + + Returns: + A handler for setting an attribute on the model instance. Used for memoization of the handler. + Memoizing the handlers leads to a dramatic performance improvement in `__setattr__` + Returns `None` when memoization is not safe, then the attribute is set directly. + """ + cls = self.__class__ + if name in cls.__class_vars__: + raise AttributeError( + f'{name!r} is a ClassVar of `{cls.__name__}` and cannot be set on an instance. ' + f'If you want to set a value on the class, use `{cls.__name__}.{name} = value`.' + ) + elif not _fields.is_valid_field_name(name): + if (attribute := cls.__private_attributes__.get(name)) is not None: + if hasattr(attribute, '__set__'): + return lambda model, _name, val: attribute.__set__(model, val) + else: + return _SIMPLE_SETATTR_HANDLERS['private'] + else: + _object_setattr(self, name, value) + return None # Can not return memoized handler with possibly freeform attr names + + attr = getattr(cls, name, None) + # NOTE: We currently special case properties and `cached_property`, but we might need + # to generalize this to all data/non-data descriptors at some point. For non-data descriptors + # (such as `cached_property`), it isn't obvious though. `cached_property` caches the value + # to the instance's `__dict__`, but other non-data descriptors might do things differently. + if isinstance(attr, cached_property): + return _SIMPLE_SETATTR_HANDLERS['cached_property'] + + _check_frozen(cls, name, value) + + # We allow properties to be set only on non frozen models for now (to match dataclasses). + # This can be changed if it ever gets requested. + if isinstance(attr, property): + return lambda model, _name, val: attr.__set__(model, val) + elif cls.model_config.get('validate_assignment'): + return _SIMPLE_SETATTR_HANDLERS['validate_assignment'] + elif name not in cls.__pydantic_fields__: + if cls.model_config.get('extra') != 'allow': + # TODO - matching error + raise ValueError(f'"{cls.__name__}" object has no field "{name}"') + elif attr is None: + # attribute does not exist, so put it in extra + self.__pydantic_extra__[name] = value + return None # Can not return memoized handler with possibly freeform attr names + else: + # attribute _does_ exist, and was not in extra, so update it + return _SIMPLE_SETATTR_HANDLERS['extra_known'] + else: + return _SIMPLE_SETATTR_HANDLERS['model_field'] + + def __delattr__(self, item: str) -> Any: + cls = self.__class__ + + if item in self.__private_attributes__: + attribute = self.__private_attributes__[item] + if hasattr(attribute, '__delete__'): + attribute.__delete__(self) # type: ignore + return + + try: + # Note: self.__pydantic_private__ cannot be None if self.__private_attributes__ has items + del self.__pydantic_private__[item] # type: ignore + return + except KeyError as exc: + raise AttributeError(f'{cls.__name__!r} object has no attribute {item!r}') from exc + + # Allow cached properties to be deleted (even if the class is frozen): + attr = getattr(cls, item, None) + if isinstance(attr, cached_property): + return object.__delattr__(self, item) + + _check_frozen(cls, name=item, value=None) + + if item in self.__pydantic_fields__: + object.__delattr__(self, item) + elif self.__pydantic_extra__ is not None and item in self.__pydantic_extra__: + del self.__pydantic_extra__[item] + else: + try: + object.__delattr__(self, item) + except AttributeError: + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + # Because we make use of `@dataclass_transform()`, `__replace__` is already synthesized by + # type checkers, so we define the implementation in this `if not TYPE_CHECKING:` block: + def __replace__(self, **changes: Any) -> Self: + return self.model_copy(update=changes) + + def __getstate__(self) -> dict[Any, Any]: + private = self.__pydantic_private__ + if private: + private = {k: v for k, v in private.items() if v is not PydanticUndefined} + return { + '__dict__': self.__dict__, + '__pydantic_extra__': self.__pydantic_extra__, + '__pydantic_fields_set__': self.__pydantic_fields_set__, + '__pydantic_private__': private, + } + + def __setstate__(self, state: dict[Any, Any]) -> None: + _object_setattr(self, '__pydantic_fields_set__', state.get('__pydantic_fields_set__', {})) + _object_setattr(self, '__pydantic_extra__', state.get('__pydantic_extra__', {})) + _object_setattr(self, '__pydantic_private__', state.get('__pydantic_private__', {})) + _object_setattr(self, '__dict__', state.get('__dict__', {})) + + if not TYPE_CHECKING: + + def __eq__(self, other: Any) -> bool: + if isinstance(other, BaseModel): + # When comparing instances of generic types for equality, as long as all field values are equal, + # only require their generic origin types to be equal, rather than exact type equality. + # This prevents headaches like MyGeneric(x=1) != MyGeneric[Any](x=1). + self_type = self.__pydantic_generic_metadata__['origin'] or self.__class__ + other_type = other.__pydantic_generic_metadata__['origin'] or other.__class__ + + # Perform common checks first + if not ( + self_type == other_type + and getattr(self, '__pydantic_private__', None) == getattr(other, '__pydantic_private__', None) + and self.__pydantic_extra__ == other.__pydantic_extra__ + ): + return False + + # We only want to compare pydantic fields but ignoring fields is costly. + # We'll perform a fast check first, and fallback only when needed + # See GH-7444 and GH-7825 for rationale and a performance benchmark + + # First, do the fast (and sometimes faulty) __dict__ comparison + if self.__dict__ == other.__dict__: + # If the check above passes, then pydantic fields are equal, we can return early + return True + + # We don't want to trigger unnecessary costly filtering of __dict__ on all unequal objects, so we return + # early if there are no keys to ignore (we would just return False later on anyway) + model_fields = type(self).__pydantic_fields__.keys() + if self.__dict__.keys() <= model_fields and other.__dict__.keys() <= model_fields: + return False + + # If we reach here, there are non-pydantic-fields keys, mapped to unequal values, that we need to ignore + # Resort to costly filtering of the __dict__ objects + # We use operator.itemgetter because it is much faster than dict comprehensions + # NOTE: Contrary to standard python class and instances, when the Model class has a default value for an + # attribute and the model instance doesn't have a corresponding attribute, accessing the missing attribute + # raises an error in BaseModel.__getattr__ instead of returning the class attribute + # So we can use operator.itemgetter() instead of operator.attrgetter() + getter = operator.itemgetter(*model_fields) if model_fields else lambda _: _utils._SENTINEL + try: + return getter(self.__dict__) == getter(other.__dict__) + except KeyError: + # In rare cases (such as when using the deprecated BaseModel.copy() method), + # the __dict__ may not contain all model fields, which is how we can get here. + # getter(self.__dict__) is much faster than any 'safe' method that accounts + # for missing keys, and wrapping it in a `try` doesn't slow things down much + # in the common case. + self_fields_proxy = _utils.SafeGetItemProxy(self.__dict__) + other_fields_proxy = _utils.SafeGetItemProxy(other.__dict__) + return getter(self_fields_proxy) == getter(other_fields_proxy) + + # other instance is not a BaseModel + else: + return NotImplemented # delegate to the other item in the comparison + + if TYPE_CHECKING: + # We put `__init_subclass__` in a TYPE_CHECKING block because, even though we want the type-checking benefits + # described in the signature of `__init_subclass__` below, we don't want to modify the default behavior of + # subclass initialization. + + def __init_subclass__(cls, **kwargs: Unpack[ConfigDict]): + """This signature is included purely to help type-checkers check arguments to class declaration, which + provides a way to conveniently set model_config key/value pairs. + + ```python + from pydantic import BaseModel + + class MyModel(BaseModel, extra='allow'): ... + ``` + + However, this may be deceiving, since the _actual_ calls to `__init_subclass__` will not receive any + of the config arguments, and will only receive any keyword arguments passed during class initialization + that are _not_ expected keys in ConfigDict. (This is due to the way `ModelMetaclass.__new__` works.) + + Args: + **kwargs: Keyword arguments passed to the class definition, which set model_config + + Note: + You may want to override `__pydantic_init_subclass__` instead, which behaves similarly but is called + *after* the class is fully initialized. + """ + + def __iter__(self) -> TupleGenerator: + """So `dict(model)` works.""" + yield from [(k, v) for (k, v) in self.__dict__.items() if not k.startswith('_')] + extra = self.__pydantic_extra__ + if extra: + yield from extra.items() + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + def __repr_args__(self) -> _repr.ReprArgs: + # Eagerly create the repr of computed fields, as this may trigger access of cached properties and as such + # modify the instance's `__dict__`. If we don't do it now, it could happen when iterating over the `__dict__` + # below if the instance happens to be referenced in a field, and would modify the `__dict__` size *during* iteration. + computed_fields_repr_args = [ + (k, getattr(self, k)) for k, v in self.__pydantic_computed_fields__.items() if v.repr + ] + + for k, v in self.__dict__.items(): + field = self.__pydantic_fields__.get(k) + if field and field.repr: + if v is not self: + yield k, v + else: + yield k, self.__repr_recursion__(v) + # `__pydantic_extra__` can fail to be set if the model is not yet fully initialized. + # This can happen if a `ValidationError` is raised during initialization and the instance's + # repr is generated as part of the exception handling. Therefore, we use `getattr` here + # with a fallback, even though the type hints indicate the attribute will always be present. + try: + pydantic_extra = object.__getattribute__(self, '__pydantic_extra__') + except AttributeError: + pydantic_extra = None + + if pydantic_extra is not None: + yield from ((k, v) for k, v in pydantic_extra.items()) + yield from computed_fields_repr_args + + # take logic from `_repr.Representation` without the side effects of inheritance, see #5740 + __repr_name__ = _repr.Representation.__repr_name__ + __repr_recursion__ = _repr.Representation.__repr_recursion__ + __repr_str__ = _repr.Representation.__repr_str__ + __pretty__ = _repr.Representation.__pretty__ + __rich_repr__ = _repr.Representation.__rich_repr__ + + def __str__(self) -> str: + return self.__repr_str__(' ') + + # ##### Deprecated methods from v1 ##### + @property + @typing_extensions.deprecated( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', category=None + ) + def __fields__(self) -> dict[str, FieldInfo]: + warnings.warn( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return getattr(type(self), '__pydantic_fields__', {}) + + @property + @typing_extensions.deprecated( + 'The `__fields_set__` attribute is deprecated, use `model_fields_set` instead.', + category=None, + ) + def __fields_set__(self) -> set[str]: + warnings.warn( + 'The `__fields_set__` attribute is deprecated, use `model_fields_set` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return self.__pydantic_fields_set__ + + @typing_extensions.deprecated('The `dict` method is deprecated; use `model_dump` instead.', category=None) + def dict( # noqa: D102 + self, + *, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> Dict[str, Any]: # noqa UP006 + warnings.warn( + 'The `dict` method is deprecated; use `model_dump` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return self.model_dump( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + @typing_extensions.deprecated('The `json` method is deprecated; use `model_dump_json` instead.', category=None) + def json( # noqa: D102 + self, + *, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + encoder: Callable[[Any], Any] | None = PydanticUndefined, # type: ignore[assignment] + models_as_dict: bool = PydanticUndefined, # type: ignore[assignment] + **dumps_kwargs: Any, + ) -> str: + warnings.warn( + 'The `json` method is deprecated; use `model_dump_json` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if encoder is not PydanticUndefined: + raise TypeError('The `encoder` argument is no longer supported; use field serializers instead.') + if models_as_dict is not PydanticUndefined: + raise TypeError('The `models_as_dict` argument is no longer supported; use a model serializer instead.') + if dumps_kwargs: + raise TypeError('`dumps_kwargs` keyword arguments are no longer supported.') + return self.model_dump_json( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + @classmethod + @typing_extensions.deprecated('The `parse_obj` method is deprecated; use `model_validate` instead.', category=None) + def parse_obj(cls, obj: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `parse_obj` method is deprecated; use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `parse_raw` method is deprecated; if your data is JSON use `model_validate_json`, ' + 'otherwise load the data then use `model_validate` instead.', + category=None, + ) + def parse_raw( # noqa: D102 + cls, + b: str | bytes, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: DeprecatedParseProtocol | None = None, + allow_pickle: bool = False, + ) -> Self: # pragma: no cover + warnings.warn( + 'The `parse_raw` method is deprecated; if your data is JSON use `model_validate_json`, ' + 'otherwise load the data then use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import parse + + try: + obj = parse.load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + except (ValueError, TypeError) as exc: + import json + + # try to match V1 + if isinstance(exc, UnicodeDecodeError): + type_str = 'value_error.unicodedecode' + elif isinstance(exc, json.JSONDecodeError): + type_str = 'value_error.jsondecode' + elif isinstance(exc, ValueError): + type_str = 'value_error' + else: + type_str = 'type_error' + + # ctx is missing here, but since we've added `input` to the error, we're not pretending it's the same + error: pydantic_core.InitErrorDetails = { + # The type: ignore on the next line is to ignore the requirement of LiteralString + 'type': pydantic_core.PydanticCustomError(type_str, str(exc)), # type: ignore + 'loc': ('__root__',), + 'input': b, + } + raise pydantic_core.ValidationError.from_exception_data(cls.__name__, [error]) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `parse_file` method is deprecated; load the data from file, then if your data is JSON ' + 'use `model_validate_json`, otherwise `model_validate` instead.', + category=None, + ) + def parse_file( # noqa: D102 + cls, + path: str | Path, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: DeprecatedParseProtocol | None = None, + allow_pickle: bool = False, + ) -> Self: + warnings.warn( + 'The `parse_file` method is deprecated; load the data from file, then if your data is JSON ' + 'use `model_validate_json`, otherwise `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import parse + + obj = parse.load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + return cls.parse_obj(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `from_orm` method is deprecated; set ' + "`model_config['from_attributes']=True` and use `model_validate` instead.", + category=None, + ) + def from_orm(cls, obj: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `from_orm` method is deprecated; set ' + "`model_config['from_attributes']=True` and use `model_validate` instead.", + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if not cls.model_config.get('from_attributes', None): + raise PydanticUserError( + 'You must set the config attribute `from_attributes=True` to use from_orm', code=None + ) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated('The `construct` method is deprecated; use `model_construct` instead.', category=None) + def construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `construct` method is deprecated; use `model_construct` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_construct(_fields_set=_fields_set, **values) + + @typing_extensions.deprecated( + 'The `copy` method is deprecated; use `model_copy` instead. ' + 'See the docstring of `BaseModel.copy` for details about how to handle `include` and `exclude`.', + category=None, + ) + def copy( + self, + *, + include: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude: AbstractSetIntStr | MappingIntStrAny | None = None, + update: Dict[str, Any] | None = None, # noqa UP006 + deep: bool = False, + ) -> Self: # pragma: no cover + """Returns a copy of the model. + + !!! warning "Deprecated" + This method is now deprecated; use `model_copy` instead. + + If you need `include` or `exclude`, use: + + ```python {test="skip" lint="skip"} + data = self.model_dump(include=include, exclude=exclude, round_trip=True) + data = {**data, **(update or {})} + copied = self.model_validate(data) + ``` + + Args: + include: Optional set or mapping specifying which fields to include in the copied model. + exclude: Optional set or mapping specifying which fields to exclude in the copied model. + update: Optional dictionary of field-value pairs to override field values in the copied model. + deep: If True, the values of fields that are Pydantic models will be deep-copied. + + Returns: + A copy of the model with included, excluded and updated fields as specified. + """ + warnings.warn( + 'The `copy` method is deprecated; use `model_copy` instead. ' + 'See the docstring of `BaseModel.copy` for details about how to handle `include` and `exclude`.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + values = dict( + copy_internals._iter( + self, to_dict=False, by_alias=False, include=include, exclude=exclude, exclude_unset=False + ), + **(update or {}), + ) + if self.__pydantic_private__ is None: + private = None + else: + private = {k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined} + + if self.__pydantic_extra__ is None: + extra: dict[str, Any] | None = None + else: + extra = self.__pydantic_extra__.copy() + for k in list(self.__pydantic_extra__): + if k not in values: # k was in the exclude + extra.pop(k) + for k in list(values): + if k in self.__pydantic_extra__: # k must have come from extra + extra[k] = values.pop(k) + + # new `__pydantic_fields_set__` can have unset optional fields with a set value in `update` kwarg + if update: + fields_set = self.__pydantic_fields_set__ | update.keys() + else: + fields_set = set(self.__pydantic_fields_set__) + + # removing excluded fields from `__pydantic_fields_set__` + if exclude: + fields_set -= set(exclude) + + return copy_internals._copy_and_set_values(self, values, fields_set, extra, private, deep=deep) + + @classmethod + @typing_extensions.deprecated('The `schema` method is deprecated; use `model_json_schema` instead.', category=None) + def schema( # noqa: D102 + cls, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE + ) -> Dict[str, Any]: # noqa UP006 + warnings.warn( + 'The `schema` method is deprecated; use `model_json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_json_schema(by_alias=by_alias, ref_template=ref_template) + + @classmethod + @typing_extensions.deprecated( + 'The `schema_json` method is deprecated; use `model_json_schema` and json.dumps instead.', + category=None, + ) + def schema_json( # noqa: D102 + cls, *, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE, **dumps_kwargs: Any + ) -> str: # pragma: no cover + warnings.warn( + 'The `schema_json` method is deprecated; use `model_json_schema` and json.dumps instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + import json + + from .deprecated.json import pydantic_encoder + + return json.dumps( + cls.model_json_schema(by_alias=by_alias, ref_template=ref_template), + default=pydantic_encoder, + **dumps_kwargs, + ) + + @classmethod + @typing_extensions.deprecated('The `validate` method is deprecated; use `model_validate` instead.', category=None) + def validate(cls, value: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `validate` method is deprecated; use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_validate(value) + + @classmethod + @typing_extensions.deprecated( + 'The `update_forward_refs` method is deprecated; use `model_rebuild` instead.', + category=None, + ) + def update_forward_refs(cls, **localns: Any) -> None: # noqa: D102 + warnings.warn( + 'The `update_forward_refs` method is deprecated; use `model_rebuild` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if localns: # pragma: no cover + raise TypeError('`localns` arguments are not longer accepted.') + cls.model_rebuild(force=True) + + @typing_extensions.deprecated( + 'The private method `_iter` will be removed and should no longer be used.', category=None + ) + def _iter(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_iter` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._iter(self, *args, **kwargs) + + @typing_extensions.deprecated( + 'The private method `_copy_and_set_values` will be removed and should no longer be used.', + category=None, + ) + def _copy_and_set_values(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_copy_and_set_values` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._copy_and_set_values(self, *args, **kwargs) + + @classmethod + @typing_extensions.deprecated( + 'The private method `_get_value` will be removed and should no longer be used.', + category=None, + ) + def _get_value(cls, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_get_value` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._get_value(cls, *args, **kwargs) + + @typing_extensions.deprecated( + 'The private method `_calculate_keys` will be removed and should no longer be used.', + category=None, + ) + def _calculate_keys(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_calculate_keys` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._calculate_keys(self, *args, **kwargs) + + +ModelT = TypeVar('ModelT', bound=BaseModel) + + +@overload +def create_model( + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: None = None, + __module__: str = __name__, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + **field_definitions: Any | tuple[str, Any], +) -> type[BaseModel]: ... + + +@overload +def create_model( + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: type[ModelT] | tuple[type[ModelT], ...], + __module__: str = __name__, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + **field_definitions: Any | tuple[str, Any], +) -> type[ModelT]: ... + + +def create_model( # noqa: C901 + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: type[ModelT] | tuple[type[ModelT], ...] | None = None, + __module__: str | None = None, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + # TODO PEP 747: replace `Any` by the TypeForm: + **field_definitions: Any | tuple[str, Any], +) -> type[ModelT]: + """!!! abstract "Usage Documentation" + [Dynamic Model Creation](../concepts/models.md#dynamic-model-creation) + + Dynamically creates and returns a new Pydantic model, in other words, `create_model` dynamically creates a + subclass of [`BaseModel`][pydantic.BaseModel]. + + !!! warning + This function may execute arbitrary code contained in field annotations, if string references need to be evaluated. + + See [Security implications of introspecting annotations](https://docs.python.org/3/library/annotationlib.html#annotationlib-security) for more information. + + Args: + model_name: The name of the newly created model. + __config__: The configuration of the new model. + __doc__: The docstring of the new model. + __base__: The base class or classes for the new model. + __module__: The name of the module that the model belongs to; + if `None`, the value is taken from `sys._getframe(1)` + __validators__: A dictionary of methods that validate fields. The keys are the names of the validation methods to + be added to the model, and the values are the validation methods themselves. You can read more about functional + validators [here](https://docs.pydantic.dev/2.9/concepts/validators/#field-validators). + __cls_kwargs__: A dictionary of keyword arguments for class creation, such as `metaclass`. + __qualname__: The qualified name of the newly created model. + **field_definitions: Field definitions of the new model. Either: + + - a single element, representing the type annotation of the field. + - a two-tuple, the first element being the type and the second element the assigned value + (either a default or the [`Field()`][pydantic.Field] function). + + Returns: + The new [model][pydantic.BaseModel]. + + Raises: + PydanticUserError: If `__base__` and `__config__` are both passed. + """ + if __base__ is None: + __base__ = (cast('type[ModelT]', BaseModel),) + elif not isinstance(__base__, tuple): + __base__ = (__base__,) + + __cls_kwargs__ = __cls_kwargs__ or {} + + fields: dict[str, Any] = {} + annotations: dict[str, Any] = {} + + for f_name, f_def in field_definitions.items(): + if isinstance(f_def, tuple): + if len(f_def) != 2: + raise PydanticUserError( + f'Field definition for {f_name!r} should a single element representing the type or a two-tuple, the first element ' + 'being the type and the second element the assigned value (either a default or the `Field()` function).', + code='create-model-field-definitions', + ) + + annotations[f_name] = f_def[0] + fields[f_name] = f_def[1] + else: + annotations[f_name] = f_def + + if __module__ is None: + f = sys._getframe(1) + __module__ = f.f_globals['__name__'] + + namespace: dict[str, Any] = {'__annotations__': annotations, '__module__': __module__} + if __doc__: + namespace['__doc__'] = __doc__ + if __qualname__ is not None: + namespace['__qualname__'] = __qualname__ + if __validators__: + namespace.update(__validators__) + namespace.update(fields) + if __config__: + namespace['model_config'] = __config__ + resolved_bases = types.resolve_bases(__base__) + meta, ns, kwds = types.prepare_class(model_name, resolved_bases, kwds=__cls_kwargs__) + if resolved_bases is not __base__: + ns['__orig_bases__'] = __base__ + namespace.update(ns) + + return meta( + model_name, + resolved_bases, + namespace, + __pydantic_reset_parent_namespace__=False, + _create_model_module=__module__, + **kwds, + ) + + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/mypy.py b/backend/venv/Lib/site-packages/pydantic/mypy.py new file mode 100644 index 0000000..6e8228e --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/mypy.py @@ -0,0 +1,1374 @@ +"""This module includes classes and functions designed specifically for use with the mypy plugin.""" + +from __future__ import annotations + +import sys +from collections.abc import Iterator +from configparser import ConfigParser +from typing import Any, Callable + +from mypy.errorcodes import ErrorCode +from mypy.expandtype import expand_type, expand_type_by_instance +from mypy.nodes import ( + ARG_NAMED, + ARG_NAMED_OPT, + ARG_OPT, + ARG_POS, + ARG_STAR2, + INVARIANT, + MDEF, + Argument, + AssignmentStmt, + Block, + CallExpr, + ClassDef, + Context, + Decorator, + DictExpr, + EllipsisExpr, + Expression, + FuncDef, + IfStmt, + JsonDict, + MemberExpr, + NameExpr, + PassStmt, + PlaceholderNode, + RefExpr, + Statement, + StrExpr, + SymbolTableNode, + TempNode, + TypeAlias, + TypeInfo, + Var, +) +from mypy.options import Options +from mypy.plugin import ( + CheckerPluginInterface, + ClassDefContext, + MethodContext, + Plugin, + ReportConfigContext, + SemanticAnalyzerPluginInterface, +) +from mypy.plugins.common import ( + deserialize_and_fixup_type, +) +from mypy.semanal import set_callable_name +from mypy.server.trigger import make_wildcard_trigger +from mypy.state import state +from mypy.type_visitor import TypeTranslator +from mypy.typeops import map_type_from_supertype +from mypy.types import ( + AnyType, + CallableType, + Instance, + NoneType, + Type, + TypeOfAny, + TypeType, + TypeVarType, + UnionType, + get_proper_type, +) +from mypy.typevars import fill_typevars +from mypy.util import get_unique_redefinition_name +from mypy.version import __version__ as mypy_version + +from pydantic._internal import _fields +from pydantic.version import parse_mypy_version + +CONFIGFILE_KEY = 'pydantic-mypy' +METADATA_KEY = 'pydantic-mypy-metadata' +BASEMODEL_FULLNAME = 'pydantic.main.BaseModel' +BASESETTINGS_FULLNAME = 'pydantic_settings.main.BaseSettings' +ROOT_MODEL_FULLNAME = 'pydantic.root_model.RootModel' +MODEL_METACLASS_FULLNAME = 'pydantic._internal._model_construction.ModelMetaclass' +FIELD_FULLNAME = 'pydantic.fields.Field' +DATACLASS_FULLNAME = 'pydantic.dataclasses.dataclass' +MODEL_VALIDATOR_FULLNAME = 'pydantic.functional_validators.model_validator' +DECORATOR_FULLNAMES = { + 'pydantic.functional_validators.field_validator', + 'pydantic.functional_validators.model_validator', + 'pydantic.functional_serializers.serializer', + 'pydantic.functional_serializers.model_serializer', + 'pydantic.deprecated.class_validators.validator', + 'pydantic.deprecated.class_validators.root_validator', +} +IMPLICIT_CLASSMETHOD_DECORATOR_FULLNAMES = DECORATOR_FULLNAMES - {'pydantic.functional_serializers.model_serializer'} + + +MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version) +BUILTINS_NAME = 'builtins' + +# Increment version if plugin changes and mypy caches should be invalidated +__version__ = 2 + + +def plugin(version: str) -> type[Plugin]: + """`version` is the mypy version string. + + We might want to use this to print a warning if the mypy version being used is + newer, or especially older, than we expect (or need). + + Args: + version: The mypy version string. + + Return: + The Pydantic mypy plugin type. + """ + return PydanticPlugin + + +class PydanticPlugin(Plugin): + """The Pydantic mypy plugin.""" + + def __init__(self, options: Options) -> None: + self.plugin_config = PydanticPluginConfig(options) + self._plugin_data = self.plugin_config.to_data() + super().__init__(options) + + def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None: + """Update Pydantic model class.""" + sym = self.lookup_fully_qualified(fullname) + if sym and isinstance(sym.node, TypeInfo): # pragma: no branch + # No branching may occur if the mypy cache has not been cleared + if sym.node.has_base(BASEMODEL_FULLNAME): + return self._pydantic_model_class_maker_callback + return None + + def get_metaclass_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None: + """Update Pydantic `ModelMetaclass` definition.""" + if fullname == MODEL_METACLASS_FULLNAME: + return self._pydantic_model_metaclass_marker_callback + return None + + def get_method_hook(self, fullname: str) -> Callable[[MethodContext], Type] | None: + """Adjust return type of `from_orm` method call.""" + if fullname.endswith('.from_orm'): + return from_attributes_callback + return None + + def report_config_data(self, ctx: ReportConfigContext) -> dict[str, Any]: + """Return all plugin config data. + + Used by mypy to determine if cache needs to be discarded. + """ + return self._plugin_data + + def _pydantic_model_class_maker_callback(self, ctx: ClassDefContext) -> None: + transformer = PydanticModelTransformer(ctx.cls, ctx.reason, ctx.api, self.plugin_config) + transformer.transform() + + def _pydantic_model_metaclass_marker_callback(self, ctx: ClassDefContext) -> None: + """Reset dataclass_transform_spec attribute of ModelMetaclass. + + Let the plugin handle it. This behavior can be disabled + if 'debug_dataclass_transform' is set to True', for testing purposes. + """ + if self.plugin_config.debug_dataclass_transform: + return + info_metaclass = ctx.cls.info.declared_metaclass + assert info_metaclass, "callback not passed from 'get_metaclass_hook'" + if getattr(info_metaclass.type, 'dataclass_transform_spec', None): + info_metaclass.type.dataclass_transform_spec = None + + +class PydanticPluginConfig: + """A Pydantic mypy plugin config holder. + + Attributes: + init_forbid_extra: Whether to add a `**kwargs` at the end of the generated `__init__` signature. + init_typed: Whether to annotate fields in the generated `__init__`. + warn_required_dynamic_aliases: Whether to raise required dynamic aliases error. + debug_dataclass_transform: Whether to not reset `dataclass_transform_spec` attribute + of `ModelMetaclass` for testing purposes. + """ + + __slots__ = ( + 'init_forbid_extra', + 'init_typed', + 'warn_required_dynamic_aliases', + 'debug_dataclass_transform', + ) + init_forbid_extra: bool + init_typed: bool + warn_required_dynamic_aliases: bool + debug_dataclass_transform: bool # undocumented + + def __init__(self, options: Options) -> None: + if options.config_file is None: # pragma: no cover + return + + toml_config = parse_toml(options.config_file) + if toml_config is not None: + config = toml_config.get('tool', {}).get('pydantic-mypy', {}) + for key in self.__slots__: + setting = config.get(key, False) + if not isinstance(setting, bool): + raise ValueError(f'Configuration value must be a boolean for key: {key}') + setattr(self, key, setting) + else: + plugin_config = ConfigParser() + plugin_config.read(options.config_file) + for key in self.__slots__: + setting = plugin_config.getboolean(CONFIGFILE_KEY, key, fallback=False) + setattr(self, key, setting) + + def to_data(self) -> dict[str, Any]: + """Returns a dict of config names to their values.""" + return {key: getattr(self, key) for key in self.__slots__} + + +def from_attributes_callback(ctx: MethodContext) -> Type: + """Raise an error if from_attributes is not enabled.""" + model_type: Instance + ctx_type = ctx.type + if isinstance(ctx_type, TypeType): + ctx_type = ctx_type.item + if isinstance(ctx_type, CallableType) and isinstance(ctx_type.ret_type, Instance): + model_type = ctx_type.ret_type # called on the class + elif isinstance(ctx_type, Instance): + model_type = ctx_type # called on an instance (unusual, but still valid) + else: # pragma: no cover + detail = f'ctx.type: {ctx_type} (of type {ctx_type.__class__.__name__})' + error_unexpected_behavior(detail, ctx.api, ctx.context) + return ctx.default_return_type + pydantic_metadata = model_type.type.metadata.get(METADATA_KEY) + if pydantic_metadata is None: + return ctx.default_return_type + if not model_type.type.has_base(BASEMODEL_FULLNAME): + # not a Pydantic v2 model + return ctx.default_return_type + from_attributes = pydantic_metadata.get('config', {}).get('from_attributes') + if from_attributes is not True: + error_from_attributes(model_type.type.name, ctx.api, ctx.context) + return ctx.default_return_type + + +class PydanticModelField: + """Based on mypy.plugins.dataclasses.DataclassAttribute.""" + + def __init__( + self, + name: str, + alias: str | None, + is_frozen: bool, + has_dynamic_alias: bool, + has_default: bool, + strict: bool | None, + line: int, + column: int, + type: Type | None, + info: TypeInfo, + ): + self.name = name + self.alias = alias + self.is_frozen = is_frozen + self.has_dynamic_alias = has_dynamic_alias + self.has_default = has_default + self.strict = strict + self.line = line + self.column = column + self.type = type + self.info = info + + def to_argument( + self, + current_info: TypeInfo, + typed: bool, + model_strict: bool, + force_optional: bool, + use_alias: bool, + api: SemanticAnalyzerPluginInterface, + force_typevars_invariant: bool, + is_root_model_root: bool, + ) -> Argument: + """Based on mypy.plugins.dataclasses.DataclassAttribute.to_argument.""" + variable = self.to_var(current_info, api, use_alias, force_typevars_invariant) + + strict = model_strict if self.strict is None else self.strict + if typed or strict: + type_annotation = self.expand_type(current_info, api, include_root_type=True) + else: + type_annotation = AnyType(TypeOfAny.explicit) + + return Argument( + variable=variable, + type_annotation=type_annotation, + initializer=None, + kind=ARG_OPT + if is_root_model_root + else (ARG_NAMED_OPT if force_optional or self.has_default else ARG_NAMED), + ) + + def expand_type( + self, + current_info: TypeInfo, + api: SemanticAnalyzerPluginInterface, + force_typevars_invariant: bool = False, + include_root_type: bool = False, + ) -> Type | None: + """Based on mypy.plugins.dataclasses.DataclassAttribute.expand_type.""" + if force_typevars_invariant: + # In some cases, mypy will emit an error "Cannot use a covariant type variable as a parameter" + # To prevent that, we add an option to replace typevars with invariant ones while building certain + # method signatures (in particular, `__init__`). There may be a better way to do this, if this causes + # us problems in the future, we should look into why the dataclasses plugin doesn't have this issue. + if isinstance(self.type, TypeVarType): + modified_type = self.type.copy_modified() + modified_type.variance = INVARIANT + self.type = modified_type + + if self.type is not None and self.info.self_type is not None: + # In general, it is not safe to call `expand_type()` during semantic analysis, + # however this plugin is called very late, so all types should be fully ready. + # Also, it is tricky to avoid eager expansion of Self types here (e.g. because + # we serialize attributes). + with state.strict_optional_set(api.options.strict_optional): + filled_with_typevars = fill_typevars(current_info) + # Cannot be TupleType as current_info represents a Pydantic model: + assert isinstance(filled_with_typevars, Instance) + if force_typevars_invariant: + for arg in filled_with_typevars.args: + if isinstance(arg, TypeVarType): + arg.variance = INVARIANT + + expanded_type = expand_type(self.type, {self.info.self_type.id: filled_with_typevars}) + if include_root_type and isinstance(expanded_type, Instance) and is_root_model(expanded_type.type): + # When a root model is used as a field, Pydantic allows both an instance of the root model + # as well as instances of the `root` field type: + root_type = expanded_type.type['root'].type + if root_type is None: + # Happens if the hint for 'root' has unsolved forward references + return expanded_type + expanded_root_type = expand_type_by_instance(root_type, expanded_type) + expanded_type = UnionType([expanded_type, expanded_root_type]) + return expanded_type + return self.type + + def to_var( + self, + current_info: TypeInfo, + api: SemanticAnalyzerPluginInterface, + use_alias: bool, + force_typevars_invariant: bool = False, + ) -> Var: + """Based on mypy.plugins.dataclasses.DataclassAttribute.to_var.""" + if use_alias and self.alias is not None: + name = self.alias + else: + name = self.name + + return Var(name, self.expand_type(current_info, api, force_typevars_invariant)) + + def serialize(self) -> JsonDict: + """Based on mypy.plugins.dataclasses.DataclassAttribute.serialize.""" + assert self.type + return { + 'name': self.name, + 'alias': self.alias, + 'is_frozen': self.is_frozen, + 'has_dynamic_alias': self.has_dynamic_alias, + 'has_default': self.has_default, + 'strict': self.strict, + 'line': self.line, + 'column': self.column, + 'type': self.type.serialize(), + } + + @classmethod + def deserialize(cls, info: TypeInfo, data: JsonDict, api: SemanticAnalyzerPluginInterface) -> PydanticModelField: + """Based on mypy.plugins.dataclasses.DataclassAttribute.deserialize.""" + data = data.copy() + typ = deserialize_and_fixup_type(data.pop('type'), api) + return cls(type=typ, info=info, **data) + + def expand_typevar_from_subtype(self, sub_type: TypeInfo, api: SemanticAnalyzerPluginInterface) -> None: + """Expands type vars in the context of a subtype when an attribute is inherited + from a generic super type. + """ + if self.type is not None: + with state.strict_optional_set(api.options.strict_optional): + self.type = map_type_from_supertype(self.type, sub_type, self.info) + + +class PydanticModelClassVar: + """Based on mypy.plugins.dataclasses.DataclassAttribute. + + ClassVars are ignored by subclasses. + + Attributes: + name: the ClassVar name + """ + + def __init__(self, name): + self.name = name + + @classmethod + def deserialize(cls, data: JsonDict) -> PydanticModelClassVar: + """Based on mypy.plugins.dataclasses.DataclassAttribute.deserialize.""" + data = data.copy() + return cls(**data) + + def serialize(self) -> JsonDict: + """Based on mypy.plugins.dataclasses.DataclassAttribute.serialize.""" + return { + 'name': self.name, + } + + +class PydanticModelTransformer: + """Transform the BaseModel subclass according to the plugin settings. + + Attributes: + tracked_config_fields: A set of field configs that the plugin has to track their value. + """ + + tracked_config_fields: set[str] = { + 'extra', + 'frozen', + 'from_attributes', + 'populate_by_name', + 'validate_by_alias', + 'validate_by_name', + 'alias_generator', + 'strict', + } + + def __init__( + self, + cls: ClassDef, + reason: Expression | Statement, + api: SemanticAnalyzerPluginInterface, + plugin_config: PydanticPluginConfig, + ) -> None: + self._cls = cls + self._reason = reason + self._api = api + + self.plugin_config = plugin_config + + def transform(self) -> bool: + """Configures the BaseModel subclass according to the plugin settings. + + In particular: + + * determines the model config and fields, + * adds a fields-aware signature for the initializer and construct methods + * freezes the class if frozen = True + * stores the fields, config, and if the class is settings in the mypy metadata for access by subclasses + """ + info = self._cls.info + is_a_root_model = is_root_model(info) + config = self.collect_config() + fields, class_vars = self.collect_fields_and_class_vars(config, is_a_root_model) + if fields is None or class_vars is None: + # Some definitions are not ready. We need another pass. + return False + for field in fields: + if field.type is None: + return False + + is_settings = info.has_base(BASESETTINGS_FULLNAME) + self.add_initializer(fields, config, is_settings, is_a_root_model) + self.add_model_construct_method(fields, config, is_settings, is_a_root_model) + self.set_frozen(fields, self._api, frozen=config.frozen is True) + + self.adjust_decorator_signatures() + + info.metadata[METADATA_KEY] = { + 'fields': {field.name: field.serialize() for field in fields}, + 'class_vars': {class_var.name: class_var.serialize() for class_var in class_vars}, + 'config': config.get_values_dict(), + } + + return True + + def adjust_decorator_signatures(self) -> None: + """When we decorate a function `f` with `pydantic.validator(...)`, `pydantic.field_validator` + or `pydantic.serializer(...)`, mypy sees `f` as a regular method taking a `self` instance, + even though pydantic internally wraps `f` with `classmethod` if necessary. + + Teach mypy this by marking any function whose outermost decorator is a `validator()`, + `field_validator()` or `serializer()` call as a `classmethod`. + """ + for sym in self._cls.info.names.values(): + if isinstance(sym.node, Decorator): + first_dec = sym.node.original_decorators[0] + if ( + isinstance(first_dec, CallExpr) + and isinstance(first_dec.callee, NameExpr) + and first_dec.callee.fullname in IMPLICIT_CLASSMETHOD_DECORATOR_FULLNAMES + # @model_validator(mode="after") is an exception, it expects a regular method + and not ( + first_dec.callee.fullname == MODEL_VALIDATOR_FULLNAME + and any( + first_dec.arg_names[i] == 'mode' and isinstance(arg, StrExpr) and arg.value == 'after' + for i, arg in enumerate(first_dec.args) + ) + ) + ): + # TODO: Only do this if the first argument of the decorated function is `cls` + sym.node.func.is_class = True + + def collect_config(self) -> ModelConfigData: # noqa: C901 (ignore complexity) + """Collects the values of the config attributes that are used by the plugin, accounting for parent classes.""" + cls = self._cls + config = ModelConfigData() + + has_config_kwargs = False + has_config_from_namespace = False + + # Handle `class MyModel(BaseModel, =, ...):` + for name, expr in cls.keywords.items(): + config_data = self.get_config_update(name, expr) + if config_data: + has_config_kwargs = True + config.update(config_data) + + # Handle `model_config` + stmt: Statement | None = None + for stmt in cls.defs.body: + if not isinstance(stmt, (AssignmentStmt, ClassDef)): + continue + + if isinstance(stmt, AssignmentStmt): + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or lhs.name != 'model_config': + continue + + if isinstance(stmt.rvalue, CallExpr): # calls to `dict` or `ConfigDict` + for arg_name, arg in zip(stmt.rvalue.arg_names, stmt.rvalue.args): + if arg_name is None: + continue + config.update(self.get_config_update(arg_name, arg, lax_extra=True)) + elif isinstance(stmt.rvalue, DictExpr): # dict literals + for key_expr, value_expr in stmt.rvalue.items: + if not isinstance(key_expr, StrExpr): + continue + config.update(self.get_config_update(key_expr.value, value_expr)) + + elif isinstance(stmt, ClassDef): + if stmt.name != 'Config': # 'deprecated' Config-class + continue + for substmt in stmt.defs.body: + if not isinstance(substmt, AssignmentStmt): + continue + lhs = substmt.lvalues[0] + if not isinstance(lhs, NameExpr): + continue + config.update(self.get_config_update(lhs.name, substmt.rvalue)) + + if has_config_kwargs: + self._api.fail( + 'Specifying config in two places is ambiguous, use either Config attribute or class kwargs', + cls, + ) + break + + has_config_from_namespace = True + + if has_config_kwargs or has_config_from_namespace: + if ( + stmt + and config.has_alias_generator + and not (config.validate_by_name or config.populate_by_name) + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(self._api, stmt) + + for info in cls.info.mro[1:]: # 0 is the current class + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of fields in its ancestors + self._api.add_plugin_dependency(make_wildcard_trigger(info.fullname)) + for name, value in info.metadata[METADATA_KEY]['config'].items(): + config.setdefault(name, value) + return config + + def collect_fields_and_class_vars( + self, model_config: ModelConfigData, is_root_model: bool + ) -> tuple[list[PydanticModelField] | None, list[PydanticModelClassVar] | None]: + """Collects the fields for the model, accounting for parent classes.""" + cls = self._cls + + # First, collect fields and ClassVars belonging to any class in the MRO, ignoring duplicates. + # + # We iterate through the MRO in reverse because attrs defined in the parent must appear + # earlier in the attributes list than attrs defined in the child. See: + # https://docs.python.org/3/library/dataclasses.html#inheritance + # + # However, we also want fields defined in the subtype to override ones defined + # in the parent. We can implement this via a dict without disrupting the attr order + # because dicts preserve insertion order in Python 3.7+. + found_fields: dict[str, PydanticModelField] = {} + found_class_vars: dict[str, PydanticModelClassVar] = {} + for info in reversed(cls.info.mro[1:-1]): # 0 is the current class, -2 is BaseModel, -1 is object + # if BASEMODEL_METADATA_TAG_KEY in info.metadata and BASEMODEL_METADATA_KEY not in info.metadata: + # # We haven't processed the base class yet. Need another pass. + # return None, None + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of attributes in its dataclass ancestors. + self._api.add_plugin_dependency(make_wildcard_trigger(info.fullname)) + + for name, data in info.metadata[METADATA_KEY]['fields'].items(): + field = PydanticModelField.deserialize(info, data, self._api) + # (The following comment comes directly from the dataclasses plugin) + # TODO: We shouldn't be performing type operations during the main + # semantic analysis pass, since some TypeInfo attributes might + # still be in flux. This should be performed in a later phase. + field.expand_typevar_from_subtype(cls.info, self._api) + found_fields[name] = field + + sym_node = cls.info.names.get(name) + if sym_node and sym_node.node and not isinstance(sym_node.node, Var): + self._api.fail( + 'BaseModel field may only be overridden by another field', + sym_node.node, + ) + # Collect ClassVars + for name, data in info.metadata[METADATA_KEY]['class_vars'].items(): + found_class_vars[name] = PydanticModelClassVar.deserialize(data) + + # Second, collect fields and ClassVars belonging to the current class. + current_field_names: set[str] = set() + current_class_vars_names: set[str] = set() + for stmt in self._get_assignment_statements_from_block(cls.defs): + maybe_field = self.collect_field_or_class_var_from_stmt(stmt, model_config, found_class_vars) + if maybe_field is None: + continue + + lhs = stmt.lvalues[0] + assert isinstance(lhs, NameExpr) # collect_field_or_class_var_from_stmt guarantees this + if isinstance(maybe_field, PydanticModelField): + if is_root_model and lhs.name != 'root': + error_extra_fields_on_root_model(self._api, stmt) + else: + current_field_names.add(lhs.name) + found_fields[lhs.name] = maybe_field + elif isinstance(maybe_field, PydanticModelClassVar): + current_class_vars_names.add(lhs.name) + found_class_vars[lhs.name] = maybe_field + + return list(found_fields.values()), list(found_class_vars.values()) + + def _get_assignment_statements_from_if_statement(self, stmt: IfStmt) -> Iterator[AssignmentStmt]: + for body in stmt.body: + if not body.is_unreachable: + yield from self._get_assignment_statements_from_block(body) + if stmt.else_body is not None and not stmt.else_body.is_unreachable: + yield from self._get_assignment_statements_from_block(stmt.else_body) + + def _get_assignment_statements_from_block(self, block: Block) -> Iterator[AssignmentStmt]: + for stmt in block.body: + if isinstance(stmt, AssignmentStmt): + yield stmt + elif isinstance(stmt, IfStmt): + yield from self._get_assignment_statements_from_if_statement(stmt) + + def collect_field_or_class_var_from_stmt( # noqa C901 + self, stmt: AssignmentStmt, model_config: ModelConfigData, class_vars: dict[str, PydanticModelClassVar] + ) -> PydanticModelField | PydanticModelClassVar | None: + """Get pydantic model field from statement. + + Args: + stmt: The statement. + model_config: Configuration settings for the model. + class_vars: ClassVars already known to be defined on the model. + + Returns: + A pydantic model field if it could find the field in statement. Otherwise, `None`. + """ + cls = self._cls + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or not _fields.is_valid_field_name(lhs.name) or lhs.name == 'model_config': + return None + + if not stmt.new_syntax: + if ( + isinstance(stmt.rvalue, CallExpr) + and isinstance(stmt.rvalue.callee, CallExpr) + and isinstance(stmt.rvalue.callee.callee, NameExpr) + and stmt.rvalue.callee.callee.fullname in DECORATOR_FULLNAMES + ): + # This is a (possibly-reused) validator or serializer, not a field + # In particular, it looks something like: my_validator = validator('my_field')(f) + # Eventually, we may want to attempt to respect model_config['ignored_types'] + return None + + if lhs.name in class_vars: + # Class vars are not fields and are not required to be annotated + return None + + # The assignment does not have an annotation, and it's not anything else we recognize + error_untyped_fields(self._api, stmt) + return None + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr): + return None + + if not _fields.is_valid_field_name(lhs.name) or lhs.name == 'model_config': + return None + + sym = cls.info.names.get(lhs.name) + if sym is None: # pragma: no cover + # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation) + # This is the same logic used in the dataclasses plugin + return None + + node = sym.node + if isinstance(node, PlaceholderNode): # pragma: no cover + # See the PlaceholderNode docstring for more detail about how this can occur + # Basically, it is an edge case when dealing with complex import logic + + # The dataclasses plugin now asserts this cannot happen, but I'd rather not error if it does.. + return None + + if isinstance(node, TypeAlias): + self._api.fail( + 'Type aliases inside BaseModel definitions are not supported at runtime', + node, + ) + # Skip processing this node. This doesn't match the runtime behaviour, + # but the only alternative would be to modify the SymbolTable, + # and it's a little hairy to do that in a plugin. + return None + + if not isinstance(node, Var): # pragma: no cover + # Don't know if this edge case still happens with the `is_valid_field` check above + # but better safe than sorry + + # The dataclasses plugin now asserts this cannot happen, but I'd rather not error if it does.. + return None + + # x: ClassVar[int] is not a field + if node.is_classvar: + return PydanticModelClassVar(lhs.name) + + # x: InitVar[int] is not supported in BaseModel + node_type = get_proper_type(node.type) + if isinstance(node_type, Instance) and node_type.type.fullname == 'dataclasses.InitVar': + self._api.fail( + 'InitVar is not supported in BaseModel', + node, + ) + + has_default = self.get_has_default(stmt) + strict = self.get_strict(stmt) + + if sym.type is None and node.is_final and node.is_inferred: + # This follows the logic from the dataclasses plugin. The following comment is taken verbatim: + # + # This is a special case, assignment like x: Final = 42 is classified + # annotated above, but mypy strips the `Final` turning it into x = 42. + # We do not support inferred types in dataclasses, so we can try inferring + # type for simple literals, and otherwise require an explicit type + # argument for Final[...]. + typ = self._api.analyze_simple_literal_type(stmt.rvalue, is_final=True) + if typ: + node.type = typ + else: + self._api.fail( + 'Need type argument for Final[...] with non-literal default in BaseModel', + stmt, + ) + node.type = AnyType(TypeOfAny.from_error) + + if node.is_final and has_default: + # TODO this path should be removed (see https://github.com/pydantic/pydantic/issues/11119) + return PydanticModelClassVar(lhs.name) + + alias, has_dynamic_alias = self.get_alias_info(stmt) + if ( + has_dynamic_alias + and not (model_config.validate_by_name or model_config.populate_by_name) + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(self._api, stmt) + is_frozen = self.is_field_frozen(stmt) + + init_type = self._infer_dataclass_attr_init_type(sym, lhs.name, stmt) + return PydanticModelField( + name=lhs.name, + has_dynamic_alias=has_dynamic_alias, + has_default=has_default, + strict=strict, + alias=alias, + is_frozen=is_frozen, + line=stmt.line, + column=stmt.column, + type=init_type, + info=cls.info, + ) + + def _infer_dataclass_attr_init_type(self, sym: SymbolTableNode, name: str, context: Context) -> Type | None: + """Infer __init__ argument type for an attribute. + + In particular, possibly use the signature of __set__. + """ + default = sym.type + if sym.implicit: + return default + t = get_proper_type(sym.type) + + # Perform a simple-minded inference from the signature of __set__, if present. + # We can't use mypy.checkmember here, since this plugin runs before type checking. + # We only support some basic scanerios here, which is hopefully sufficient for + # the vast majority of use cases. + if not isinstance(t, Instance): + return default + setter = t.type.get('__set__') + if setter: + if isinstance(setter.node, FuncDef): + super_info = t.type.get_containing_type_info('__set__') + assert super_info + if setter.type: + setter_type = get_proper_type(map_type_from_supertype(setter.type, t.type, super_info)) + else: + return AnyType(TypeOfAny.unannotated) + if isinstance(setter_type, CallableType) and setter_type.arg_kinds == [ + ARG_POS, + ARG_POS, + ARG_POS, + ]: + return expand_type_by_instance(setter_type.arg_types[2], t) + else: + self._api.fail(f'Unsupported signature for "__set__" in "{t.type.name}"', context) + else: + self._api.fail(f'Unsupported "__set__" in "{t.type.name}"', context) + + return default + + def add_initializer( + self, fields: list[PydanticModelField], config: ModelConfigData, is_settings: bool, is_root_model: bool + ) -> None: + """Adds a fields-aware `__init__` method to the class. + + The added `__init__` will be annotated with types vs. all `Any` depending on the plugin settings. + """ + if '__init__' in self._cls.info.names and not self._cls.info.names['__init__'].plugin_generated: + return # Don't generate an __init__ if one already exists + + typed = self.plugin_config.init_typed + model_strict = bool(config.strict) + use_alias = not (config.validate_by_name or config.populate_by_name) and config.validate_by_alias is not False + requires_dynamic_aliases = bool(config.has_alias_generator and not config.validate_by_name) + args = self.get_field_arguments( + fields, + typed=typed, + model_strict=model_strict, + requires_dynamic_aliases=requires_dynamic_aliases, + use_alias=use_alias, + is_settings=is_settings, + is_root_model=is_root_model, + force_typevars_invariant=True, + ) + + if is_settings: + base_settings_node = self._api.lookup_fully_qualified(BASESETTINGS_FULLNAME).node + assert isinstance(base_settings_node, TypeInfo) + if '__init__' in base_settings_node.names: + base_settings_init_node = base_settings_node.names['__init__'].node + assert isinstance(base_settings_init_node, FuncDef) + if base_settings_init_node is not None and base_settings_init_node.type is not None: + func_type = base_settings_init_node.type + assert isinstance(func_type, CallableType) + for arg_idx, arg_name in enumerate(func_type.arg_names): + if arg_name is None or arg_name.startswith('__') or not arg_name.startswith('_'): + continue + analyzed_variable_type = self._api.anal_type(func_type.arg_types[arg_idx]) + if analyzed_variable_type is not None and arg_name == '_cli_settings_source': + # _cli_settings_source is defined as CliSettingsSource[Any], and as such + # the Any causes issues with --disallow-any-explicit. As a workaround, change + # the Any type (as if CliSettingsSource was left unparameterized): + analyzed_variable_type = analyzed_variable_type.accept( + ChangeExplicitTypeOfAny(TypeOfAny.from_omitted_generics) + ) + variable = Var(arg_name, analyzed_variable_type) + args.append(Argument(variable, analyzed_variable_type, None, ARG_OPT)) + + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + args.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + add_method(self._api, self._cls, '__init__', args=args, return_type=NoneType()) + + def add_model_construct_method( + self, + fields: list[PydanticModelField], + config: ModelConfigData, + is_settings: bool, + is_root_model: bool, + ) -> None: + """Adds a fully typed `model_construct` classmethod to the class. + + Similar to the fields-aware __init__ method, but always uses the field names (not aliases), + and does not treat settings fields as optional. + """ + set_str = self._api.named_type(f'{BUILTINS_NAME}.set', [self._api.named_type(f'{BUILTINS_NAME}.str')]) + optional_set_str = UnionType([set_str, NoneType()]) + fields_set_argument = Argument(Var('_fields_set', optional_set_str), optional_set_str, None, ARG_OPT) + with state.strict_optional_set(self._api.options.strict_optional): + args = self.get_field_arguments( + fields, + typed=True, + model_strict=bool(config.strict), + requires_dynamic_aliases=False, + use_alias=False, + is_settings=is_settings, + is_root_model=is_root_model, + ) + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + args.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + args = args + [fields_set_argument] if is_root_model else [fields_set_argument] + args + + add_method( + self._api, + self._cls, + 'model_construct', + args=args, + return_type=fill_typevars(self._cls.info), + is_classmethod=True, + ) + + def set_frozen(self, fields: list[PydanticModelField], api: SemanticAnalyzerPluginInterface, frozen: bool) -> None: + """Marks all fields as properties so that attempts to set them trigger mypy errors. + + This is the same approach used by the attrs and dataclasses plugins. + """ + info = self._cls.info + for field in fields: + sym_node = info.names.get(field.name) + if sym_node is not None: + var = sym_node.node + if isinstance(var, Var): + var.is_property = frozen or field.is_frozen + elif isinstance(var, PlaceholderNode) and not self._api.final_iteration: + # See https://github.com/pydantic/pydantic/issues/5191 to hit this branch for test coverage + self._api.defer() + # `var` can also be a FuncDef or Decorator node (e.g. when overriding a field with a function or property). + # In that case, we don't want to do anything. Mypy will already raise an error that a field was not properly + # overridden. + else: + var = field.to_var(info, api, use_alias=False) + var.info = info + var.is_property = frozen + var._fullname = info.fullname + '.' + var.name + info.names[var.name] = SymbolTableNode(MDEF, var) + + def get_config_update(self, name: str, arg: Expression, lax_extra: bool = False) -> ModelConfigData | None: + """Determines the config update due to a single kwarg in the ConfigDict definition. + + Warns if a tracked config attribute is set to a value the plugin doesn't know how to interpret (e.g., an int) + """ + if name not in self.tracked_config_fields: + return None + if name == 'extra': + if isinstance(arg, StrExpr): + forbid_extra = arg.value == 'forbid' + elif isinstance(arg, MemberExpr): + forbid_extra = arg.name == 'forbid' + else: + if not lax_extra: + # Only emit an error for other types of `arg` (e.g., `NameExpr`, `ConditionalExpr`, etc.) when + # reading from a config class, etc. If a ConfigDict is used, then we don't want to emit an error + # because you'll get type checking from the ConfigDict itself. + # + # It would be nice if we could introspect the types better otherwise, but I don't know what the API + # is to evaluate an expr into its type and then check if that type is compatible with the expected + # type. Note that you can still get proper type checking via: `model_config = ConfigDict(...)`, just + # if you don't use an explicit string, the plugin won't be able to infer whether extra is forbidden. + error_invalid_config_value(name, self._api, arg) + return None + return ModelConfigData(forbid_extra=forbid_extra) + if name == 'alias_generator': + has_alias_generator = True + if isinstance(arg, NameExpr) and arg.fullname == 'builtins.None': + has_alias_generator = False + return ModelConfigData(has_alias_generator=has_alias_generator) + if isinstance(arg, NameExpr) and arg.fullname in ('builtins.True', 'builtins.False'): + return ModelConfigData(**{name: arg.fullname == 'builtins.True'}) + error_invalid_config_value(name, self._api, arg) + return None + + @staticmethod + def get_has_default(stmt: AssignmentStmt) -> bool: + """Returns a boolean indicating whether the field defined in `stmt` is a required field.""" + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only, so has no default + return False + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + # The "default value" is a call to `Field`; at this point, the field has a default if and only if: + # * there is a positional argument that is not `...` + # * there is a keyword argument named "default" that is not `...` + # * there is a "default_factory" that is not `None` + for arg, name in zip(expr.args, expr.arg_names): + # If name is None, then this arg is the default because it is the only positional argument. + if name is None or name == 'default': + return arg.__class__ is not EllipsisExpr + if name == 'default_factory': + return not (isinstance(arg, NameExpr) and arg.fullname == 'builtins.None') + return False + # Has no default if the "default value" is Ellipsis (i.e., `field_name: Annotation = ...`) + return not isinstance(expr, EllipsisExpr) + + @staticmethod + def get_strict(stmt: AssignmentStmt) -> bool | None: + """Returns a the `strict` value of a field if defined, otherwise `None`.""" + expr = stmt.rvalue + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + for arg, name in zip(expr.args, expr.arg_names): + if name != 'strict': + continue + if isinstance(arg, NameExpr): + if arg.fullname == 'builtins.True': + return True + elif arg.fullname == 'builtins.False': + return False + return None + return None + + @staticmethod + def get_alias_info(stmt: AssignmentStmt) -> tuple[str | None, bool]: + """Returns a pair (alias, has_dynamic_alias), extracted from the declaration of the field defined in `stmt`. + + `has_dynamic_alias` is True if and only if an alias is provided, but not as a string literal. + If `has_dynamic_alias` is True, `alias` will be None. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return None, False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return None, False + + if 'validation_alias' in expr.arg_names: + arg = expr.args[expr.arg_names.index('validation_alias')] + elif 'alias' in expr.arg_names: + arg = expr.args[expr.arg_names.index('alias')] + else: + return None, False + + if isinstance(arg, StrExpr): + return arg.value, False + else: + return None, True + + @staticmethod + def is_field_frozen(stmt: AssignmentStmt) -> bool: + """Returns whether the field is frozen, extracted from the declaration of the field defined in `stmt`. + + Note that this is only whether the field was declared to be frozen in a ` = Field(frozen=True)` + sense; this does not determine whether the field is frozen because the entire model is frozen; that is + handled separately. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return False + + for i, arg_name in enumerate(expr.arg_names): + if arg_name == 'frozen': + arg = expr.args[i] + return isinstance(arg, NameExpr) and arg.fullname == 'builtins.True' + return False + + def get_field_arguments( + self, + fields: list[PydanticModelField], + typed: bool, + model_strict: bool, + use_alias: bool, + requires_dynamic_aliases: bool, + is_settings: bool, + is_root_model: bool, + force_typevars_invariant: bool = False, + ) -> list[Argument]: + """Helper function used during the construction of the `__init__` and `model_construct` method signatures. + + Returns a list of mypy Argument instances for use in the generated signatures. + """ + info = self._cls.info + arguments = [ + field.to_argument( + info, + typed=typed, + model_strict=model_strict, + force_optional=requires_dynamic_aliases or is_settings, + use_alias=use_alias, + api=self._api, + force_typevars_invariant=force_typevars_invariant, + is_root_model_root=is_root_model and field.name == 'root', + ) + for field in fields + if not (use_alias and field.has_dynamic_alias) + ] + return arguments + + def should_init_forbid_extra(self, fields: list[PydanticModelField], config: ModelConfigData) -> bool: + """Indicates whether the generated `__init__` should get a `**kwargs` at the end of its signature. + + We disallow arbitrary kwargs if the extra config setting is "forbid", or if the plugin config says to, + *unless* a required dynamic alias is present (since then we can't determine a valid signature). + """ + if not (config.validate_by_name or config.populate_by_name): + if self.is_dynamic_alias_present(fields, bool(config.has_alias_generator)): + return False + if config.forbid_extra: + return True + return self.plugin_config.init_forbid_extra + + @staticmethod + def is_dynamic_alias_present(fields: list[PydanticModelField], has_alias_generator: bool) -> bool: + """Returns whether any fields on the model have a "dynamic alias", i.e., an alias that cannot be + determined during static analysis. + """ + for field in fields: + if field.has_dynamic_alias: + return True + if has_alias_generator: + for field in fields: + if field.alias is None: + return True + return False + + +class ChangeExplicitTypeOfAny(TypeTranslator): + """A type translator used to change type of Any's, if explicit.""" + + def __init__(self, type_of_any: int) -> None: + self._type_of_any = type_of_any + super().__init__() + + def visit_any(self, t: AnyType) -> Type: # noqa: D102 + if t.type_of_any == TypeOfAny.explicit: + return t.copy_modified(type_of_any=self._type_of_any) + else: + return t + + +class ModelConfigData: + """Pydantic mypy plugin model config class.""" + + def __init__( + self, + forbid_extra: bool | None = None, + frozen: bool | None = None, + from_attributes: bool | None = None, + populate_by_name: bool | None = None, + validate_by_alias: bool | None = None, + validate_by_name: bool | None = None, + has_alias_generator: bool | None = None, + strict: bool | None = None, + ): + self.forbid_extra = forbid_extra + self.frozen = frozen + self.from_attributes = from_attributes + self.populate_by_name = populate_by_name + self.validate_by_alias = validate_by_alias + self.validate_by_name = validate_by_name + self.has_alias_generator = has_alias_generator + self.strict = strict + + def get_values_dict(self) -> dict[str, Any]: + """Returns a dict of Pydantic model config names to their values. + + It includes the config if config value is not `None`. + """ + return {k: v for k, v in self.__dict__.items() if v is not None} + + def update(self, config: ModelConfigData | None) -> None: + """Update Pydantic model config values.""" + if config is None: + return + for k, v in config.get_values_dict().items(): + setattr(self, k, v) + + def setdefault(self, key: str, value: Any) -> None: + """Set default value for Pydantic model config if config value is `None`.""" + if getattr(self, key) is None: + setattr(self, key, value) + + +def is_root_model(info: TypeInfo) -> bool: + """Return whether the type info is a root model subclass (or the `RootModel` class itself).""" + return info.has_base(ROOT_MODEL_FULLNAME) + + +ERROR_ORM = ErrorCode('pydantic-orm', 'Invalid from_attributes call', 'Pydantic') +ERROR_CONFIG = ErrorCode('pydantic-config', 'Invalid config value', 'Pydantic') +ERROR_ALIAS = ErrorCode('pydantic-alias', 'Dynamic alias disallowed', 'Pydantic') +ERROR_UNEXPECTED = ErrorCode('pydantic-unexpected', 'Unexpected behavior', 'Pydantic') +ERROR_UNTYPED = ErrorCode('pydantic-field', 'Untyped field disallowed', 'Pydantic') +ERROR_FIELD_DEFAULTS = ErrorCode('pydantic-field', 'Invalid Field defaults', 'Pydantic') +ERROR_EXTRA_FIELD_ROOT_MODEL = ErrorCode('pydantic-field', 'Extra field on RootModel subclass', 'Pydantic') + + +def error_from_attributes(model_name: str, api: CheckerPluginInterface, context: Context) -> None: + """Emits an error when the model does not have `from_attributes=True`.""" + api.fail(f'"{model_name}" does not have from_attributes=True', context, code=ERROR_ORM) + + +def error_invalid_config_value(name: str, api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits an error when the config value is invalid.""" + api.fail(f'Invalid value for "Config.{name}"', context, code=ERROR_CONFIG) + + +def error_required_dynamic_aliases(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits required dynamic aliases error. + + This will be called when `warn_required_dynamic_aliases=True`. + """ + api.fail('Required dynamic aliases disallowed', context, code=ERROR_ALIAS) + + +def error_unexpected_behavior( + detail: str, api: CheckerPluginInterface | SemanticAnalyzerPluginInterface, context: Context +) -> None: # pragma: no cover + """Emits unexpected behavior error.""" + # Can't think of a good way to test this, but I confirmed it renders as desired by adding to a non-error path + link = 'https://github.com/pydantic/pydantic/issues/new/choose' + full_message = f'The pydantic mypy plugin ran into unexpected behavior: {detail}\n' + full_message += f'Please consider reporting this bug at {link} so we can try to fix it!' + api.fail(full_message, context, code=ERROR_UNEXPECTED) + + +def error_untyped_fields(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits an error when there is an untyped field in the model.""" + api.fail('Untyped fields disallowed', context, code=ERROR_UNTYPED) + + +def error_extra_fields_on_root_model(api: CheckerPluginInterface, context: Context) -> None: + """Emits an error when there is more than just a root field defined for a subclass of RootModel.""" + api.fail('Only `root` is allowed as a field of a `RootModel`', context, code=ERROR_EXTRA_FIELD_ROOT_MODEL) + + +def add_method( + api: SemanticAnalyzerPluginInterface | CheckerPluginInterface, + cls: ClassDef, + name: str, + args: list[Argument], + return_type: Type, + self_type: Type | None = None, + tvar_def: TypeVarType | None = None, + is_classmethod: bool = False, +) -> None: + """Very closely related to `mypy.plugins.common.add_method_to_class`, with a few pydantic-specific changes.""" + info = cls.info + + # First remove any previously generated methods with the same name + # to avoid clashes and problems in the semantic analyzer. + if name in info.names: + sym = info.names[name] + if sym.plugin_generated and isinstance(sym.node, FuncDef): + cls.defs.body.remove(sym.node) # pragma: no cover + + if isinstance(api, SemanticAnalyzerPluginInterface): + function_type = api.named_type('builtins.function') + else: + function_type = api.named_generic_type('builtins.function', []) + + if is_classmethod: + self_type = self_type or TypeType(fill_typevars(info)) + first = [Argument(Var('_cls'), self_type, None, ARG_POS, True)] + else: + self_type = self_type or fill_typevars(info) + # `self` is positional *ONLY* here, but this can't be expressed + # fully in the mypy internal API. ARG_POS is the closest we can get. + # Using ARG_POS will, however, give mypy errors if a `self` field + # is present on a model: + # + # Name "self" already defined (possibly by an import) [no-redef] + # + # As a workaround, we give this argument a name that will + # never conflict. By its positional nature, this name will not + # be used or exposed to users. + first = [Argument(Var('__pydantic_self__'), self_type, None, ARG_POS)] + args = first + args + + arg_types, arg_names, arg_kinds = [], [], [] + for arg in args: + assert arg.type_annotation, 'All arguments must be fully typed.' + arg_types.append(arg.type_annotation) + arg_names.append(arg.variable.name) + arg_kinds.append(arg.kind) + + signature = CallableType( + arg_types, arg_kinds, arg_names, return_type, function_type, variables=[tvar_def] if tvar_def else None + ) + + func = FuncDef(name, args, Block([PassStmt()])) + func.info = info + func.type = set_callable_name(signature, func) + func.is_class = is_classmethod + func._fullname = info.fullname + '.' + name + func.line = info.line + + # NOTE: we would like the plugin generated node to dominate, but we still + # need to keep any existing definitions so they get semantically analyzed. + if name in info.names: + # Get a nice unique name instead. + r_name = get_unique_redefinition_name(name, info.names) + info.names[r_name] = info.names[name] + + # Add decorator for is_classmethod + # The dataclasses plugin claims this is unnecessary for classmethods, but not including it results in a + # signature incompatible with the superclass, which causes mypy errors to occur for every subclass of BaseModel. + if is_classmethod: + func.is_decorated = True + v = Var(name, func.type) + v.info = info + v._fullname = func._fullname + v.is_classmethod = True + dec = Decorator(func, [NameExpr('classmethod')], v) + dec.line = info.line + sym = SymbolTableNode(MDEF, dec) + else: + sym = SymbolTableNode(MDEF, func) + sym.plugin_generated = True + info.names[name] = sym + + info.defn.defs.body.append(func) + + +def parse_toml(config_file: str) -> dict[str, Any] | None: + """Returns a dict of config keys to values. + + It reads configs from toml file and returns `None` if the file is not a toml file. + """ + if not config_file.endswith('.toml'): + return None + + if sys.version_info >= (3, 11): + import tomllib as toml_ + else: + try: + import tomli as toml_ + except ImportError: # pragma: no cover + import warnings + + warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.', stacklevel=2) + return None + + with open(config_file, 'rb') as rf: + return toml_.load(rf) diff --git a/backend/venv/Lib/site-packages/pydantic/networks.py b/backend/venv/Lib/site-packages/pydantic/networks.py new file mode 100644 index 0000000..04a7cac --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/networks.py @@ -0,0 +1,1331 @@ +"""The networks module contains types for common network-related fields.""" + +from __future__ import annotations as _annotations + +import dataclasses as _dataclasses +import re +from dataclasses import fields +from functools import lru_cache +from importlib.metadata import version +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from typing import TYPE_CHECKING, Annotated, Any, ClassVar + +from pydantic_core import ( + MultiHostHost, + PydanticCustomError, + PydanticSerializationUnexpectedValue, + SchemaSerializer, + core_schema, +) +from pydantic_core import MultiHostUrl as _CoreMultiHostUrl +from pydantic_core import Url as _CoreUrl +from typing_extensions import Self, TypeAlias + +from pydantic.errors import PydanticUserError + +from ._internal import _repr, _schema_generation_shared +from ._migration import getattr_migration +from .annotated_handlers import GetCoreSchemaHandler +from .json_schema import JsonSchemaValue +from .type_adapter import TypeAdapter + +if TYPE_CHECKING: + import email_validator + + NetworkType: TypeAlias = 'str | bytes | int | tuple[str | bytes | int, str | int]' + +else: + email_validator = None + + +__all__ = [ + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'FtpUrl', + 'HttpUrl', + 'WebsocketUrl', + 'AnyWebsocketUrl', + 'UrlConstraints', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'NatsDsn', + 'validate_email', + 'MySQLDsn', + 'MariaDBDsn', + 'ClickHouseDsn', + 'SnowflakeDsn', +] + + +@_dataclasses.dataclass +class UrlConstraints: + """Url constraints. + + Attributes: + max_length: The maximum length of the url. Defaults to `None`. + allowed_schemes: The allowed schemes. Defaults to `None`. + host_required: Whether the host is required. Defaults to `None`. + default_host: The default host. Defaults to `None`. + default_port: The default port. Defaults to `None`. + default_path: The default path. Defaults to `None`. + preserve_empty_path: Whether to preserve empty URL paths. Defaults to `None`. + """ + + max_length: int | None = None + allowed_schemes: list[str] | None = None + host_required: bool | None = None + default_host: str | None = None + default_port: int | None = None + default_path: str | None = None + preserve_empty_path: bool | None = None + + def __hash__(self) -> int: + return hash( + ( + self.max_length, + tuple(self.allowed_schemes) if self.allowed_schemes is not None else None, + self.host_required, + self.default_host, + self.default_port, + self.default_path, + self.preserve_empty_path, + ) + ) + + @property + def defined_constraints(self) -> dict[str, Any]: + """Fetch a key / value mapping of constraints to values that are not None. Used for core schema updates.""" + return {field.name: value for field in fields(self) if (value := getattr(self, field.name)) is not None} + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + + # for function-wrap schemas, url constraints is applied to the inner schema + # because when we generate schemas for urls, we wrap a core_schema.url_schema() with a function-wrap schema + # that helps with validation on initialization, see _BaseUrl and _BaseMultiHostUrl below. + schema_to_mutate = schema['schema'] if schema['type'] == 'function-wrap' else schema + if annotated_type := schema_to_mutate['type'] not in ('url', 'multi-host-url'): + raise PydanticUserError( + f"'UrlConstraints' cannot annotate '{annotated_type}'.", code='invalid-annotated-type' + ) + for constraint_key, constraint_value in self.defined_constraints.items(): + schema_to_mutate[constraint_key] = constraint_value + return schema + + +class _BaseUrl: + _constraints: ClassVar[UrlConstraints] = UrlConstraints() + _url: _CoreUrl + + def __init__(self, url: str | _CoreUrl | _BaseUrl) -> None: + self._url = _build_type_adapter(self.__class__).validate_python(url)._url + + @property + def scheme(self) -> str: + """The scheme part of the URL. + + e.g. `https` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.scheme + + @property + def username(self) -> str | None: + """The username part of the URL, or `None`. + + e.g. `user` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.username + + @property + def password(self) -> str | None: + """The password part of the URL, or `None`. + + e.g. `pass` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.password + + @property + def host(self) -> str | None: + """The host part of the URL, or `None`. + + If the URL must be punycode encoded, this is the encoded host, e.g if the input URL is `https://£££.com`, + `host` will be `xn--9aaa.com` + """ + return self._url.host + + def unicode_host(self) -> str | None: + """The host part of the URL as a unicode string, or `None`. + + e.g. `host` in `https://user:pass@host:port/path?query#fragment` + + If the URL must be punycode encoded, this is the decoded host, e.g if the input URL is `https://£££.com`, + `unicode_host()` will be `£££.com` + """ + return self._url.unicode_host() + + @property + def port(self) -> int | None: + """The port part of the URL, or `None`. + + e.g. `port` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.port + + @property + def path(self) -> str | None: + """The path part of the URL, or `None`. + + e.g. `/path` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.path + + @property + def query(self) -> str | None: + """The query part of the URL, or `None`. + + e.g. `query` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.query + + def query_params(self) -> list[tuple[str, str]]: + """The query part of the URL as a list of key-value pairs. + + e.g. `[('foo', 'bar')]` in `https://user:pass@host:port/path?foo=bar#fragment` + """ + return self._url.query_params() + + @property + def fragment(self) -> str | None: + """The fragment part of the URL, or `None`. + + e.g. `fragment` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.fragment + + def unicode_string(self) -> str: + """The URL as a unicode string, unlike `__str__()` this will not punycode encode the host. + + If the URL must be punycode encoded, this is the decoded string, e.g if the input URL is `https://£££.com`, + `unicode_string()` will be `https://£££.com` + """ + return self._url.unicode_string() + + def encoded_string(self) -> str: + """The URL's encoded string representation via __str__(). + + This returns the punycode-encoded host version of the URL as a string. + """ + return str(self) + + def __str__(self) -> str: + """The URL as a string, this will punycode encode the host if required.""" + return str(self._url) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({str(self._url)!r})' + + def __deepcopy__(self, memo: dict) -> Self: + return self.__class__(self._url) + + def __eq__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url == other._url + + def __lt__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url < other._url + + def __gt__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url > other._url + + def __le__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url <= other._url + + def __ge__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url >= other._url + + def __hash__(self) -> int: + return hash(self._url) + + def __len__(self) -> int: + return len(str(self._url)) + + @classmethod + def build( + cls, + *, + scheme: str, + username: str | None = None, + password: str | None = None, + host: str, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: + """Build a new `Url` instance from its component parts. + + Args: + scheme: The scheme part of the URL. + username: The username part of the URL, or omit for no username. + password: The password part of the URL, or omit for no password. + host: The host part of the URL. + port: The port part of the URL, or omit for no port. + path: The path part of the URL, or omit for no path. + query: The query part of the URL, or omit for no query. + fragment: The fragment part of the URL, or omit for no fragment. + + Returns: + An instance of URL + """ + return cls( + _CoreUrl.build( + scheme=scheme, + username=username, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + ) + ) + + @classmethod + def serialize_url(cls, url: Any, info: core_schema.SerializationInfo) -> str | Self: + if not isinstance(url, cls): + raise PydanticSerializationUnexpectedValue( + f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected." + ) + if info.mode == 'json': + return str(url) + return url + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[_BaseUrl], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + def wrap_val(v, h): + if isinstance(v, source): + return v + if isinstance(v, _BaseUrl): + v = str(v) + core_url = h(v) + instance = source.__new__(source) + instance._url = core_url + return instance + + return core_schema.no_info_wrap_validator_function( + wrap_val, + schema=core_schema.url_schema(**cls._constraints.defined_constraints), + serialization=core_schema.plain_serializer_function_ser_schema( + cls.serialize_url, info_arg=True, when_used='always' + ), + ) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + # we use the url schema for json schema generation, but we might have to extract it from + # the function-wrap schema we use as a tool for validation on initialization + inner_schema = core_schema['schema'] if core_schema['type'] == 'function-wrap' else core_schema + return handler(inner_schema) + + __pydantic_serializer__ = SchemaSerializer(core_schema.any_schema(serialization=core_schema.to_string_ser_schema())) + + +class _BaseMultiHostUrl: + _constraints: ClassVar[UrlConstraints] = UrlConstraints() + _url: _CoreMultiHostUrl + + def __init__(self, url: str | _CoreMultiHostUrl | _BaseMultiHostUrl) -> None: + self._url = _build_type_adapter(self.__class__).validate_python(url)._url + + @property + def scheme(self) -> str: + """The scheme part of the URL. + + e.g. `https` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.scheme + + @property + def path(self) -> str | None: + """The path part of the URL, or `None`. + + e.g. `/path` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.path + + @property + def query(self) -> str | None: + """The query part of the URL, or `None`. + + e.g. `query` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.query + + def query_params(self) -> list[tuple[str, str]]: + """The query part of the URL as a list of key-value pairs. + + e.g. `[('foo', 'bar')]` in `https://foo.com,bar.com/path?foo=bar#fragment` + """ + return self._url.query_params() + + @property + def fragment(self) -> str | None: + """The fragment part of the URL, or `None`. + + e.g. `fragment` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.fragment + + def hosts(self) -> list[MultiHostHost]: + '''The hosts of the `MultiHostUrl` as [`MultiHostHost`][pydantic_core.MultiHostHost] typed dicts. + + ```python + from pydantic_core import MultiHostUrl + + mhu = MultiHostUrl('https://foo.com:123,foo:bar@bar.com/path') + print(mhu.hosts()) + """ + [ + {'username': None, 'password': None, 'host': 'foo.com', 'port': 123}, + {'username': 'foo', 'password': 'bar', 'host': 'bar.com', 'port': 443} + ] + ``` + Returns: + A list of dicts, each representing a host. + ''' + return self._url.hosts() + + def encoded_string(self) -> str: + """The URL's encoded string representation via __str__(). + + This returns the punycode-encoded host version of the URL as a string. + """ + return str(self) + + def unicode_string(self) -> str: + """The URL as a unicode string, unlike `__str__()` this will not punycode encode the hosts.""" + return self._url.unicode_string() + + def __str__(self) -> str: + """The URL as a string, this will punycode encode the host if required.""" + return str(self._url) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({str(self._url)!r})' + + def __deepcopy__(self, memo: dict) -> Self: + return self.__class__(self._url) + + def __eq__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url == other._url + + def __hash__(self) -> int: + return hash(self._url) + + def __len__(self) -> int: + return len(str(self._url)) + + @classmethod + def build( + cls, + *, + scheme: str, + hosts: list[MultiHostHost] | None = None, + username: str | None = None, + password: str | None = None, + host: str | None = None, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: + """Build a new `MultiHostUrl` instance from its component parts. + + This method takes either `hosts` - a list of `MultiHostHost` typed dicts, or the individual components + `username`, `password`, `host` and `port`. + + Args: + scheme: The scheme part of the URL. + hosts: Multiple hosts to build the URL from. + username: The username part of the URL. + password: The password part of the URL. + host: The host part of the URL. + port: The port part of the URL. + path: The path part of the URL. + query: The query part of the URL, or omit for no query. + fragment: The fragment part of the URL, or omit for no fragment. + + Returns: + An instance of `MultiHostUrl` + """ + return cls( + _CoreMultiHostUrl.build( + scheme=scheme, + hosts=hosts, + username=username, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + ) + ) + + @classmethod + def serialize_url(cls, url: Any, info: core_schema.SerializationInfo) -> str | Self: + if not isinstance(url, cls): + raise PydanticSerializationUnexpectedValue( + f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected." + ) + if info.mode == 'json': + return str(url) + return url + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[_BaseMultiHostUrl], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + def wrap_val(v, h): + if isinstance(v, source): + return v + if isinstance(v, _BaseMultiHostUrl): + v = str(v) + core_url = h(v) + instance = source.__new__(source) + instance._url = core_url + return instance + + return core_schema.no_info_wrap_validator_function( + wrap_val, + schema=core_schema.multi_host_url_schema(**cls._constraints.defined_constraints), + serialization=core_schema.plain_serializer_function_ser_schema( + cls.serialize_url, info_arg=True, when_used='always' + ), + ) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + # we use the url schema for json schema generation, but we might have to extract it from + # the function-wrap schema we use as a tool for validation on initialization + inner_schema = core_schema['schema'] if core_schema['type'] == 'function-wrap' else core_schema + return handler(inner_schema) + + __pydantic_serializer__ = SchemaSerializer(core_schema.any_schema(serialization=core_schema.to_string_ser_schema())) + + +@lru_cache +def _build_type_adapter(cls: type[_BaseUrl | _BaseMultiHostUrl]) -> TypeAdapter: + return TypeAdapter(cls) + + +class AnyUrl(_BaseUrl): + """Base type for all URLs. + + * Any scheme allowed + * Top-level domain (TLD) not required + * Host not required + + Assuming an input URL of `http://samuel:pass@example.com:8000/the/path/?query=here#fragment=is;this=bit`, + the types export the following properties: + + - `scheme`: the URL scheme (`http`), always set. + - `host`: the URL host (`example.com`). + - `username`: optional username if included (`samuel`). + - `password`: optional password if included (`pass`). + - `port`: optional port (`8000`). + - `path`: optional path (`/the/path/`). + - `query`: optional URL query (for example, `GET` arguments or "search string", such as `query=here`). + - `fragment`: optional fragment (`fragment=is;this=bit`). + """ + + +# Note: all single host urls inherit from `AnyUrl` to preserve compatibility with pre-v2.10 code +# Where urls were annotated variants of `AnyUrl`, which was an alias to `pydantic_core.Url` + + +class AnyHttpUrl(AnyUrl): + """A type that will accept any http or https URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['http', 'https']) + + +class HttpUrl(AnyUrl): + """A type that will accept any http or https URL. + + * TLD not required + * Host not required + * Max length 2083 + + ```python + from pydantic import BaseModel, HttpUrl, ValidationError + + class MyModel(BaseModel): + url: HttpUrl + + m = MyModel(url='http://www.example.com') # (1)! + print(m.url) + #> http://www.example.com/ + + try: + MyModel(url='ftp://invalid.url') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyModel + url + URL scheme should be 'http' or 'https' [type=url_scheme, input_value='ftp://invalid.url', input_type=str] + ''' + + try: + MyModel(url='not a url') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyModel + url + Input should be a valid URL, relative URL without a base [type=url_parsing, input_value='not a url', input_type=str] + ''' + ``` + + 1. Note: mypy would prefer `m = MyModel(url=HttpUrl('http://www.example.com'))`, but Pydantic will convert the string to an HttpUrl instance anyway. + + "International domains" (e.g. a URL where the host or TLD includes non-ascii characters) will be encoded via + [punycode](https://en.wikipedia.org/wiki/Punycode) (see + [this article](https://www.xudongz.com/blog/2017/idn-phishing/) for a good description of why this is important): + + ```python + from pydantic import BaseModel, HttpUrl + + class MyModel(BaseModel): + url: HttpUrl + + m1 = MyModel(url='http://puny£code.com') + print(m1.url) + #> http://xn--punycode-eja.com/ + m2 = MyModel(url='https://www.аррӏе.com/') + print(m2.url) + #> https://www.xn--80ak6aa92e.com/ + m3 = MyModel(url='https://www.example.珠宝/') + print(m3.url) + #> https://www.example.xn--pbt977c/ + ``` + + + !!! warning "Underscores in Hostnames" + In Pydantic, underscores are allowed in all parts of a domain except the TLD. + Technically this might be wrong - in theory the hostname cannot have underscores, but subdomains can. + + To explain this; consider the following two cases: + + - `exam_ple.co.uk`: the hostname is `exam_ple`, which should not be allowed since it contains an underscore. + - `foo_bar.example.com` the hostname is `example`, which should be allowed since the underscore is in the subdomain. + + Without having an exhaustive list of TLDs, it would be impossible to differentiate between these two. Therefore + underscores are allowed, but you can always do further validation in a validator if desired. + + Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good + (or at least big) company. + """ + + _constraints = UrlConstraints(max_length=2083, allowed_schemes=['http', 'https']) + + +class AnyWebsocketUrl(AnyUrl): + """A type that will accept any ws or wss URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['ws', 'wss']) + + +class WebsocketUrl(AnyUrl): + """A type that will accept any ws or wss URL. + + * TLD not required + * Host not required + * Max length 2083 + """ + + _constraints = UrlConstraints(max_length=2083, allowed_schemes=['ws', 'wss']) + + +class FileUrl(AnyUrl): + """A type that will accept any file URL. + + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['file']) + + +class FtpUrl(AnyUrl): + """A type that will accept ftp URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['ftp']) + + +class PostgresDsn(_BaseMultiHostUrl): + """A type that will accept any Postgres DSN. + + * User info required + * TLD not required + * Host required + * Supports multiple hosts + + If further validation is required, these properties can be used by validators to enforce specific behaviour: + + ```python + from pydantic import ( + BaseModel, + HttpUrl, + PostgresDsn, + ValidationError, + field_validator, + ) + + class MyModel(BaseModel): + url: HttpUrl + + m = MyModel(url='http://www.example.com') + + # the repr() method for a url will display all properties of the url + print(repr(m.url)) + #> HttpUrl('http://www.example.com/') + print(m.url.scheme) + #> http + print(m.url.host) + #> www.example.com + print(m.url.port) + #> 80 + + class MyDatabaseModel(BaseModel): + db: PostgresDsn + + @field_validator('db') + def check_db_name(cls, v): + assert v.path and len(v.path) > 1, 'database must be provided' + return v + + m = MyDatabaseModel(db='postgres://user:pass@localhost:5432/foobar') + print(m.db) + #> postgres://user:pass@localhost:5432/foobar + + try: + MyDatabaseModel(db='postgres://user:pass@localhost:5432') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyDatabaseModel + db + Assertion failed, database must be provided + assert (None) + + where None = PostgresDsn('postgres://user:pass@localhost:5432').path [type=assertion_error, input_value='postgres://user:pass@localhost:5432', input_type=str] + ''' + ``` + """ + + _constraints = UrlConstraints( + host_required=True, + allowed_schemes=[ + 'postgres', + 'postgresql', + 'postgresql+asyncpg', + 'postgresql+pg8000', + 'postgresql+psycopg', + 'postgresql+psycopg2', + 'postgresql+psycopg2cffi', + 'postgresql+py-postgresql', + 'postgresql+pygresql', + ], + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportAttributeAccessIssue] + + +class CockroachDsn(AnyUrl): + """A type that will accept any Cockroach DSN. + + * User info required + * TLD not required + * Host required + """ + + _constraints = UrlConstraints( + host_required=True, + allowed_schemes=[ + 'cockroachdb', + 'cockroachdb+psycopg2', + 'cockroachdb+asyncpg', + ], + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +class AmqpDsn(AnyUrl): + """A type that will accept any AMQP DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['amqp', 'amqps']) + + +class RedisDsn(AnyUrl): + """A type that will accept any Redis DSN. + + * User info required + * TLD not required + * Host required (e.g., `rediss://:pass@localhost`) + """ + + _constraints = UrlConstraints( + allowed_schemes=['redis', 'rediss'], + default_host='localhost', + default_port=6379, + default_path='/0', + host_required=True, + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +class MongoDsn(_BaseMultiHostUrl): + """A type that will accept any MongoDB DSN. + + * User info not required + * Database name not required + * Port not required + * User info may be passed without user part (e.g., `mongodb://mongodb0.example.com:27017`). + + !!! warning + If a port isn't specified, the default MongoDB port `27017` will be used. If this behavior is + undesirable, you can use the following: + + ```python + from typing import Annotated + + from pydantic import UrlConstraints + from pydantic_core import MultiHostUrl + + MongoDsnNoDefaultPort = Annotated[ + MultiHostUrl, + UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv']), + ] + ``` + """ + + _constraints = UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv'], default_port=27017) + + +class KafkaDsn(AnyUrl): + """A type that will accept any Kafka DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['kafka'], default_host='localhost', default_port=9092) + + +class NatsDsn(_BaseMultiHostUrl): + """A type that will accept any NATS DSN. + + NATS is a connective technology built for the ever increasingly hyper-connected world. + It is a single technology that enables applications to securely communicate across + any combination of cloud vendors, on-premise, edge, web and mobile, and devices. + More: https://nats.io + """ + + _constraints = UrlConstraints( + allowed_schemes=['nats', 'tls', 'ws', 'wss'], default_host='localhost', default_port=4222 + ) + + +class MySQLDsn(AnyUrl): + """A type that will accept any MySQL DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=[ + 'mysql', + 'mysql+mysqlconnector', + 'mysql+aiomysql', + 'mysql+asyncmy', + 'mysql+mysqldb', + 'mysql+pymysql', + 'mysql+cymysql', + 'mysql+pyodbc', + ], + default_port=3306, + host_required=True, + ) + + +class MariaDBDsn(AnyUrl): + """A type that will accept any MariaDB DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=['mariadb', 'mariadb+mariadbconnector', 'mariadb+pymysql'], + default_port=3306, + ) + + +class ClickHouseDsn(AnyUrl): + """A type that will accept any ClickHouse DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=[ + 'clickhouse+native', + 'clickhouse+asynch', + 'clickhouse+http', + 'clickhouse', + 'clickhouses', + 'clickhousedb', + ], + default_host='localhost', + default_port=9000, + ) + + +class SnowflakeDsn(AnyUrl): + """A type that will accept any Snowflake DSN. + + * User info required + * TLD not required + * Host required + """ + + _constraints = UrlConstraints( + allowed_schemes=['snowflake'], + host_required=True, + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +def import_email_validator() -> None: + global email_validator + try: + import email_validator + except ImportError as e: + raise ImportError("email-validator is not installed, run `pip install 'pydantic[email]'`") from e + if not version('email-validator').partition('.')[0] == '2': + raise ImportError('email-validator version >= 2.0 required, run pip install -U email-validator') + + +if TYPE_CHECKING: + EmailStr = Annotated[str, ...] +else: + + class EmailStr: + """ + Info: + To use this type, you need to install the optional + [`email-validator`](https://github.com/JoshData/python-email-validator) package: + + ```bash + pip install email-validator + ``` + + Validate email addresses. + + ```python + from pydantic import BaseModel, EmailStr + + class Model(BaseModel): + email: EmailStr + + print(Model(email='contact@mail.com')) + #> email='contact@mail.com' + ``` + """ # noqa: D212 + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + import_email_validator() + return core_schema.no_info_after_validator_function(cls._validate, core_schema.str_schema()) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format='email') + return field_schema + + @classmethod + def _validate(cls, input_value: str, /) -> str: + return validate_email(input_value)[1] + + +class NameEmail(_repr.Representation): + """ + Info: + To use this type, you need to install the optional + [`email-validator`](https://github.com/JoshData/python-email-validator) package: + + ```bash + pip install email-validator + ``` + + Validate a name and email address combination, as specified by + [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4). + + The `NameEmail` has two properties: `name` and `email`. + In case the `name` is not provided, it's inferred from the email address. + + ```python + from pydantic import BaseModel, NameEmail + + class User(BaseModel): + email: NameEmail + + user = User(email='Fred Bloggs ') + print(user.email) + #> Fred Bloggs + print(user.email.name) + #> Fred Bloggs + + user = User(email='fred.bloggs@example.com') + print(user.email) + #> fred.bloggs + print(user.email.name) + #> fred.bloggs + ``` + """ # noqa: D212 + + __slots__ = 'name', 'email' + + def __init__(self, name: str, email: str): + self.name = name + self.email = email + + def __eq__(self, other: Any) -> bool: + return isinstance(other, NameEmail) and (self.name, self.email) == (other.name, other.email) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format='name-email') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + import_email_validator() + + return core_schema.no_info_after_validator_function( + cls._validate, + core_schema.json_or_python_schema( + json_schema=core_schema.str_schema(), + python_schema=core_schema.union_schema( + [core_schema.is_instance_schema(cls), core_schema.str_schema()], + custom_error_type='name_email_type', + custom_error_message='Input is not a valid NameEmail', + ), + serialization=core_schema.to_string_ser_schema(), + ), + ) + + @classmethod + def _validate(cls, input_value: Self | str, /) -> Self: + if isinstance(input_value, str): + name, email = validate_email(input_value) + return cls(name, email) + else: + return input_value + + def __str__(self) -> str: + if '@' in self.name: + return f'"{self.name}" <{self.email}>' + + return f'{self.name} <{self.email}>' + + +IPvAnyAddressType: TypeAlias = 'IPv4Address | IPv6Address' +IPvAnyInterfaceType: TypeAlias = 'IPv4Interface | IPv6Interface' +IPvAnyNetworkType: TypeAlias = 'IPv4Network | IPv6Network' + +if TYPE_CHECKING: + IPvAnyAddress = IPvAnyAddressType + IPvAnyInterface = IPvAnyInterfaceType + IPvAnyNetwork = IPvAnyNetworkType +else: + + class IPvAnyAddress: + """Validate an IPv4 or IPv6 address. + + ```python + from pydantic import BaseModel + from pydantic.networks import IPvAnyAddress + + class IpModel(BaseModel): + ip: IPvAnyAddress + + print(IpModel(ip='127.0.0.1')) + #> ip=IPv4Address('127.0.0.1') + + try: + IpModel(ip='http://www.example.com') + except ValueError as e: + print(e.errors()) + ''' + [ + { + 'type': 'ip_any_address', + 'loc': ('ip',), + 'msg': 'value is not a valid IPv4 or IPv6 address', + 'input': 'http://www.example.com', + } + ] + ''' + ``` + """ + + __slots__ = () + + def __new__(cls, value: Any) -> IPvAnyAddressType: + """Validate an IPv4 or IPv6 address.""" + try: + return IPv4Address(value) + except ValueError: + pass + + try: + return IPv6Address(value) + except ValueError: + raise PydanticCustomError('ip_any_address', 'value is not a valid IPv4 or IPv6 address') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanyaddress') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: Any, /) -> IPvAnyAddressType: + return cls(input_value) # type: ignore[return-value] + + class IPvAnyInterface: + """Validate an IPv4 or IPv6 interface.""" + + __slots__ = () + + def __new__(cls, value: NetworkType) -> IPvAnyInterfaceType: + """Validate an IPv4 or IPv6 interface.""" + try: + return IPv4Interface(value) + except ValueError: + pass + + try: + return IPv6Interface(value) + except ValueError: + raise PydanticCustomError('ip_any_interface', 'value is not a valid IPv4 or IPv6 interface') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanyinterface') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: NetworkType, /) -> IPvAnyInterfaceType: + return cls(input_value) # type: ignore[return-value] + + class IPvAnyNetwork: + """Validate an IPv4 or IPv6 network.""" + + __slots__ = () + + def __new__(cls, value: NetworkType) -> IPvAnyNetworkType: + """Validate an IPv4 or IPv6 network.""" + # Assume IP Network is defined with a default value for `strict` argument. + # Define your own class if you want to specify network address check strictness. + try: + return IPv4Network(value) + except ValueError: + pass + + try: + return IPv6Network(value) + except ValueError: + raise PydanticCustomError('ip_any_network', 'value is not a valid IPv4 or IPv6 network') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanynetwork') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: NetworkType, /) -> IPvAnyNetworkType: + return cls(input_value) # type: ignore[return-value] + + +def _build_pretty_email_regex() -> re.Pattern[str]: + name_chars = r'[\w!#$%&\'*+\-/=?^_`{|}~]' + unquoted_name_group = rf'((?:{name_chars}+\s+)*{name_chars}+)' + quoted_name_group = r'"((?:[^"]|\")+)"' + email_group = r'<(.+)>' + return re.compile(rf'\s*(?:{unquoted_name_group}|{quoted_name_group})?\s*{email_group}\s*') + + +pretty_email_regex = _build_pretty_email_regex() + +MAX_EMAIL_LENGTH = 2048 +"""Maximum length for an email. +A somewhat arbitrary but very generous number compared to what is allowed by most implementations. +""" + + +def validate_email(value: str) -> tuple[str, str]: + """Email address validation using [email-validator](https://pypi.org/project/email-validator/). + + Returns: + A tuple containing the local part of the email (or the name for "pretty" email addresses) + and the normalized email. + + Raises: + PydanticCustomError: If the email is invalid. + + Note: + Note that: + + * Raw IP address (literal) domain parts are not allowed. + * `"John Doe "` style "pretty" email addresses are processed. + * Spaces are striped from the beginning and end of addresses, but no error is raised. + """ + if email_validator is None: + import_email_validator() + + if len(value) > MAX_EMAIL_LENGTH: + raise PydanticCustomError( + 'value_error', + 'value is not a valid email address: {reason}', + {'reason': f'Length must not exceed {MAX_EMAIL_LENGTH} characters'}, + ) + + m = pretty_email_regex.fullmatch(value) + name: str | None = None + if m: + unquoted_name, quoted_name, value = m.groups() + name = unquoted_name or quoted_name + + email = value.strip() + + try: + parts = email_validator.validate_email(email, check_deliverability=False) + except email_validator.EmailNotValidError as e: + raise PydanticCustomError( + 'value_error', 'value is not a valid email address: {reason}', {'reason': str(e.args[0])} + ) from e + + email = parts.normalized + assert email is not None + name = name or parts.local_part + return name, email + + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/parse.py b/backend/venv/Lib/site-packages/pydantic/parse.py new file mode 100644 index 0000000..68b7f04 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/parse.py @@ -0,0 +1,5 @@ +"""The `parse` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/plugin/__init__.py b/backend/venv/Lib/site-packages/pydantic/plugin/__init__.py new file mode 100644 index 0000000..840d20a --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/plugin/__init__.py @@ -0,0 +1,193 @@ +"""!!! abstract "Usage Documentation" + [Build a Plugin](../concepts/plugins.md#build-a-plugin) + +Plugin interface for Pydantic plugins, and related types. +""" + +from __future__ import annotations + +from typing import Any, Callable, Literal, NamedTuple + +from pydantic_core import CoreConfig, CoreSchema, ValidationError +from typing_extensions import Protocol, TypeAlias + +from pydantic.config import ExtraValues + +__all__ = ( + 'PydanticPluginProtocol', + 'BaseValidateHandlerProtocol', + 'ValidatePythonHandlerProtocol', + 'ValidateJsonHandlerProtocol', + 'ValidateStringsHandlerProtocol', + 'NewSchemaReturns', + 'SchemaTypePath', + 'SchemaKind', +) + +NewSchemaReturns: TypeAlias = 'tuple[ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None]' + + +class SchemaTypePath(NamedTuple): + """Path defining where `schema_type` was defined, or where `TypeAdapter` was called.""" + + module: str + name: str + + +SchemaKind: TypeAlias = Literal['BaseModel', 'TypeAdapter', 'dataclass', 'create_model', 'validate_call'] + + +class PydanticPluginProtocol(Protocol): + """Protocol defining the interface for Pydantic plugins.""" + + def new_schema_validator( + self, + schema: CoreSchema, + schema_type: Any, + schema_type_path: SchemaTypePath, + schema_kind: SchemaKind, + config: CoreConfig | None, + plugin_settings: dict[str, object], + ) -> tuple[ + ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None + ]: + """This method is called for each plugin every time a new [`SchemaValidator`][pydantic_core.SchemaValidator] + is created. + + It should return an event handler for each of the three validation methods, or `None` if the plugin does not + implement that method. + + Args: + schema: The schema to validate against. + schema_type: The original type which the schema was created from, e.g. the model class. + schema_type_path: Path defining where `schema_type` was defined, or where `TypeAdapter` was called. + schema_kind: The kind of schema to validate against. + config: The config to use for validation. + plugin_settings: Any plugin settings. + + Returns: + A tuple of optional event handlers for each of the three validation methods - + `validate_python`, `validate_json`, `validate_strings`. + """ + raise NotImplementedError('Pydantic plugins should implement `new_schema_validator`.') + + +class BaseValidateHandlerProtocol(Protocol): + """Base class for plugin callbacks protocols. + + You shouldn't implement this protocol directly, instead use one of the subclasses with adds the correctly + typed `on_error` method. + """ + + on_enter: Callable[..., None] + """`on_enter` is changed to be more specific on all subclasses""" + + def on_success(self, result: Any) -> None: + """Callback to be notified of successful validation. + + Args: + result: The result of the validation. + """ + return + + def on_error(self, error: ValidationError) -> None: + """Callback to be notified of validation errors. + + Args: + error: The validation error. + """ + return + + def on_exception(self, exception: Exception) -> None: + """Callback to be notified of validation exceptions. + + Args: + exception: The exception raised during validation. + """ + return + + +class ValidatePythonHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_python`.""" + + def on_enter( + self, + input: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + self_instance: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The input to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + from_attributes: Whether to validate objects as inputs by extracting attributes. + context: The context to use for validation, this is passed to functional validators. + self_instance: An instance of a model to set attributes on from validation, this is used when running + validation from the `__init__` method of a model. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ + + +class ValidateJsonHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_json`.""" + + def on_enter( + self, + input: str | bytes | bytearray, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + self_instance: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The JSON data to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + context: The context to use for validation, this is passed to functional validators. + self_instance: An instance of a model to set attributes on from validation, this is used when running + validation from the `__init__` method of a model. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ + + +StringInput: TypeAlias = 'dict[str, StringInput]' + + +class ValidateStringsHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_strings`.""" + + def on_enter( + self, + input: StringInput, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The string data to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + context: The context to use for validation, this is passed to functional validators. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ diff --git a/backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75f47cbaa8c6f063a552699f6716357b976c57a6 GIT binary patch literal 8938 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/_loader.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/plugin/__pycache__/_loader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae06731b73e1951ce767ba1852bbaa4a48c39025 GIT binary patch literal 2428 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/plugin/_loader.py b/backend/venv/Lib/site-packages/pydantic/plugin/_loader.py new file mode 100644 index 0000000..a789092 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/plugin/_loader.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import importlib.metadata as importlib_metadata +import os +import warnings +from collections.abc import Iterable +from typing import TYPE_CHECKING, Final + +if TYPE_CHECKING: + from . import PydanticPluginProtocol + + +PYDANTIC_ENTRY_POINT_GROUP: Final[str] = 'pydantic' + +# cache of plugins +_plugins: dict[str, PydanticPluginProtocol] | None = None +# return no plugins while loading plugins to avoid recursion and errors while import plugins +# this means that if plugins use pydantic +_loading_plugins: bool = False + + +def get_plugins() -> Iterable[PydanticPluginProtocol]: + """Load plugins for Pydantic. + + Inspired by: https://github.com/pytest-dev/pluggy/blob/1.3.0/src/pluggy/_manager.py#L376-L402 + """ + disabled_plugins = os.getenv('PYDANTIC_DISABLE_PLUGINS') + global _plugins, _loading_plugins + if _loading_plugins: + # this happens when plugins themselves use pydantic, we return no plugins + return () + elif disabled_plugins in ('__all__', '1', 'true'): + return () + elif _plugins is None: + _plugins = {} + # set _loading_plugins so any plugins that use pydantic don't themselves use plugins + _loading_plugins = True + try: + for dist in importlib_metadata.distributions(): + for entry_point in dist.entry_points: + if entry_point.group != PYDANTIC_ENTRY_POINT_GROUP: + continue + if entry_point.value in _plugins: + continue + if disabled_plugins is not None and entry_point.name in disabled_plugins.split(','): + continue + try: + _plugins[entry_point.value] = entry_point.load() + except (ImportError, AttributeError) as e: + warnings.warn( + f'{e.__class__.__name__} while loading the `{entry_point.name}` Pydantic plugin, ' + f'this plugin will not be installed.\n\n{e!r}', + stacklevel=2, + ) + finally: + _loading_plugins = False + + return _plugins.values() diff --git a/backend/venv/Lib/site-packages/pydantic/plugin/_schema_validator.py b/backend/venv/Lib/site-packages/pydantic/plugin/_schema_validator.py new file mode 100644 index 0000000..83f2562 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/plugin/_schema_validator.py @@ -0,0 +1,140 @@ +"""Pluggable schema validator for pydantic.""" + +from __future__ import annotations + +import functools +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar + +from pydantic_core import CoreConfig, CoreSchema, SchemaValidator, ValidationError +from typing_extensions import ParamSpec + +if TYPE_CHECKING: + from . import BaseValidateHandlerProtocol, PydanticPluginProtocol, SchemaKind, SchemaTypePath + + +P = ParamSpec('P') +R = TypeVar('R') +Event = Literal['on_validate_python', 'on_validate_json', 'on_validate_strings'] +events: list[Event] = list(Event.__args__) # type: ignore + + +def create_schema_validator( + schema: CoreSchema, + schema_type: Any, + schema_type_module: str, + schema_type_name: str, + schema_kind: SchemaKind, + config: CoreConfig | None = None, + plugin_settings: dict[str, Any] | None = None, +) -> SchemaValidator | PluggableSchemaValidator: + """Create a `SchemaValidator` or `PluggableSchemaValidator` if plugins are installed. + + Returns: + If plugins are installed then return `PluggableSchemaValidator`, otherwise return `SchemaValidator`. + """ + from . import SchemaTypePath + from ._loader import get_plugins + + plugins = get_plugins() + if plugins: + return PluggableSchemaValidator( + schema, + schema_type, + SchemaTypePath(schema_type_module, schema_type_name), + schema_kind, + config, + plugins, + plugin_settings or {}, + ) + else: + return SchemaValidator(schema, config) + + +class PluggableSchemaValidator: + """Pluggable schema validator.""" + + __slots__ = '_schema_validator', 'validate_json', 'validate_python', 'validate_strings' + + def __init__( + self, + schema: CoreSchema, + schema_type: Any, + schema_type_path: SchemaTypePath, + schema_kind: SchemaKind, + config: CoreConfig | None, + plugins: Iterable[PydanticPluginProtocol], + plugin_settings: dict[str, Any], + ) -> None: + self._schema_validator = SchemaValidator(schema, config) + + python_event_handlers: list[BaseValidateHandlerProtocol] = [] + json_event_handlers: list[BaseValidateHandlerProtocol] = [] + strings_event_handlers: list[BaseValidateHandlerProtocol] = [] + for plugin in plugins: + try: + p, j, s = plugin.new_schema_validator( + schema, schema_type, schema_type_path, schema_kind, config, plugin_settings + ) + except TypeError as e: # pragma: no cover + raise TypeError(f'Error using plugin `{plugin.__module__}:{plugin.__class__.__name__}`: {e}') from e + if p is not None: + python_event_handlers.append(p) + if j is not None: + json_event_handlers.append(j) + if s is not None: + strings_event_handlers.append(s) + + self.validate_python = build_wrapper(self._schema_validator.validate_python, python_event_handlers) + self.validate_json = build_wrapper(self._schema_validator.validate_json, json_event_handlers) + self.validate_strings = build_wrapper(self._schema_validator.validate_strings, strings_event_handlers) + + def __getattr__(self, name: str) -> Any: + return getattr(self._schema_validator, name) + + +def build_wrapper(func: Callable[P, R], event_handlers: list[BaseValidateHandlerProtocol]) -> Callable[P, R]: + if not event_handlers: + return func + else: + on_enters = tuple(h.on_enter for h in event_handlers if filter_handlers(h, 'on_enter')) + on_successes = tuple(h.on_success for h in event_handlers if filter_handlers(h, 'on_success')) + on_errors = tuple(h.on_error for h in event_handlers if filter_handlers(h, 'on_error')) + on_exceptions = tuple(h.on_exception for h in event_handlers if filter_handlers(h, 'on_exception')) + + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + for on_enter_handler in on_enters: + on_enter_handler(*args, **kwargs) + + try: + result = func(*args, **kwargs) + except ValidationError as error: + for on_error_handler in on_errors: + on_error_handler(error) + raise + except Exception as exception: + for on_exception_handler in on_exceptions: + on_exception_handler(exception) + raise + else: + for on_success_handler in on_successes: + on_success_handler(result) + return result + + return wrapper + + +def filter_handlers(handler_cls: BaseValidateHandlerProtocol, method_name: str) -> bool: + """Filter out handler methods which are not implemented by the plugin directly - e.g. are missing + or are inherited from the protocol. + """ + handler = getattr(handler_cls, method_name, None) + if handler is None: + return False + elif handler.__module__ == 'pydantic.plugin': + # this is the original handler, from the protocol due to runtime inheritance + # we don't want to call it + return False + else: + return True diff --git a/backend/venv/Lib/site-packages/pydantic/py.typed b/backend/venv/Lib/site-packages/pydantic/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pydantic/root_model.py b/backend/venv/Lib/site-packages/pydantic/root_model.py new file mode 100644 index 0000000..80a5420 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/root_model.py @@ -0,0 +1,155 @@ +"""RootModel class and type definitions.""" + +from __future__ import annotations as _annotations + +from copy import copy, deepcopy +from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar + +from pydantic_core import PydanticUndefined +from typing_extensions import Self, dataclass_transform + +from . import PydanticUserError +from ._internal import _model_construction, _repr +from .main import BaseModel, _object_setattr + +if TYPE_CHECKING: + from .fields import Field as PydanticModelField + from .fields import PrivateAttr as PydanticModelPrivateAttr + + # dataclass_transform could be applied to RootModel directly, but `ModelMetaclass`'s dataclass_transform + # takes priority (at least with pyright). We trick type checkers into thinking we apply dataclass_transform + # on a new metaclass. + @dataclass_transform(kw_only_default=False, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr)) + class _RootModelMetaclass(_model_construction.ModelMetaclass): ... +else: + _RootModelMetaclass = _model_construction.ModelMetaclass + +__all__ = ('RootModel',) + +RootModelRootType = TypeVar('RootModelRootType') + + +class RootModel(BaseModel, Generic[RootModelRootType], metaclass=_RootModelMetaclass): + """!!! abstract "Usage Documentation" + [`RootModel` and Custom Root Types](../concepts/models.md#rootmodel-and-custom-root-types) + + A Pydantic `BaseModel` for the root object of the model. + + Attributes: + root: The root object of the model. + __pydantic_root_model__: Whether the model is a RootModel. + __pydantic_private__: Private fields in the model. + __pydantic_extra__: Extra fields in the model. + + """ + + __pydantic_root_model__ = True + __pydantic_private__ = None + __pydantic_extra__ = None + + root: RootModelRootType + + def __init_subclass__(cls, **kwargs): + extra = cls.model_config.get('extra') + if extra is not None: + raise PydanticUserError( + "`RootModel` does not support setting `model_config['extra']`", code='root-model-extra' + ) + super().__init_subclass__(**kwargs) + + def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None: # type: ignore + __tracebackhide__ = True + if data: + if root is not PydanticUndefined: + raise ValueError( + '"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments' + ) + root = data # type: ignore + self.__pydantic_validator__.validate_python(root, self_instance=self) + + __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] + + @classmethod + def model_construct(cls, root: RootModelRootType, _fields_set: set[str] | None = None) -> Self: # type: ignore + """Create a new model using the provided root object and update fields set. + + Args: + root: The root object of the model. + _fields_set: The set of fields to be updated. + + Returns: + The new model. + + Raises: + NotImplemented: If the model is not a subclass of `RootModel`. + """ + return super().model_construct(root=root, _fields_set=_fields_set) + + def __getstate__(self) -> dict[Any, Any]: + return { + '__dict__': self.__dict__, + '__pydantic_fields_set__': self.__pydantic_fields_set__, + } + + def __setstate__(self, state: dict[Any, Any]) -> None: + _object_setattr(self, '__pydantic_fields_set__', state['__pydantic_fields_set__']) + _object_setattr(self, '__dict__', state['__dict__']) + + def __copy__(self) -> Self: + """Returns a shallow copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', copy(self.__dict__)) + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + return m + + def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: + """Returns a deep copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) + # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str], + # and attempting a deepcopy would be marginally slower. + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + return m + + if TYPE_CHECKING: + + def model_dump( # type: ignore + self, + *, + mode: Literal['json', 'python'] | str = 'python', + include: Any = None, + exclude: Any = None, + context: dict[str, Any] | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + serialize_as_any: bool = False, + ) -> Any: + """This method is included just to get a more accurate return type for type checkers. + It is included in this `if TYPE_CHECKING:` block since no override is actually necessary. + + See the documentation of `BaseModel.model_dump` for more details about the arguments. + + Generally, this method will have a return type of `RootModelRootType`, assuming that `RootModelRootType` is + not a `BaseModel` subclass. If `RootModelRootType` is a `BaseModel` subclass, then the return + type will likely be `dict[str, Any]`, as `model_dump` calls are recursive. The return type could + even be something different, in the case of a custom serializer. + Thus, `Any` is used here to catch all of these cases. + """ + ... + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, RootModel): + return NotImplemented + return self.__pydantic_fields__['root'].annotation == other.__pydantic_fields__[ + 'root' + ].annotation and super().__eq__(other) + + def __repr_args__(self) -> _repr.ReprArgs: + yield 'root', self.root diff --git a/backend/venv/Lib/site-packages/pydantic/schema.py b/backend/venv/Lib/site-packages/pydantic/schema.py new file mode 100644 index 0000000..a3245a6 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/schema.py @@ -0,0 +1,5 @@ +"""The `schema` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/tools.py b/backend/venv/Lib/site-packages/pydantic/tools.py new file mode 100644 index 0000000..fdc68c4 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/tools.py @@ -0,0 +1,5 @@ +"""The `tools` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/type_adapter.py b/backend/venv/Lib/site-packages/pydantic/type_adapter.py new file mode 100644 index 0000000..6f1a082 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/type_adapter.py @@ -0,0 +1,795 @@ +"""Type adapter specification.""" + +from __future__ import annotations as _annotations + +import sys +import types +from collections.abc import Callable, Iterable +from dataclasses import is_dataclass +from types import FrameType +from typing import ( + Any, + Generic, + Literal, + TypeVar, + cast, + final, + overload, +) + +from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator, Some +from typing_extensions import ParamSpec, is_typeddict + +from pydantic.errors import PydanticUserError +from pydantic.main import BaseModel, IncEx + +from ._internal import _config, _generate_schema, _mock_val_ser, _namespace_utils, _repr, _typing_extra, _utils +from .config import ConfigDict, ExtraValues +from .errors import PydanticUndefinedAnnotation +from .json_schema import ( + DEFAULT_REF_TEMPLATE, + GenerateJsonSchema, + JsonSchemaKeyT, + JsonSchemaMode, + JsonSchemaValue, +) +from .plugin._schema_validator import PluggableSchemaValidator, create_schema_validator + +T = TypeVar('T') +R = TypeVar('R') +P = ParamSpec('P') +TypeAdapterT = TypeVar('TypeAdapterT', bound='TypeAdapter') + + +def _getattr_no_parents(obj: Any, attribute: str) -> Any: + """Returns the attribute value without attempting to look up attributes from parent types.""" + if hasattr(obj, '__dict__'): + try: + return obj.__dict__[attribute] + except KeyError: + pass + + slots = getattr(obj, '__slots__', None) + if slots is not None and attribute in slots: + return getattr(obj, attribute) + else: + raise AttributeError(attribute) + + +def _type_has_config(type_: Any) -> bool: + """Returns whether the type has config.""" + type_ = _typing_extra.annotated_type(type_) or type_ + try: + return issubclass(type_, BaseModel) or is_dataclass(type_) or is_typeddict(type_) + except TypeError: + # type is not a class + return False + + +@final +class TypeAdapter(Generic[T]): + """!!! abstract "Usage Documentation" + [`TypeAdapter`](../concepts/type_adapter.md) + + Type adapters provide a flexible way to perform validation and serialization based on a Python type. + + A `TypeAdapter` instance exposes some of the functionality from `BaseModel` instance methods + for types that do not have such methods (such as dataclasses, primitive types, and more). + + **Note:** `TypeAdapter` instances are not types, and cannot be used as type annotations for fields. + + Args: + type: The type associated with the `TypeAdapter`. + config: Configuration for the `TypeAdapter`, should be a dictionary conforming to + [`ConfigDict`][pydantic.config.ConfigDict]. + + !!! note + You cannot provide a configuration when instantiating a `TypeAdapter` if the type you're using + has its own config that cannot be overridden (ex: `BaseModel`, `TypedDict`, and `dataclass`). A + [`type-adapter-config-unused`](../errors/usage_errors.md#type-adapter-config-unused) error will + be raised in this case. + _parent_depth: Depth at which to search for the [parent frame][frame-objects]. This frame is used when + resolving forward annotations during schema building, by looking for the globals and locals of this + frame. Defaults to 2, which will result in the frame where the `TypeAdapter` was instantiated. + + !!! note + This parameter is named with an underscore to suggest its private nature and discourage use. + It may be deprecated in a minor version, so we only recommend using it if you're comfortable + with potential change in behavior/support. It's default value is 2 because internally, + the `TypeAdapter` class makes another call to fetch the frame. + module: The module that passes to plugin if provided. + + Attributes: + core_schema: The core schema for the type. + validator: The schema validator for the type. + serializer: The schema serializer for the type. + pydantic_complete: Whether the core schema for the type is successfully built. + + ??? tip "Compatibility with `mypy`" + Depending on the type used, `mypy` might raise an error when instantiating a `TypeAdapter`. As a workaround, you can explicitly + annotate your variable: + + ```py + from typing import Union + + from pydantic import TypeAdapter + + ta: TypeAdapter[Union[str, int]] = TypeAdapter(Union[str, int]) # type: ignore[arg-type] + ``` + + ??? info "Namespace management nuances and implementation details" + + Here, we collect some notes on namespace management, and subtle differences from `BaseModel`: + + `BaseModel` uses its own `__module__` to find out where it was defined + and then looks for symbols to resolve forward references in those globals. + On the other hand, `TypeAdapter` can be initialized with arbitrary objects, + which may not be types and thus do not have a `__module__` available. + So instead we look at the globals in our parent stack frame. + + It is expected that the `ns_resolver` passed to this function will have the correct + namespace for the type we're adapting. See the source code for `TypeAdapter.__init__` + and `TypeAdapter.rebuild` for various ways to construct this namespace. + + This works for the case where this function is called in a module that + has the target of forward references in its scope, but + does not always work for more complex cases. + + For example, take the following: + + ```python {title="a.py"} + IntList = list[int] + OuterDict = dict[str, 'IntList'] + ``` + + ```python {test="skip" title="b.py"} + from a import OuterDict + + from pydantic import TypeAdapter + + IntList = int # replaces the symbol the forward reference is looking for + v = TypeAdapter(OuterDict) + v({'x': 1}) # should fail but doesn't + ``` + + If `OuterDict` were a `BaseModel`, this would work because it would resolve + the forward reference within the `a.py` namespace. + But `TypeAdapter(OuterDict)` can't determine what module `OuterDict` came from. + + In other words, the assumption that _all_ forward references exist in the + module we are being called from is not technically always true. + Although most of the time it is and it works fine for recursive models and such, + `BaseModel`'s behavior isn't perfect either and _can_ break in similar ways, + so there is no right or wrong between the two. + + But at the very least this behavior is _subtly_ different from `BaseModel`'s. + """ + + core_schema: CoreSchema + validator: SchemaValidator | PluggableSchemaValidator + serializer: SchemaSerializer + pydantic_complete: bool + + @overload + def __init__( + self, + type: type[T], + *, + config: ConfigDict | None = ..., + _parent_depth: int = ..., + module: str | None = ..., + ) -> None: ... + + # This second overload is for unsupported special forms (such as Annotated, Union, etc.) + # Currently there is no way to type this correctly + # See https://github.com/python/typing/pull/1618 + @overload + def __init__( + self, + type: Any, + *, + config: ConfigDict | None = ..., + _parent_depth: int = ..., + module: str | None = ..., + ) -> None: ... + + def __init__( + self, + type: Any, + *, + config: ConfigDict | None = None, + _parent_depth: int = 2, + module: str | None = None, + ) -> None: + if _type_has_config(type) and config is not None: + raise PydanticUserError( + 'Cannot use `config` when the type is a BaseModel, dataclass or TypedDict.' + ' These types can have their own config and setting the config via the `config`' + ' parameter to TypeAdapter will not override it, thus the `config` you passed to' + ' TypeAdapter becomes meaningless, which is probably not what you want.', + code='type-adapter-config-unused', + ) + + self._type = type + self._config = config + self._parent_depth = _parent_depth + self.pydantic_complete = False + + parent_frame = self._fetch_parent_frame() + if isinstance(type, types.FunctionType): + # Special case functions, which are *not* pushed to the `NsResolver` stack and without this special case + # would only have access to the parent namespace where the `TypeAdapter` was instantiated (if the function is defined + # in another module, we need to look at that module's globals). + if parent_frame is not None: + # `f_locals` is the namespace where the type adapter was instantiated (~ to `f_globals` if at the module level): + parent_ns = parent_frame.f_locals + else: # pragma: no cover + parent_ns = None + globalns, localns = _namespace_utils.ns_for_function( + type, + parent_namespace=parent_ns, + ) + parent_namespace = None + else: + if parent_frame is not None: + globalns = parent_frame.f_globals + # Do not provide a local ns if the type adapter happens to be instantiated at the module level: + localns = parent_frame.f_locals if parent_frame.f_locals is not globalns else {} + else: # pragma: no cover + globalns = {} + localns = {} + parent_namespace = localns + + self._module_name = module or cast(str, globalns.get('__name__', '')) + self._init_core_attrs( + ns_resolver=_namespace_utils.NsResolver( + namespaces_tuple=_namespace_utils.NamespacesTuple(locals=localns, globals=globalns), + parent_namespace=parent_namespace, + ), + force=False, + ) + + def _fetch_parent_frame(self) -> FrameType | None: + frame = sys._getframe(self._parent_depth) + if frame.f_globals.get('__name__') == 'typing': + # Because `TypeAdapter` is generic, explicitly parametrizing the class results + # in a `typing._GenericAlias` instance, which proxies instantiation calls to the + # "real" `TypeAdapter` class and thus adding an extra frame to the call. To avoid + # pulling anything from the `typing` module, use the correct frame (the one before): + return frame.f_back + + return frame + + def _init_core_attrs( + self, ns_resolver: _namespace_utils.NsResolver, force: bool, raise_errors: bool = False + ) -> bool: + """Initialize the core schema, validator, and serializer for the type. + + Args: + ns_resolver: The namespace resolver to use when building the core schema for the adapted type. + force: Whether to force the construction of the core schema, validator, and serializer. + If `force` is set to `False` and `_defer_build` is `True`, the core schema, validator, and serializer will be set to mocks. + raise_errors: Whether to raise errors if initializing any of the core attrs fails. + + Returns: + `True` if the core schema, validator, and serializer were successfully initialized, otherwise `False`. + + Raises: + PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__` + and `raise_errors=True`. + """ + if not force and self._defer_build: + _mock_val_ser.set_type_adapter_mocks(self) + self.pydantic_complete = False + return False + + try: + self.core_schema = _getattr_no_parents(self._type, '__pydantic_core_schema__') + self.validator = _getattr_no_parents(self._type, '__pydantic_validator__') + self.serializer = _getattr_no_parents(self._type, '__pydantic_serializer__') + + # TODO: we don't go through the rebuild logic here directly because we don't want + # to repeat all of the namespace fetching logic that we've already done + # so we simply skip to the block below that does the actual schema generation + if ( + isinstance(self.core_schema, _mock_val_ser.MockCoreSchema) + or isinstance(self.validator, _mock_val_ser.MockValSer) + or isinstance(self.serializer, _mock_val_ser.MockValSer) + ): + raise AttributeError() + except AttributeError: + config_wrapper = _config.ConfigWrapper(self._config) + + schema_generator = _generate_schema.GenerateSchema(config_wrapper, ns_resolver=ns_resolver) + + try: + core_schema = schema_generator.generate_schema(self._type) + except PydanticUndefinedAnnotation: + if raise_errors: + raise + _mock_val_ser.set_type_adapter_mocks(self) + return False + + try: + self.core_schema = schema_generator.clean_schema(core_schema) + except _generate_schema.InvalidSchemaError: + _mock_val_ser.set_type_adapter_mocks(self) + return False + + core_config = config_wrapper.core_config(None) + + self.validator = create_schema_validator( + schema=self.core_schema, + schema_type=self._type, + schema_type_module=self._module_name, + schema_type_name=str(self._type), + schema_kind='TypeAdapter', + config=core_config, + plugin_settings=config_wrapper.plugin_settings, + ) + self.serializer = SchemaSerializer(self.core_schema, core_config) + + self.pydantic_complete = True + return True + + @property + def _defer_build(self) -> bool: + config = self._config if self._config is not None else self._model_config + if config: + return config.get('defer_build') is True + return False + + @property + def _model_config(self) -> ConfigDict | None: + type_: Any = _typing_extra.annotated_type(self._type) or self._type # Eg FastAPI heavily uses Annotated + if _utils.lenient_issubclass(type_, BaseModel): + return type_.model_config + return getattr(type_, '__pydantic_config__', None) + + def __repr__(self) -> str: + return f'TypeAdapter({_repr.display_as_type(self._type)})' + + def rebuild( + self, + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: _namespace_utils.MappingNamespace | None = None, + ) -> bool | None: + """Try to rebuild the pydantic-core schema for the adapter's type. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + Args: + force: Whether to force the rebuilding of the type adapter's schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: Depth at which to search for the [parent frame][frame-objects]. This + frame is used when resolving forward annotations during schema rebuilding, by looking for + the locals of this frame. Defaults to 2, which will result in the frame where the method + was called. + _types_namespace: An explicit types namespace to use, instead of using the local namespace + from the parent frame. Defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + if not force and self.pydantic_complete: + return None + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + # we have to manually fetch globals here because there's no type on the stack of the NsResolver + # and so we skip the globalns = get_module_ns_of(typ) call that would normally happen + globalns = sys._getframe(max(_parent_namespace_depth - 1, 1)).f_globals + ns_resolver = _namespace_utils.NsResolver( + namespaces_tuple=_namespace_utils.NamespacesTuple(locals=rebuild_ns, globals=globalns), + parent_namespace=rebuild_ns, + ) + return self._init_core_attrs(ns_resolver=ns_resolver, force=True, raise_errors=raise_errors) + + def validate_python( + self, + object: Any, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """Validate a Python object against the model. + + Args: + object: The Python object to validate against the model. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + from_attributes: Whether to extract data from object attributes. + context: Additional context to pass to the validator. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + !!! note + When using `TypeAdapter` with a Pydantic `dataclass`, the use of the `from_attributes` + argument is not supported. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_python( + object, + strict=strict, + extra=extra, + from_attributes=from_attributes, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def validate_json( + self, + data: str | bytes | bytearray, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """!!! abstract "Usage Documentation" + [JSON Parsing](../concepts/json.md#json-parsing) + + Validate a JSON string or bytes against the model. + + Args: + data: The JSON data to validate against the model. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Additional context to use during validation. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_json( + data, + strict=strict, + extra=extra, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def validate_strings( + self, + obj: Any, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """Validate object contains string data against the model. + + Args: + obj: The object contains string data to validate. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Additional context to use during validation. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_strings( + obj, + strict=strict, + extra=extra, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def get_default_value(self, *, strict: bool | None = None, context: Any | None = None) -> Some[T] | None: + """Get the default value for the wrapped type. + + Args: + strict: Whether to strictly check types. + context: Additional context to pass to the validator. + + Returns: + The default value wrapped in a `Some` if there is one or None if not. + """ + return self.validator.get_default_value(strict=strict, context=context) + + def dump_python( + self, + instance: T, + /, + *, + mode: Literal['json', 'python'] = 'python', + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + context: Any | None = None, + ) -> Any: + """Dump an instance of the adapted type to a Python object. + + Args: + instance: The Python object to serialize. + mode: The output format. + include: Fields to include in the output. + exclude: Fields to exclude from the output. + by_alias: Whether to use alias names for field names. + exclude_unset: Whether to exclude unset fields. + exclude_defaults: Whether to exclude fields with default values. + exclude_none: Whether to exclude fields with None values. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: Whether to output the serialized data in a way that is compatible with deserialization. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + context: Additional context to pass to the serializer. + + Returns: + The serialized object. + """ + return self.serializer.to_python( + instance, + mode=mode, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + context=context, + ) + + def dump_json( + self, + instance: T, + /, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + context: Any | None = None, + ) -> bytes: + """!!! abstract "Usage Documentation" + [JSON Serialization](../concepts/json.md#json-serialization) + + Serialize an instance of the adapted type to JSON. + + Args: + instance: The instance to be serialized. + indent: Number of spaces for JSON indentation. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: Fields to include. + exclude: Fields to exclude. + by_alias: Whether to use alias names for field names. + exclude_unset: Whether to exclude unset fields. + exclude_defaults: Whether to exclude fields with default values. + exclude_none: Whether to exclude fields with a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: Whether to serialize and deserialize the instance to ensure round-tripping. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + context: Additional context to pass to the serializer. + + Returns: + The JSON representation of the given instance as bytes. + """ + return self.serializer.to_json( + instance, + indent=indent, + ensure_ascii=ensure_ascii, + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + context=context, + ) + + def json_schema( + self, + *, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', + ) -> dict[str, Any]: + """Generate a JSON schema for the adapted type. + + Args: + by_alias: Whether to use alias names for field names. + ref_template: The format string used for generating $ref strings. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: To override the logic used to generate the JSON schema, as a subclass of + `GenerateJsonSchema` with your desired modifications + mode: The mode in which to generate the schema. + schema_generator: The generator class used for creating the schema. + mode: The mode to use for schema generation. + + Returns: + The JSON schema for the model as a dictionary. + """ + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + if isinstance(self.core_schema, _mock_val_ser.MockCoreSchema): + self.core_schema.rebuild() + assert not isinstance(self.core_schema, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' + return schema_generator_instance.generate(self.core_schema, mode=mode) + + @staticmethod + def json_schemas( + inputs: Iterable[tuple[JsonSchemaKeyT, JsonSchemaMode, TypeAdapter[Any]]], + /, + *, + by_alias: bool = True, + title: str | None = None, + description: str | None = None, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: + """Generate a JSON schema including definitions from multiple type adapters. + + Args: + inputs: Inputs to schema generation. The first two items will form the keys of the (first) + output mapping; the type adapters will provide the core schemas that get converted into + definitions in the output JSON schema. + by_alias: Whether to use alias names. + title: The title for the schema. + description: The description for the schema. + ref_template: The format string used for generating $ref strings. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The generator class used for creating the schema. + + Returns: + A tuple where: + + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a JSON schema containing all definitions referenced in the first returned + element, along with the optional title and description keys. + + """ + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + + inputs_ = [] + for key, mode, adapter in inputs: + # This is the same pattern we follow for model json schemas - we attempt a core schema rebuild if we detect a mock + if isinstance(adapter.core_schema, _mock_val_ser.MockCoreSchema): + adapter.core_schema.rebuild() + assert not isinstance(adapter.core_schema, _mock_val_ser.MockCoreSchema), ( + 'this is a bug! please report it' + ) + inputs_.append((key, mode, adapter.core_schema)) + + json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs_) + + json_schema: dict[str, Any] = {} + if definitions: + json_schema['$defs'] = definitions + if title: + json_schema['title'] = title + if description: + json_schema['description'] = description + + return json_schemas_map, json_schema diff --git a/backend/venv/Lib/site-packages/pydantic/types.py b/backend/venv/Lib/site-packages/pydantic/types.py new file mode 100644 index 0000000..59160ab --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/types.py @@ -0,0 +1,3295 @@ +"""The types module contains custom types used by pydantic.""" + +from __future__ import annotations as _annotations + +import base64 +import dataclasses as _dataclasses +import re +from collections.abc import Hashable, Iterator +from datetime import date, datetime +from decimal import Decimal +from enum import Enum +from pathlib import Path +from re import Pattern +from types import ModuleType +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Callable, + ClassVar, + Generic, + Literal, + TypeVar, + Union, + cast, +) +from uuid import UUID + +import annotated_types +from annotated_types import BaseMetadata, MaxLen, MinLen +from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema +from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin +from typing_inspection.introspection import is_union_origin + +from ._internal import _fields, _internal_dataclass, _utils, _validators +from ._migration import getattr_migration +from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from .errors import PydanticUserError +from .json_schema import JsonSchemaValue +from .warnings import PydanticDeprecatedSince20 + +if TYPE_CHECKING: + from ._internal._core_metadata import CoreMetadata + +__all__ = ( + 'Strict', + 'StrictStr', + 'SocketPath', + 'conbytes', + 'conlist', + 'conset', + 'confrozenset', + 'constr', + 'ImportString', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'condecimal', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'UUID6', + 'UUID7', + 'UUID8', + 'FilePath', + 'DirectoryPath', + 'NewPath', + 'Json', + 'Secret', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'PastDatetime', + 'FutureDatetime', + 'condate', + 'AwareDatetime', + 'NaiveDatetime', + 'AllowInfNan', + 'EncoderProtocol', + 'EncodedBytes', + 'EncodedStr', + 'Base64Encoder', + 'Base64Bytes', + 'Base64Str', + 'Base64UrlBytes', + 'Base64UrlStr', + 'GetPydanticSchema', + 'StringConstraints', + 'Tag', + 'Discriminator', + 'JsonValue', + 'OnErrorOmit', + 'FailFast', +) + + +T = TypeVar('T') + + +@_dataclasses.dataclass +class Strict(_fields.PydanticMetadata, BaseMetadata): + """!!! abstract "Usage Documentation" + [Strict Mode with `Annotated` `Strict`](../concepts/strict_mode.md#strict-mode-with-annotated-strict) + + A field metadata class to indicate that a field should be validated in strict mode. + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + strict: Whether to validate the field in strict mode. + + Example: + ```python + from typing import Annotated + + from pydantic.types import Strict + + StrictBool = Annotated[bool, Strict()] + ``` + """ + + strict: bool = True + + def __hash__(self) -> int: + return hash(self.strict) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +StrictBool = Annotated[bool, Strict()] +"""A boolean that must be either ``True`` or ``False``.""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def conint( + *, + strict: bool | None = None, + gt: int | None = None, + ge: int | None = None, + lt: int | None = None, + le: int | None = None, + multiple_of: int | None = None, +) -> type[int]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `conint` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, conint + + class Foo(BaseModel): + bar: conint(strict=True, gt=0) + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[int, Field(strict=True, gt=0)] + ``` + + A wrapper around `int` that allows for additional constraints. + + Args: + strict: Whether to validate the integer in strict mode. Defaults to `None`. + gt: The value must be greater than this. + ge: The value must be greater than or equal to this. + lt: The value must be less than this. + le: The value must be less than or equal to this. + multiple_of: The value must be a multiple of this. + + Returns: + The wrapped integer type. + + ```python + from pydantic import BaseModel, ValidationError, conint + + class ConstrainedExample(BaseModel): + constrained_int: conint(gt=1) + + m = ConstrainedExample(constrained_int=2) + print(repr(m)) + #> ConstrainedExample(constrained_int=2) + + try: + ConstrainedExample(constrained_int=0) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_int',), + 'msg': 'Input should be greater than 1', + 'input': 0, + 'ctx': {'gt': 1}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + int, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + ] + + +PositiveInt = Annotated[int, annotated_types.Gt(0)] +"""An integer that must be greater than zero. + +```python +from pydantic import BaseModel, PositiveInt, ValidationError + +class Model(BaseModel): + positive_int: PositiveInt + +m = Model(positive_int=1) +print(repr(m)) +#> Model(positive_int=1) + +try: + Model(positive_int=-1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('positive_int',), + 'msg': 'Input should be greater than 0', + 'input': -1, + 'ctx': {'gt': 0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' +``` +""" +NegativeInt = Annotated[int, annotated_types.Lt(0)] +"""An integer that must be less than zero. + +```python +from pydantic import BaseModel, NegativeInt, ValidationError + +class Model(BaseModel): + negative_int: NegativeInt + +m = Model(negative_int=-1) +print(repr(m)) +#> Model(negative_int=-1) + +try: + Model(negative_int=1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than', + 'loc': ('negative_int',), + 'msg': 'Input should be less than 0', + 'input': 1, + 'ctx': {'lt': 0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than', + } + ] + ''' +``` +""" +NonPositiveInt = Annotated[int, annotated_types.Le(0)] +"""An integer that must be less than or equal to zero. + +```python +from pydantic import BaseModel, NonPositiveInt, ValidationError + +class Model(BaseModel): + non_positive_int: NonPositiveInt + +m = Model(non_positive_int=0) +print(repr(m)) +#> Model(non_positive_int=0) + +try: + Model(non_positive_int=1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than_equal', + 'loc': ('non_positive_int',), + 'msg': 'Input should be less than or equal to 0', + 'input': 1, + 'ctx': {'le': 0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', + } + ] + ''' +``` +""" +NonNegativeInt = Annotated[int, annotated_types.Ge(0)] +"""An integer that must be greater than or equal to zero. + +```python +from pydantic import BaseModel, NonNegativeInt, ValidationError + +class Model(BaseModel): + non_negative_int: NonNegativeInt + +m = Model(non_negative_int=0) +print(repr(m)) +#> Model(non_negative_int=0) + +try: + Model(non_negative_int=-1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than_equal', + 'loc': ('non_negative_int',), + 'msg': 'Input should be greater than or equal to 0', + 'input': -1, + 'ctx': {'ge': 0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', + } + ] + ''' +``` +""" +StrictInt = Annotated[int, Strict()] +"""An integer that must be validated in strict mode. + +```python +from pydantic import BaseModel, StrictInt, ValidationError + +class StrictIntModel(BaseModel): + strict_int: StrictInt + +try: + StrictIntModel(strict_int=3.14159) +except ValidationError as e: + print(e) + ''' + 1 validation error for StrictIntModel + strict_int + Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float] + ''' +``` +""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass +class AllowInfNan(_fields.PydanticMetadata): + """A field metadata class to indicate that a field should allow `-inf`, `inf`, and `nan`. + + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. Defaults to `True`. + + Example: + ```python + from typing import Annotated + + from pydantic.types import AllowInfNan + + LaxFloat = Annotated[float, AllowInfNan()] + ``` + """ + + allow_inf_nan: bool = True + + def __hash__(self) -> int: + return hash(self.allow_inf_nan) + + +def confloat( + *, + strict: bool | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + multiple_of: float | None = None, + allow_inf_nan: bool | None = None, +) -> type[float]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `confloat` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, confloat + + class Foo(BaseModel): + bar: confloat(strict=True, gt=0) + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[float, Field(strict=True, gt=0)] + ``` + + A wrapper around `float` that allows for additional constraints. + + Args: + strict: Whether to validate the float in strict mode. + gt: The value must be greater than this. + ge: The value must be greater than or equal to this. + lt: The value must be less than this. + le: The value must be less than or equal to this. + multiple_of: The value must be a multiple of this. + allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. + + Returns: + The wrapped float type. + + ```python + from pydantic import BaseModel, ValidationError, confloat + + class ConstrainedExample(BaseModel): + constrained_float: confloat(gt=1.0) + + m = ConstrainedExample(constrained_float=1.1) + print(repr(m)) + #> ConstrainedExample(constrained_float=1.1) + + try: + ConstrainedExample(constrained_float=0.9) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_float',), + 'msg': 'Input should be greater than 1', + 'input': 0.9, + 'ctx': {'gt': 1.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + float, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, + ] + + +PositiveFloat = Annotated[float, annotated_types.Gt(0)] +"""A float that must be greater than zero. + +```python +from pydantic import BaseModel, PositiveFloat, ValidationError + +class Model(BaseModel): + positive_float: PositiveFloat + +m = Model(positive_float=1.0) +print(repr(m)) +#> Model(positive_float=1.0) + +try: + Model(positive_float=-1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('positive_float',), + 'msg': 'Input should be greater than 0', + 'input': -1.0, + 'ctx': {'gt': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' +``` +""" +NegativeFloat = Annotated[float, annotated_types.Lt(0)] +"""A float that must be less than zero. + +```python +from pydantic import BaseModel, NegativeFloat, ValidationError + +class Model(BaseModel): + negative_float: NegativeFloat + +m = Model(negative_float=-1.0) +print(repr(m)) +#> Model(negative_float=-1.0) + +try: + Model(negative_float=1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than', + 'loc': ('negative_float',), + 'msg': 'Input should be less than 0', + 'input': 1.0, + 'ctx': {'lt': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than', + } + ] + ''' +``` +""" +NonPositiveFloat = Annotated[float, annotated_types.Le(0)] +"""A float that must be less than or equal to zero. + +```python +from pydantic import BaseModel, NonPositiveFloat, ValidationError + +class Model(BaseModel): + non_positive_float: NonPositiveFloat + +m = Model(non_positive_float=0.0) +print(repr(m)) +#> Model(non_positive_float=0.0) + +try: + Model(non_positive_float=1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than_equal', + 'loc': ('non_positive_float',), + 'msg': 'Input should be less than or equal to 0', + 'input': 1.0, + 'ctx': {'le': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', + } + ] + ''' +``` +""" +NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] +"""A float that must be greater than or equal to zero. + +```python +from pydantic import BaseModel, NonNegativeFloat, ValidationError + +class Model(BaseModel): + non_negative_float: NonNegativeFloat + +m = Model(non_negative_float=0.0) +print(repr(m)) +#> Model(non_negative_float=0.0) + +try: + Model(non_negative_float=-1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than_equal', + 'loc': ('non_negative_float',), + 'msg': 'Input should be greater than or equal to 0', + 'input': -1.0, + 'ctx': {'ge': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', + } + ] + ''' +``` +""" +StrictFloat = Annotated[float, Strict(True)] +"""A float that must be validated in strict mode. + +```python +from pydantic import BaseModel, StrictFloat, ValidationError + +class StrictFloatModel(BaseModel): + strict_float: StrictFloat + +try: + StrictFloatModel(strict_float='1.0') +except ValidationError as e: + print(e) + ''' + 1 validation error for StrictFloatModel + strict_float + Input should be a valid number [type=float_type, input_value='1.0', input_type=str] + ''' +``` +""" +FiniteFloat = Annotated[float, AllowInfNan(False)] +"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). + +```python +from pydantic import BaseModel, FiniteFloat + +class Model(BaseModel): + finite: FiniteFloat + +m = Model(finite=1.0) +print(m) +#> finite=1.0 +``` +""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def conbytes( + *, + min_length: int | None = None, + max_length: int | None = None, + strict: bool | None = None, +) -> type[bytes]: + """A wrapper around `bytes` that allows for additional constraints. + + Args: + min_length: The minimum length of the bytes. + max_length: The maximum length of the bytes. + strict: Whether to validate the bytes in strict mode. + + Returns: + The wrapped bytes type. + """ + return Annotated[ # pyright: ignore[reportReturnType] + bytes, + Strict(strict) if strict is not None else None, + annotated_types.Len(min_length or 0, max_length), + ] + + +StrictBytes = Annotated[bytes, Strict()] +"""A bytes that must be validated in strict mode.""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass(frozen=True) +class StringConstraints(annotated_types.GroupedMetadata): + """!!! abstract "Usage Documentation" + [String types](./standard_library_types.md#strings) + + A field metadata class to apply constraints to `str` types. + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + strip_whitespace: Whether to remove leading and trailing whitespace. + to_upper: Whether to convert the string to uppercase. + to_lower: Whether to convert the string to lowercase. + strict: Whether to validate the string in strict mode. + min_length: The minimum length of the string. + max_length: The maximum length of the string. + pattern: A regex pattern that the string must match. + + Example: + ```python + from typing import Annotated + + from pydantic.types import StringConstraints + + ConstrainedStr = Annotated[str, StringConstraints(min_length=1, max_length=10)] + ``` + """ + + strip_whitespace: bool | None = None + to_upper: bool | None = None + to_lower: bool | None = None + strict: bool | None = None + min_length: int | None = None + max_length: int | None = None + pattern: str | Pattern[str] | None = None + + def __iter__(self) -> Iterator[BaseMetadata]: + if self.min_length is not None: + yield MinLen(self.min_length) + if self.max_length is not None: + yield MaxLen(self.max_length) + if self.strict is not None: + yield Strict(self.strict) + if ( + self.strip_whitespace is not None + or self.pattern is not None + or self.to_lower is not None + or self.to_upper is not None + ): + yield _fields.pydantic_general_metadata( + strip_whitespace=self.strip_whitespace, + to_upper=self.to_upper, + to_lower=self.to_lower, + pattern=self.pattern, + ) + + +def constr( + *, + strip_whitespace: bool | None = None, + to_upper: bool | None = None, + to_lower: bool | None = None, + strict: bool | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | Pattern[str] | None = None, +) -> type[str]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`StringConstraints`][pydantic.types.StringConstraints] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `constr` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, constr + + class Foo(BaseModel): + bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$') + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, StringConstraints + + class Foo(BaseModel): + bar: Annotated[ + str, + StringConstraints( + strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$' + ), + ] + ``` + + A wrapper around `str` that allows for additional constraints. + + ```python + from pydantic import BaseModel, constr + + class Foo(BaseModel): + bar: constr(strip_whitespace=True, to_upper=True) + + foo = Foo(bar=' hello ') + print(foo) + #> bar='HELLO' + ``` + + Args: + strip_whitespace: Whether to remove leading and trailing whitespace. + to_upper: Whether to turn all characters to uppercase. + to_lower: Whether to turn all characters to lowercase. + strict: Whether to validate the string in strict mode. + min_length: The minimum length of the string. + max_length: The maximum length of the string. + pattern: A regex pattern to validate the string against. + + Returns: + The wrapped string type. + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + str, + StringConstraints( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + strict=strict, + min_length=min_length, + max_length=max_length, + pattern=pattern, + ), + ] + + +StrictStr = Annotated[str, Strict()] +"""A string that must be validated in strict mode.""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +HashableItemType = TypeVar('HashableItemType', bound=Hashable) + + +def conset( + item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None +) -> type[set[HashableItemType]]: + """A wrapper around `typing.Set` that allows for additional constraints. + + Args: + item_type: The type of the items in the set. + min_length: The minimum length of the set. + max_length: The maximum length of the set. + + Returns: + The wrapped set type. + """ + return Annotated[set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +def confrozenset( + item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None +) -> type[frozenset[HashableItemType]]: + """A wrapper around `typing.FrozenSet` that allows for additional constraints. + + Args: + item_type: The type of the items in the frozenset. + min_length: The minimum length of the frozenset. + max_length: The maximum length of the frozenset. + + Returns: + The wrapped frozenset type. + """ + return Annotated[frozenset[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +AnyItemType = TypeVar('AnyItemType') + + +def conlist( + item_type: type[AnyItemType], + *, + min_length: int | None = None, + max_length: int | None = None, + unique_items: bool | None = None, +) -> type[list[AnyItemType]]: + """A wrapper around [`list`][] that adds validation. + + Args: + item_type: The type of the items in the list. + min_length: The minimum length of the list. Defaults to None. + max_length: The maximum length of the list. Defaults to None. + unique_items: Whether the items in the list must be unique. Defaults to None. + !!! warning Deprecated + The `unique_items` parameter is deprecated, use `Set` instead. + See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details. + + Returns: + The wrapped list type. + """ + if unique_items is not None: + raise PydanticUserError( + ( + '`unique_items` is removed, use `Set` instead' + '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)' + ), + code='removed-kwargs', + ) + return Annotated[list[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +AnyType = TypeVar('AnyType') +if TYPE_CHECKING: + ImportString = Annotated[AnyType, ...] +else: + + class ImportString: + """A type that can be used to import a Python object from a string. + + `ImportString` expects a string and loads the Python object importable at that dotted path. + Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` is provided, + the resulting field value would be the function `cos`. If a `.` is used and both an attribute and submodule + are present at the same path, the module will be preferred. + + On model instantiation, pointers will be evaluated and imported. There is + some nuance to this behavior, demonstrated in the examples below. + + ```python + import math + + from pydantic import BaseModel, Field, ImportString, ValidationError + + class ImportThings(BaseModel): + obj: ImportString + + # A string value will cause an automatic import + my_cos = ImportThings(obj='math.cos') + + # You can use the imported function as you would expect + cos_of_0 = my_cos.obj(0) + assert cos_of_0 == 1 + + # A string whose value cannot be imported will raise an error + try: + ImportThings(obj='foo.bar') + except ValidationError as e: + print(e) + ''' + 1 validation error for ImportThings + obj + Invalid python path: No module named 'foo.bar' [type=import_error, input_value='foo.bar', input_type=str] + ''' + + # Actual python objects can be assigned as well + my_cos = ImportThings(obj=math.cos) + my_cos_2 = ImportThings(obj='math.cos') + my_cos_3 = ImportThings(obj='math:cos') + assert my_cos == my_cos_2 == my_cos_3 + + # You can set default field value either as Python object: + class ImportThingsDefaultPyObj(BaseModel): + obj: ImportString = math.cos + + # or as a string value (but only if used with `validate_default=True`) + class ImportThingsDefaultString(BaseModel): + obj: ImportString = Field(default='math.cos', validate_default=True) + + my_cos_default1 = ImportThingsDefaultPyObj() + my_cos_default2 = ImportThingsDefaultString() + assert my_cos_default1.obj == my_cos_default2.obj == math.cos + + # note: this will not work! + class ImportThingsMissingValidateDefault(BaseModel): + obj: ImportString = 'math.cos' + + my_cos_default3 = ImportThingsMissingValidateDefault() + assert my_cos_default3.obj == 'math.cos' # just string, not evaluated + ``` + + Serializing an `ImportString` type to json is also possible. + + ```python + from pydantic import BaseModel, ImportString + + class ImportThings(BaseModel): + obj: ImportString + + # Create an instance + m = ImportThings(obj='math.cos') + print(m) + #> obj= + print(m.model_dump_json()) + #> {"obj":"math.cos"} + ``` + """ + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') + if cls is source: + # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any] + return core_schema.no_info_plain_validator_function( + function=_validators.import_string, serialization=serializer + ) + else: + return core_schema.no_info_before_validator_function( + function=_validators.import_string, schema=handler(source), serialization=serializer + ) + + @classmethod + def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + return handler(core_schema.str_schema()) + + @staticmethod + def _serialize(v: Any) -> str: + if isinstance(v, ModuleType): + return v.__name__ + elif hasattr(v, '__module__') and hasattr(v, '__name__'): + return f'{v.__module__}.{v.__name__}' + # Handle special cases for sys.XXX streams + # if we see more of these, we should consider a more general solution + elif hasattr(v, 'name'): + if v.name == '': + return 'sys.stdout' + elif v.name == '': + return 'sys.stdin' + elif v.name == '': + return 'sys.stderr' + return v + + def __repr__(self) -> str: + return 'ImportString' + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def condecimal( + *, + strict: bool | None = None, + gt: int | Decimal | None = None, + ge: int | Decimal | None = None, + lt: int | Decimal | None = None, + le: int | Decimal | None = None, + multiple_of: int | Decimal | None = None, + max_digits: int | None = None, + decimal_places: int | None = None, + allow_inf_nan: bool | None = None, +) -> type[Decimal]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, condecimal + + class Foo(BaseModel): + bar: condecimal(strict=True, allow_inf_nan=True) + ``` + + === ":white_check_mark: Do this" + ```python + from decimal import Decimal + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)] + ``` + + A wrapper around Decimal that adds validation. + + Args: + strict: Whether to validate the value in strict mode. Defaults to `None`. + gt: The value must be greater than this. Defaults to `None`. + ge: The value must be greater than or equal to this. Defaults to `None`. + lt: The value must be less than this. Defaults to `None`. + le: The value must be less than or equal to this. Defaults to `None`. + multiple_of: The value must be a multiple of this. Defaults to `None`. + max_digits: The maximum number of digits. Defaults to `None`. + decimal_places: The number of decimal places. Defaults to `None`. + allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`. + + ```python + from decimal import Decimal + + from pydantic import BaseModel, ValidationError, condecimal + + class ConstrainedExample(BaseModel): + constrained_decimal: condecimal(gt=Decimal('1.0')) + + m = ConstrainedExample(constrained_decimal=Decimal('1.1')) + print(repr(m)) + #> ConstrainedExample(constrained_decimal=Decimal('1.1')) + + try: + ConstrainedExample(constrained_decimal=Decimal('0.9')) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_decimal',), + 'msg': 'Input should be greater than 1.0', + 'input': Decimal('0.9'), + 'ctx': {'gt': Decimal('1.0')}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + Decimal, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places), + AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, + ] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class UuidVersion: + """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version. + + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + uuid_version: The version of the UUID. Must be one of 1, 3, 4, 5, 6, 7 or 8. + + Example: + ```python + from typing import Annotated + from uuid import UUID + + from pydantic.types import UuidVersion + + UUID1 = Annotated[UUID, UuidVersion(1)] + ``` + """ + + uuid_version: Literal[1, 3, 4, 5, 6, 7, 8] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.pop('anyOf', None) # remove the bytes/str union + field_schema.update(type='string', format=f'uuid{self.uuid_version}') + return field_schema + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) + schema['version'] = self.uuid_version # type: ignore + return schema + + def __hash__(self) -> int: + return hash(type(self.uuid_version)) + + +UUID1 = Annotated[UUID, UuidVersion(1)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. + +```python +import uuid + +from pydantic import UUID1, BaseModel + +class Model(BaseModel): + uuid1: UUID1 + +Model(uuid1=uuid.uuid1()) +``` +""" +UUID3 = Annotated[UUID, UuidVersion(3)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. + +```python +import uuid + +from pydantic import UUID3, BaseModel + +class Model(BaseModel): + uuid3: UUID3 + +Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org')) +``` +""" +UUID4 = Annotated[UUID, UuidVersion(4)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. + +```python +import uuid + +from pydantic import UUID4, BaseModel + +class Model(BaseModel): + uuid4: UUID4 + +Model(uuid4=uuid.uuid4()) +``` +""" +UUID5 = Annotated[UUID, UuidVersion(5)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. + +```python +import uuid + +from pydantic import UUID5, BaseModel + +class Model(BaseModel): + uuid5: UUID5 + +Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org')) +``` +""" +UUID6 = Annotated[UUID, UuidVersion(6)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 6. + +```python +import uuid + +from pydantic import UUID6, BaseModel + +class Model(BaseModel): + uuid6: UUID6 + +Model(uuid6=uuid.UUID('1efea953-c2d6-6790-aa0a-69db8c87df97')) +``` +""" +UUID7 = Annotated[UUID, UuidVersion(7)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 7. + +```python +import uuid + +from pydantic import UUID7, BaseModel + +class Model(BaseModel): + uuid7: UUID7 + +Model(uuid7=uuid.UUID('0194fdcb-1c47-7a09-b52c-561154de0b4a')) +``` +""" +UUID8 = Annotated[UUID, UuidVersion(8)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 8. + +```python +import uuid + +from pydantic import UUID8, BaseModel + +class Model(BaseModel): + uuid8: UUID8 + +Model(uuid8=uuid.UUID('81a0b92e-6078-8551-9c81-8ccb666bdab8')) +``` +""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass +class PathType: + path_type: Literal['file', 'dir', 'new', 'socket'] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + format_conversion = {'file': 'file-path', 'dir': 'directory-path'} + field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') + return field_schema + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + function_lookup = { + 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file), + 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory), + 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new), + 'socket': cast(core_schema.WithInfoValidatorFunction, self.validate_socket), + } + + return core_schema.with_info_after_validator_function( + function_lookup[self.path_type], + handler(source), + ) + + @staticmethod + def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_file(): + return path + else: + raise PydanticCustomError('path_not_file', 'Path does not point to a file') + + @staticmethod + def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_socket(): + return path + else: + raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') + + @staticmethod + def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_dir(): + return path + else: + raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') + + @staticmethod + def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.exists(): + raise PydanticCustomError('path_exists', 'Path already exists') + elif not path.parent.exists(): + raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') + else: + return path + + def __hash__(self) -> int: + return hash(type(self.path_type)) + + +FilePath = Annotated[Path, PathType('file')] +"""A path that must point to a file. + +```python +from pathlib import Path + +from pydantic import BaseModel, FilePath, ValidationError + +class Model(BaseModel): + f: FilePath + +path = Path('text.txt') +path.touch() +m = Model(f='text.txt') +print(m.model_dump()) +#> {'f': PosixPath('text.txt')} +path.unlink() + +path = Path('directory') +path.mkdir(exist_ok=True) +try: + Model(f='directory') # directory +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a file [type=path_not_file, input_value='directory', input_type=str] + ''' +path.rmdir() + +try: + Model(f='not-exists-file') +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str] + ''' +``` +""" +DirectoryPath = Annotated[Path, PathType('dir')] +"""A path that must point to a directory. + +```python +from pathlib import Path + +from pydantic import BaseModel, DirectoryPath, ValidationError + +class Model(BaseModel): + f: DirectoryPath + +path = Path('directory/') +path.mkdir() +m = Model(f='directory/') +print(m.model_dump()) +#> {'f': PosixPath('directory')} +path.rmdir() + +path = Path('file.txt') +path.touch() +try: + Model(f='file.txt') # file +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str] + ''' +path.unlink() + +try: + Model(f='not-exists-directory') +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str] + ''' +``` +""" +NewPath = Annotated[Path, PathType('new')] +"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" + +SocketPath = Annotated[Path, PathType('socket')] +"""A path to an existing socket file""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + # Json[list[str]] will be recognized by type checkers as list[str] + Json = Annotated[AnyType, ...] + +else: + + class Json: + """A special type wrapper which loads JSON before parsing. + + You can use the `Json` data type to make Pydantic first load a raw JSON string before + validating the loaded data into the parametrized type: + + ```python + from typing import Any + + from pydantic import BaseModel, Json, ValidationError + + class AnyJsonModel(BaseModel): + json_obj: Json[Any] + + class ConstrainedJsonModel(BaseModel): + json_obj: Json[list[int]] + + print(AnyJsonModel(json_obj='{"b": 1}')) + #> json_obj={'b': 1} + print(ConstrainedJsonModel(json_obj='[1, 2, 3]')) + #> json_obj=[1, 2, 3] + + try: + ConstrainedJsonModel(json_obj=12) + except ValidationError as e: + print(e) + ''' + 1 validation error for ConstrainedJsonModel + json_obj + JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int] + ''' + + try: + ConstrainedJsonModel(json_obj='[a, b]') + except ValidationError as e: + print(e) + ''' + 1 validation error for ConstrainedJsonModel + json_obj + Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str] + ''' + + try: + ConstrainedJsonModel(json_obj='["a", "b"]') + except ValidationError as e: + print(e) + ''' + 2 validation errors for ConstrainedJsonModel + json_obj.0 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + json_obj.1 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str] + ''' + ``` + + When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation, + not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back: + + ```python + from pydantic import BaseModel, Json + + class ConstrainedJsonModel(BaseModel): + json_obj: Json[list[int]] + + print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json()) + #> {"json_obj":[1,2,3]} + print( + ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True) + ) + #> {"json_obj":"[1,2,3]"} + ``` + """ + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + if cls is source: + return core_schema.json_schema(None) + else: + return core_schema.json_schema(handler(source)) + + def __repr__(self) -> str: + return 'Json' + + def __hash__(self) -> int: + return hash(type(self)) + + def __eq__(self, other: Any) -> bool: + return type(other) is type(self) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# The `Secret` class being conceptually immutable, make the type variable covariant: +SecretType = TypeVar('SecretType', covariant=True) + + +class _SecretBase(Generic[SecretType]): + def __init__(self, secret_value: SecretType) -> None: + self._secret_value: SecretType = secret_value + + def get_secret_value(self) -> SecretType: + """Get the secret value. + + Returns: + The secret value. + """ + return self._secret_value + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() + + def __hash__(self) -> int: + return hash(self.get_secret_value()) + + def __str__(self) -> str: + return str(self._display()) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({self._display()!r})' + + def _display(self) -> str | bytes: + raise NotImplementedError + + +def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: + if info.mode == 'json': + return str(value) + else: + return value + + +class Secret(_SecretBase[SecretType]): + """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks. + + You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing + is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both + ways of using `Secret` to create a new secret type. + + 1. Directly parametrizing `Secret` with a type: + + ```python + from pydantic import BaseModel, Secret + + SecretBool = Secret[bool] + + class Model(BaseModel): + secret_bool: SecretBool + + m = Model(secret_bool=True) + print(m.model_dump()) + #> {'secret_bool': Secret('**********')} + + print(m.model_dump_json()) + #> {"secret_bool":"**********"} + + print(m.secret_bool.get_secret_value()) + #> True + ``` + + 2. Subclassing from parametrized `Secret`: + + ```python + from datetime import date + + from pydantic import BaseModel, Secret + + class SecretDate(Secret[date]): + def _display(self) -> str: + return '****/**/**' + + class Model(BaseModel): + secret_date: SecretDate + + m = Model(secret_date=date(2022, 1, 1)) + print(m.model_dump()) + #> {'secret_date': SecretDate('****/**/**')} + + print(m.model_dump_json()) + #> {"secret_date":"****/**/**"} + + print(m.secret_date.get_secret_value()) + #> 2022-01-01 + ``` + + The value returned by the `_display` method will be used for `repr()` and `str()`. + + You can enforce constraints on the underlying type through annotations: + For example: + + ```python + from typing import Annotated + + from pydantic import BaseModel, Field, Secret, ValidationError + + SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]] + + class Model(BaseModel): + sensitive_int: SecretPosInt + + m = Model(sensitive_int=42) + print(m.model_dump()) + #> {'sensitive_int': Secret('**********')} + + try: + m = Model(sensitive_int=-42) # (1)! + except ValidationError as exc_info: + print(exc_info.errors(include_url=False, include_input=False)) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('sensitive_int',), + 'msg': 'Input should be greater than 0', + 'ctx': {'gt': 0}, + } + ] + ''' + + try: + m = Model(sensitive_int='42') # (2)! + except ValidationError as exc_info: + print(exc_info.errors(include_url=False, include_input=False)) + ''' + [ + { + 'type': 'int_type', + 'loc': ('sensitive_int',), + 'msg': 'Input should be a valid integer', + } + ] + ''' + ``` + + 1. The input value is not greater than 0, so it raises a validation error. + 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled. + """ + + def _display(self) -> str | bytes: + return '**********' if self.get_secret_value() else '' + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + inner_type = None + # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly + origin_type = get_origin(source) + if origin_type is not None: + inner_type = get_args(source)[0] + # otherwise, we need to get the inner type from the base class + else: + bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) + for base in bases: + if get_origin(base) is Secret: + inner_type = get_args(base)[0] + if bases == [] or inner_type is None: + raise TypeError( + f"Can't get secret type from {cls.__name__}. " + 'Please use Secret[], or subclass from Secret[] instead.' + ) + + inner_schema = handler.generate_schema(inner_type) # type: ignore + + def validate_secret_value(value, handler) -> Secret[SecretType]: + if isinstance(value, Secret): + value = value.get_secret_value() + validated_inner = handler(value) + return cls(validated_inner) + + return core_schema.json_or_python_schema( + python_schema=core_schema.no_info_wrap_validator_function( + validate_secret_value, + inner_schema, + ), + json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema), + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret, + info_arg=True, + when_used='always', + ), + ) + + __pydantic_serializer__ = SchemaSerializer( + core_schema.any_schema( + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret, + info_arg=True, + when_used='always', + ) + ) + ) + + +def _secret_display(value: SecretType) -> str: # type: ignore + return '**********' if value else '' + + +def _serialize_secret_field( + value: _SecretField[SecretType], info: core_schema.SerializationInfo +) -> str | _SecretField[SecretType]: + if info.mode == 'json': + # we want the output to always be string without the `b'` prefix for bytes, + # hence we just use `secret_display` + return _secret_display(value.get_secret_value()) + else: + return value + + +class _SecretField(_SecretBase[SecretType]): + _inner_schema: ClassVar[CoreSchema] + _error_kind: ClassVar[str] + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(cls._inner_schema) + _utils.update_not_none( + json_schema, + type='string', + writeOnly=True, + format='password', + ) + return json_schema + + def get_secret_schema(strict: bool) -> CoreSchema: + inner_schema = {**cls._inner_schema, 'strict': strict} + json_schema = core_schema.no_info_after_validator_function( + source, # construct the type + inner_schema, # pyright: ignore[reportArgumentType] + ) + return core_schema.json_or_python_schema( + python_schema=core_schema.union_schema( + [ + core_schema.is_instance_schema(source), + json_schema, + ], + custom_error_type=cls._error_kind, + ), + json_schema=json_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret_field, + info_arg=True, + when_used='always', + ), + ) + + return core_schema.lax_or_strict_schema( + lax_schema=get_secret_schema(strict=False), + strict_schema=get_secret_schema(strict=True), + metadata={'pydantic_js_functions': [get_json_schema]}, + ) + + __pydantic_serializer__ = SchemaSerializer( + core_schema.any_schema( + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret_field, + info_arg=True, + when_used='always', + ) + ) + ) + + +class SecretStr(_SecretField[str]): + """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks. + + When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in + calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`. + + ```python + from pydantic import BaseModel, SecretStr + + class User(BaseModel): + username: str + password: SecretStr + + user = User(username='scolvin', password='password1') + + print(user) + #> username='scolvin' password=SecretStr('**********') + print(user.password.get_secret_value()) + #> password1 + print((SecretStr('password'), SecretStr(''))) + #> (SecretStr('**********'), SecretStr('')) + ``` + + As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes]) + will be serialized as `**********` when serializing to json. + + You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the + secret as plain-text when serializing to json. + + ```python + from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer + + class Model(BaseModel): + password: SecretStr + password_bytes: SecretBytes + + @field_serializer('password', 'password_bytes', when_used='json') + def dump_secret(self, v): + return v.get_secret_value() + + model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes') + print(model) + #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********') + print(model.password) + #> ********** + print(model.model_dump()) + ''' + { + 'password': SecretStr('**********'), + 'password_bytes': SecretBytes(b'**********'), + } + ''' + print(model.model_dump_json()) + #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"} + ``` + """ + + _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() + _error_kind: ClassVar[str] = 'string_type' + + def __len__(self) -> int: + return len(self._secret_value) + + def _display(self) -> str: + return _secret_display(self._secret_value) + + +class SecretBytes(_SecretField[bytes]): + """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks. + + It displays `b'**********'` instead of the string value on `repr()` and `str()` calls. + When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in + calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`. + + ```python + from pydantic import BaseModel, SecretBytes + + class User(BaseModel): + username: str + password: SecretBytes + + user = User(username='scolvin', password=b'password1') + #> username='scolvin' password=SecretBytes(b'**********') + print(user.password.get_secret_value()) + #> b'password1' + print((SecretBytes(b'password'), SecretBytes(b''))) + #> (SecretBytes(b'**********'), SecretBytes(b'')) + ``` + """ + + _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() + _error_kind: ClassVar[str] = 'bytes_type' + + def __len__(self) -> int: + return len(self._secret_value) + + def _display(self) -> bytes: + return _secret_display(self._secret_value).encode() + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class PaymentCardBrand(str, Enum): + amex = 'American Express' + mastercard = 'Mastercard' + visa = 'Visa' + other = 'other' + + def __str__(self) -> str: + return self.value + + +@deprecated( + 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. ' + 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.', + category=PydanticDeprecatedSince20, +) +class PaymentCardNumber(str): + """Based on: https://en.wikipedia.org/wiki/Payment_card_number.""" + + strip_whitespace: ClassVar[bool] = True + min_length: ClassVar[int] = 12 + max_length: ClassVar[int] = 19 + bin: str + last4: str + brand: PaymentCardBrand + + def __init__(self, card_number: str): + self.validate_digits(card_number) + + card_number = self.validate_luhn_check_digit(card_number) + + self.bin = card_number[:6] + self.last4 = card_number[-4:] + self.brand = self.validate_brand(card_number) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + return core_schema.with_info_after_validator_function( + cls.validate, + core_schema.str_schema( + min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace + ), + ) + + @classmethod + def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: + """Validate the card number and return a `PaymentCardNumber` instance.""" + return cls(input_value) + + @property + def masked(self) -> str: + """Mask all but the last 4 digits of the card number. + + Returns: + A masked card number string. + """ + num_masked = len(self) - 10 # len(bin) + len(last4) == 10 + return f'{self.bin}{"*" * num_masked}{self.last4}' + + @classmethod + def validate_digits(cls, card_number: str) -> None: + """Validate that the card number is all digits.""" + if not card_number.isdigit(): + raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') + + @classmethod + def validate_luhn_check_digit(cls, card_number: str) -> str: + """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm.""" + sum_ = int(card_number[-1]) + length = len(card_number) + parity = length % 2 + for i in range(length - 1): + digit = int(card_number[i]) + if i % 2 == parity: + digit *= 2 + if digit > 9: + digit -= 9 + sum_ += digit + valid = sum_ % 10 == 0 + if not valid: + raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') + return card_number + + @staticmethod + def validate_brand(card_number: str) -> PaymentCardBrand: + """Validate length based on BIN for major brands: + https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN). + """ + if card_number[0] == '4': + brand = PaymentCardBrand.visa + elif 51 <= int(card_number[:2]) <= 55: + brand = PaymentCardBrand.mastercard + elif card_number[:2] in {'34', '37'}: + brand = PaymentCardBrand.amex + else: + brand = PaymentCardBrand.other + + required_length: None | int | str = None + if brand in PaymentCardBrand.mastercard: + required_length = 16 + valid = len(card_number) == required_length + elif brand == PaymentCardBrand.visa: + required_length = '13, 16 or 19' + valid = len(card_number) in {13, 16, 19} + elif brand == PaymentCardBrand.amex: + required_length = 15 + valid = len(card_number) == required_length + else: + valid = True + + if not valid: + raise PydanticCustomError( + 'payment_card_number_brand', + 'Length for a {brand} card must be {required_length}', + {'brand': brand, 'required_length': required_length}, + ) + return brand + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ByteSize(int): + """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer. + + You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into + an integer, and also to print out human-readable strings representing a number of bytes. + + In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes, + and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2, + rather than a power of 10 (so, for example, `'1 MB'` is treated as `1_000_000` bytes, whereas `'1 MiB'` is treated as `1_048_576` bytes). + + !!! info + Note that `1b` will be parsed as "1 byte" and not "1 bit". + + ```python + from pydantic import BaseModel, ByteSize + + class MyModel(BaseModel): + size: ByteSize + + print(MyModel(size=52000).size) + #> 52000 + print(MyModel(size='3000 KiB').size) + #> 3072000 + + m = MyModel(size='50 PB') + print(m.size.human_readable()) + #> 44.4PiB + print(m.size.human_readable(decimal=True)) + #> 50.0PB + print(m.size.human_readable(separator=' ')) + #> 44.4 PiB + + print(m.size.to('TiB')) + #> 45474.73508864641 + ``` + """ + + byte_sizes = { + 'b': 1, + 'kb': 10**3, + 'mb': 10**6, + 'gb': 10**9, + 'tb': 10**12, + 'pb': 10**15, + 'eb': 10**18, + 'kib': 2**10, + 'mib': 2**20, + 'gib': 2**30, + 'tib': 2**40, + 'pib': 2**50, + 'eib': 2**60, + 'bit': 1 / 8, + 'kbit': 10**3 / 8, + 'mbit': 10**6 / 8, + 'gbit': 10**9 / 8, + 'tbit': 10**12 / 8, + 'pbit': 10**15 / 8, + 'ebit': 10**18 / 8, + 'kibit': 2**10 / 8, + 'mibit': 2**20 / 8, + 'gibit': 2**30 / 8, + 'tibit': 2**40 / 8, + 'pibit': 2**50 / 8, + 'eibit': 2**60 / 8, + } + byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) + + byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' + byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + return core_schema.with_info_after_validator_function( + function=cls._validate, + schema=core_schema.union_schema( + [ + core_schema.str_schema(pattern=cls.byte_string_pattern), + core_schema.int_schema(ge=0), + ], + custom_error_type='byte_size', + custom_error_message='could not parse value and unit from byte string', + ), + serialization=core_schema.plain_serializer_function_ser_schema( + int, return_schema=core_schema.int_schema(ge=0) + ), + ) + + @classmethod + def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: + try: + return cls(int(input_value)) + except ValueError: + pass + + str_match = cls.byte_string_re.match(str(input_value)) + if str_match is None: + raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string') + + scalar, unit = str_match.groups() + if unit is None: + unit = 'b' + + try: + unit_mult = cls.byte_sizes[unit.lower()] + except KeyError: + raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) + + return cls(int(float(scalar) * unit_mult)) + + def human_readable(self, decimal: bool = False, separator: str = '') -> str: + """Converts a byte size to a human readable string. + + Args: + decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units + (e.g. 1024 bytes per KiB). + separator: A string used to split the value and unit. Defaults to an empty string (''). + + Returns: + A human readable string representation of the byte size. + """ + if decimal: + divisor = 1000 + units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' + final_unit = 'EB' + else: + divisor = 1024 + units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' + final_unit = 'EiB' + + num = float(self) + for unit in units: + if abs(num) < divisor: + if unit == 'B': + return f'{num:0.0f}{separator}{unit}' + else: + return f'{num:0.1f}{separator}{unit}' + num /= divisor + + return f'{num:0.1f}{separator}{final_unit}' + + def to(self, unit: str) -> float: + """Converts a byte size to another unit, including both byte and bit units. + + Args: + unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB, + KiB, MiB, GiB, TiB, PiB, EiB (byte units) and + bit, kbit, mbit, gbit, tbit, pbit, ebit, + kibit, mibit, gibit, tibit, pibit, eibit (bit units). + + Returns: + The byte size in the new unit. + """ + try: + unit_div = self.byte_sizes[unit.lower()] + except KeyError: + raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) + + return self / unit_div + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: + if annotated_type != expected_type: + raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') + + +if TYPE_CHECKING: + PastDate = Annotated[date, ...] + FutureDate = Annotated[date, ...] +else: + + class PastDate: + """A date in the past.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.date_schema(now_op='past') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'date', cls.__name__) + schema['now_op'] = 'past' + return schema + + def __repr__(self) -> str: + return 'PastDate' + + class FutureDate: + """A date in the future.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.date_schema(now_op='future') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'date', cls.__name__) + schema['now_op'] = 'future' + return schema + + def __repr__(self) -> str: + return 'FutureDate' + + +def condate( + *, + strict: bool | None = None, + gt: date | None = None, + ge: date | None = None, + lt: date | None = None, + le: date | None = None, +) -> type[date]: + """A wrapper for date that adds constraints. + + Args: + strict: Whether to validate the date value in strict mode. Defaults to `None`. + gt: The value must be greater than this. Defaults to `None`. + ge: The value must be greater than or equal to this. Defaults to `None`. + lt: The value must be less than this. Defaults to `None`. + le: The value must be less than or equal to this. Defaults to `None`. + + Returns: + A date type with the specified constraints. + """ + return Annotated[ # pyright: ignore[reportReturnType] + date, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + ] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + AwareDatetime = Annotated[datetime, ...] + NaiveDatetime = Annotated[datetime, ...] + PastDatetime = Annotated[datetime, ...] + FutureDatetime = Annotated[datetime, ...] + +else: + + class AwareDatetime: + """A datetime that requires timezone info.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(tz_constraint='aware') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['tz_constraint'] = 'aware' + return schema + + def __repr__(self) -> str: + return 'AwareDatetime' + + class NaiveDatetime: + """A datetime that doesn't require timezone info.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(tz_constraint='naive') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['tz_constraint'] = 'naive' + return schema + + def __repr__(self) -> str: + return 'NaiveDatetime' + + class PastDatetime: + """A datetime that must be in the past.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(now_op='past') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['now_op'] = 'past' + return schema + + def __repr__(self) -> str: + return 'PastDatetime' + + class FutureDatetime: + """A datetime that must be in the future.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(now_op='future') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['now_op'] = 'future' + return schema + + def __repr__(self) -> str: + return 'FutureDatetime' + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class EncoderProtocol(Protocol): + """Protocol for encoding and decoding data to and from bytes.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data using the encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + ... + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data using the encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + ... + + @classmethod + def get_json_format(cls) -> str: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + ... + + +class Base64Encoder(EncoderProtocol): + """Standard (non-URL-safe) Base64 encoder.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data from base64 encoded bytes to original bytes data. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + try: + return base64.b64decode(data) + except ValueError as e: + raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data from bytes to a base64 encoded bytes. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return base64.b64encode(value) + + @classmethod + def get_json_format(cls) -> Literal['base64']: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + return 'base64' + + +class Base64UrlEncoder(EncoderProtocol): + """URL-safe Base64 encoder.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data from base64 encoded bytes to original bytes data. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + try: + return base64.urlsafe_b64decode(data) + except ValueError as e: + raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data from bytes to a base64 encoded bytes. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return base64.urlsafe_b64encode(value) + + @classmethod + def get_json_format(cls) -> Literal['base64url']: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + return 'base64url' + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class EncodedBytes: + """A bytes type that is encoded and decoded using the specified encoder. + + `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate. + + ```python + from typing import Annotated + + from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError + + class MyEncoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + if data == b'**undecodable**': + raise ValueError('Cannot decode data') + return data[13:] + + @classmethod + def encode(cls, value: bytes) -> bytes: + return b'**encoded**: ' + value + + @classmethod + def get_json_format(cls) -> str: + return 'my-encoder' + + MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)] + + class Model(BaseModel): + my_encoded_bytes: MyEncodedBytes + + # Initialize the model with encoded data + m = Model(my_encoded_bytes=b'**encoded**: some bytes') + + # Access decoded value + print(m.my_encoded_bytes) + #> b'some bytes' + + # Serialize into the encoded form + print(m.model_dump()) + #> {'my_encoded_bytes': b'**encoded**: some bytes'} + + # Validate encoded data + try: + Model(my_encoded_bytes=b'**undecodable**') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + my_encoded_bytes + Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes] + ''' + ``` + """ + + encoder: type[EncoderProtocol] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format=self.encoder.get_json_format()) + return field_schema + + def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) + return core_schema.with_info_after_validator_function( + function=self.decode, + schema=schema, + serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode), + ) + + def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: + """Decode the data using the specified encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + return self.encoder.decode(data) + + def encode(self, value: bytes) -> bytes: + """Encode the data using the specified encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return self.encoder.encode(value) + + def __hash__(self) -> int: + return hash(self.encoder) + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class EncodedStr: + """A str type that is encoded and decoded using the specified encoder. + + `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate. + + ```python + from typing import Annotated + + from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError + + class MyEncoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + if data == b'**undecodable**': + raise ValueError('Cannot decode data') + return data[13:] + + @classmethod + def encode(cls, value: bytes) -> bytes: + return b'**encoded**: ' + value + + @classmethod + def get_json_format(cls) -> str: + return 'my-encoder' + + MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)] + + class Model(BaseModel): + my_encoded_str: MyEncodedStr + + # Initialize the model with encoded data + m = Model(my_encoded_str='**encoded**: some str') + + # Access decoded value + print(m.my_encoded_str) + #> some str + + # Serialize into the encoded form + print(m.model_dump()) + #> {'my_encoded_str': '**encoded**: some str'} + + # Validate encoded data + try: + Model(my_encoded_str='**undecodable**') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + my_encoded_str + Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str] + ''' + ``` + """ + + encoder: type[EncoderProtocol] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format=self.encoder.get_json_format()) + return field_schema + + def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'str', self.__class__.__name__) + return core_schema.with_info_after_validator_function( + function=self.decode_str, + schema=schema, + serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str), + ) + + def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: + """Decode the data using the specified encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + return self.encoder.decode(data.encode()).decode() + + def encode_str(self, value: str) -> str: + """Encode the data using the specified encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return self.encoder.encode(value.encode()).decode() # noqa: UP008 + + def __hash__(self) -> int: + return hash(self.encoder) + + +Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] +"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. + +Note: + Under the hood, `Base64Bytes` uses the standard library `base64.b64encode` and `base64.b64decode` functions. + + As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect + decoding. + +Warning: + In versions of Pydantic prior to v2.10, `Base64Bytes` used [`base64.encodebytes`][base64.encodebytes] + and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html), + these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern + [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions. + + If you'd still like to use these legacy encoders / decoders, you can achieve this by creating a custom annotated type, + like follows: + + ```python + import base64 + from typing import Annotated, Literal + + from pydantic_core import PydanticCustomError + + from pydantic import EncodedBytes, EncoderProtocol + + class LegacyBase64Encoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + try: + return base64.decodebytes(data) + except ValueError as e: + raise PydanticCustomError( + 'base64_decode', + "Base64 decoding error: '{error}'", + {'error': str(e)}, + ) + + @classmethod + def encode(cls, value: bytes) -> bytes: + return base64.encodebytes(value) + + @classmethod + def get_json_format(cls) -> Literal['base64']: + return 'base64' + + LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)] + ``` + +```python +from pydantic import Base64Bytes, BaseModel, ValidationError + +class Model(BaseModel): + base64_bytes: Base64Bytes + +# Initialize the model with base64 data +m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5') + +# Access decoded value +print(m.base64_bytes) +#> b'This is the way' + +# Serialize into the base64 form +print(m.model_dump()) +#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'} + +# Validate base64 data +try: + print(Model(base64_bytes=b'undecodable').base64_bytes) +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + base64_bytes + Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes] + ''' +``` +""" +Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] +"""A str type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. + +Note: + Under the hood, `Base64Str` uses the standard library `base64.b64encode` and `base64.b64decode` functions. + + As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect + decoding. + +Warning: + In versions of Pydantic prior to v2.10, `Base64Str` used [`base64.encodebytes`][base64.encodebytes] + and [`base64.decodebytes`][base64.decodebytes] functions. According to the [base64 documentation](https://docs.python.org/3/library/base64.html), + these methods are considered legacy implementation, and thus, Pydantic v2.10+ now uses the modern + [`base64.b64encode`][base64.b64encode] and [`base64.b64decode`][base64.b64decode] functions. + + See the [`Base64Bytes`][pydantic.types.Base64Bytes] type for more information on how to + replicate the old behavior with the legacy encoders / decoders. + +```python +from pydantic import Base64Str, BaseModel, ValidationError + +class Model(BaseModel): + base64_str: Base64Str + +# Initialize the model with base64 data +m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') + +# Access decoded value +print(m.base64_str) +#> These aren't the droids you're looking for + +# Serialize into the base64 form +print(m.model_dump()) +#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'} + +# Validate base64 data +try: + print(Model(base64_str='undecodable').base64_str) +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + base64_str + Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str] + ''' +``` +""" +Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] +"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. + +Note: + Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` + functions. + + As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data + (using `'+'` and `'/'`). + +```python +from pydantic import Base64UrlBytes, BaseModel + +class Model(BaseModel): + base64url_bytes: Base64UrlBytes + +# Initialize the model with base64 data +m = Model(base64url_bytes=b'SHc_dHc-TXc==') +print(m) +#> base64url_bytes=b'Hw?tw>Mw' +``` +""" +Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] +"""A str type that is encoded and decoded using the URL-safe base64 encoder. + +Note: + Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` + functions. + + As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`). + +```python +from pydantic import Base64UrlStr, BaseModel + +class Model(BaseModel): + base64url_str: Base64UrlStr + +# Initialize the model with base64 data +m = Model(base64url_str='SHc_dHc-TXc==') +print(m) +#> base64url_str='Hw?tw>Mw' +``` +""" + + +__getattr__ = getattr_migration(__name__) + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class GetPydanticSchema: + """!!! abstract "Usage Documentation" + [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate) + + A convenience class for creating an annotation that provides pydantic custom type hooks. + + This class is intended to eliminate the need to create a custom "marker" which defines the + `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods. + + For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do: + ```python + from typing import Annotated, Any + + from pydantic import BaseModel, GetPydanticSchema + + HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any)) + + class Model(BaseModel): + x: Annotated[int, HandleAsAny] # pydantic sees `x: Any` + + print(repr(Model(x='abc').x)) + #> 'abc' + ``` + """ + + get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None + get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None + + # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:` + # which returns `GetPydanticSchema(lambda _s, h: h(type_))` + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls.""" + if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: + return self.get_pydantic_core_schema + elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: + return self.get_pydantic_json_schema + else: + return object.__getattribute__(self, item) + + __hash__ = object.__hash__ + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class Tag: + """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union. + + Also provides a way to label a union case in error messages. + + When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that + should be used to identify that case. For example, in the below example, the `Tag` is used to specify that + if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it + returns `'pumpkin'`, the input should be validated as a `PumpkinPie`. + + The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to + the appropriate member of the `Union` in question. + + ```python + from typing import Annotated, Any, Literal, Union + + from pydantic import BaseModel, Discriminator, Tag + + class Pie(BaseModel): + time_to_cook: int + num_ingredients: int + + class ApplePie(Pie): + fruit: Literal['apple'] = 'apple' + + class PumpkinPie(Pie): + filling: Literal['pumpkin'] = 'pumpkin' + + def get_discriminator_value(v: Any) -> str: + if isinstance(v, dict): + return v.get('fruit', v.get('filling')) + return getattr(v, 'fruit', getattr(v, 'filling', None)) + + class ThanksgivingDinner(BaseModel): + dessert: Annotated[ + Union[ + Annotated[ApplePie, Tag('apple')], + Annotated[PumpkinPie, Tag('pumpkin')], + ], + Discriminator(get_discriminator_value), + ] + + apple_variation = ThanksgivingDinner.model_validate( + {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} + ) + print(repr(apple_variation)) + ''' + ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) + ''' + + pumpkin_variation = ThanksgivingDinner.model_validate( + { + 'dessert': { + 'filling': 'pumpkin', + 'time_to_cook': 40, + 'num_ingredients': 6, + } + } + ) + print(repr(pumpkin_variation)) + ''' + ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) + ''' + ``` + + !!! note + You must specify a `Tag` for every case in a `Tag` that is associated with a + callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code + [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag). + + See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s. + + [Discriminated Unions]: ../concepts/unions.md#discriminated-unions + """ + + tag: str + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + schema = handler(source_type) + metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) + metadata['pydantic_internal_union_tag_key'] = self.tag + return schema + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class Discriminator: + """!!! abstract "Usage Documentation" + [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator) + + Provides a way to use a custom callable as the way to extract the value of a union discriminator. + + This allows you to get validation behavior like you'd get from `Field(discriminator=)`, + but without needing to have a single shared field across all the union choices. This also makes it + possible to handle unions of models and primitive types with discriminated-union-style validation errors. + Finally, this allows you to use a custom callable as the way to identify which member of a union a value + belongs to, while still seeing all the performance benefits of a discriminated union. + + Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion` + than it would be as a normal `Union`. + + ```python + from typing import Annotated, Any, Literal, Union + + from pydantic import BaseModel, Discriminator, Tag + + class Pie(BaseModel): + time_to_cook: int + num_ingredients: int + + class ApplePie(Pie): + fruit: Literal['apple'] = 'apple' + + class PumpkinPie(Pie): + filling: Literal['pumpkin'] = 'pumpkin' + + def get_discriminator_value(v: Any) -> str: + if isinstance(v, dict): + return v.get('fruit', v.get('filling')) + return getattr(v, 'fruit', getattr(v, 'filling', None)) + + class ThanksgivingDinner(BaseModel): + dessert: Annotated[ + Union[ + Annotated[ApplePie, Tag('apple')], + Annotated[PumpkinPie, Tag('pumpkin')], + ], + Discriminator(get_discriminator_value), + ] + + apple_variation = ThanksgivingDinner.model_validate( + {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} + ) + print(repr(apple_variation)) + ''' + ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) + ''' + + pumpkin_variation = ThanksgivingDinner.model_validate( + { + 'dessert': { + 'filling': 'pumpkin', + 'time_to_cook': 40, + 'num_ingredients': 6, + } + } + ) + print(repr(pumpkin_variation)) + ''' + ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) + ''' + ``` + + See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s. + + [Discriminated Unions]: ../concepts/unions.md#discriminated-unions + """ + + discriminator: str | Callable[[Any], Hashable] + """The callable or field name for discriminating the type in a tagged union. + + A `Callable` discriminator must extract the value of the discriminator from the input. + A `str` discriminator must be the name of a field to discriminate against. + """ + custom_error_type: str | None = None + """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union + validation errors. + """ + custom_error_message: str | None = None + """Message to use in custom errors.""" + custom_error_context: dict[str, int | str | float] | None = None + """Context to use in custom errors.""" + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + if not is_union_origin(get_origin(source_type)): + raise TypeError(f'{type(self).__name__} must be used with a Union type, not {source_type}') + + if isinstance(self.discriminator, str): + from pydantic import Field + + return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) + else: + original_schema = handler(source_type) + return self._convert_schema(original_schema, handler) + + def _convert_schema( + self, original_schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler | None = None + ) -> core_schema.TaggedUnionSchema: + if original_schema['type'] != 'union': + # This likely indicates that the schema was a single-item union that was simplified. + # In this case, we do the same thing we do in + # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely, + # package the generated schema back into a single-item union. + original_schema = core_schema.union_schema([original_schema]) + + tagged_union_choices = {} + for choice in original_schema['choices']: + tag = None + if isinstance(choice, tuple): + choice, tag = choice + metadata = cast('CoreMetadata | None', choice.get('metadata')) + if metadata is not None: + tag = metadata.get('pydantic_internal_union_tag_key') or tag + if tag is None: + # `handler` is None when this method is called from `apply_discriminator()` (deferred discriminators) + if handler is not None and choice['type'] == 'definition-ref': + # If choice was built from a PEP 695 type alias, try to resolve the def: + try: + choice = handler.resolve_ref_schema(choice) + except LookupError: + pass + else: + metadata = cast('CoreMetadata | None', choice.get('metadata')) + if metadata is not None: + tag = metadata.get('pydantic_internal_union_tag_key') + + if tag is None: + raise PydanticUserError( + f'`Tag` not provided for choice {choice} used with `Discriminator`', + code='callable-discriminator-no-tag', + ) + tagged_union_choices[tag] = choice + + # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored + custom_error_type = self.custom_error_type + if custom_error_type is None: + custom_error_type = original_schema.get('custom_error_type') + + custom_error_message = self.custom_error_message + if custom_error_message is None: + custom_error_message = original_schema.get('custom_error_message') + + custom_error_context = self.custom_error_context + if custom_error_context is None: + custom_error_context = original_schema.get('custom_error_context') + + custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type + return core_schema.tagged_union_schema( + tagged_union_choices, + self.discriminator, + custom_error_type=custom_error_type, + custom_error_message=custom_error_message, + custom_error_context=custom_error_context, + strict=original_schema.get('strict'), + ref=original_schema.get('ref'), + metadata=original_schema.get('metadata'), + serialization=original_schema.get('serialization'), + ) + + +_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} + + +def _get_type_name(x: Any) -> str: + type_ = type(x) + if type_ in _JSON_TYPES: + return type_.__name__ + + # Handle proper subclasses; note we don't need to handle None or bool here + if isinstance(x, int): + return 'int' + if isinstance(x, float): + return 'float' + if isinstance(x, str): + return 'str' + if isinstance(x, list): + return 'list' + if isinstance(x, dict): + return 'dict' + + # Fail by returning the type's actual name + return getattr(type_, '__name__', '') + + +class _AllowAnyJson: + @classmethod + def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + python_schema = handler(source_type) + return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) + + +if TYPE_CHECKING: + # This seems to only be necessary for mypy + JsonValue: TypeAlias = Union[ + list['JsonValue'], + dict[str, 'JsonValue'], + str, + bool, + int, + float, + None, + ] + """A `JsonValue` is used to represent a value that can be serialized to JSON. + + It may be one of: + + * `list['JsonValue']` + * `dict[str, 'JsonValue']` + * `str` + * `bool` + * `int` + * `float` + * `None` + + The following example demonstrates how to use `JsonValue` to validate JSON data, + and what kind of errors to expect when input data is not json serializable. + + ```python + import json + + from pydantic import BaseModel, JsonValue, ValidationError + + class Model(BaseModel): + j: JsonValue + + valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}} + invalid_json_data = {'j': {'a': {'b': ...}}} + + print(repr(Model.model_validate(valid_json_data))) + #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) + print(repr(Model.model_validate_json(json.dumps(valid_json_data)))) + #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) + + try: + Model.model_validate(invalid_json_data) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + j.dict.a.dict.b + input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis] + ''' + ``` + """ + +else: + JsonValue = TypeAliasType( + 'JsonValue', + Annotated[ + Union[ + Annotated[list['JsonValue'], Tag('list')], + Annotated[dict[str, 'JsonValue'], Tag('dict')], + Annotated[str, Tag('str')], + Annotated[bool, Tag('bool')], + Annotated[int, Tag('int')], + Annotated[float, Tag('float')], + Annotated[None, Tag('NoneType')], + ], + Discriminator( + _get_type_name, + custom_error_type='invalid-json-value', + custom_error_message='input was not a valid JSON value', + ), + _AllowAnyJson, + ], + ) + + +class _OnErrorOmit: + @classmethod + def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + # there is no actual default value here but we use with_default_schema since it already has the on_error + # behavior implemented and it would be no more efficient to implement it on every other validator + # or as a standalone validator + return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') + + +OnErrorOmit = Annotated[T, _OnErrorOmit] +""" +When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc. +this annotation omits the item from the iteration if there is any error validating it. +That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded +any invalid items are discarded and the valid ones are returned. +""" + + +@_dataclasses.dataclass +class FailFast(_fields.PydanticMetadata, BaseMetadata): + """A `FailFast` annotation can be used to specify that validation should stop at the first error. + + This can be useful when you want to validate a large amount of data and you only need to know if it's valid or not. + + You might want to enable this setting if you want to validate your data faster (basically, if you use this, + validation will be more performant with the caveat that you get less information). + + ```python + from typing import Annotated + + from pydantic import BaseModel, FailFast, ValidationError + + class Model(BaseModel): + x: Annotated[list[int], FailFast()] + + # This will raise a single error for the first invalid value and stop validation + try: + obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c']) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + x.2 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + ''' + ``` + """ + + fail_fast: bool = True diff --git a/backend/venv/Lib/site-packages/pydantic/typing.py b/backend/venv/Lib/site-packages/pydantic/typing.py new file mode 100644 index 0000000..0bda22d --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/typing.py @@ -0,0 +1,5 @@ +"""`typing` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/utils.py b/backend/venv/Lib/site-packages/pydantic/utils.py new file mode 100644 index 0000000..8d1e2a8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/utils.py @@ -0,0 +1,5 @@ +"""The `utils` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__init__.py b/backend/venv/Lib/site-packages/pydantic/v1/__init__.py new file mode 100644 index 0000000..4807865 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/__init__.py @@ -0,0 +1,142 @@ +# flake8: noqa +import sys +import warnings + +from pydantic.v1 import dataclasses +from pydantic.v1.annotated_types import create_model_from_namedtuple, create_model_from_typeddict +from pydantic.v1.class_validators import root_validator, validator +from pydantic.v1.config import BaseConfig, ConfigDict, Extra +from pydantic.v1.decorator import validate_arguments +from pydantic.v1.env_settings import BaseSettings +from pydantic.v1.error_wrappers import ValidationError +from pydantic.v1.errors import * +from pydantic.v1.fields import Field, PrivateAttr, Required +from pydantic.v1.main import * +from pydantic.v1.networks import * +from pydantic.v1.parse import Protocol +from pydantic.v1.tools import * +from pydantic.v1.types import * +from pydantic.v1.version import VERSION, compiled + +__version__ = VERSION + +# WARNING __all__ from pydantic.errors is not included here, it will be removed as an export here in v2 +# please use "from pydantic.v1.errors import ..." instead +__all__ = [ + # annotated types utils + 'create_model_from_namedtuple', + 'create_model_from_typeddict', + # dataclasses + 'dataclasses', + # class_validators + 'root_validator', + 'validator', + # config + 'BaseConfig', + 'ConfigDict', + 'Extra', + # decorator + 'validate_arguments', + # env_settings + 'BaseSettings', + # error_wrappers + 'ValidationError', + # fields + 'Field', + 'Required', + # main + 'BaseModel', + 'create_model', + 'validate_model', + # network + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'stricturl', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'validate_email', + # parse + 'Protocol', + # tools + 'parse_file_as', + 'parse_obj_as', + 'parse_raw_as', + 'schema_of', + 'schema_json_of', + # types + 'NoneStr', + 'NoneBytes', + 'StrBytes', + 'NoneStrBytes', + 'StrictStr', + 'ConstrainedBytes', + 'conbytes', + 'ConstrainedList', + 'conlist', + 'ConstrainedSet', + 'conset', + 'ConstrainedFrozenSet', + 'confrozenset', + 'ConstrainedStr', + 'constr', + 'PyObject', + 'ConstrainedInt', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'ConstrainedFloat', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'ConstrainedDecimal', + 'condecimal', + 'ConstrainedDate', + 'condate', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'FilePath', + 'DirectoryPath', + 'Json', + 'JsonWrapper', + 'SecretField', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'PrivateAttr', + 'ByteSize', + 'PastDate', + 'FutureDate', + # version + 'compiled', + 'VERSION', +] + + +if sys.version_info >= (3, 14): + warnings.warn( + "Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater.", + UserWarning, + stacklevel=2, + ) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..477ac30fee216e2816e5561abe3b3645b2696273 GIT binary patch literal 2517 zcmZWr%WoS+7@v*pc>PY|^g$b1x0PB2iIk{?1FewqR8yKXYLrx3ES8CP>})c#bjF(}f-l&z+G|ODiWjQZr z&TgugFSX$?8UFnN_@s<+F5*jeFykcj*MHdR5Ek=;Y5Mmdn#K?5uZ|o%7DI z^WOQs^_{*oM=$ib0=>wlys5tZ-8c42eXd9^vzk|9SG+3@A~o-73k9X`9q$@JyY~i< zKV5_JUL7HEb_5Y;_x`DVzy%d@JsA6G{Kr(RaZu0cInxs-MqHbAbRobBHz<~p$mtP1 z)erNf>veuNnbRHsdezW9Hu>a|G_gbfA3Wx=`fyO@TsDHl5ThMi97{5+Oq zfk(}-rStK+2w^(2^i&B9H<{>r6CaCKhmlB0&=yVD22m=ET1KvH#oLEGS`vZ_P&x0x z_L=37&_EZ~Mc9Q0%qb@c!N{8XLf7p(Z0&ZZy8Py0HmiDcF6wOx zs`IekQ>tzF>@r-#G6PLcDgpWFfYDuIIHVi!qTCu3!%DievfhOa=7K;FDRm_lS0Y73 z6F11fzDCqO7kiKxE>#O$7iFZ23%s!>IBx71DLcoWv<(CK3PS7PuJWkGt?pCY+{1=D zeFibt5fkRor8X9l_)WOIkEJfgBH!LkNCNL0DJL5{5b5)#F8A48$s;3Y*LXzY_W?8C zQ$%VP*e!CD6`E4=9H92w^q(4^`MDMp;-REj$p) z@VvL>q;v9>%amhf+BRxht~79r4W+?8u{f64`BXC;Qdkb7P?6X?kx0QJX@m?zm%?E| zpHC)r5vI&06=t32%;x6G;%vO!ikI8*@}YK3Z?9vuqf3i0jSYZ?o)y#gq5isH=wpG~ zZ6b7GgTU;lc$jmsU`pNB$5qb9EilhH1%qveq2915j`i`o#@BJr0LlUu!CHrH6CuV- z_qrx*BYZ}nfLJQ~r2KLRhK?9sOq$`Y0+}8;F{p4-2J-B|0vDvV-V1P~!bWXtw$|)K z4F!k<(4=~`P)0XY%|Hv(c$<>ieyDc9U+wUyc57z#c8!Y~jG{SV=48Zd@94Y)7~Z3# zOX&0sosvD6fPE|?1ADsA?jJVOowe|!FD5iIIEuJ}-2&gBu{?z`J(YB`D1Qpi@)YCr z#E_o_>9=rCpGmqvLvUd*-ol|ipR|#v>%**Az_viCFASLtYWw?fy`=@w;p3q=T*zTv z(}25-!PZnRM%=OFzJN)Qo=j?@82Y3hPiief#o#rhSI|vwx!P>%YBIV@goHxdrm*dy z3%=i1`o7NkKBg3y;y@QhO|H|XlDe=diFh2>^au1Bo`L@TY~ka2Tkw{^j6tdE`y76w z7$c%V{4nZ5&%&_Ox1lvi6x2cP)*po1b$}A`ejBv7MPz+&!JFOLn?8hv%J*m5J?-9w zADj*)pNOyEEcl;<dWM>G9|H ezFGZx^}yXaaH|K^$$zrx%;+m{yDYwh!~X-4TvH1G literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/_hypothesis_plugin.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/_hypothesis_plugin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9f45dc8fcadd5265dbf84ecad55368b1bdf2446 GIT binary patch literal 20504 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 MV@tKaDWM_!|3$p8od5s; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/annotated_types.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/annotated_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f78eb135287b20a4b5114839e85eff8a246583a GIT binary patch literal 3883 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/color.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/color.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9574b6455e54653ba1cb70fb9ad6cbccf8af41ea GIT binary patch literal 25849 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


        FK+u@Vb#0ym&Phte7+Jp6O0uG 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 A-~a#s literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/config.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50558017aa5b595cf0416b231557b8e870474e23 GIT binary patch literal 8398 zcmaJ`YiwIbcAm?7N%5%{Nr{puiPXaqEn9v&j^j8{^l;)R+9b9U`_?u?^Nu9Sd?<4- z?MS5)b&+l5Cfg|JVohVa01bE%8eX(2us@9c*k=2uE&8Km=rruDgSu#nMgB3d`wIG_ z=gcLkN8ApibI+V}<~{SBGsC}gx$FeenLm9!_I?K;|B9JfvR0W#e<%=ggD6B1;zY); zDJ~>TvPnQ*jEf0LmJ(*!oUq82M1$Oru*%kiO|~WMvOVFD9SNuGyXZs)hDa(_N`*7ocsb z2ij|ez6Rx>K)9V7>^wB6cz@Yex9m%rXusUY_3fZ{+%;9}7*KrFN&BdS4q|(XFe~zJ z2S^5xo0XK#_a%9U(xv#7Zusw^W~D>%&svpUkPkums-+U3y`T|hElLnH!%IS_?`v#k zCM4+6WHOxy*>upfmOpRD)93804(cRAMm}rwa0^E0o1k5#;T!q!b#TiqSacY%fGq$|brT+3{3z zHZ~W<@zqj8m3ed#m>Yx=Sx|^mtED_6Rr74YEY;2s3vG z%$KCn_$w z>%oqifvk{+&gMtJ5Z#f$6$wY<5mk*=PYWt|+A=cc2N~-I5)xSt@;Exy4@5=7Kp?<+ zQ4#?1|98ZPW}8FwzX7Df~_TYFfZm$<*m1lR|sU+m2dI$NF?@FuCG{X z+&0TkrBBcOrim9SoIblz>Km-pXdIginMP+q7S;x=ZZ|fzaS-RI7B*H+H}j3AH^!3l zl*Q`e#zjUKBaBwfqEJOW0T%Q02;0~=4~ig*ib<9fQ8q70Au}5RwQhzzk-Dl|Vspt9 zqq=1_#V*AZ?A9Qt*$yN_NcJGvi)0^?ZPSQ#@d|OV)D|ExjZXKh{VWB9cIXR31|=NdpJaZaQSRcmwI#=RP$3kv1uALk@L%xXjM`)NDu`gq<3ZlsyF z)LJj!!8JI;opr8@b8f|7?NxU*-&4)^Vty$Q3bGI|x><{9;5D3)a+9PmOpbu;*tif(pv0E@s1-uzcAVN{y0Vf$eURXi@+63K? zsNp%91kVXTKB_lfrgSl!22@Xj|4OK>&4ByrJiw&hG3hOrC?EsH$-*VTnQo5E;?Oop8W&Tl27U@*3aXq5dA5Uy4F<@D zag#dR^3)HsfC6lYGf=h%&q!YoKI9MvV9aov)-v_PX8YeIQ5 z5*Lzf*n}IB@5)hN)DR%ck4U+xJu6%wa#w$D{N}SI z>u^=qN_V}~W?3vtD_CnD! zf~|O997PW=)sCgwZcgV%3jRaI_QNIX;qs21CF{;|dsoTYRqhKFc8(YOCQ8>~P623}HCV6slL7nJ5W#Htnllj5$^hBa%;CXeKs9)t28gdL21rBB z#&aB^A!p|~4%1454B!Zs9H5~t0JADsS`-e|VBg5?4Y+Pv2tX&dCAoz*K^+{%6{p*GqwNqy`rseGW&N%tK1<9+R(zQ+olY%a;Vx?wG{N*0Q;eZ(@(G-fjdt}tzTf< zgEd3jyP#zsjAaM!tC{XLZa8$b-Use7VElXd_yc@yobq0t3-Vl_ypQfz`m3WI;4)D@ zz%2%OZijpjEQYEU!ziPNln}VCotsAvasSAsNd7R`>{fPdk~{^srcoY=&9H+|$rL*T zwC=ysi;Lg^4ugncq|Tl~as(F z8f8<+BL1@zNM1zp5|WchUPdyF1Q(3Gg5)(IxLi*0Gs7^O`;m%cwn)u*A`;YqP%qy_Xp+tSa-&rP*C`yq^O0WTTbQbtnD zzig=W8b@}DgsjUK>~L4&2`vdw-53vYFPZ*LwoREUc#nRV&b0hg0S9*DuaVZ(y7PtfwX;ljt zSKR;vbGriI$O9o0i$EcE2}sD!cfKw{{G;1rYAmU0kz|w_zF*?ukX@ykLT4lCxW*5H zaVMC>Kufp5brf%#5Eod|ix~5T%(@tjt1Jw)>rP{|M(C#7c@E+Zh)}QxD(+1_b^MB_ zH{x|_!)Cc-;~imit16A9e+^`XRGh@ubz}MC%6Vpca4-g2Ctud*wM9m@}Z-3ZK3E0l$~u~IDH+2-O9o%bg zIrA{2El&_a$h7=weK*wJdIIyQ)a8Jd3P3O#y&Oof07QbZ*`2&WOTX@_U0S(n*|%vOwrKtc%BXl1gk`W3n~RSpB(b+a z#PETFgW62!$oB9Ok(4Z7|!AQEM_+_d<3(5kszA?-(ZgYGUC$b zksCwu0um1EJWS=-ju2)5JdavAzGLXh&LQC-kNZ@YFp$^HJi_O&ubX*NNt`kA!}7<&nJwsV@iY-m*Wq@`E*~I#@n<7}aa;HJTmId2-SGf!zG9 zo`Qc*v2AamWpB~BuOuBV2L=mLd)8Bu2Fp8laW)&x9mvk#>?ujR%A0!X?Ob_rRVhiG z<$=+am)AUSEL(ylX|#O!D71JsJD(SG>3lS|TFG=Gt1D`D4T3$K1X3h3zy-=#N*bJril?Owg z$hTy!a6@43D>nC)q&?-6(<`s69n6{`s6TKsmUrhD3Oz@PzNha!Q}9g{-6u-YbU8Fy zkODcVWwhMcgXS>R6)Tw#UJ(kCKRZ|0@m#Uzd9Z{RD422>SV`)BctVDrpD6et=AS4@ z@1uDG<18R6{1ng;qk&L#R}WK`X+F+ zKSKTwkgNjHotNN;7b75}s)`31qbuY6d>2|FxdZ>|GLRMWkB+wT{^tt&#;!ZdHc!^| znQgG_>tB2Ky7OUsU+$Gc`@U6YMUwg~59}>#yK}wkeI@&$iU@+QKroVhZ{1X~AE=l? z0Bh^;e6;)e?rc-OwPfE_X#nBMORK4()brR$oXr5cyYjY@V}C)~Z=jYH!bJYYw`Gy) zko8y4#T%O^pDa|T4ixqDeb`d{HnK6LaC>+{sTz=FNVvYZOYnnFKiRlH41hxx$Oinu ztw;D7{9yXz8bKre++3^ohX5<@i08;v0l`J+TNe9{29|??n93vYNPs`aAx+Z&M8knT z{)pHIOUe&Dk8DO@kh=X1wBf-v1Z;S=*#|&W98_&-ccT=^U!Vq~rxo%5Lg3jO@sH!T zC+|CUR!pKTEIjB65XwKZrjW zZb0Lw9Xxr)Lm@7&5&7{L3y&iY()1Ri5Wc3;qzboW)rguJ!9s7X{Zux3W#4GE_WE0* z-m+Pn)?#q`!0=9YZdl+WB_gq;@q^UwV@bUE>kaTG zioekDTaxh#x*wGxBna3Be#^*lh~<}an*f0K59DeZjN0+*d)OaIEr$5Mm2B|HD` z1U?lHf!EQei=De6?0RSquQWWih(g=y_?qW20p^=lVudL`ozmiW03CMNw~x5@k!4E&4^vh9JyP0)>Y>0432O zQzdaL(s66*w5h4HZcL}yQ@U1LX5&3ky4j8L*w#JU-2x({@DYW>N<9N zcK7$)!2loy+3_al?2x!~-}k%s`|ka|``z!(e{ndh9G)ls{PEDg_Ho=lQb2nebDpIs zBgehQiQFJ3@}e%x5Ay7-8`QD4eo&9MJ}g8Gg9e`R2w`KyG-%>E3xx~_nFq}*#Td3m zY=gFleb63p3_2oZgJlutpflncbVb~Q?nwDydBij5iBt?$L@Ea>Ss7EfDpEaI&HUzY zO{8|PmiaB=x=8(CeWYQqA+l<4RitsSk;PlXt0Ue)FZ0{NYa(k0*D}97+!SdZY>uoO zTo+kCxIWS{*uvr+;ns+6&=+YNY-8cF@P6(zXbi(Gy2^CI?PcXqs!kEJy(>X=sacDh?`$B6)0LV zh@F_{ZU(_aY(BX1Vazsl_6!-tEiVcAQoGnXuode-MSdOV5x3>ni)Qqzp4GSxHEx%7 zi>;{1D(-km7~CTs6?fvjx2WB2$&MUuw6Y5+`y|ZsA>E4l?5w`+7_;5X*NWD9$Twsb zcfVv9-2Z^}W)E9$Y~o(AT--;HNL^@WKiWAEwXTRgK(XS(VlUnY#e*nu2qhk3(CN@l zAL4sOqA?X3s!I?LBlge=Xw}}giqzH-r1y>LnmEbQ%*g`JJ;P1uUs-#JyR3hPyTtn* z2|O)uoOR%wFi9!9redFc9^gk-TT6s3ZpxlIR_hV-asWh(Pe1 zHzup$fYwMXDs@<`2c&bMsOU`qu6Ph7+r5EObpy=dk$A!z4xN{fLzd2tgafh{b>Qc{ zbS{JzE+HiWz|UC&-qQyHap_o0l)|UI0n{G}oCT~ADRC|)vK}Yo(Al$+%o;9q%o`hG zF*E=j*3*7}C>l!m{c0TuV#pGOI9c+ZlW5pt7bRH^iJ}x`jhzczl)TdAgdFgOW7IB2 z_>5!?oC!5!B`aCCOij*5*W!) z6n)E+1uzr$N*!m>v(u+fUl_IS%R?r`JMw-jBQx)@ZmSp1-JP$p zP^h?q)?+?u0OLpFDM|n*o(P4*-b)})8twSVg$ptCNP1xewI)W}z2^dP(A?Q}P|*ds z-P_U8;SI#8$DssDfjWp5)ro*!tkF6^(}6}N9*V{jG+SB=V76Y~-RW!h0+w8^6-nOR zyS>L)CKcF$b0Fx56o|%&YTMexShR&2S3wTS66OzxAu3%eAQW&h#GRAmP$I5Qrck1- zt$@4SWX>1ABnK{B0A>PmYy@-Q^s&=w9hYc)0zsfLP827{E|1bke7OJkVMV_`I;xlt2Et*QD)7+~^khI*gx*jvp;!*9 zD@#mP%#U86btn*4gn`iul42s4avGk9B3?1mj10#DBHH!jiOr808I6OkBZ#g%8vvqZ zKU(wWdK{DEK0&e4(s3{r9SWUQtm>OJZ#YCVTCtv$5`Od&$<(PFqS5FfS&mVM%X_ue zlYmlV1;x-8lER{5VXyw^P)spD4w4MX5+a`f;SPnOlIYVZb`^d82rXVpSq?Nw4Ws%p zHY)oQz}A_OgoGGNeyu}sw>Er*!Ezms?U&DDY_%lCS^!b8BYsKG{I(GJ$@z^@FsjiM8b)FG9LF3Bpg zIuY*%11>KTO`N%O549;)NJixGploGP9@nVFS0y(igHqx5iyBS%hlmd1e*f}VEV_XR zVtu-f86c+6!>Pp_o6nBp{Ozkk7^y^wu5cNjb6aVI)aOB9=olFCe&mW% z8E+04yI%tYMDt=*F&KF=@IQqD@;-8?ZJ(RQEgFarnOXg`G>wGGkGhD_AObdtN^!o$RXe`0R4)j|#Q><_%77NP`%I~GHF?MEH3MS-k3fP#4po(ttUdq!; z4vnok5;Uf4qA}+HLh*lw^V{5=#`QCa*@JVQ*&}a$In}s*!Mr_#sQC5Bf_X!xdi9KX zwl?M6lB(XiVBVTFa_c*0#W$Z{FmK7MZJX_y>rZXilUloX!MvBkTi@(hFmKK@G|vpo z`rh=X8n!K%w`EY|^3D32j$4Uj*TbnzkEGTgTQDEXY}_^{zJ;20Wd+{io>`ye@S5vm zubYV_3ZXq~WmZSYy|eYH=4~u7*?sIIN?p=xsfB#g;!IDfakE<2Nwuz1h1_?kE)_op z#geCUr7T{cHR6rUIR>N63YD|?Nmwr|Q%XfB?msgU3MWF*qS%^9;Jj1_Ym@_ytn&}N zrTYaD-!BN|;3Y1$()r^Tq+keMIX=+W@s?E)Xf09%lD!n2^nzlD$)Y4HwvlK&FeLd& zI8%%O=0z#07*#&2xbl>UHIJ3Ij9`spl8a(Gf5{(#gwvn^g8I}~mkF_MfjC@WjKAS92bziuXaT|(haN)fIv{9tSbD()O(B86qp?2~k zMKhkB2aVKOq{S&y9-bA@{4Qn4LDQf?lOLkbsorP(;zRV=c>5!OBa7tFvX_U0P(`E4 zx_JejtNc~nRsB`rs^O~fs`;wrs`aYJi!@ z(-!8!C}j62b~4!i24oRi=M@`!$n|WGn1GmCv{CF})eN8pS&EaakFAP?eE@AFQ0aZ! zezq-PTMBKKVk4$)Y*}5{NCv#xW~7ikx8EpgTHC1vwEb6p6=U^aj}o{T3t=}O6GKCz zv>(BiO@s^`OoT^S7M01-yq3?v$)k+Mnb79JZ>bRo_=fd0ZnEqvy2-NWGewBX59(!J zKE`un+;ARQRE7G8JfW+Aybq4O5h8mEEsg6%{kRbI1A4obT6hCi9hCD_woHp1c4@xCTNId5t1&@i#-8B{ z%~yDjag*jr+oW;QI_a1+OoK7$ z$7Mpi!u81~@%EWMXF()(;xm4BrU53i_?$Aym5RmhKZA`X$v_WNSPwR>=t0c#dJ3Ab zXNUzMQ|aTQam9}9Y@7sslDHLHep*Oz#$OkD&x44e^h~5pvC3I>in>D z^n_!YH$;wUhmCwJk<(>G=E#JNT-Q7Pu__z9Z5B}Y;zd4p1d^YvSsf8oYE%ZL0 z+VXtX##w6bx;T47rnY|K=P50cEy7FtrdsSTBx_r)Q zakgS^?af2)ekmCY-P7yp%BPIzSZjL{t?fCU-1B5=ZFlliIB8ye+q?k+a9wiuK=R4c zi{?PaynDi!Hm^yU*QCw6Q}jP@%k$R_KWcb4p4@kG-aL?TR!%rnF;XvA(cm+=oTjGF z@x>XeDrk*SJzpX`P-R{y?C^N$w{L|6@E4S+7ta6rN-V|xEDa%;cx*_qHo(8~8P{33F@B6ADpa2_?hkdZ(ORJ^jvYmH%VRY4`=9AA@oY=z zBilu#@$Jw zKC2T92l!0erV0I`xg}HPe%W%TZU2P+J#))1lR3}7#%U4%s$&yBWozR8jd>IQ$Ch^e z4gDrQi1_@2BW(68{SICQEsx0K@LDGcs`f?{L<2M%~?yI3K*@pg#iEFXt>55i@m24AJRGD16& zpXgY#E(1Vy_eWg+_%aOBmRXPA66q8mkik`-VTxVxjN$NojDI_q!b3UX(;b(;f?PhG zx)_N*@!_7qHkme(l!Zxmq&xWe5wm!-{hDRbTQ)|u6F z>)$i)RH-$u16d}!5I&gV!!A*J?m1Qbu)>iXZ!5MlxO?Ldai7H+OcikvF+11 z2^g=HZ_$6(&|^{r(l#u^I?Zc_bz*p*KUTnbPR2XQsdH4Pn4p0nJZtD@sHUk%d7eorRu(D zbsa0F-#nFX{uTQR=_yyfsK+_VR(q^hiTh<#D1V*0U5sA&Yltb)-~8Nw?FttsiEVj* zx6kcZaPCT)cd0!#Yv(AxBJ!{RmlBfiN1nBCM6(QkzegP*RBL4FCPklmmV=Xt;CW!t zyBrH_;x5Z!E5>E*bn8rSx_Nu5dHaHMN7B55^=#S1%_HY=G+a!Ki98BR^$L9@GG6g$ zTLA5?p--=_j6yJWVN~rh&k$Iwbfh_n1NvE_N9ZS&T=5j9=8`Bst4{q$g5jG6kso+vGb!&LlZBmE@!3TqEZX$eAW* zg?e*6#gX$b_{FJ@FL4>y>MQ+FFdDk26EhE|R+DDX&^d z!~BegiX7&XzMc1&hYgL&k}mo- z%jP0@%oT?vv;+4F!L z?t(HPQIpS$sY}lT%9IzC$*To4EEdXu9%%hr@eI?Fu;Ll^u82TT_M!aR`{Re3?~jX@ zFB@%7g61}R3eb!i>92`P~S%rR0*nm*$j&x{*?i3%i*gCKy*`ef=@{>C4glF z6ll=9hXX-XLx^q1xkSz=ro-DmD~(*BkB99FOjE$!q1P)mju170#|puZ8BZ`P z1_`Hduzm@_TBkLLLu}F?7VKBZ5Cy8mq3|eK7M;%5A;nMoSUm?uH6w#|vW>uj=Q0H$ zGc_qP%zGK%>E&k7pBx4WfHG_rPv<0e{dsY9c5Y&gbpzb+HO{dWQIP`a8 z`qInOMM&kZR3cUQecday0vANyalNX$8vT5zODt{-YWee^d~Qt@V%0;br%|3AdeAiTUb&*~q1>>@ z6LG4_+GQ%W7x(-MTE2qn>%Q`9Nxb<-G)8IzoBP$C$)4A@z0q^MXWrKGGrMc5B54<= zg?YO;xBh$W-)VoRW6>M@PRCo#vukD_yS4w_igf>(RR5Xz-ZL}qnf-58%yrCrg9~=? zj>GfnsmW8XKk>%1*Poqtv}S4=->_e|f3xhGFvU-GW?U7oIj%XO1aHfXalzj5$&#B}Bl4dtS?R^LAAebOaA(<%+y=Nmu~Z%0 zTlN#L0j}JJF<3VDNl0gN|6k!@b6;O-?u$H|DRxkiuzY^!G{+@3D5cg3xdU_iGu8w! z#iA1gG0%SGa<-Q*F^3C#d7hgr4ZWU0?|2aOqonZ=jw|jn64b(ycD4&8vfPegQC!T- zuPEAQRLTklk+iQTxtE>RL+;&xGV&%WXaWymn`x@XXIL>8*c?zS`HGmqMbSKPzzD8j zcll!X7n%dh%5Ee2CxM&j-&vVK2&kik1X7>9;JdCe#4z@YQ&lT^3~(t5K8^44}z z@(xo2E1uG=AvP~x77A!%`dKhO!@cryUUt(TXLC+FFq%bGg$X6Ug`i@Qq9d?_!YPi* zfQ(Er6o*nuwY#8GT{%uU%lv))haTzm_aE;ccyj;a^6yZjwI4Qzmzi~3Fm>+^FvawC0FfObarK}+>V_|SJUl=bu;3hMBj|2*Y~H^_ovsN zNUcAyu>SGCZ#a3acWVFC3z_Pg*T%1n->{`y52RWT%vT?PCcXA){!aIvn=gF7CE2iP zj{lzVJI48j9a#&vYJktWICsaCkalfM(SL7p^T7pIZ*~>u+WAWy)p*-*o`mw5?tMRO z`+nQ4$Nu`sA3gc*V}JL|-#oL>{ZziX1yrY}e4oaNzJKf~Kd?*p<6S)myA40t$-`Aq zz7c7C?C_2)r>gbSUPLnGfv^_azjhMHkS_l&Wuvu5 zeiV*USEN)2cFEA6u>hc1euOf3w3WZe{s-ng6?;K>WpKf8V zcenmCMK0+%qnqWrSHqc|6Bnm`Ytht_)#)u8A^D_h+EX>{>6)%oP1i*KJu_!@PK+*C zYEi(_$*Q$TjWI{ep`+0m@_O2+jD`|#kS+`UQ9mqT+$y}Xd7M>&gT*yTHJbkQFxSvrjCF6 z;YCb==H5l&kXG=Z|1bs?|&0 zb)>CzDQn$=Q1?lkX5?30sVdup z@D*!|<^MoQHmEloFCOzliOVd_s1^7fm)O71)xDa z9PJ^jQh2EcAzadUz= zGJ7yHyg6^tYY0juq^vE9%6Z3dr9u=!xIg|nR7VUt%b4yf_>EcodHH$Fa+2iW=KIU% z%)*Q-bNkHfxc9p#p*S^bpCQ~Hg5f>gK7f&6EPQdLDN&zKkpCl!urm=zphYqQ$s)8( zjQiD#0;nQPIqAg1=TSvgqk2n1CV5?EO`DGOpFD|6Lh@fzR6RLtij%Z0)4``qGP+`h zop^whii*GlV3KuZ>b*?EU35%y0YMmyUZz+kRggfTxK-JisSj~ME*6a|1{TGDU~MZ_ zH4n4I((Xz@^id4#Dn&_yQj)Nkm^DU=N)sH29#+n`0X8bP-3@7XQ_9^m)A#r84HJgj z)!qqHrmJVd36mbX`_BcRo#x0YNepuBwari^5R%c%yU9|Z!wcd%NnVq{Q`rfl||FE_(S$k&Y(k*AI z_Du5R)9I6e6#i?^OdP%A>-dYhx9a8wldb!b=Gy6XZ?s)+n>Vk^uH(wv@3nH}Ei)Gv z+#Oer-d?>SV=jBuIqA&mOl|wHb%h+639s#%Cdx-yG^!w5IJ&z|(Jf2U`j@bqH%RIF~tzDW|;G*)D{7YyDQEL^<1tC!DZ@(Jd?9pHwg;K7N_45RNV%XI7|DN0#mV_|B6D;a zWDaXiY{wEX+gvnl#^Q9_R7Rohn}-%n2e8`Ku6o09-I1=@kgD0RShMk-L8!8RP_t3h zQs1s$e7?@ zs{P=t!Q>Oqq@M_;o(L|k5>rCmmHk&Te6yv{022RPDyiiuZ&)pDa}aoKKeQT-7-~PRF%3eFuAtKh{Wn|GHo#@No@H_& z$^C4#d>(`LpwoBx<-*ztvZZxr#iNnixE{vW`H5S|#8%hb!tkII%TlsmDcxalT{spK zS2m3lhB8`!=}@JhF_k6qv$WhF61>PjBSv?$iJf`v!*s-^GK$NTr`P{st%nAH{+D_ zK9#YZkH#)VRsN$G+060B3E!j#(Jub{kg}8WQ<^zsbOHupvZYPU^QPw8bR_fIs%xtj z?5ijEjM?(4VbU-mPW3LDYco}K>8g#Xs*UNYu2fZ5x~eBt)pK*;*4BlpBNMit*{U)P zE$N2MsfNvSl{fjDiFYghuJLaglMR~}8lIj!HgRZb`_G(}x2x98T%0*KCw#B$J7o)1 zdy}rc9~KCEdSGVTdxB5pfB-N5kbusJ_CLW>%;HP&o&t-<9S&#_iMhKT-p`gR37rYO;kwcXQ6S$3ullH>xo7|@W?r+9tWgy|ioteVn zkUo%LF&lBd4q^SY3SIuZ{=PI^>Lh67SWv=;62ww)wX*9*0WaNqV8U|ldmXs<{-Ema zzit$YvJW7zj}hc<{;c@0$Z{CjHz;VdVQtP@*_Tf*{*DAoQqizq{TKz6(LP8){(ag= zm;Mk%Q3VHD_xlQUjH(~Cpei&F`pF0a2nu2#VC6tx{=mQwg=E-FsKbByz-eawK=&>2 zO_AK!MAS6;o=G?sJ5S&7AX|!}3$@7Z({m4r*WZxSx(R0?u8y_2vhXCOmHTcvoD}WAzakj1tlqwsQOe!V*jD zPr%X#H-BJ^qkhnYePBSsVNtyJ8#gM!Q%$*>KrC~FeGLSZg(DmggL+?BEI`FtARBPD zaXyWK0HaftqQ?+`KfkSBwmEqWi849=lW=ZU7R+8&+o+5lO-=DF6%;WAPHgeT5@RCshDi0%((W3r3q5d;}kEGlO%`s z_No9x6sD?p*OTuEIixXE>5r*znYx8-N7z1ri9EElFxpc$&buhM6OLl;Q9oa>NB#ss zn$YpT2cB`p!1H%?US3!_fZGrDf8fghfwR8Pt$UxV&kDHJ|Gwb+*vj!Ee40z(KgA{f ziR=6)ZqLuTBMaP-_qpxwbDcludKb9fpL09k=h{EeyWSVtelGNV;I5f&n0}b+yBWOhm*~RQ;kP(kLP2d+Tgy+!TD&b(Wbj%!sRlfV`AWI&t1{o(HqlxPfG8Z zx-_qE{J>B%yDPn+C$*vHrj%^!T{IlZ7#vU>Rn=uGp^~YFz9`eMCR5!2jZ$XArc5); zbLu~;b{On;%F43_yph@I$(qP#hE+}0LOv_!s>s^Nhs{M@)Gh45BWIYtB;3^uXd#~-uR#K>nE3e8@%h?*vT0XUP zT6e8$sx8^LBU!#9W$F5;7D;rtRz^-ApA`_k+sGMfOZCwFIX$c`GuSg_w$p3Cat z&-IdgX6mnnd{*kOjeJ;vDzXmpl~I44u)uMYN)>i zN45@X{EzD4E9%}|0pYvN59r=!A@HM0dk%Ye=lVrH6?^1Uu}3}?d*oBGN50b7qm%;n zC{(~6g{n&8tQtv0oyrOb-)(q6r#=g3j3o02BO)m#OF|gMsR$#ViZJr22qT}0F!Gf~ z7^M^tMxg@2CDour6PFFeerF2VIs-^4Zy5#zOi~RmOtDCa=J$w}aEw9SBD{=KO zQ(m2^S(WkBWVUu?S~g_7&6$eYk7|)AqY-?{+Mt!PIkP4zZ|2~$kk86l99bLr?3~?| zb&#)&sK`k^7g4L5eC3>@e5wtf1KEB(JlmTr-<+~{W<8Wr!BwxGPF#y-D=AdPxoW0` z$uDQCDOAH@#uG50N26_`YieM6?X{<;j^ZL^vSMe-)}8EmB58XfWq9(VdgKCHbqDyY zjtU&maXMF4XXFp?)57$rR83o!qrlu&^?kGdmiTT@s_*IK;Pc7TVzN(6^++GFEL2Ud z=*Q*N{9zvJ8rCp3u_0xsTCz~^IL`^D+|qk-UcZViUL4_PzC<@5j_`9h zf~WV*1YLwU!e_0#0VG3_m1?xB_h#FzeA`?-!Ps_-f!dZlagqg-PoE-~ z+p=|ayb%{W4qhM4a`4XLUI$*;ZX^E~k8jXyNUhsWqyHFxOSmd&KmIklxc}xH$KwC{cVrom_h$v1s?AI1#=hTApigX literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/datetime_parse.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/datetime_parse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..449ff112ffd88daaf72a3ebc991b0621c58eb687 GIT binary patch literal 10351 zcmb_ieQX;?cHdooe~TuqFY99^i?OLs%bzkGTec-RPA+zwNd8jf2o!fEkrqjHcWGM+ zg;Rn8C!LL&M%SsEQ z+p`fjXVrMT8}isRp3T6+aCXkYIX>3qr7eZBGR~>-l#}m*q!ql4ujIGzWqj4Jz5*)s zS92wNHRt9lxlO!{V+ciulwl+1`BQy=4d;bA$j@LYa52MrZZlA7p{9keB&DUim1pyG zr4{3_+DaMl)&Z}L*YVX_D>`VU94PgKqA#N8fl>jKt%Sl9QLyJqpfmub8YD5m_ZIl} zO)&nd;G3W<)?Iy+=lowcOG#F#CYO5#-+AH58AwagktbB(6T9!Ej7{Pe|c0kqASkvUPld4NBJi``SB(gFE?- z;1Iui*N)JxJv;XX_wU@-!EyWd?cKe57q>ge?+Wd;TDxEZM|cj_B4BNV`Q}+sf|&^l zFgX*_D9n>OP*$24=S4OamsmxdR?>GXj(;*9!7*9i2ji3tr(^Kx zr)48qI&pH>_Rdo;PVhnD&;a-L?kRr@en(-AMzNs1d1tJi$O5%{r#bDNHi?C{T2p6S}rEgJwo z61?n<0fb!Q2LX@(u6S+`w}xy~6gdPSrzIo2A@Z;O1!T7rwUv^vWs({wK}S>PsR>Fl7nPOJl%!f|u)9eb>>N|DaqrTX zsVlnk)MeVQJ2_bvjuB)ed;9}# zFhDdyMu?YnK$8uGB3lb6AX{)p5kT-Wf(v96N+1()q%8YQuq!YCh&dtzqfzK+;Bq_; zkQW62cIE}7mP{aP}`+;4Ved3 zM3ikKyfhd~K%3!^fHv?b_J1C-X=>TzPWf(cy`4x`EtphoTMM-?}`@HZQ&c*;$sUY|rdGmT7+}^AeXS=X1{CjCpuPhtzLGC$#>T zRv-0OmLq1}d^u#YDX(-PO$&er*PdudJ(S);y?_EGUF^oGD(Fc>(-W100v#!?VWTd> ztgfk}=}B>&f@T!7N+RAKa*=+^lb|(|Wa)7Q!+yV`?mypI1P%mf1^fIq*?Qv0xxtgCPaN%e zL%^w$bTI@lzNQ3#+6t+S63HXU|$fl_!lk;Zfebbg@SK0OCEb7ma zrR3%-sRQ>dHHET=R>#c9)#lq(_pQDqvn#cG)-_{#tfOpBr8sBxJ+wG)R?O{Na5rTw zP18r0Y>w-J*}&~{KOcC1U?z~WHD>gUtI#DS8;FfsA9$#|T519t%m)7?*-WgR09R>;^Jok9Y$z)E9e7_inPF8cP;u#!|WLZ@zQ-PnlUcfN>c9Gj+FS*&ZW|- z)Y+M1D~t}B@@%>N@}1#@sy#W+-i&?kikT|$e*M@)l~e+jSt@_KsqDRNGbaGKES2Ag zxQ#z6^&V-aK5KR#IjCEMR%l@eS~b8FZe-6i8&+RfOh74|7Lqi2Ns@|SYfmI~0Z|!y zsWs|Et921c-l-^35n5G@XScXUB29VJRt1#E@q{?=sY(P`hzdi}dN@|V$0;VsOnW7d z#=Q=%sja?CCz(i@%2{}-^az@)Cz49*rmpL*>qELQ6=E&`vJSwyOzEcdNu9Jst&-HM zbMqc^&7-HL49EdnO`Cg;2~$bKFX%s`d!Zeg3ITmecNsTWmD&nyu+898Jm-iC-o@lU zTX8d-B9UHD37)`FXd`|?o8ny%M_zHCScL_5ODj6?5G!HzH=YbF!ov{!@!*b(CnPp3 zvX}X>F^mi#z5tJm9fDE}Rf0;$N4jl&u9h%JS=*RWPr%vwi1NDxoC5MitPF7|h!Kzt z#7B~i960hEFPl*QK>>mZ67&eTvt&y*6cT4hwu}hz#5jlHhXK5qsHh+f0U09!8QBP4 z%MhS@0ISj$W%`oLT)Zrz(ZX3#F~&+hkGDwbXBTxrg=ebLpD zb+zPNZ5eahL*guLUNF@zm2AFczhQsRIb(Qe_gp_Qdm`=2+1cqHfV1hTWv6%1S(A0v z?7l3!Z-L#vU?}?pklkef7+&Kf~^yKAN=z zR`fbU-LlIwJDD1qoy?dke!ps>tOve+Y^Lm`=zrBc(F1y2b>E2SMtp88?P@Z9&RV+XCJyyWAXJFS97=6VF5X#lJ zh=y7PDLDgYR7Zk*Xtl@+uA6C!4$PI)iR)pY}$HC#95 zaTex^;H+WFm^4n)*DOhcv{kK@G^#xV+Li*^ngDN&Nqy49nNadIxN8R7HLby2lvOga)?7K<*ENwn|foPk#)zpGI2@G4bdJqB(Nv2S6W| zSUe4bV=p}NVHGzkkIEPyho@hsDFH2&Y>PsOmp?3dM0|UChk&{w?1jwlQNSB3DY&g* zavw|%!DI!|StMg+VIO84kjW+-6M#8^VgVOYHjG6QV876xlXc_qap53x<3=Km;zwr1 zQ9OhN2;jmI%!n|Z_;wgFS$FaBpooBhvxQ0V8uN&boeCIS%)(DR2EOrHL?`j;)7ZUa zbEi)KwDaMn^2JT{*-iDiO$`})!*WSEV)pHc`O<~jj%-QCqU%uBbtvaLoG~B%zR+%Q zUay_4%~>iTLNQrpTJD?5m#S*gQ`xGP#j0J|s$KI(=EYpqff;7zVAfpm&{36so(av@{X_3v z_urrS)c>V*x+~kxEqN=ayJpPqoX`x#+o{m(+Zl7^?^i9 zm1>qGqQ%|?=BLnGi@+mV++E;STP0rU=0dsprqT&|lN$$u-sEjP+W|qMUL6UbH$%`{ zvkHK^>mt57H%jK6$jT}vz^gd*LpACLNd+gf=m_6{N2nj@rzqG? z#kIZ%z=PBHoDhG77BNgOz~-|J0vw}=UP*)b2nL@|Bo*+%Akfcr=i$g>T`(^)0GxrG z_A#6hP76(7LYT-pu+3?wePCJ`&Wt;7T_@iH7xH-%fPA>$HfT}1loxhvz)|S47TU6r zKI@*C3i#v2c))ie;OlMm z4R6agb7V}67tGbmy|1wydv~7IF^CF}75Ql^`P zHkji_a8&%Qazbn`3M<4Si%|(|N@TG~u^1$3ARz$msUnNvRqxdYx%~K5(;<7pVjKsx zhJxpT%88MqJ71y5sGup4b#Sdk%!_P=#sx`4>q`ub-=u^dg{Y$so718W;Z^t)F{DHr z3P}k%RI8KkPq+XKzd=r3u{tG+)u~u8ZB?w!n!7VNM@qX>{#nDa#gpo}y=TEvS9D5* zp89!uxujvSq%m94cxO+pr2T%$>4iPV7x$dZ?m78oBDd%CjNvOd;c-8K>TAr9+jFb* zMrqnOr^~q;?&$8jn`U>;yQjM$`1r}CcP`Du7EIMk)wOfZY<1gW^`30?p84QiPppcCxt5uZkFilL?XRhX+I_isk)}H;wUolS1 z>o)i7)%jnLO@o76JTy2cGZ2Xq?*zd>An`0wJzP_`5}O!@t5g9EjbOnHPr3yg(roHg zY3rr-{D~y`GI*CQD1VVqUQKWbJ02e6h5cCdIA*V5b`G=im?6k1(QZAy!C%BcB_SSG zlpfVzF6otoqj+!pa!fjgH^xPWrIwy6A)fr{Lh+7{Vj~#p5@(0#9@$yKb}U1aE}P*G z7hGbDKO~I8Cz@389^^2CH2oFhqV=mRMO%MI9r_J*=yz0Wj%xi+s^)?H=(J@;&lp-( zbUyg<=`sMV2IquH> zJ58C2y*cN;Y1@Ocx|DEh^2X!}V>DP+b>?y=LwQ$9DJUPh6}b^vVa!-=ErW8;SLKw& zo${vsBwd#?S4|tfGEya;)b6Vj)AoONl%%{@&re(7I5zD`^K-p-e3^>2tY=4tDp@g_ z=@B|pwrz#Nm%F0!yqEa0FVlM_bM8Xs#D(ljZ>8=$DO77}c@v(B4-ue_7N{|eXl~;l6OZ(=`nZ`hd4P+}1tU$T%o*BtLLf)FG QY{bH?cP1X=gRJoX0jg?J@&Et; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/decorator.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/decorator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4351d7866d68a968c3fd49bf33b06d0ef5448115 GIT binary patch literal 13916 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 L-2Z?|*vkEX+I}59 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/error_wrappers.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/error_wrappers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3e5c825393d815538e09ddec2e3bb6b6da65055 GIT binary patch literal 8926 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 QA7ltr7Y}UUgHh@K0iZdCYybcN literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/errors.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87955c682df5771edb40a2aa4dc0d42bf85c3be9 GIT binary patch literal 29601 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 UgfDmN8?<^9>+eGNE4IS_2kw{Nng9R* literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/fields.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f54cdadcbfc08b07752dbde234bcee72939e10c2 GIT binary patch literal 57441 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 ATL1t6 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/generics.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/generics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8be2b0eaeaadd0749a762049fb38d9dec57eb1b GIT binary patch literal 16991 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 Qjztd2;`rJLDMAqb4@P&Ky#N3J literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/json.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/json.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76b57fa6881ab1087880a7df37a70a4881e05262 GIT binary patch literal 5209 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/main.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c497b212accc53e8fe2bfc0d72c4bc2da1d267df GIT binary patch literal 48215 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%0D9Z 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 O@T>N&s3;>FCjJ9MSs1wh literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/mypy.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/mypy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f6b433c2dcbedf43346a7f47bdebbe3f1b7cb09 GIT binary patch literal 46357 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 L5%UQ{Mj#0Qw8fC; literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/networks.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/networks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ceb9cb5324b032b62b31f7fefb63beb2d64319ed GIT binary patch literal 29548 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 Og{!x!SINte?EeF420p(4 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/parse.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/parse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4f939c0603a136172fbde303d6acd80b072c393 GIT binary patch literal 2746 zcma)7-EY%Y6uWl>0CBHBCApw{>Rc^6mn_3V90w)Fq^$9>*-Qi%Bn^o-!-hK(@T9F~nytmeJs`e2ekje&3F z9|zDTGudZSxW}Z1JuO)DNTTNJvzSu%nJnJ=9zA+ZFKW=9^>7{5-ap|JjM`v8k+~!> zCiM;acFp=GWimG?Jwl;Zyzrj(I-g)n=D#&Yc0v-82Dx*GOk|L2aA>~1LmV~Huvg&T zB5-qUKNC=>rq4v)=?2hiao=%1CvK0)>ViRT*&&Jb>~B*4vm@F>Y8ZCa=-ICG`MNm4 z8RQ-v8YWl&2AP}}Z2-NJX`jiwp6MjlpQN3l06b;KvU(mDN`_M)PE zFAO@D(+LO@F5wsn-au?Kx`8uJB)lCa2|9EOhDlV5AwD!Y@pYReYT&zg<)*f|GqY!=dSAviRof3dNIX*t$j?HF8&U95^1mt$>}bKmo4hhJ#i9pwo+Nwgf%D1vdOb66ku!Jw(*Y-ediN&4JYy53pWnkrz6oW~Ag z8PHP4q&_+{RJh>+dF`2T00ingK>fW?bb$Ic76T3zhYE^}cY}EseEJX!lV~-D#K;VL z=P*1byf_`63NP_3liilTvFhJs3E}A@Q%9<;yB3691cj$(Pfzt)q3HDGsmqnV#n9F| zG;jC56k04kFcZI@{^eA4AX8PwRvB94YKZo64k(hb^%v7-Wq8~%xoq1{u%Z-lZW=h~ z4A2oUX-Sx*6_dKMqu#UFIkvZxG!Gq<8@3rJFE>rw$S<4IG{wo2b4(l|4xHD~sYw1a z_bESy_rU^zpw7ZrVS~gov ztyXiZ)zWV5*!{!!cjJGBH&dTj{&0-}UgJ<>bIngA9))AI0Fi=7Y^n)F5>exZT8Kyu zDB4o_s1m==R9Y7z+iJuKxaR^ZQ6lwG?~K$)aaJ%q!^~Wm2`mI#YYa@(LlVgiNhCKU Uk=&3(dMhNEBq3L$AURq37bs?2BLDyZ literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/schema.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/schema.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8b4040d222e81913b1e2c4604403afbc515dae4 GIT binary patch literal 48474 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 F{|ANz1LFVy literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/tools.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/tools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eab10ae6d694caa69503c239c617591d5d3d50af GIT binary patch literal 3879 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 ug#+?uBDxualQZQ^3LaRop^1z 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

          l+fruX#O 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�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 qx=AREBHUYN60uK9*x)5n=X&#;oHrl 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 z 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%0DuweAksm#g+^X`wML| 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%0D0SVR~iSP6as8p8VRa+!CN@d#9fFhDvPROU%? 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 z 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�Q{1|9uo+DBDNXWE5CZl%45pQ1CJAv)7; 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

          !pnfi#b)SVl0Qm~>~tYi_10VuMB^2% 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

          iOMD%M>NN;7wnF2Bq&nT%T>2l-( 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�fx<2<#0 zuet#EL@12WI3t1|U&Re|nummf`B_E+-};&n<0t-4PB&g`o)=AEuz7X%R)Oc{ zc{bk_TsE9(s{2USyV|Oo{+sK5_WDP*nbT>e<0iDnqPuywo^Pb%Mu=7raIDdu9!({c zzGNB^r_zrX{Yv_gxB|?R#yQ3aflegxe?CF$C=oJ(t#_cEc8lzdY1HZF!P96wxZJ=s zJM=G=0%;E04I}4UNS^ao3)ohBoA`APAoQsdRbePAol&Je0CO}b!jep(Mx|V0XS*x!(pq#Khaz%COKu$ zW85!})`@1JPwYZBkBa+`vPvJspWKe8IR4CZk!c zT#B@!o!jOq#ySJYE{%AtxsCKBGB28s^R-=pItmA#s+;u9{F)Dm9o={5lODPp!%% zyp~!BIFGbuwYn^bX^N(f1oNk>206dcH&d-rItEZlZyo~*B+7-zq~_y_{ZA^3u2vl2 zN_v{JeI(Ud&A=ku@?A6c(xeq=(s?vSzg2`Pwz%Hv9D8Uw=&DP6AuzK<1e1p^zz|(L za56z7IUbmEU=JQ>|7MN{TnhE(fzP1m91ncRb=tq^|CN@F|Ka~e%i0>5jMh&zGzwsFI(Sci;y*R zr=e9(v72w^&Jy&g!f_937R;C|bP@Es7pSJ51ijWSMmAmyP2~vM?0eaw!6UCTpQAD@ zn4E@~Y2ymXEwg6+^$9ygk{GC1-Ayr}sFE?$cs10lMb$fvGLXEf)_Xuam0#J$)A$7< z)A<1+ddt{f;D4A^58Z4bdj^M`tQV>BwKE*Ciat(uwx+$p#q;fpbxuYZGxSn5hR-k# zEzIT7>Z^FbwQu;RyJ%rI~e8V`tk@2vciYl}?w;B{A{k-McV=)oJ-FIH~ zKwGt|{GZ0e{p=g6y7ojQZ2dD!=vWUI8CeH~;21qshBq>8I5Sc9x!f1z8N^s1l@$pHn-Zb%bcboMkWGWS%7 zH=AQ$G!FQW_<0=p#QCYGu|$pCDYP5(BJm1cQ6&=vk?KqpxR%1Au{wU4R~-d!oj^T$HC7{!+<0YNI}OKZv{d9; z=6aV~AoH23K%5(u1_`bHjc> z%`@ZFu%+2VwXW5a+r)9%$#&Qs+88PQwD~$qAG2Vf-X<uf^4?-YQQCh> zmB;IB?X`pAEl-;ufqp$i5s@RB55HPu-{@aWR*EgrVm+nX|9c&Ksq;S<5%)wdFnSIF+7B}B<@XP?}KGuqzHTb;9f4s$Xsniie8F! zd6p9`nx%zz&`0tx4~r9$3g+YEnhXInPLn1B0!<6a&k)YU7`0S}(s3F;L#std+$Yj_ zy?H;Ujv{2fOw$&b{rMp6eV+0SjeHdvjb|eazFF7{jRo)kGkwzM<*AYi%|Rl78Wc)X znL!iraWKo1tbc$Is{v(nOEAj&A#GL}Dai0uvLf^akvR+@uR^D39s;Q20SU5dQx86v z?ZJ6x%GXL2(#QZSJcsKpVJAP$_8_4$31HYm#%~Lg42qV&VNsF8L>Q4r(^v_-e`%u3 zpfxOM86!6s!X2iRtf|>Aijs4&CvAqT?L5Wk0pzV@S$FJ-IuF>0;WAa8B+*a8AH|+b zi`*CIkDN)=NgeO`E*Evu#9dd^Nh3D^v|c5$|Fc|#>}T?#PMpSnnnqu&i~`<_lLx^qW*O!7h=d}OjTj>EcneHt@d(co_X0?}@hF7# zG4L-NwM_G!jatz|*ui;2PG)b^cv;r!fyNgs8e48Q()<~Fhh)^+RI9;0db~Ses3MqY zmq|3Yx8~ZRj6@Q+7Bmu5VC3O*Vg|8GQXxaukae0SZ-L-b(JG1X+EE4A{P3oF2HSN0NIzFOcutlpX(9Z+Z7!ii?-C4S$`!q7)hjKKDa%2HvJ;r`77n2;F z*`jxT(WALO{7WRt$qPdI&+loq&a^tzQxER6*WbFD>zlcjGq*SRHb_8i0;0iT7Yhwt zAy>6~%dKvyj^=Y((^{k;)#5Z>#0#bTjmkPrA8@odYti8~NR*WK zB7p(Dn%A7DS=eO66~W)9_vnDr@Tr~dG(4z^z0D2mk-mmUAkS&KE~+~r;)7szrwA2!(}kl@`N(&Ij;+Tc?Y$em%z@$9_;d;2f*N&hn#u8p zE~>_8`IG`CjG@PLCYUiqN@!}&xlHI}Uep2PyqRX-ycj;o1H)r#qpQmrM5&8olU7lg z8x$>d{S?#RZnNTjw3=WqFPluJX*nv+=_A+sG@K@IM@Y!oXZyN#(_Fq zW^gB$4&aw{ZlV#xsmwjB)zYo=jDD9=n+^(dgAQ-poDa#!iPHm&Zwid5lY4>jE{k@~ z=LCe|1@OOB*p@YKA9)9(k;0zGuN3wJ{4%4}YvG?(5sP~0_9B5{(%g6O0$dvqGp%hi zYA00=DJJB3xtEICm68M$}EE?uQo{QFnlksB43GsPyb8B(9YX^)ZX>7IiKKgTa%n zsB1MiG&<0TIwSgW)d>dBQVg`P%{=A?aS>4KmGFYxLF%w9LCJJhE7or z9-CyuTO`xND?up(8%OwB@CRP)C?Uk!rH0)&N1$6m>~|tvVl|;_)_*2L62}eLB-BZ> zYm$PT5T~8Y!@PSfI&2!P-6WFkUd~DJ z(e@e9fg;Sw`0!Op0J_w-w#t#?(BB?pQ7Es2MpB~RY|+s-+Le(J_V%E&zZ!)adw8U% zEf1hKoA0e>DXcXWW4Xx4f);t2A8;7Sf6GOigWt_E$jy0+YK9YV zC?FtLoW_vEVxe&nD8A5uCI|X3*lU!q+GT-9(kKjTj22>rq<1eQ-lW-tQ6@shZQZLk z1A6tQWL}KGW~cF6z$AQ{Z<$Fb#_|EPj=rew7{N^{3T72rY-Xu8HJr>1891n7pM9q68=_##UOu-SS zmGp3x|A!AuY{YmK&az1+-adI04_W<4dXvleHzK}x@>sm&cRv8xCzU5%6IK7b;+9FH zn#qhO(|l~&Kd&T?T({c*c8Ry#J~Eo(6T+zdS0w0@&UufTN##~MLsaILF50pvR_kh7 z$ZfS-{_Lfkde2m*ZhSw&_miC_Vt;JPJFjGMVLz1S`!xfx9DZC-bG=sBsjG+M(1ki( zBY;Q-xIJja&8D`<9Yk9lx46iZ+YbQn$eyw6E!18%d=srjqAdbIKOv4jIA|E!x8+9d zGMD*Nieb$9zOry1Pd4+8W<=rgCyk7cKaraq{5cLMXNNXRME-{ByfwjI`&CC7ro3-t zoxsrEcn3e&!<@~^b9H7qD-qQkXZ!l4yBpuA%J64l#c&;g`mwYt{KN*huvoM(=@pioKsu8T>)`GLlRik3H`&atEIGAS`mp{Q>mGUnuKZBOl9OGuqqlC9E-WK+cXVz_so9qo~?~TNm*DAerY3Ht0$yINTS;`SQ z6=^5&D*aw@?Ea_kQheR?e_N11%`(JB%@m|M3H6H(4KT-xSO*Fn; zvuix_84FXhWmsj}P&ZR5IKRrtTvDQ5zsddBN`GVvMV;nb@I5Bm-Y!kHy;sVyN%&lj zE!i>v$1=tnDWHbA-ZFReLU;5MmqhVyY>vbuFNK_xcPT5K)A%>DglqCHzwTrdP|4xm zPKG1>3P`nEd8p3hY3P3~UogOW5}|btG>7v{8D%=Pw-(?0Nu~afW-_ofzW^r4RPH^G zHffx~yLdfwr_OZ`T*ZBavAQF{;$=pp4;^=#kqamB^Z34e z5q!ded%FBnC$pG4`gFy&OrOT>v`y18DX*wn96bf%X$ zM6{Ulem>S|l)CGt$+qI&H0d;b0xZJaAty*KbB%tzwFd}16S6}JI?3KDpmIjh|MVWf ze?u~M0LM`+0JcL|08f*1)cZIOxKvWyO#x2B{c_ad!XLdNHTqSkV1*mI(J0A_=nU;M zet@B!VqAUOnY}M{TA17i)I?MHwf)=Fw%HxsmKwc@+S($TBAMr*27t|RpmDL_7ygv* zyBKgIFiU2qz<^aS;5zP7-tVQgl72;T%a9TvvQ&JK@~;;YrUqXxCQSLai3wAKZxa)y z2d%0(Gi8}D<=r6uNf0~N)&VcRwJE*;_~RgbA1-_+x$5mLZDPUq(%!PT*EXM5k|Jv> zy(MXHManl{AGiPcdletI|H!@4gWhu*@1no(&59jzrKJt8~<`Q|0uWOgFzEa5yzYvcZ{iIDNo zfp{-;R+ZMxTFvz9W@8r5TFd$A&Yb5==dUWu%sK>w+Ob%?roGTTU@2Hm$A8K8RJd)uy;nQ2Cm;|sKcwRn9wq$%y|UoN9~9tESDTS z1x>eWdhoF&$w4b>5@S}zO=_={bC>APC=8=4&=1laP$x%!t$d71MVBj%+5e{kiEwu5Z1-%5^Eihyf;#;Mm+!_(Hs`K$*t`1yshqBE$B9 z+(0dt6_eq%w@_SyCXr3pTPTLR$kN@h#$uUioLIq8Os2K&wubR0$_VGAysOk$7hha< zFlk%qPIseDOQPO8Q51Sk;W%974sVH)O6_C*BcG} zYksVTu0G-*Mn zGjAd+4NQ@`);q2zR4nR%N&;QlrPAJITvnx}U;?Ys*3gaK*xQAE_k}&q8~I^4nt@9k zF@!x0mW^6Sc!r8}M}=IHtJsD!r8-&uvXfa&v9xB1S3yjZsw%w?+up>q90Jvx zR8kxa-Gk!gq#6t&72{+k{0DoPg<-dS@(5AcPUvu?>_PvyvWOOy!x!=h?`EdggM^`7 zKijN&awObv1PeCt`nT0#*H4#*r_zkLLY7Vk&KO-?j?PAPzZSg4ra{>}^FUKH^luvw znW0BI;maWKvP%0G^*Q`qch~TNPGcQC>;l0mTrx>57v+JVk8yl1S9=c77a4k+R26Sq zUwE`Xr0i(_q_Se*8twx|gcU2020fFl`W&x+f0KCDnYav9)UW^skjb1O4!F?)8YU6! z)q2{=AlFC?s_FH#Vpl?a*=Vbm(Z@`BH#eO?4^{6ey zS5@S+h0gjxXZ=hYA2RV1BL6}&CewJ>A^7#edoqXjx29RV|HpXF(p6r(u+lr5xBbJL zA-$buf9&AuU;FyWl9~EU_A8!_V&2f3h+_)K@-K%;gOC3 z6Zjj1j6WHH8*$>XhGBLfkZr*lrqSWwXoQumT;&e&2%|a zFFsbDt8^7UPeWflHhp*RA8Jv$hT&SgF=ZpVL90gt2tor2^*QN1gS>(|i=2k?4^h=s zT3YQAwA->q(C)?>jTN*Tf2<^-@dcu8Oe0qSJJ@9fJAwp(6?D-n1*?b3za?YtxI-FcUw z#h}8J-X3-AO}VzRiK?_$>Sl}P;_#MZi0h$c%jF*#x{h@-dw4+mVZ>!o6da67dIcTI z-oJN~LDnJsSY-XQOofWBp949Z1vzlNRiM=h&L=@yPrP+3`<5b{E}4N**1zUJ{x7Wk zg`|<0PEu_HpY!Ei{5(DqNCX{+TFSE1tXOc+&&fgirw>HUMGo~_i0%+u*6o#Vp-@o! z1J#m%dZre7Zt>!R{^3K^PD>}|`nW8(XN>9fd2*uv-d-oTW(2|2_V&d_Ud`5Z_fQTq zLz%3h5T@odo?_za(^X6jfmemNCj6HcJAelcCONSxsDZNK!4&23S{_qjFj|j|yt=$N zEJ1xCoe8Q@znfj=F;(ndms$2HvOqpB1P4UzM=n zT^`IB6t5d!`1Dm}9sOzuFTv@jM8|R#o`~C3&ce}K2F7YQ^m1}>$4eZh-Hy$S!AEfN zCdOKtH&(KbFYXA)1Y7^!Hj01`th8~((|5r$sRufP8-Hr4(g#xiTWsCKH5oj2K71DC zUo&~B%D!oGkaa9EUc+AgLQ`}0zL9lmp*=Aj#KFxkReFg^@8k-ddc5A~_1)$x28c}C zQ{DcvWs+C=r78bnyj61oK27?6*u+oTzh4z5+s#9+bg377t4qDqA5sUTMhD2*L7Z>N z0Mhs%mPsaNKHuUrok5Gq?5sh@WDg#Ms+sumDqAI$?3;LB$0}w-+8{TK6xQn)I_8gFm|ZxlCp+&9%5VaUo!2wu~eWj(fqJj|&8t z=zHqxtg#e`F|5^Sz)``GD^|02%XD>d;sTD|ORRRuWPQrY)!2fMJlR0qB)?pZs9x*( zX9Q$-k;y9N=bTVw*naY#v>=$>3(Uw|4m66L=8d|UAA)QC*zD&2gOq3Xy#!D19_~|! zUi)gl#Y*G-VUXB0O5<%J^x6$Vb#k*1OYd=t6QREt-v;M$+Lj+Hd8ae&Upb2W1J$HS zE~LL%sp-dQyTD!bCJ7A6_?j85$JVrpbZlF?|D@^Z{&Qq2^E1!>wAvp*QHK?03!9Vu zEy?wt~$WTtY1Q*gObw>PwK!(8pV zN&oNaPiFm5HW84wIk^fS^d#nVc+<9XNW3#=G6gu5{0DA!7^JuYQe45=okdTWF*p-n z1vqURjwF`@RFKLR{+{Lvl8<4^80hJ|y(VK93j@Qc%TR3@=zRdH9c4ffeD4sE>;sVO zcxpi;&rf=jN|WB1BS2|Y=G|D^yZclQ>WpXJj$ya%J)ymDKCRS=B^n+80u$ORjX7Co z4q?ArFqIplPXCVfQuB*5U$8Y*?5mO`xyQqjnP<0i+5uCz?WyeLvGzg%zK*+O=L@y( z#|M3u_O2WSHm8#5@@D$(4xVit@h!$7HMqq(;@h0Y<7FYl{vdS73L+O~fphh*<$~}p ztxk@+)O8v*s|fQi5lGuQ3}YM{-Z125g1Js*F$bhCPI{MCFHT%U73t;p^n>eOS2axP-)wc*zqjz-(&DpM{>AOOqy?{B|yKp50{mq*2bCx2VZ^ z#LN}l_JzU~1i5u(<3gu#39rzKLfD0-&r>Rr<*zuIYs}50v6H-!^XG%7+-xRglI%#Z z<%#Yy7D;}EjhOC0xG?-HVwKUChTqpkXM6Yu{bt(xg*R{kcl2ZJ7b%cN3M9tb$-ydP zdY-Ww2^p9PWjNT(1d3XIQUuFcOX$1p#uB=U1ck_kQPvuIjHUbVQ_)g(=oxj!T$#hq z;|J5p;PeBf+Rv!wyaMvAF4>h0+`Cfzc@_7TWoA_{1A9~0*5O{?m_HqyhDCTc65d-a zzir^I#jE50wD$={A4b?`hdBkuaXLuaoDO0nAt+#H&jnM{-YW_3Urs~7=XHY%!?pbO z7OKN`5USz*@}>AwOLCY;Ge*e&Qp8K;zd^<+V?-F0f6qJIK@MT3v3QE^!Dh<=?)_&C z;GV)>>IPgL%lhF$csoiJ`C+hNC{G^X351EYlr9Mtl!^$?sN$&C?@GLBpyBmkrmMuQ zT_v0bof#3aL~+HVvDzWj0pY(I9PrvJona~c(q~}e^BKjsfX1v0o&`VQk=-p$m7Zv) z%7#`o%SI(ll>EfhmS#yWn}B=OdY98iji{3x*K0RBUu;_cB9BYSl@^`A`WnmDZvCf{ zi>A7!N~#;vTFFUU&Rs!@<*Bv}{o{t-k~p9==ra&15#)bu=2!9trkRGL{ZmBnI)qdYkSF&0b z?o0KwGa&p7%o;70QzbQgVsL(+d~gD^JzZQKEU%aE%sRTo)T9-jDgy9UgfHMxY2XZ( zf79T+GVDJ8qwgB^EMZ9ilNoDh~vF1xL zKPL5W+c2VeN?~X!8(;I?zKR#_P`ppxOff6NZH}Zkk#*g=@x?gprQ9KoYVqtab8SXx zl;ygkdU+CWpg_)(_%@vTV9C7kH3yg;oyh=J+X1YJ7q2iKy3+Q)V?^_rh4c1dv3>h4 zHHUSa;w{X)S=zRth+B@0Qp$J(9$R8)&9II`>$VT&O|D$SikkgR8^^}HWo;WG3ym>P ziZx%@uX&0w(2gzabI7NH3dE4NWN1M}tf2XrSo6>N0p;e2kyRItRX`Hs|FS~e@+};s z;>;_})@|&z9rqD+&-JdPP~h#SX`E)NWkzU_1N(|@$#f#;Y$I0->vNOa4M>EJALxU$ zhjoY?$`;*tdG`n3u^+6Gh?jjEJjMskU_M|qrj)|R=hgn7R#W@kU4`dT`1!A!&(|vV z;#xB4BgXubtAaCLe#J_@Os`W!dgf2>jv|T9ABpCFvq}qUhIbA>a9t!Aum`F;hi`hr z&is0vD)QC&lIc<1tcwb2zL}G`wS&~t;L(4+(nq4?udXjMtJw6fX>E7^n5$ONKg@CF zuR9DHX5VqXJ1Tb~!K@1kY7TKTERE^-klMAK!~ZK+vk{3~UsuK0|Gg{j^WoR&Kk(gq z3pLgP#78=w1x+j!PV*19FHKSNyDyeLV#kaJ^Y6oJsQgD&c3q0vpqsi*1 z(1G5N!W9=p%BvX4&WlaaWv;%|nAR=vl72ONVX!w2g-khwB{{nF5+{kf<RoR#v`q`u}1BsUQ)lF z=4Q6eBTaQYX*NC#9k*f@C@a0?#;eQ;qRCZZvU~+b9cBOr!Em^ilPLfmOw1}U{$3KE%`2G)j}&eEVRtgikmP zbL6d+-kSKT_3843PSbLhLlc8OsPs0k2;-UcvG~^4<6~Y-#5ngeJ)SUuW-8Qr;+$tG znDS4Xp7I~6KcRvG|nmR>kYyDvY;w^rPBV4wMeh zEmjMKWr?yy@h8wh1y9w1yttG2sB+MY^a7jbS{lW6<2lt9I*s>G6X!?AIT#yXd!m7m zlf>q&EB0H`xXEd}iI+wq6I|-gsz{CACfACS(Lp)nJ;9~o17sG^2f5ip1|`e4aJ20f z<5HQya~;*#cmd-#lT!kg&E&MW%catCKyH5eZ4+FSn2$SUtZ}D|1&lzwb{dpB9cTAU z*T2TNRlJ#uYD*jbkw^OSM@=0 zI(zU<{@(@bwhxLcoJa6Q5{y#nd8aDqQyrm7U{1H%9SXATL&~@F?Sab0fGk&OGAM@oCOQ^P><{(nf8{pOnxPOa9 zUZ*QWaFB4rm0ZjN&=2x!yM*K;9I0-=MArPOI@h6$4e>Lp-P@ z&TvHpN<5ntEWgZvZivVCITO&xVj?Ht+KOasQK~=u-QVy$Kl4;m|Jz#akN6VbP7?pj zaX4>M{fz+SM;PJB&FR?k)VQWr!vHt665CPY9>K5&#+~b*O%y-NxfNn&r|~$&IAk9h z!Dl!T*r&*PP4N1{$h|eGkY+e{vH4%3=q}e5OS>!q^9~|q5%Gcw7Iyn`Z=L(;tHw>% zpfC>@Wu)8N#br>^?d6Kv|HtQV6YcpcAU4rBxgs5s^KqqOn^=N30Q4u~;tEpzCjzNV zvw=;p$lj7uV71H~?s<=K^uW zfg+C@bm87I8z1G~dY67$_ZCX%C1;L29DTUA;#!X-3}zyslh(gA2AVoHTX+|bd;7Oa zd1X9|r%+ih5u$2>qxZ|nkN4>sOf#SJLrPQL&qf%<(Y9VLErG(iw6;SDII8C9TkFzN z4viizt$Eg^rQBgES)!77y5`~1YRBWgfrAJJy4j;~X-T@&;nzrVn&)5JAHn{$bYIocW7yB}Mj2j&I zjQD6`w|C2gvsnk1sVC>-a=jVViyQx!x+Jix68P)?!new0o_Qj$k007(-Zs|h$FuC> z8z$f+6!Wgz+yK!RR5*=4rN<_%`6cG!eW&q0ME~N(zo^DBTPn@$Tp1!?t@IP;MEWm? z!#v(5A|hB&ke$@Sfn~G>);I^{g+rLv8Fjeyd*O$;hNY6?^DFB6p}0uTg(})4#U(}6 zpbbqZu2IbB&)`y0-iY`0^epAiK%$Sok%-osAIAONlbOXxLL-$HH{P$l=F8Byw<#w^ z4}1i7!cwPX;#8;PnCVW*^>vhWN^UcfVYkz!awv?sEHNy_K{V4jS4Je|lw{`XXSa;` zVz=vchgr8oKc2Cx@@%T`Q3i*2#uEK9WbA+ir=eL!`&GYik_yY2;2%>;VLnKVupYwS z;-p}D_v=aB{=nTIGSj<@Dvdv|*v<#<*%KGY)4)GcR9Nf-4lyQnaLRCAY2SO7$#M_9 za0$dFPZVHi)6u;B#oi6q@}gqw#Y3E?IVzGpz8IhTHl7T{zj4XGD*Ycq(P;FOXGYBg zacr0_^hPSu=pD_GN})Semvb0SJdC3JFDmZpNU7-vp@!pbFu0vFPm-U=G}q7SK`xrO zVXFx;=-KpQ!=n*peMQsD9-`?7sU)I7<{N)KOKv5s^o7Cs-vC0hiv>JGp#X2t>3Yiv z#jgf?4CC!Nyk!k^UdkJR!d;8P1xX5B*mTN&@U=#v3*OPZO^jzFSSd)W{gzhiCNMKB z+T}EGfzhQf26@8z3S-EzM|SuSN(Ym7qgjPVvdebNQpMO3p<;qzE3>B#jMu$;74~Ik zeAT;&L7z`*8P7h4h1l*$h?y@Fn!9iK1J>-jh+*jEgr=D&w=pXf3-fDLel3-EmpJR} z?)legdVO*J>!N8?V4Ro5-{jrNJ>JbdiqTn&1)*Sh7_W`<`H}~5&mFmKI~nYG1YCdn zO9R(np^7=CmK?|j;hi?Y1G#9EU3z_%_al;l69%IBWw-~oT}T`H@fn8V zh0tKKn4bSDGixkHbQ{)?qzioqAvWSnpR#O3| z@jH6s_VPhh#G0q|YpycxBsVAEd}9)an`zBfRsUuTFKk!KIvt|^6U_wK7f+#30XjM3 zbT2z&aUOYr<45lOi5zviVevht%Bo`C3T6dNBbuw!Fzc0=5AqOJ6^1uaq8p9Vj}V@M zTO5sF4u2iNN{Ex!W+I%9Gmj=#Y0ilw*dJ1CPc>`MbC%frvXno)IP*jSLyy&#B1Vh3 zqD*lu4i{fH81(XE29ut7rL#R_3IbPjj+ZIaYwsbIN_h{dRLW|#@Vj!znZmxWQeOI; zp4Hi!grSV)MhCzpCK1fuD40me!ELuPt%8c4;OFsClnss-bG8G?+@*>On$3Tl`Mm}bv#1F#2hwz6 z=&2%iBeCkn?*c{rQqQgNKZN!)XQ(TNDDq7CaFX!Ycqe^6pa)Gnk417s0Y($c%oGWg z{se)s4tGm#9pixiH3EMNE)yB{R^ZPU8@>pXy4Ep1{unk}z!PhHXepy0*bIx&*Jj#f zHRB-Jv82BZ?}4WCi!IA9<}{qDPITEr#c{i;k(GTE9Ji2FjUO6ODjP=&8zYfdMmD^s zWv24HE_mBf0l|CJ-q7ka`Vc{jnPBX&q>-YlwykN)T1B$79$Z*L4oR>iK*HpL`Al-$={m zeE0BgTmjelsKC~6AJz@>79?z?fMXW;3X&gzjqfuYc^vR3EUMh)_riXh&1z1=Q*8Q# z=1Ri9bAd=O_+QBG)t-We^?)xEG{5BoSaT5j`@m=L_f{~|VK8geVKzO@Ev{GKrTW7swYk0Vvd$GHpLko_k{k?-9i1%`5e-px?|xW_P5 z<9Ru6`mZD^>Z8xn-l*=+cGKqPXd(9Z_OoNVK0AcZI?`4;i4ShaN(cfV(J_|I2;m~4 zfx3bC1A1zJ*scP5bieq1?#2DQ(20RGxO4w<9$QKx8=j09Jb3si9QDzNd;5GjG4QL- z>%O-R2!J&F;kXEDOFDm?KY))xs-Jv;n%I-HU9QJa&_DFfVJ(aT(-cD zp7Ae-hY@adPf8dSD6Lg)8dt29SSzz`d$O;!0S>oq&_`bi@46>Nlm#_E1~AhsU^o{3 zCxD`Rm2>2m^nGVz`ai*o#Lc@H*pTlIC;z`_FVD$;*W$jM{9hX%Pu7_MvgXmyU9a)L zbq+t8s&m?R2b6y;eAhi`Ca78x>27H69U5BqY+qy8k<7k&Jw(T@k4ps3b**5`Enq>h zxJ^L&GegM(+Vnmfv!3jN#_b2&=r}v-SUCq6!rt8lXMLD{DY)eH&tOh&lcnsRvRfyr#xC-}@6XOr? zrb_3mVM)_bVhsHX)NlA(A1v3#f{2(^d+Tc6k+xR~594cpp zLKEGTf259B8hCD{^UB)z)_<^5n@NK5DnT5NO`+Yfq zr^d`DTIC~W!Adu_EVbVTB5QZYTA(4v`#vqiN!`&|x!*ds^Ch<}C{JZ4Y)bDJ#G4Cu zpV(YEpu}xk-=9V=RT743R=M1^H+6r4TAj)+Y<9U3uQMY=F$9@EU2o8;h0#TiK z>FP|E3U~D9Deth9N47xk!V)3~Ylz<~JdJQZ(n+@bIzc1osK1(WHAWit;FqIQu{6|KfA?Eyx(IINJ(enOFSw` zI}_SdF&yY02H$!2ZM#=VC!cb<$s%?#A6|HvQ-3Gr8K81E=(mCc>XM_MO=o`&_AM?C z7A`*!Eor(*SqgSTKEKBaUESdR)xZvw}C-l16DVyB=R)Ahy+j}%u?o!eL_kEZu z|CGGWE}nDF4CBU`J;tE#IE2(>JT6E|Z=vP_mQ9xf#A0ofPC*dbuQgQxc-|6PIHGnu zp^5$7$FComyiR}hc8bC zNx~iznk)ArW5*|*HRIBwUrhRmfEdRh>81HMiR%PWeaDhUBh9}_Tqm}1zm0qTP1**H zhqsC!wytrrlQy~gPcCMmVpoVeh(FL-*E*uFL$HEPKCQW1i zNZ*i^Hw9YCk{<5*p`Tpw85lPig@#XI-W;FL3I>9&EoePkr^8Dn<-YE99(?A#nL6QZ zI+60xG4KQrTwJVGk4dBWS3$mqDzjtEn^YZKTp>Afqn3YMMbi6d0u?oJ%Wmf!X1w7ZkNvmxHoTU785bTZSVfsI8aiWut)&#FHeb*QF zQzrN97nD)DhFeujW>$b-;~!kcv4X&(^GG$T#*;?a>AP7sCY;uO+ZNo$x9rZOizSIc zTQhIP+TPl`a?qz=u?kbOyZwGU&YGpRM-B4P(Oy7~1J?{Rv56Tjp~k1HTmF@-$Xsbw zWQaPv;a&t$_UaL)+@vZtU?gqW@us6~*l}>I4Lj!CgewUWKKIpuJ5SM>kdeR>9Dao6-E&I0W~sa8=;%4ZW48x8gTi%K2maN1 zyK`a6vFW06{ehrIaT$ISF2v@02eH_OiOMv6{?4VMA=vEjc@zwO^$E_A7HVReK0mDx zIp{K5bSD;V&a^AL)tGkca6MSluDyV1^QodmgDr)p!6hdL!Bc-#c-j{jR9H{Q5f<=B zd7p1=J<~{C%}>fCR1u@2+hNoRES!OFCk+k z>M`jdi;6C->PB|In+>%*bV`m|Zuw$+w}Mb)qMg%KnQdPf_#_&;7(tAQu-T-4xsB>E zwA|QsXSSRWy*7h%+3ug@R?FqMVzvB9etNE!Usl6XTJ1^X0Y)8-O|tXO&5{Djh6_mk z^kb=fT&xCCW+>7HDep*D#~+}gI`T?j>DF#iJ_(>vC0TQ3{4AzVlZrX$&MXm4xU3^EDBe*&whUtO5b4LGNoyL{$zZTfTX4ru z`qGaP_@?JH<2KBLPBdgIUy1Kmr{H~~72+oNEGUmDAYe7F&JR_>Ppn;B0lL~%o}a{O z`RrKcT+4M}t|dIOC$A2EaJ#JE+EzSJOHBNdY>@6~4-Q$MQG+Jh!+ip^r$1M@`z_Lx z=+&TMO*AEHHI=vT5a7`!!`W=t+Z25M8bU8KYd#s9h?9Jz%bsT+;Yokj9Y*?x;9$DJ z!5NDPecA-oZ5q|R5Lv`ZkM@-BX9u{x=V&C|f#mv32e!r+= zm@_IWy{+!JJ!`(@`tjn5=J6xkPBu)QTH+l)0>qS>8J0Fk7X2zNkiMwXkroDjc;TPW z_GWKG#}WeZrtwP8U!tPg!B|Y%>Gm6nux)-wo$mcpikl1fGF6{dLW^x12hxGgqh$Mh zL0XtOmqTP7PvnFpzW{O6mRP^8kXhU|>=+wzX^|fv)bTz_CqtuoUg;sM%;bHp?_KOw zWtyw7tH{5+W2@oEGNE>qX5OWiDTc@KHdEu#{Mb2wnDn4CEks>w#CAts1J(NXmWV|B z26OySrT>k1=Q4sEW5hd+o4{P_1M~I-Hn{eC+POwHn`;xth3j-Jq2QGCb4rdbaY{}o zRYJ?@acA_gCHyyle^W}+{<+xX$C85QLbirpSeoPn7njXtO8i%$V?>75T~Sm(-SWtG z46sLu8|TA8MkSnz32M>_ksml+{*KdRV*bt#zgpB`m?{#wQlrA$u4`i1&IH731(h`Xv5 zDQx9@DH&vL*IFQWDUP#Gk^U9#I{A<)u zs(h)F(c_fgr1q2k5ad3Ya&B0dDqj+Ju4_w_vNuLqLzKoX=@+(|Sd~Glo~e2#r?RxM zI;dMux^Ys8Hzf+Ud6&`o{dLS|zf1OHL^~XK(YO&shT$=;iQRPtPTev-aO)QeT1;Nl z9VS$!mswLn?19dPusFA9iGj+R;DYZVDs;A3!%b>0@w|WX^6&#HuKNu+6L)p%e^XKi z+?^(!Kjr!@rPQAC>#Hbi;!YQ-Q6hhEuet{vGa~6s05;ccqeIwZ{pZEvPZSiC7AUu2 zrMEh>c5Je(L&xjIl9|^)#cHPIhbP_EsppGwD<=N_s2VgS8b)Vx^l2VpNKI z5;!^PL;XTg0C+FePY&;Y)<6v~^!VZ<%<%phJoSBHe1qHGq{sR*znK4AuL)IHVD`N< znWQUTQ-vPv*5vXNrF~`ZdMY~$NRjaYC%~Fu`9T8KQDAeGfd<(?vbY6|yY_8z#OKWS zva5}5ZA<4Yx^{$U$24{`jzWpV~y7K zYjGbAy+1NO%>Iy9?z0-ZXG(T2a${pWX)d{A1$S$yRu-t$l1)U)kHbyr#jy)t4@>lOa3WzZJOprkI+1xbow(3Po! zCXK+mx{#5ILFI4GF=*=l#-QTP%@J!Z)MkyQM-6MX39?DRo_$FCW(Kc|i^-9@IT&-0 zG+9Ou^e5uPOcy8G^haK%f&xTDc5z}Jgp{P#FyrQ6;wTHD#@8(`Zh{xrT3)RFVK*<{ z*Cj`MB=Ah+Fzz zuZ)ONHZD}B-BfSfn@`>M+>>YDT8dh9ZQgqEj^F>W$M@&;@qN$rqRe~KlHLnxri)4c z^3qiK))`kMF-Kbp$2yO!j{C8Me>|Z+EjHY^#b(gFRdFn-!M7^hI63IKnu=7`Jn~*| z`=Ebj{U#f&O>m31hRm6t5wtyK>6S&xo%t?Qv^~B5IX@~+??3)W=|S(}q=T_4TW;U$ zTJYVmOVncgA?2=p4qwhtqgPjmG00q-^sC8SyT-}fOUzBupFY;#=V}rnG?z)EwY^p9 zvhgzQpFJX3{#oti#wh!Rx|+R;bgx@+#G9|;#Uuqhgz+`}@LKBi)^z2d#Zf@I)HWyc z6H~CFw2~yW31ynxl?H64yXUoR<2=5O6sK2EH`zZ;BDmQJX_uv8gWAJ@Ukx zQj$c_uK%ERKBW9xwG2oI<59#s0&XYs6jhTJ_Xvf&&+V7rqf~5Z+IL486T+huH>GiZ zh^G!cX_T4woP3&>&?PoR<7T+D+*?g|_P%7e%~K~Ar@A*|zwl)~!0C-EMS@ zg;ef)qzls|t4gt$Pc4yejvF2vVh)=4NGns-9SvJ%*V7!Hy;Y>DqN5Rr-10xDbIzPC z>P+?!)~SYE4DyGBU!V$=;?%4wfx{~fVB>GY;rSpVk#H9hZ$L<}fuDQuI1D_lbedNg zunB1I3JuQVZ-U3mXs*&*Zt++GFrCNWB5&YMN_eP~yUqHu5|gJ9v$F^TBsFX1nQ6Ud z0xkB#Tt>>E>%-2DXQ9IuGZ2e!G6@%VMo?Yi%&7;0y`lPG*HBui$U-$^ zv}+H4jt)Ea%~7J$_yAw#o?D94sRx2}${UsPW)?FII)oWZh`nYeKlXW5amRYQurBr= zv}lLad^O*eP%vrv>I6%jT>Zol@XUF|LyYy{7NfN|id!<~~%HUTJ4l-4}$^Qe92+36&Y_C>2 znX0Z{y{TT6(5n*DtB0N;x)~`D?gJo9IzIa4dia9yBH|gC%JG2`8wAxGnWOj&Z&mOf zpCx5pS;1k2$ttr39)6B@wFTK}x~Fttg4r26?b_c#D0<11u*1x?{<61_vx5@K{rge^ zv+kz9YxP3z6wEEwm9;>toO-tsup8b4P`ypPM!@2&`oBmC=gLi&SCjUDNo4pe-?*Kv zWU^BtyZkYmFWU9RK=TDD2UpN!xE^UPUoZ|<7J!RRAnG|cbJ$XEtd&1QG1eoO<=_r) zTd&S|ue#oUFm0(i?Y$n{!?c#1bXcga_W@gm!%wsyrjsPX>&UK0?u7163D6vVyO_PD zDesNoBEC#|pK7Vi+oCUbXW11;nlo08v}M8SxA6RBi>B_Y9x7K@u-HDiaJ-(h1&`X> z%gpVo!907r{KtArAiKRC#OF++I-aJgLn+DLgy2g1>M2Tg+`#j1ndd8lbM5oH^?ZR0 z{T}`yW6z**iF#24f~*QRJDDWmahyZ5#m;_GDf+*@bu+2Abz@>>IpPU%W(=IItc>Lh zoG&nNHmCQ$LI%zu7&u=b#GJ+tkdI$!nn^M!uQx7^B~*jqwxw0!A#vJsjEW>7=p_kD+t)@{9{)&&uK( z^<@^H$!D2wDV)=#)9UG8WGTD{0Y#R=j9-gu%B-M1&xpi}DEQ^db1yTBJbUDbu2#OA zYh}iMJLq+Ztz0sC&I*CC*K#5)i4C5KxlZEqq&F~0YUhM^){d$^-^kjFYI+)3my(hu z&%mljuBE(eiZ3i zT+SvBaWEw+_!I@BrqMc)W`35^Uus1-4L3@X(hgJDz79w?R16W7^B_j*^2NJ6jDp!k#?L` z&B_QMVPmfONQ>v`(HEshkGo%*2lq%XJ$e`wn$%%kdX!FeSpueS(xjw)PoRau1xnxb zDLLrT#%LkqBM;9~1W*qp)?J6y#V9dOWmOG-&egCnssSzAXjB=YmsZQZm*+LR_SZ(s z#t+YF*#kM486`AgjFi*LVBNpWZQCAQYVReU;4(N+1&GJz=kbwHNpSUAQ}QfRd0Q~g zemKqCz8c&T)l-Ht8_0LdxsYD0x6emYj9q-eCERxTw0h{f`uCb?#mssAi%XN`A9Fg8 zUGQKDK(Bfj{_(oYM-lmQ9nVpbqyyz#mT$q*cFND`1FZ>vw}gKxQ~q0T7HJQ@)lT^z zyq3Gv;0MLh$w9BzOipFZqc|yu+ct7q#=D!M^jz<|-g7KGJ9oWLEchwM5vEANJDmwgc(<4k}NR%n~Vke`V2wmOEc_NrTt6TUU z?8fKE)h&1MKX4WX+?v_j(*(1iQ1loDuJnCdH`h&+$iadDQkEJ8S$TFOOp(|XNKy;6E;Y|3brf44Lyy1aJY(tI=bgvVqYuEuhUEM3iM z-A?vV7sP7zL42`-R>jE?tCFJ^rA9BuOTQ=?tE(2l+2jOCZ#vaZ$M1K@HqWMrYO@B`TSY|3trK)+ll2JWY{!-B`$b21rn?1_py189tmP(`ES( zCKb)7h#Hjbla}rC(yoF*Rq14GA2UDS6C$wl^Fvvztn{9%|CAPro$Fh159~v3hqlUw zB{hdzTZqFvfV@^V%P2%wqb_$%&8rwR>-uQB%8@fItE9@;yV*-IiVl|*)Ib5AToUSZ zD?m32I4YntdvT0|EKVA#|9|%l7zN#o1p)w`N?5iBmI_p+0Q9 zTB+E}aetqOlqgT(C+C?uI=kvf#$KK554%1YMW-BTKK`QD$I-W=>BDEqOxx$_@^$pc z$xM?z?pz#><2T{G+%Y`axm3TqQ0NO-504J#uaXdC=Fm!en%k)GX*2~#W#f4HC(smj zz(>lQ1+`!ojVjK>BlbzMe4(ZB%#F~vx@g=s_kvN2i+cbw^_yMk_@r>c=Zr;+zUlcE z<0LBB(PC_uPwIP*h;E610A0A9@k*IS!_(-bs8;j~h3b#fus3ZJ$CeyTG|gHqG({wA zJW**Z=5Bu5k0x`uZ}=Y5Ho!{`Gv5 z_LIfC!9W zc8lPQ8E{_V-powQq%0K+;(lS1O&@dF>81)Xt*s&%Yn$jFat(4M47+p4o9>BAU;MuouoH&_Z@`-p>uM=L_u@A7R^n#AvlAX_ym8oM8h2h;c>P3 zI^g3jj@@7MW;u2r0r$SWEW@^?W1*3q*Td34^BVKrgZi%RE#hx*DkQx~b-Z9y$1C!( zJe%-VhkHw0_MTmQ1cjO~E0%?144z$#_skrc(WPVY6(5Ika;=Va%l~L~?9Jf8&5l1U zojv4Aqhl351()??K4h9Z|p%RTzaL84@V-rs5cL4$-uAl??aR{L&fQkb}gL$a%YQ-;|3&UEqvqNXk5?Z6q(xTys<4eMQ*-Rf{315E~ zp0=6+RQ06#pDc-k;hF!aMWI$ji;M0>X%*uPQk1P{-OZJM4JI1QNN}c#GNgs^#*w;3eWi%?^R~ z0j9PornVP%>f(Od^4X3q?sJ(~+CY6M=S9dY{up2$x4oXt1=&9k^OaXE~` zK9ZBA5zXib8Dl#GAK*0ZI5dCmUzx2ir~CB!bT3W*bD!3pVJ7=_m_IR3?Vw{Fskn)S z4QC)|try_WidNd03;zv}BO)9@@k;M_ox9R8plkXb+(Dozn|uJib!!|*)&}|7oD7FS z>`1E@0Rmxy3HRtWceFWAF_J;X7+yEOrAw_QaBFSFjpx`YTV@4!otbUM7xW$Nm~AtYE8_ z!XFs`8}Gh>c+kSu6}H&m?6E|&8~g4-@J@lOZH0CidFv!{_hSown~@k7|MqYpqW(*O z(MT;qmAovt+w;XTV=!X*q>!@Y-?O^mBLv6Ki=L1ysGNl|4$&1XpK8qLsMHd zwowx609I?FDCb}T``|eety-|6xz~w%tCdQEIG}-?5Ka!K4t1=y(pD?hq1dWLMNMSX zI)D>ktBuv_KE@%UGB}Xm=eyS4XGlPM|MxzBo`;-0ti9H|-t|uFUGI9=Di$t?Ws$?> zwOjNd3l|&>n`t~}0b@0|N>`ZSGI6q4V#}eZNAbyZ+Z&!OS|3Qu=RbbXkUP=EHh_*9l)xZSG()$e`nF%W& zJ)cg{7I}pj3>HD2$Q{qDn)O$OymRfBtZ|s;Hm18UF#IK&f?iQ|u=<*-Fydb41Cf2)#*v!(Kn8>%F+%k^gM9 zw1&)?xCtpv?xOQ@3NPBr#uKm7TlS0Vz#QjFLKO?r8~F28F~mQ`rSVf@h%YZ8mKaKy zLV`RNV!RntH0<#!W^%U9h00nQzm>|Osf&?2=MkXJD$b~AU9Z!TQnMW2(Gl1C#L}v( z^Z>OS+Fsc3JH3zx!X+f1t!u)DLndq(&y0;3ZfWbSZTW8IoaXU3){ozQknk$3DHJ-( z4C71ev0%}}{=F|6er6?JFbs$Ze)ldspV^q;dq!kpg0Fd95rzW#%VUE7fE(32oMloo zMtSkS*1s9#KXz)^W5AXQgbd98EP~I(?J{`d+}0)LV0EW`2uh`OiH=rh_O1=UZgTc4 zvZ1rTX?`tF$rw=S7C!IlObi`45G+(V@lxJGK0kST7(eGPLHK%Cf(~|eGH*Q}S;iQd zT^*LaW5`_P@KogX5xrlqBVqrA8?RPhid5QJyt7s z9bcowMyIUhMYsFyq4-JxvIh==@4ch{@MgdB^_fL>I5Imqy5gDeu=VWgXd7DKRD%-V z)ysC8)523t;2}E+;Bg>im5 zzA|IbUw#}1qC3^5z;ZWl-(yBr=pv6E2gal4Q(-`7<3?quQBK1QHQLeRm|T(nnPYD zfE9TZ0Q)8((k@w#314q1gKBbM?R_vA+maYxM8vx@Z<4EZT_)IcG~0kgl+)vuYo>84jUx6vgv0g^1^?B#s&Ytj=B^+)9 z5%n1&dY{f4To@u+a{17LL?8J|<}6oFEmJCx8hM5h?Z^2d@g&`XM*lWuTYu{@1vzP0}mP4?Lm{fgPSrv^^v zX%;ejb+QF;&bzIY4m5W*;+_QP>-H8|YfOl!A#f4q_`a^q`~ z#~(;A_u_EEJusXI)i`B4Ib~)O7p|Wg7ips7$3m6im7!`ZWyq9j3&Q?}LuO5%dcSAx zqS)eVyP&mJ-uhbzgJ69&)C>yNciJ1F1jVfT8)}j;MkZi?l>+vSiljDkQ7L@6si})y z1@24E;D_<#=3_JA5&TOa5ier)-Zb(!n3Uars+p8E>={hTjzfC) z9wJR4nzA3Lp5TKv`@tTW5B4;AfY#Cmsn%U#fEW2-n-CFh>sAY=n$t?yC%8|;>mo>(xv^Pm6 znAAtBD!ub~-OFy~(jOOs>w6y>C;_w|J7~NtuW_3!OD&Jkd;$Sh=5kal9rC`RN_(jE zUR63Jw^G}mCNoF7xTNjz0^l;qTRTd)3X)q~sT&f5l=0&weoAtS4i(fty5((tSo}m* zmsWYU-Q?m%72mv)*R3s+-PEKeWe~d6s8{6L61H9Oa2CSeyW3n}sjNqoSZ#hbde_^h zi~ZXU-6n1|wI&E_Ufv`mGiTq8{%9*KXdc4tt=m4P+&EBKe40oMjE>UmNT3=|@~Utp zmt3C!Zo))=me-4$s*docj z_pei0k?Zt2yu=JK*m>?(>=vK1(%hy_UX*?DATO>$K&rJfpipO@5TJ=Z0YYimeBun+ zLu_3|=POk<&uAHE&5;VIbc7v`5u#|wy@=J)Pi_F07QT-U z%H5qjHB+zOLH~OnF6HN8$0ShLk4Kn~wICuguN?R>b@=^*W#H51;#ZlZz^|+4;PZiD z_sNHT!o*BBE%Z6)_-+n5zMCy)(ee9l258-Ge{;vT5E*S)J<3M&`sUfWqwSWwId{TTsN^Bn5wOinAN`4Q`q%b z8nL$(I3FO4(pSpOTl^x&BL+*4vu|soiBm${o@Q^|XyWunZqK*3lMz%++`hGk`F7ev z!%RO6n;8qz4$H7_%4b=66(5EDoaNo#?)wQxbC#=faBp^efp$&Ke)c1?Ri1CESygR8%eT!! zmzxwXA;QWJOaog0l^8!{Eq3FB2=F%`UQNhteF)Mn=x@f>WX5u6G;w-XcHScL>hEk@f^5I@-LH|q2Mpa8?&V#EG8%S@iEXnn&RY|L9Ic|TMPfbRw zUAjd&LLtN%HC=v%Glovi=xVRwg_legEEC7O%C=y> z$D26cd=xicMSYjJrOK!`P|(V)cjuKtffN5bH;66r#+A&6$j?Eh?VHePh4W9U`YzsI zveH%3?W)=*T6SN=vEzwuI>(%3)H!wC&F4wSR|?X}a%|F@`YJNg)mKf^?Q}Y~XV5u$ z*5L4?D}6Y#EnVcKb}b%g^Z^$GaMebK`H zE9kG2xLI`9$oc#j;|C5Z{p0nr8?b?-qfUe(OG|;BCA4` z3<~+X*1lv^?X+ci{3ZWXhNsA1A)ZRIA`xCtB$klU z-&Et@J#J`W&8TntcTK%V1@t|{^ew3 zm*MENn=rRjxog1lDL~jutV$mU`GLiB6~9kA4>F*oGc`#_7IkxZGnXz03cH1?gJDf_ zbOuXj{jWnWo#9zyhBoguW=Jzb9&VBW+f4dRF7ZrHgWb}6NZjuVj zY2_-KiZr2V=a|cz=IUMQzBcpoP~7}X85K?4*KXcl3{p;LjHb@gMvFbFq|Q*CLvZzc zgqn?FlSUI0%eXB9aonPWl^~_K+}>746Q_>iajl!UFvKrto!CfcM;J6u1hM-rzS27>7+xZ8q>QQ`?`74tkYn|al1gP*)VHtNYKIJD(N9A=Hl{}W)(YWD zNa^KlIcrQ!DGQ7#%m1~^X$DsQtL#U4mKp|P@k77KR(^4|oUQzGC#UjE{e>+*V0RD# z!dSnmWREGzs$;F+!vce+& z#n6ESvEY~t4hIoLbq;{jvgIs*y`^~o`t;m7t6~t%)nq@-YXSjPykAZe#o2PUiTOEA zkYh=_8VuP9712}}y0E4}ETN+SZaQT%UT1=^m0W8Y56)!)Ru3j~efPN-qFf_$5i#hW zW6kO;i}_qnGBp$Gs=+r#P1A0A1ObGMy(~%~&;oH#K17wKO7|x0%jR7Zv)@}TWY`5S z%i|1+OCW1B36#l5g-J2q(>F1-EB@7P4i1vc&Hc9n`gw26j)y0gexA&hv$%`ynm0U8 z0}o;7M&DZfAH~*2x}B#P33(Z{XT)jf-kxeOVERO+Y^pn_uQ+vGe^!+F?`?+U=69e``&awHjOtN3fZzAuv=kh#la8vPi%1LGXbMnia|;#Et`v(J}Q z^83&+{Bi2LNtOK2>GqP2MP*cmWDP|1fuZ13@m04fTbea=^)93vDILkr_aubBvp`}(v z(`4`7Rn{!876!=bm6}xH)_veQ_4IQK$I3bFnssQN1s-plOeqp`7drFS8>q@R?Ml%)M@B8m+MtHx$MKH%XXoS(Am&q7fTGhp8$)d-6lPPZQ zg#uwOnz+r6I>70X5tR{zUNm3d#GA7JJqoC>SSR0dBiG?8DJ&#BUX$%+w* zBMAb-LM03zrfG=1`ypAcY&i*4^1~2QHN)Xm8A$FU4$z!tmn#49*Cc54o#6>Yd#?>} zx{%Es-iq6BDyNE%VO`8kU26%e#6C%L-s->o2WW>IUju#3qpQGYtW?h@qS6=Lvt zIVKWD|GGr?;=(vbLTLwXGg-?Vk59NeuV#_}&u?n}R)8)|b@$(Z9pAss*zU!Gxd9Ep>T9a_6(l>C zTev)=PP4Lx#Xfc#marPv$0VbRhpSm6S|eCAAxnHJXS{dCa?36gsZr@eGq9#L1?O!jX>h?y1{K5;5yp~L_hb=j~u znxIJe2cDE!Berpaq znLp=y$bP$+Z?{Lfy;I#(7!Vr(aX^jH1Vmq4hXzm_AGMazz>&5Aj=2dYm6LZCb2O-d zuu1f{-8tp%%QUAPjJsv@B8i5z0N8;Q#^|f2K96jCiCDD=lfW>Oz(~+6qa8-&sae2Q zzl>xDM6smUthXJqsr_z7q7m%Yzb<`=8CdeyE;;37^RL)!2%N;%9JyT`RW_YWX8$oE z_Tjdiy`+TdNS$&aD!*tuJxKpZ6se@R`IUZZC|#BQ$G}QClN6S)6+fR=<`)}$@`en)}B^WPG+G}Lmr@o>vLBu|BJc$;YG;yTMW3<(ox@13b= zy(IH^jt6kcNN+xT7!zB!ZB+$p^DWmz3*QjXylHf56do}Z)SSEpI%S~Nd!)C7d0Q5< z7FR|KOByJ{bQM31l7V|+t|?vJs_{kyvzkl- zl<`Ic^IIwWXnFnjT`%=>CP9GJJLdXWRZ=vC+Z#q4?ppcjV|Am~3S$vKWl`E8RC5UF zaj9KHQ7jBa6GLvZ!P?Y5G8n?b4Q@1Xb}lxrqyitCw;g7&=_Y0`i6&-u@teh@l5KAE zesh{dq;kLrkzr?egW7i^{Y2fbs6aZFu;ZuY`T&=-n8Bs@eYLe?MAn}MB8`w73feY( zx;^RIpuNSY@6Lkz}pz9tYpjN#IpYKYfjHyEj(>1u@&sRp}^w8^d45VO*)$N zy$`o@l!G`(3q(n7b`-ymiD#+KEd0d!yi0%liJ6?`r{Dh4_^izL0@|F%HMzh14FJT% zCv{wc#m#$8vx}qowSLw4VQ_%gd+PrUJU`5XXRrTH@IWi#A*QbR{n&nd$oBBt=zZ&d z(Vzc|_HUlDJ$#zEh_PShyemyt--&wdj1;r6xpp;46mcXRTt6Q}1t*oEu?}5o)uDQqGY4b-SgoAMns#E*v9GzV>mn^}S1;4tpt6GE zHq^u$eg{1@K3tx)lH0R+J=*#xW{{f77R@yVpzOaTSaktH2iSkI#dGXGf0g&ySbJA^ zshWy8^*v7fXd^b)ML6qtQtH4^gvbY6<3rs?d>wi+mfQMh!qeg?yUq6}>c?}3P67Xs ziWw{)l|J}rDL5}av9 z>^F^1(#uqg%DO%g5sdV4k*vd2er~T-VZ<|Y(I0g=!_89tz97*%??%E&MkCT^{5zk#zm!kv z_{1S6Yw2p;eXkX9Y{7WN`}_(kj=%D}1sf%zqfLxFMS}ifa;`j`%IWrUq2$ zKpi?)`suM5ANCdX(CChR*a5Bj{BLMfOQhR#7M)i=z*%%8^Q^#Gbj8U7oJAveDaR4^ zPWgAZ_dzx&LRK~!qe89LTm7)FJykg!u3K7 zAKdAS%-v0k`O(6)v4$Qp31L$=nbfSQtF^SNwN^aoM6zTY=?_b;WF6^$wYSJ2<48Ym zD-o56an;6=o+^IEzC|YDPfr!UW^d6Jmo#$wfxVrKJH3h9f}y77X>MZTbOvfTw_MKh zz3V*L$2{rOK$z6*IlfhJR|zs7RTZhy{rL&vB#1}Y$s$O&5Ibnm+xQoazc%YZEgfl) zWo!B?9my`5$F@pJwq=hT3jC8_9?3)0Ar;x%r#BO9;r ztKwXT;XPXhz(=4(p#m+M|1&2r%4xryltD(y`~A=9d~Q6)oeWHN>7j98<>DvByCiAC z#&eX~W_A$IaZz;!4Yqe#y;l5PgLCVE|6#VAMc2!lgKmB0c+;Vk0RG~JlD0)sIaUk?go`e zm0o995;ig{xow+;ds;@L=EalzZ-PmBKfyJV4JP^A-ok$4fu=O|k$DUI9Y2cOZT4-g zA57wGGH;nKm|&7hdkg!SV3M0QnzuU&CV80Bbo5w$vV5^(h-IxMbUYhO0?ym&hLV0X z^+n*<{c?J{xj=(w5#R0gd=iYhKX_SsYpWf!;;`rbJ0`CE&3IVi+O%J$oF%S{bDQ}} z`r5xlAeQMN)^;OH;pM_mldF$76-c@8;EV0}*$67>e%+?8;g;}#ukVwm0 z>GrSrvvpaoN15xBJeM`6UNEKan9TDq`C7TVHjS@B5)}E~D8H%1Y!nCYYV#Yf+G2heRQ2&odIpR+{N#9o zndyFFTK*Sv)EW-ZblMI!Psy+yv|6-U5L~4%+ey55ZB+qKH}8w}c0k}=Q`UyD1y0*~ zGodU$2yFD0WnRK*-{c9dU{}7kqv)Qz(Ga;|$c(?c>Sfv4fxo->b_QLjob310#G5Rz z&T&)*B7yZC80A+*Di_s8_jpySz{LF;k_#0*#pmAN7h4zI6VjBT_JRVC1A7tnJKDF11=jk=6)9SKAkzbrsZ)6?l7#jFy|;&%`TQ+yD{0)meh17xav z^-e@}_?X#O020Kro*JTs^h-A&MZuK*uSN2LF5PU87jgPCbM)pKm!@(`{R70cqYlzpuA1Bi6|8>*2=F zVJZsOzT0v^X#ROs2Wvwp;`658+!rphN$eSpY!HCFw0=!u|n zmoOdZ@7I_6u5{vGC`xF1%(hCjmceRqt5H7x3ktvJ9-Zm4RSbSA5T%JxW1sZX9IC;t zQce@;o{%bXAlcR7KNa$%c`6zF63>t*1o~=F61`QNsz{zcw$-ymk36tYSj(lZ-h9kq zUWSI5J2s>yFk?TC?V+FWtYrl?uWBe*72ft-B=v2kSTr@Px!lxq!qDd=w-Q)rzE2DL+7O2_W5RHtr!>2 zZ{a@5w-VOQ+!&c~Y5Ue8Qh`RuB+|jyGXuu?@3$6&%_T3w<-Do+BFP3-9VHEYn8Y0fkczK)T9 zhfi!fw7pt43EI2gXF#$u?iHdvvwtU5e01OT+9TK6s)6faro9oSz2;$mE=(_CUq#S6 z0zF-V=BI%fD?LDi<@Z~v78-Dhi~eT~-SY=^?9VK_h15=}{LK%f+^s}0s81|Q@26MY zZw(30UqSxyduWK&pB0f*5$C6N72yOZa%-M7bL4PxL?pqna_q}m;Hw!;7?B3KI!9Zm z4Y>SD&gkA3YWL8*ktIg?Sb1`quXGGh88KpZ8Csp^-DyS0v#5HUByHP@bf8b+JDf9J z#BM|~li`y1+-W}@c1TAkgn3wh7X!j(&cDysmU=@7z*$`WYukP$y0-8RV@OV91Mz`C`-EWS#qn#F3RppSj&19H5ik*i1XNz}O^r;@3;TGro3^q6DnEZ#I>2TH)T6fejA?$to~vDk1G6?(fGG1ls=n3 zqr1`?x4=rZ`%geN&Mh5BvT{}hY|3I|4E0##|TVG%`gnq^p?9Giu+#Lz0}FkVJ} z2cqPLJ48^;7cbUPn>v(_4UaU|^8>1L;#P!RQZnZaGtxAAVBR?VmuVX`rHY^Z*1v}w zjl*|Lqb*6c^dXg=Tb*5hNN}Q6m~A-kJ(C*D!&em7EE?NBqqK0!2n-*_Poi* z&Hnr&-Q=l&SAONELBzP$*ne1I0#Cj!@jc*-f^hQS@Z*)x*GKiv(l5eo{rk);Vu9}^ z4!!$6tL!!+KB|aSIbv!RVTwY5iS&o7YH)GrUnLFA2vJ1Vdr094O!A}};OoiM4*|1U z_li7`yZ_$E+;7x7fBquB@yZK--8+Xcgdc){f&EL?DEj4c4S~M`pE}Ab$6QD+Gj z61RjC?}azN8s7Ik(rw|Xro3}yiuS{)Sby8ru}+5(?++(i3tD;F>N>xB%4vI***mYm)Ggy3PAjMr+q4*ocPbwf2FP)!p&L1O<{r4{zrWyni1y%NDGO#xUhE!4&MPUe2)aNoKE|>J-#<6;}6?`Kj`RB#Rt37 z6FD41Z+*%9d{DUFB_qUVpoJJ8*vgPdje8azTn)%B4`A^Jl^$H)v zU*&!)p3U|DoG?l^c6+tZz1CkPTO9(<*jK`FG^- zOqG88W-f-dy=y_w`hW11Y4w;`y&N~e5gRfBIDij7Ym?5Cq#!P*nKK7Cj!)l`1@7XP zA%{H2aR?GJ^T!~#a73>Gt~)K@48RQEe+&W+{G=awbz4RmSbWvuFWUhkO63YBa4#pUp-zg zB3EUn@KqKi$M+5zFW+C79gj*H7d_-Pey*2oJTZ7YGQ_frC6;*%1dWg6t8C+I-x=6= zfIng^XAKUqt@-+n8EVCgq6y1T#o2O}q2~WHi)7IwDt)Fl=zc$F(#-EdHa0tdvbU*H4aovBvkaoG11hiAvbkly_>oOUOqJ%O{U);nmF25<$DgF_)a62oSxKE=1SDs*=BxHt06Azh@N?fgJU^MZYh303D8Mnlp zi@5`kMH>Xj)l0a0*b1`DDju?_k`nvBX88RKgDbn)quaaM2%9;}g_NAt+00Ubp&!{_ z)+VRdFLTm4i_GM**XlltMyc|pdyD<3p+H+Dv5BhZV;rrluNqCF*Z$_SBFb@-I{a{% z3{2Xqjd5mdC+3wU)*4iV(n+rp*4DOaOUoN(`{O8o`(w2Ubu!x@f0)}+X8WTypV&D? z^K-rFr=LEBQ4ZNrX2Z^f(bNeuqNypI@_hoxuGbirnT-+A#4e!voPP@W6X}S?=0wP$ z^cVIKqj@T$dBP>UW*#PL*lV(Rbt(iirHs-cA{HA^w_LiEtmKPEN?l`1P3CbEj~M5P zG+q8z;xc(Oi;^wT#5Jv8jLVtPgjq)9i3XY{(2T!P=bDA~Nhq55r5*5VG~nE6q$zq4 zUv=3_$ft9)d3ntmeh4(Um?!IXnds~>FFHN*Gq+C9-69^P%??x8Y0g0C?za<>2c z2dW8#e8*T6fzm$BXHwxfSifwo8?+cwTAGo{dBzsr%ku2k+4RbMzApTRtxQtBqJss*E7=>ziBDxeV~wGysO-~6Z`E`9NF zoDzS$$T}qqXWBoVbL32|Dh#+bZ@x6=U5$C`!&=e8->sy}ne;`t?}EG$>+5sZX5$kn z)^-#dQV-xFmb_OR&cm&bnuKpHJBK^(QMNZsdQK;|sq#$XJ0%Gr6{dIB0qaTYJ}gE! zijqw^@sB92Gn^-=_2g|;3jrwF+A)%M&LA>a#tN3y|F(T(UA9Q`>Tw$U_zTW}j#?Mral1XJBITuX8 z$e4g|j#stvv0PL0`HgTiW2A14)A6K$s@v+!?b1c+7ft*y*U+Y16q(knm?2)lWLDub@LE)#!`s<#)Wwn1^;+ePB5496j;RgF3CTdU;hjci-`r}O>y;M&DkH8-FIpoBP+YMV57{Wb@(#XK zVfm$Jd}zX#7BA&_wVwZ=#XNtG2i`7RlPeIS@E)HmYW6e8h&X=UhHL0V?Po#Ep(}*H zO6`Qjil)CrC~av-yzX6uH;gDEsAIP2YxAGz=PvRwH>ID#_S0b$2P^hEg+Pg zL!FDV?8Zr+HtnaM+-U4b@!C$YNM0M; z@gXhkCN-uKSv`7+D8O&kn?zgb^Kdg{1=s+2rNw2Avxwnjw!5g3cbnBnH#tX z-JJHi_8TBubsnr_YprSdHsftKvh|-- z0$F5b>mi($8)E!Aq@@YvC_lpW!W}&FIv*^zu^#v_^Q~6?Hi~-JPZz=2)q{rko2;_~d4&E%a9(nVPPs?M+H?SDm6zmo=n;BqvOzN>ZG@1eGOD`C>NaZUc*41nVe zO4kTBl;nE74V2{m0!>PCF9YKZ`ARYeM(G?x)@2zO10@NJR!N>O5Z%--27~CdUrU=A zMOmBHn49b?cU$VUGcm2FshR2C3D*W%!)nNu?;(K#QuMxm;urX9GDC|8T0nr3WI@j+Lwto+o@BQ zmp`1cz>ema3?IwNbgbmbyFe4^gAqv_ML!r4EoQ*@##Fq`_RK=?x;NTDP*fEIY#&EA zL#luQ$psR>eJzi`#2AbsX!liqtm*g>A|16K_)}9?ccIU7{NEpS@g0nVRcig;*S^3w z^8nvc`GYUmmrPLo*yODL8_mE_loyizn%U}=#-&uMXP6(`Ub3^vtpD4@`)iWOUQf-t zVBuC3Uezvj3|0Vw6|}k5+Azt3aZMIFKflS0;yQn#=B83IJG@6pixYXA3iPivns~GV zE1w_DA=@6eGd@-oJ96fDd^#EK_pbRp0x9{ZuA|8Zn)q?b+Lc+(scCPdZp@cqGGC57 z!kRCS@T%Zwr73G}poJ!iL=z88!KUNfi?CudM1ck`D&f74bBH_JpnkJY^;7NB}lz7i`W{GN~s^-nmf$3 zy6rV{oe9`CIdIuhRj#tJbI6Y>Bu%521sy2<-P5m*crE5*n|8W2F z%E;P&wKxh{G8uEeTH#wFD?M;K=gW+rAFUeeCW-E5nIDiVRlL~P36zy2RoOfU!cL~fDP@r7>Pvrfm4x$!f1(Gr#0 zq+@DYdP^JZjn<=r8_oUwRSW%c25`zrsG}!|9&JB=C{8X3FXo<+=(hvWy3`b)YhOeYeNOvo*|%uA5C`B;khnMM9KA`? zg&uCvCmaC4)QreBZ+V436~Uikz>0!C8BxrQ=!XsX3dJ`$?Qe?YlE+o}=0JA~B-WkY zlVZ-iJ@|`uAJ$@3x?1^)>A_hP^)5O~YIbY-U1XE8yS1+oE|kImGn@=^r(tx`57&wR zn8sttI~Ma3rn|<6<+Oj3;^EGvRfZ*YGv6vl8j0DKn10^olgPV@ZF8LtDVs>Dz6wHF z=5!p&T~3O(daUEP0Qd1LO3o)38>5!V=0G`1FgE)|25u*Quh5Zf7qmGJ0CTzm{x;;+ z{Z&FyKptl2{yU1L_`x^GGn(9qWX1ky=-4)mhAR`wsuiuEF3i_RC(d9bCg49I zg~6&}V4)!W3;wE|yG=XBlnhdLzc4~gGyvcErj6#As=teBv!hKrXY#;qwRY>?H^ju! zR^pTNtvn}`R&uAHWkeVpXr>fCDqdx$zN5I~3#a2fSu#JPw53E?h=5&J4u!__mD$H> z??1;IS1J42(yxIqY>w5h8GHEz;<~I`>el~+PB`cH_g_k0*&StXQ_$Pfd{p|8u8*+Z8bHnSMKM=r}7yus!^=4n$- zwvWI5iSan4iS3k|0(F$-mkk3Yt@rJDl6ga;Np{v7IreK{6lE*K$jGlME+TcF)A2*i zVsK1JLULSY`e|VxRk{&!^U7&3-~&Sl{t+`q!Z)jz*H*QvJO=npc)*k$*)(UJxK8|7 zp#~zKmOe!WG$*-YzFu*xPvV^7z;tzkcRVDNejg6;iOrlQa-Ot^CAMHa&GQa3jSO>> z7x?{plGY)%-2-AX0y2F9jgg4N^eLJk)%Znl>jh=$d1^!880lohpa6P*8~~~RrXh(Q zxdkVu&%|yHx-U5>C6<}kNVDmt+Dt370GNZ04c;p^n^!ewjHfW!M-&> z6=TT-!|N=hIwDE732lIn+k7>=)JU~#O!(ct)#uwa7+lh$zQJWJst;WZE`jRAe`}OQ zlrwQ;aIMsxHMo3Xi%e8|vbhAhgoHrwCSE9d3<~-C9NM;0hp2i}H>lHLLy@{yXN=>R z2TZS-s+$Z;j3IWcF}-}FP6E$jACpVE4`7>c=Y8QOJg0q~v9}m_PJ5*4g5L4cy>{%3 zrL~F!Z@g2T0lNJ;3XAQghbmWvHmw34x#8TzP@Pm4O&nLI=+ZgMMY{Rw!mm1g2gSu? zI?>UvP8j#Ktfr9RcCE8acH(zKn-P$cV~sfNL-`~i-mQQvL@m@W;@^()E&eEf7G?A& zJ00`*!cF}UeZ=b8#oYKqP3;AY;Qjmz9C1}> z;z^F}1YUzNHfvHyuPxper2~-rJQYg(7i5qu>q+sW3=)3}($_O;*>TDqh4ZI@RgI*o zym5+8=2Lk?bIb(UbRs(g(nfFgIU+t^H^_Juc}mAix^}6YhAHhB@#u3o_7UbTyr{++ zy#q+43WJ-1PF(Amgjlar2U2k}iHat0saPkuCO229R^lGUN(l%1i-H|W#Zfj8Xgn5~ zQpE?gNVtl+w|B@GO3u`l&AoN>UC7wglVygL*1TlQvp@YRFwY9681rm24}v;(EUk~D zly|wU=|{T$t-b!1uCKS(=Pu;B(_TOFqG|2TTd>ov`ZA<%R>p*4LeYJ^H=jEY=jnxL zNxuq(KwB|#zmGXTPc@3Yix}OYlAno)bb_5KyV3jxOS2llKN|gNhc=SfCf$0?QF7JU zG0jrdX%K`F*GCv(fy0nN#%FqL35;&0R4{&e7Xj!ulw|M_r<2r7J(gRe>OPnSc`+VadcA+}ilsXW+QosHa%nCr*bs8Va@P);;HR%%*u{ zX%~gK0^p_AcYwZK!@Vk4Z=U;;IZHQ|?@>b&a8lf9dLRJ4hV|{l@AL1i%3QBIOY4C) zJP8>p3qgXki^{#d*n%d5&#=8QXgBa!%HUw^&!(Dk-!Sy0o_^wIhhd1@?(1UrkY!$W4iF_g?|KbpI9X!7 zqxQs3^#3CKRRd!KRyy+@L@1)OI@lFCic=*;^m z@I_GQSp7`m%(_YpFBZp{wo7hBlBw;;Et0R1m}do69=b?2Cp=_Fz?wBtwDn@}?aM4t zXkhYh!yAMr!m^-m^>3l59@P3)|AH#P8%F5Tz`1+A&PdOd;bHmE2MjU_w=PRa$<}}mfhDJ^{ zqx*PgfClBQltoAgV#L`-B8gej(-c5JJMpbNaFf9lppwAXj69QgkuyO32^3*8#az~# zXiPBc^v#Mk+5a&H+SvcgcV=)nQ?%_KX{NT%kZ#YZDN=Xl42l(z(S+Ii?vDt9O#=eV zT{O&00EG1k4&lscUkSgYNhFj*r*o+|OQ#26>SxZEa^ml(sG-xJP;4NbUIuyP(CLNT zioBpU<|sb3UG^2!=KJ_Ht-eK8N6hD{0S9>`c?&G7Q13F~HnkrKyhyQBFk?7dstEjZW$~ zJKwyVn;j4ulU8*SLOab8ngKRTXo8esN|dPnvF|Up5Cm^G1eIwp? z`5Hod9j}Q9Y`&mI{a?kebqbx!uu6yik>5z&7c*k)d4Tm zm|B?a4c?AQeUB8F<@lMT@j?pL@pY=0F21ctgO9xK- zB2#U5@1z~qeSodoO|ph)ERt(TWg={@=UZbvOa{QbnK4f>NNg~TOu=aioSBZ1G`XPp z8T9@1d?fVE*i}|gQ$7YhoN=4+nAxX)?Y(~HA26T~Jk6@+E*k%erHuqdy<3j6p5#g` zsw*I}$Gh`%go1(z=(FZY1k`BmDm)%@Dz8rRoo^YuU5}uP05*POqNSc9lYWA^_XQLa z)0+SvR`68sb(ZLM%_1IkgktRXQHzu^PD~uet~Tg*yLY>Kn_o@+I78i1apJ3@!D= zP`}er1h6hiA0lt{P>;|#O|n4TD_U%lA%QG9OR|W_8@*HCHD0YMgVo>? zq^-CM;mV0`q}x7(=G48w1ONTN338y1lrViAh!o|c_K_lip5?>+tb zI?ZvjD@|uXY?|vH1_v9i75-!D;5IXBzRmagTe(or?8HbFUk1^x=}Rbm1>Re&HDa^g;k+2(?{*e@$CSZKUJ1Fr}~nqTR(|CK8o)V)I$@rX}RqD{U;y9g10 zv%r9pE>!D(%QvLpJ?l|f|C!(CK%(qrn#aDNttfI*oEQI_(>@jmBmpI*!hTpg!HPdI zkaVY?;qeX|nK7^tnX5u6)|-tD7~$u?W2 zVAhkZ;K*iRpAl6sUrhart{o!lAB3xD5WJZtL`U#fhv3!m>((A(F1 zRQjo|8|?LCx~{X=|7{z2WPv{~{3jRQUcB28z7Ga!QD?^|K$)J3$IDIp!$fQ1su4lq z28D!jJ!+y~q>VT81feBI%3O-D6f-ywx|rUM+GpukIo?+UU!b;N?rQTJHzGGyx5}A& zH8n<3Aw(`D5?A%mq?M$Km(}Kr$$Z1(yctJe2(s2BgJ2fxpRJSvxM2OWLw6?7_S&j; zu3?2adSsPEYtAAl{&}DdW{Y1JtHOkh22$gR70~I`d>kYs6Dw=X)ic9iVr4DtW>{IR zi;2XaQNoP#dJ=df<*h-nFn7Y5!FbTTG}9BN*5)xAH>Z$4Ywn^gKe{&LVGc1_U{P?LnO}Ev(DVppd9*cF=s`y(=maEvBZm_1z|8)7vDZD2!l|E z6^6*?GQ`2=n12E=Ss0FgrfZu6*bE_ z);fqJJTZ-!B>f@Gxc%n(=%8q73BO*EZ7#5)TaJt*p7gCTYn^4SvS{K-@1-h5S7&sD z+#aKWQkiP@r2FP(-xOE#)Mjs1EW8Mv}kj-Qpr1K2K-z72BzX9=ycIhN*nN0N& zG%{#=lbKGfXT@<~+cXzT{4;$ZEs2~h??IUU^ex2-iw*ESfB!s}-oaOATzX&6H}nUQ za5^NHzhc!5qB62iBvmQD|77iLK=xe{H3J=B-ibfWunC8uk7NkosEs6u-F+|pP4yyG zdSM5Qa2=~Rfia}XE6cVrRuNsOZZi|T-xvq3?aGJV9)2rkhLrSMm=1zO0mgjrEz9&M zI13IliwQI&LSa8vZfHyInfyN@%y$&N}b@(5~EChFk~XZp{EAT0TE+IM=SnKOPRK6lohSSi~8 zpE|8T1ovE@U>S(dEaRtJd?Z?3HY$Ax{F9+VI$=d-y-3806`vs0X(Cn(!bOn8NGXbK zO^Y8OMGy*f*<1<`?FWFyv`(<1MBWgZ`I@jYrE(Bf5O-P%-3LlZ@BcwQP!ex~!vH0j z_a$6%3=rkmAr_*C1kv++7(;31j&2q+5{XajBe3qb#+%lUn6&p;xH`aiGiIEu0zC*Evo{ZWeK>?+FA9dQKVf z;VveB!xm2TaLf3Em2`4n>%%g~hO~UE^^#dSljD_hY1pan3hS&r=eoIi8(tz&#BN3R z^r`6^DhUIp7B^X7vW5IswUCCOiL+d>aY%O9?LD)bj%oa`cV2!xxPT^d`@cgu0I4d$ zW58+X>kJ9%?{M(o-noqo=Y~dH8fl#7{gmoWlz8UE_4HjYuglrasQnGD%n8UkWL3tI zWg@Z6=6VdyN)!{yrQBOARG0q!kIGtp_EhbE))BJZTd4sWMCC$jb;nf>02Da1zQoPZC7P~_}CwJZy_vSjXW z_g?z0Cg(Xpjd5QX-$P}ArEaz)p3VdIU}v0pHV$|`Pn~%t7AaNS?^;H%l6cTMR_?a$ z(;~3K1+_?Nc5{n^r#WR4N}RGu70z%(xHFuI5~vPQeGVFQn?b|t#d&Brf_DZDXLAut zJ*I_Q_RckNH(>X6K2q+sv+fkrxvbA_1>UdRZPiX(XBtVU{*d21ybR$1ov7qs3!FmC zU$wE>9aQ;9aY0DSoLGtMjAe+W;i? zkACXySMQ6~3BL9CDz&19*;I|7OrJ%wvZHrWMsM1;ZJV`FQCOa{lorphkj%P_6rxH} z2KUx;ow1h&FG1!GT@6LO`+s0yf97(o*K;jb7qFXE1~^2pqiW6Gr>)*!@LfV=Mk#y; zs0m_ZPF9ae+X{5)$K+yMg&EBC1nE4zm1Y>br`NCSWVvSj_#&i)@wnwsgGd)^KYUG?{rq3y9SYsrG{s*if>mI(Cp5=>s zP94Y>hft;XVg$dotI7@W6fKG=-~-a*(of3=>0J%AmA2NUS?akjuv`vfxge;!WEByg%dwYId9$f4K#h1 za{U?CgNS=+)k1X;`W95)y7Mw1HJ=N8mx{C(QzE@3hqTMM&XD$5-@tnG89Yls2ah99 zU)$KimT$=ZZ-jEN#K)I_K;vOEdH51LrB`Yy;@fAv_XVtAevN+N{A+Ta&UsfLWHJ|o zlQw$C>9~o&(37+131q?wzqXdLOyfQLBMokz`}$kdlIhJF^@f9euIox4 zY^l58UPIkAGXv^gH`>tCe9_ijT#HX;Xm)=;W?1^62CU${9Mjn=<({?zG*B-nT5*}|%yXj%^GJh;HH;I`WVP=<>vpD^Th60@K^m*PO^#+3In?ghC z5zEYf+zvBm6Z6!Y#60!10Qmm00PNrfo1#4L^&i4GW=B-aH>&ny?1b(23^7}5vx;0# z$bi}DmTcQD**P73v_cY#N*!9!p*8yY#Oi3Os6icc3%jCqJu`;6{oQV2SG%h|R@dXS zCB(S>PfSegu`)e7r$sZq8|gANR^%-KH&g0Mb5Qt;zgklEcC3v=uf7^0Wg-AI~d!;Qd(F14St- zu6CB=y<2NkbFgWvd4|-pI7xGq^uu^cWH&>Ln&LIe*EU(f15FIO%c|@f6sSj9HyxKM z+L<%DV;WHn=dN1MX;jx3KBJtYb+0>Z4^UojCfhg9rf=hcFD0%(Y$d&!#!hE?^VY_}{~Y zuuN3r_e?@$lQXGoLSCbTT%b9-wDy}#LyHfPX@m#S*!{*4DwAfG>>?KjhD@WS1j+cO zzY~8HC?&SXH)?= z>!MbPs1$ax9a`d`%hYMaj_SohSbW%})*sl!b;bCv=(qZl)R5ch{7D9cDKEq>>r`_sJ)#Ap)idreU@7;VX8lA%y{y5^W@8p zP`l)M360V>D40D$?bRFQ9htLyJ++wK|JF;AHDUdHs?CKMg6x4fp#-l``Y)ev3h=od z|BM;#JpT-00~pJf{Ki1Al%Mbt!W`&AxA)mKdHxw?tX;BO)XCl^ zmDD(nK4s6BYE9azYI8af%B~R;{0Q6JKHp zA*&^T{P(AFTFFbhX^_q=LEL9tUMDn>Sytx|N8zGYo^oO}l(ON4P0%_MPOU#qvzXL9 zrAy1_i^gCnuCM+~<&dH#<$y|rXupyD9ePm9^(52MN$O~nj$i^*mgrHc{3KQbsp8go z!Y_u28LB=rRQU;I-L{7W;ZWxn7SX`J$P~wAr+nPxYfVLf=Gv--JdT+xp%tbBR+whC z0X!sv&;o6%epBVgu?(ZcKeM==aDxtEG?P0VQ|c3aE#8n)2^0j^zu}7f z@u_=0cYFY@6)XmTp7xUgnZKVU96T704=$C+%^iwyul4XR6wL+KZ| zw)Kv2C_SHsb)6Z94ZIA-K?X;59Q1jmVkcYqCK!* z70fd^b-f+u)a_rH(^?*L=jPPSO4kAMh=WVWK{UN2nw(XZl}mT#R+`_1ASG}S;9t01 z@XNB`huaPKeLDs}l-tt31^&}kmNMMH{!Jfd?Sn*Ob{R2>5Y#T{`4jLtX>bcxP8g0Y zAVy5=$(c;ZL?dbUhEe*T-30w_^+wKq31>`kC8Z7c8@+O#=*=^iTM^%gvN8k?#*!uJ z5jzJO1A1R=K3n73jMQYCZX_!;B!6Ov>?&?FbxTzjB_fHhLuV<|q7Cqf2BG$;^1H4S z)n04EVp8RIoU5Za>}I?`VDa&yxt4WjaebR<)QBjA^21hSo@DrA3Y7)?agdQyzGdr* z*Cmq=HO*O>{5ND>t_-kKc;&?lc*ST=$u4F`;+1!QZg|E0m1wWTz|rkp%lfJ$fshf% zF45g!e#y^2J!W|h1#h3&NGEo9yNoYv%Y0rb$`ad)a}BY5zGGs0fdk*d#!`n)c1Uc4 z;mzmo1-Z54!}~wx?@9~vm+<#KxvlLG=3M>`&f3<|I*nx{pc`<2WKRF03AQ_M!Shsc!A)viiRCBi%(QxlzVp0PO1GlclpFp|`YzaHl% z=O`j8L!z?(ZoK)kz`WG@AA({vii@*_x`)UPBs!W1?6q#<3Gev0t*koxJwYGLKB@_n zn^E4-SyWPAJEVE{`r2`Y&Aak%wttZR4rrT}X8d?(K8`l{JzA+zq4{+O7 z7rM@)s}rl&dTp;47Iqss;J(nKMBOjEqfIhv-;orY7DcKueQrh8(lXo_Z`>VDMu zx!&$5Mw4afkZB zd~~)+T}L|@J#l~4Lh2eHW2AwJu!Lr@+~}wBtD3&{eXZXcWrMhRkcs7 z?&*v6NO(JMY3nI$`C6=ySnapdQ$S2C@oKE*Uy<&A6~_u+QbuDZ{xOeD#)EjhOtZFr zz}lZ@Zrc}JeVZ$G`^4Bz?Tq^K(uai^G$Bz1y<|P0vJNc6EX3Qg`8JL)!}hn-f*=Vba+z5=&mD=t8lLAf-TkI zZl|F;p`OLNwB68YSm%@tampqt_9Lc04F%4FYrFqRPhVjxBW}-koOli0a~|w6{a*zL zPW&4@NvqdU=-6^#S6koMLjGLNpkjQB>VXKFKvU4DD_#;z->_VS2gfs8bIU>aX2j#A31XT1^1}ah*X$6 z9#<2!#h+}R$@ak^7sBkXNP*PH5s}2e06-PXkX&OA^;gHd_6kU&NndQ7j=dcHF^IL?O`M%ub6BW>M1I=Zocb;~k0wZ~M^0vJiZj0emb zHWL#|4UdkSzo6(r;kE8HXP!>gB@$n7t@R@KRX9_$Ne(#iykV|L^8D&pvSm~xd2$Kq z>C0k?&9RzQF=rfG)zaQupIcIiIs^c9Hq?%OGJIqM#L_+bd8Px-jZZiYPsN{f;=iIn zljHI}{5BFN!dzTyjq(vT3EB9M&LXa~@M%}URDI#ZDs7zY)22qYLwypfSrIh)vuvYY zxU;Bg^po|qh9hb7J=0WZS2eODc6C zoe*%0%yFJs&RJ%tnj;^*XL)2|3Qh1ZOj1vLL23`P4w1gsME4CAGIU#!Z;jfb)x@!V z6_EWP+!*BLl}z`+1d`^>dtmpAkn>iK6xs0QJdZ`S(LnBf1F(A^W(Ico4@wKXKaB_` zSJ($8->Wqcw4&`%Qp-85`d!t~#Aq>GF?^gj$6innS=*=k63`ZM+EP+6iIzq&s54jD zC?Y7~weQ9fZ*!qcOM7mGpKT>a)mG{SUx09b4 zk8Kb&Z$}enyRn*&XCBdz_#|xfP%JbtwMPw0N{!>3vZ8AKM61ij5zkbkzeP1(|IBS1 zlCz>R(*JbJnn>NY851~AIE-BoEBu_#__As5V`qj#em8u0QS+Ca-P**tnQIxtqZ4fi693xP(QaW4;2ex{yhjiy_v z!tL6RpuvdNz2&qY$qgJKQk9GQwD8oh$sS8)NV&ZkfU^4J15zpMCG6q0MA`#N4Y$2t z=*+zj)mNWrsj^AqNecB>xBHD@ZsA9<|JvHaN0GwKj9)E;4v{Obz8Swn3}fLORQ(T) zs>cWu1``bxNYv#TZ*T9-b}ShvLNFT|L!HwrI*+X&#Cd+h8KK&hVdt6^GI)f~dZ)qD zU__Evpbg%N)L@bw`!@U{(&0Fh9&gR2EM+uwo{I%hU;CDuY-u!BgrN;t5s}2EaP5i~ zmj){^KiryaSmiVy8^xfqw6n$Q@GAnWK2>t|8G#*QYBRP-c+?6;_8*bNYveg~YjhrW zF?_KT|6$9TSf5kV(8J!(GH@|FB)V!Q8lT;#Q$fga*g(f-h&#syDy3zW&DcT58p0Z1 z;rzl{eg=S>L|hm!sJM3J6pYrLUG2=(;=T-exTxaz)PW;M|1H8<^N9uwQ3TO!SH`Ma zxH(b>@wS9!G;7T&0%d1;Y=U^s_(%*N4Sqve_ZWjJvG&ICkH9NjDrEKHeMD(HI@gB0f^MO0tX;GszfOkBtKB zd@RcsIYII4H^Veo!&uJI2h5k#W5GH&_UAYn2s548;+_2wU?$;p44RtHn$Jakq8>o@ zdJ0fyRy#;v$zdUtAgR{!dbAGxHajHLUU-<9MoaKmbS}XBOZRB+q4WuM@fNR01f5u! zRz`TI?Pv<%Nx9+>7N#{MYrK<6xAuE~G~$aWyp7&%T!wW@OF{ZQD#ArniRsHE%#PlE zY&}SC))1zOZ#uXXNf%qZov@MY4#v+Z++?Jhxe;RMM+i)*oXp(llMge*(bqYlcJ$wju346y z46bKlHI0v_^D$C)0>hR0cuC&Jv)H$CsXei*=N08K4MIl~PP_}ZU4o`fqY69~yjBM(AO*-)oUbN4V|NRjC{25a-o zR{2LW{wVeW#1boXmO4(-wyhY5#nJ#ss*p*{nmi*%p#LK#g{%3iGmc3X6H-iVZ_x)9 zf$F=P*cR%%q9TkXMb1_{t0P0Ts~8YtO!;cJ&q%Ap2eIV&7-D~q)w~;Vj(ydyu38S( zQ?fOpFD|GU{d}kve@vfq%@dd|(ikY-wc*;ATP6zgqm0=50H8eKsaA%3bqvSDZhk$o z2S#^=YR{`0>1$pGSdClFpSP4eDj0}?^xXO zWG(g7i2%}@RvBW673rJ#wcbd(evsvS z#O1TBp|gZg;;%d)badeTl(JaO=H??J-5(U|T*_#2zh$e35HWYqwX23;nO(l6pm}&C zc}%$fMHX5|KaZFS_rF9*%;)D?{z2ZkN_p=Ok0xip2d7j->o#)GUy>|v#>w%7;xaM% z+(HbREfILqd-=UL`Xh+r1Ru1Sll}rjFXI|EUC8>|E6x0*f#c!hNqE~$&YK1?!T+IX z>aZ0RJc=eC(@re!#xmh;o!KPwHQ<%W|K`${@vba$naJbi+q`zuh9!Hb7F?LgpR1zd zQhPieO%-*zsa-o!1RT`3#}$#nmm`JG9+%pc<;J4<(ZW7NN60N+sSkai6>=MXOs)5} z3gG`o+nK;eRb7ui6M_y1zKJy&x0-6&CUpyHD>0}ukid-0u&5~3g;;#N?r#I3$@T%xuRsWSiXx%bVM1c>eL&*wwt zE%)7fwtMcm=bn2m992TsxP)4<(VoD)o#TVO4Ab(!|s@vIQiFTXzW?62po<+WAPK=|Mpqc-jS*B zI5~p8<0D#5h0oU49=ZNeL+kq!6O|)z$gb-6sGOpa$3w2ypz;mSeGqP)Srdba!T*v7 zsrUEgEIsEP&rjj`F|uRg`Ml@2{dsjbuX^N@hx1;s0KvQ2*FqNfRaMXdN3^F>{)CSL zn`d8c)!*Vy{cS|M5Y1;aw5JGQ8U8BOF^?y6`L6~OsFfJr#e*P6Q8Apy)sw-eON*mv zk=BO-Sde{hC+XXFc$NBu=VwZpZ|a9DxJDptgInE0>uwd{Gwx`2#6JC0-L0}!234Y- z)ZHp_t2)4f?}2gYCZR!c zoUka}>UBno$rCzLvHvtB>%?<+6sLwK{DV4@#i$aw74}AaR>{J6`@92#JX6vz`xjnv&X!JlQ6ckM|c-!IfRz}-I+3Rsx3o3R*?+{Q)FIZw zJJnryIBIUhCKEL!b>Y4=H`q_SFV&-ZyJbt2Ub1^5hd*rHWURQ^9fk1quuTiAB8EGU z7~h-;G2Vtz8aV#e-MWZIbNwa$B3&a(jc1;b{&TyO$o3xrQuiMLp3=SgPa98j6$pO_ zy)-v349xStWYYz91*}PMYV+&^0v1VOWCXD4J7m<7ZZPc6TPQq4u{rypOqzm`Ve<&`!0AJeg=YPWs9^IgS75Qvg9{3t+HsvBjcI@aMv zh|Xp0QuN*=y^xqFdx+3%WdNgz0)G{t)wIir`tyN1GV?Il`&rLCj0Ey~R0pEWX6v;@Bin-Q4{yO4Yfd>gwF{0BByo z@^K&&M~c^Oo`WnPkf6!ReC&yN#1S!@;D9KpY@M6L^s~Pu=Qf3`fJYXOs~iQc7d7o? zwtbmS9l3`BkG}C`I(m9h7%eIpBe3r2Hk;>uM}@|W!&h*gr*oXxcREQ^YA}jXHqyD0 zr2dr-dggFg#W>>U+3vTl|Cv(u+Aj-*6O8-fYe)m=(EhP?&D|5WZ@#$~Y@hv`#6h6FoF+AZR{GDSPX`a%jqV^igW{n@^!WVd^B9 z`of(3sJrApvFO9)E*GX zl&NwM@QE}cl3*dmd97?&Tn5P$N*Ferydb=hJroD4MeP<+z;Mr~JJFr|q2geYO*+E9 zKMWlR`}PsM580VxUtjzMdv+qLj`%fk_ac0|V_pXLV_(zE8>1%MS>}1?oD34%h71G= zAE?^re9@!jSGE?mkR5~tAAvb3(Rg_}2W`Vrz|Y)8tioBYC;{MXH1c^i6yXhgVk856 zJ?fYj$+kTx#tO0>9_7NJ7&Ns3se4?|9gz)3R^@??BYBu;`Q>qn<&?4a0ektE=s5&>*Jj9)C>u-OcWqNkv^SnuCBM_L zB}WkIU0-<;0qxh9OJGXNT@W~EeK&;h?2*g}C6%(beFwJd_g7#@=YnUsE*i3*D<(4X@-$91cSqVZyOD z{JXRMg__d(?}jTxGbn=^9s1F^8A;l$J}8X8e(a9^=&2%pGo6X#KHtAw(Crg{jo@Wu z;T+Ilk)mh!vT$~OOS_eY|2V#%tqIC><`CK=)(V?t{c5XSA5sDRvZBx35A>b=@dQn- zY1+4I+}92sP>>(!^MCSaj5(MUg`S#G0lzh=cYeud%o@ z=-L*j{WP3Nz2SFtlSU#PK0&PkNQj%y)9F)l9jzjgoC+k4&xwPD6&*qIMf>LN9x*4U z6!C=qSFuMk`VmUmPkoYS4rTVA{2$>z?cc^fvMpt0@IOXY1y}~@^r;DugFD$71oyK` zvbZk-6L3F2z0Uw}f0R=8b06p9E+QcEhSj%GCPO%uDlqJ4yO|8do|ts;`UcD6OFzZz z2gZ9nKB6J#8o}C*+1p^|uptD;r?v#)`p#h)9VPW#>J0UetpRGbf|W7_>R=y0d_pO^7+j#o zm_hLL#w=cHenhZ{n%xOP-~vi|el(TIy3eW+S)Qs;a%8zVTr~%c=2# z)wK>*PXri4Y;1hCvU8%qu{AUk;4M!=dfzT_JES)4MEqNf!g-So4E29DW}30 z=`fBez3)d)9dHk}NQNfaj}T(U2T6^VMl~DgV2vZ-R`Vm!x~dqo9$+aRqRjhB6Qyd8 z!u=Yh?2kU|#b8a3UJRD`lF*{TD)*(IW)AG|_g}8L2MB+K8pDQ0M==X|B^3~2oaGP$ z9AAVOLlrTef}fN;H9CrE3f=lM7%#+lk#0@Fzp^%iSpO2L1vrx3Cy5ZzOpDS6u z$tC>}kU{d7Uk(Jxe^SbJ=ONj@Kh1u{OGKR|jJnRZETJQ@4MUdNN;D2`n0 ze@^~*a=&996pSa*a8}J{#uEpH!tvx6KmL!$ljNiAU*Uc5&S z(DuLQD|4Jk-`uH%4zqL*-j^t)>|Z8T&+3cc?)+o1FZS#kJF8yF(yT=2!=Tz5B+l6)m6V8@p27 zYv0(#TyrWUnW;n-w(b}R2S1>c{ng)laj*~m{rSfRfcwMXwKv>r*6hJIwto9SkodMB zF%l${2rJ*%Bq4(KjeYWAE^s7kuVSz;5E2-^N^In!@VEW3$35!mFu(P?=`aJzDCGzz5n2)rI&g$>~xge*% zztgE-A{D!v4_r-g^!J1b`TG0gN&Ua%}eU$;w#-_zR0 zCyqw@`fD4GzP{!k0}-mtl(OG>=l@t=zb)EePuP|Id;0n}pAQ75FDYdk8mEk{A;15J z`r5Szb(hiC$L&d9Z~jbUvS)pLqF~bSwxhTD=&RkWXAD4Rc?Y1gu5xtN|E0d(`sqM8 zcq-JfLvQ_m(%1FiwKsj;^w=Ks^*08DM1)dyE1|~y>gzM!@1w7?{*{9DP(k*Z4+-xhRERuT z=$OzbKeTt0J0I18#|%uot!kCm0N>O@+Hxh`s@Oe?J{}0FpHa#loI&;L=)bB!o!>M2 zJz1^AcL9ry+dDu`f^mHAjUcFlaZ>E|UB^y?J+1rxlT33YqL-|vkvsH?s9Mq`TyyZI zk2D&4R)fa~8mGU}n`3*`hkDNLi!oOpukpb*BSK4HBSM?cE>5Q-fncvi+VFA~WLb8T z1={c*F-QaEWOu5KrPJMGoiTRPt27^3nsg$MVde{ShXr8euX6V5#t#R=$L~QV`?SCH zB0wMf^X=D6*3h}%Q{-*z(wgp`_REZt z`)!_*TTG{T*VY*9S;>tBPy76>8Rlfiqdm;e^YmLoKl)9x=Y@VX+oO4!?SYJDyJtWO zVDZCy)@&DPzJ2`uK=?KZ+Sr$FQCJU5pMATJK0}oaiEPcOvUlGYpelR%FB%h~jR>al z7pk)32L%5jO4+~vtAd~PX*FkNiF!!#$lJ2(W=a_O)4zRp(3`#NyIH}Ue!F7TUiF)o z;^?<;k$E_0-*x!<)o*9Z3P!-1Ni3I-Sgs9oJYrPjFJCoShbTAqWCnE~%NPuuM0;R$SumZFM1`n87s z9WETf7a3Bk-|Twb{{g;uJqz)@DUrjsvJl@98rRI4l*YAH;hJg&(R$GbSwy$LtPoxM z?m!Uz7UZx`<_kek^%v5^vSQxIZv%KE74;x<{mg zW%+XjK!VnZZw~~m+bL!L?+aP9RK5!7bp7Y5pa=OA5w~;NiNABKTf%_UHrTNqXG`1I z3Zrx^!Zmgzzh3VnE_V1ynvL)HnuXG)!}mDwfcb_2^oXB&RqO zaRJLtk#c#(w%esBBnj3TbL(Hzfwj^a|DwU#1xtSnn>Rfsh}o5HI1But7U;#)g(vjuw_jF*rNd&jeD1$n3%NPE+i#BUS=|VR?2DQ97gC!EMvrjM z2TNC}@H?}U5B%mBw(``aj+SWm4!gp?iZb#q>Noc@&vu(*hCyAoJ)XVklK3!_?m?w` zV7vEHc8ITZ(nO_RNtd0J2YI^et6PeTR0LS^FR(OSR+f9)oi5uZZzX0jxlO&@AxLK3 z(;eBj!}xTSlv4=VyH@n1Q>O^u)pi3(nVphHmFkg-!DJ`lR(VvK_vkbGNgm0T>w4kq zIhCHQ5R2>F*=wB$t+c1T^<|n5l_T5<#C7OK!6KC0)1FypW^b^yVE_)XuI3ytmgqQyGx0jOgh0htL z)cypo&ZKwkr&y)9*=w9QOJeY(YNB$UXF9}Cbp4qU0+orae0`+08vNR&-YfsiR<;e~ z^3TL4aVs1OndI0=__+(3@fvP7_eiw9LWQ^& zuFC-gOnns_d{w|_Bs zQ{QG)3}^I0soLuiO2f+Lz3t~15>wrUZx$npq+Wr&P&DQ zDYfEJ^=Q}}zj^pZzqMFbbIwLL$tpK`l+B@QvEoamWbJzLjj-WD-?^47<6*K3mTia& z4N#B?X~bS!v?HC|$a5a}1;WH)_56sVc8Ke;E-nveem`$RiKW;r7MWAUZ69w}iauHV%$_X-wARQQNfWqZs}cQ+urINAhCH%H_t4;-QmZ+($MB4{8BA>7$~#s0Pwk-( zLUHrDE;?abFcBAIA1b!5nJB<$lAQG|35mFy}YZV!0rwFbkSHKrUcj+!!(+mrUJBTTylRem@<~`2P^PXSmt{B|;J6*4S@1M3pM- z<4%At_fSLOex+QLs95tE9g~6F{gH6OQ8igMOz)-Na=Xg&zE_Q|Jl;7auz-yN`d;X0 zmsjlix7tsa?Z42`YA{n9F;5{qMz$V4KO9V_nU7SdrBbP|rk z8Yq(7ockIx*t(|BaeuIXIt(vqsqLwe1==>B)ohG&c&LSV^S zGuEEoU{3FGa4}+XOb@(Y3Sz+oS%hA+?+LO$!CJ1KV2McQxK|ZgvynnHdVP=a$hchq zF8XA;IcAqNZl^hBr*CB|?*$8;D21;;SMp50}XjC(? z-S+cG>`EseRsCnLfH&pv; z_uh&;Y56+e5B;~l2f>RD*IhTi@my!)s+T=b#Wsz+9@mD!se9b>D!cM?!NhXW>~dVz zEH;patoyZ0+R`_efyF(%Wq1!AitFq5kEz`h0mg zJAQ(7%ia8_O5}n{-k>Mgi#SbLNWh~rJ4?FdLn`81^^vt)vh?$f0V3jqWUw4&{6+AJMmjl5|5sf^cGc@RQp)$4BwP7uz++h`$XL`WAbWS__Iv;>W(l z9?2D}x7JANBwgw4l&&||%s>kIessfbKANVQSS(DcH&_2z!L7izE8gk_&2jxf(?CDI z19lX^J*cpx2!Od&wDaMp;ewK{ij0ts4nhTMmkYh-T!LM(kqhQvk;BquKZ|8e?Vfbm zm>Zm#OX^srW|ATpTn~??%g)Lx#*8~%_AN@P+0|o$lNpyPVXia*XWG<{M)ZHXmDw># zu}+ynzLiD5WnZ>bR8W?gpkZ5Y_CmE>iEBdWXJ6B$D#|cl9@Ww93J|sx#07P3K@bbd zJfX{|I)9_&B!y8WRmhV>R+qyS#!Q)mRl5PGkPOn$l$l6g1{w_U*hP zsI3Z)=b#$VA-eF(Rx0QZ48 zLH{||d$Ola`(vff-7<#8b4g@y}@MAItwLSkW~bBzOPVV4q` zV5L`)3nfiPtW1*lKr>Xukr(?Ty;8e=Jxs#&v-_2{#A1Jr<0zY?M$1|x&uX7zF3TzD z`p&ZM%sd=NPONL00qZBG-eeu9eZq(*rHHKS1nVk{mfxz%Vl(&|ZJyjFNn0f(#c3qA zlETq>Lr6t`6D1^7Gx?eyb`tGBrp_j@?p3pD@$$`)GOk^L#5k8vX&X?)aB12VqXHzxA|nmrT_`c7k7{d#0cUR7m$LkO(asOH{X+2Eek1?JQ5DECqdF&y-F29 zS#C%S+XMveaRgK}jND+{_za&~fx#r1c_sN2*ZELC%}3)CC4YdU0y(dQ=2m^P8zFY5w?X51-|)wNVc`CZNbBC@k>X2g&@fv$GR z-~J*s2@Z>R2@dig9{q}Rj8}q!FEMuQs6&m|yS%J7KZ`z9kxX$Zq^~hQuZS}y6uOO+tbPEJVLl~l{c7O z>NH*Z=(Ty(OGU}2sS=Nu;ubbMh51Ngh6nXa53pfhujT}nTAJcPeRsRuRL zXAkj3pR1@hcce-ME?@NTK!xOQFmTogrE-LWW8+rq zBFc^3Ab@w+cf9(t(&95ngkQFak9{i-kP;+pB577~?v2?!CTLn-7&rcrza!e4zbN{G zeshaRpD`LQ@!*&3p+&VfZyw1w5lr0BNvWVQZr$kGo7>A_T_7>((tt5;GbI-BO)xR~ z#LVlB6y^0H>UD5)BkzXkcfs}=UhLz%;0(0UgEBAh2Tv+?UXV9uv`fDj)^6OfZggF+ zy@bS26`R*DbH%=x7Vb$*-W=UIbXK?dRP^m_(RFL1JL$QcftgN8CMx}Jidq2mN`@eB zHbW4r)@Z}WZ73yF* za5PHn3GcLvFIrC_p782)Rq(HCu@8$f{qbN+G1qy#kAsK2b zq>4g#YkFlgdTzC!!bsnDWxAri|N4ERF_2NYf zH&VU;o*E$OwtvivK9FdL^nNGvxz#n40f3+bz~LkpRoSII=dv6(iT_SgV_ApLt;-ko z!X??IKUJY7#U#ORQkEa&!m(IiHXB%*^?La2;#D`FE2^?btjljr>1LrL@?CB?$AaVm z-%pnnF~%zMmjt&k>xoHV&oV~`xg}(YL&k1)mnCL;>=nP=LRb1U^{`WFJ4BbG z(9KF+m!C62$|QueukX*W?z>hBqj<@-Cc{N;NGzB2YnMDpNEmsJB-A1Y4~ z0%H$d#rjKUgL01eIRumO;3ydZ%?NJl2~+L6k-2o4kyl|4aEw&=zA#%3gD%8Jdws90 zNteB@sKM3^h{W{t4-{7Rog;Jo?Dr!H2r0Devrypavb*v=@21Hbq3|>+DX=eTPNbXW zuF5Z;F8jXITy{@if9(-lB7E}K*cackg*L15>&Ud3nk8*Q5s}|qdtcH(Mg~|Je3DX% z#+e?q=k_KbV(GG#`E_L4o8NzXH|Lj4mrWT+dzzjn{*T}m%>O>qmZ92;YJo4r@9_Nc z>9Y4`_QKEEk4RWTd%#%Ta|U`%4-kfbv*dH*;D(*9NY!c?;Y8t)PRQYl^G(nzc6_cZ&tY)#W5{rt8K1rWeR8*>ygc)Pj#d`KJZu(fhPL$2& zST_HqB{z^WF5R_0DW*X3=;4L3!&x{p+(uAfKgOy6k-5QMBkge(g@bgSXP}ThVp-^nex(Tf^mAWoJ>F z^gFG!-&7P6rGG@aY`=UUa>RM&8V!t$0W7)qT5r$CCjtYYN!^02DEJIPT%QU(wuyq@ zD?Pf@_=A3rDu!s)itY(GAoL#3WeKiO!!vIp{7<5-Rlmfj!;T}Ej+JG${m7hnCXBifu~w%I;SY!9_(x~YPg6xJVm!l(PK`5p*c?yv0$e~*K#uow@FN@nID z=e9W*O72v;x=NQ`617jc9ao4Pl);ybBRI@2T2FwL)EWL*>I1m))cw;Pe}s;btIDN7 z)FmeX3YNJXjtayM1jo}!Npg=ZwO1$}{H2CMYB8xrFG*%px58TuWKOn8>RA(e3@&AHD2Bb4t$O5JN*cD4kQfq_XeSHdCJKF2|s3 z+yB_9yWR6DykocW=2d;~m`Hb+AZ?_MIm>GKvbj@`;Uo+Ui{~Qm(vTxH=#$;c%OsuE zJ7D6i_R5Y5LB3EWvsU--ic6?A`4^c8BdS|AVnTDS5E1GMQk(r(B_*87< zgv*Y%OXRFS$Lx`8-reK@EwSCV6)-Awho7@C;X4T-R1M#9a)I~%^;5TIg)MnLMn&Iv znBB-13qbkurQ6y&v_Ev(>rbq-zW#UlKNI5==KuItS~0zt>mQCqlH)gr?`nRZDurX6 ze5slJeva8lxYA5jL2I-}HjqS)^OFvo&;cbJpV=*o-eJrt=WwRH!J2)wj0Ue?ArCi_ zCNOdw?#^KZ0BGjUcuGMORl;ma+1qfF}Wo6+0{eH>3o2G+B75c^b&b0 zPJxw|%)a!B%+o96saOjue{|I)*JPglM4tXlo?d!Qcvj}=Rq|9^MJq46;>XzyoBS*%|Wm9(j7zPv>5qc{)p;-Y!p@W?hkOP1SINdK$Ur(o9*NhQljoH(io_ zayd_?uZ%P`srmvXu}^0W>4;P=+b?zS%6WjqmyZNWnm@fF%(>Yek^PnpU*B9i_ouTi z3zsb0KlS;tVX03f8Tm3->iuQKsdttQN^M(Kl6rmF;MA67`=nl4wr}eBW$x6|%Z8*n zmkmwzVnBBOH4;FXe?4RA3E;6z0R7h38p8Ez3Z`ObF%?rMbFE~`4y$tWF{#1c`HTMa zVNGTN;$+Z$Zgo^QcahWFH&!XbP)GjtnP*C2yN#L&R_SMciBVT$zw?i@a!C}7j@W~$ z1N3dbNw@#T!o2zJ{ycN$yR6a)ZoTHa@{wJx;OI3Ul3j~xhN9-XzdG!z{$P;-Crj@d z4ZwvC0F}_YfX>-oCN9bXI?I>#ZMSGT?+(9ty85qJ2o$sY8>AoUa9C{%Q;1tzdeW~WHDme_`=a{cOOS`w;c3Yw+2Bi|pk4p_d$pV&vf4+SJ; zI5>aQdIgabtX8PNNpbOz@9`(w$e5lE&%!;81FC6c{lc?qe9m#T?E!PWZ{bgBLgwc| zbC)l=lM_-FZ}3LHlHbmTnjMi+xe3peSK*oUBVP$$6-vw=8LE9cWYmA|dknaWINs$Q zIW!^uu6)E{P7I~oMDFp|)rRZQ_k=mtm(z7QL67e0k#2iVIe&uX9KKS5DNLZ?&xjxi z($DF{j;B?QqtI)Y?-Q>iM;abRV}vU}Sk!?#b$34UTq{O6_LGpfz<&DVPrJ9Dj+6~1 z9rk@zAwBz%ABq2S%`}{;n~2K6AB%Am>aq8i3rqPh{PyHe#qinC1{4CVa$h8$;UJ`b z?12LLNlftD2Nry6FXl6udng&oN4X#P9+$Zx$tBDYjECJ zyhXt2W6$N_p>(Wcp8YTd`vV{&Z#wSI+ya;U)}cY`QH}NscHP}u()yUh)1tsJ`==q- zF5`xqxTMfBegZLE?kzGd1+CvN<;UN=zD=HsM0{cYi)rkLO|c#}*LEmLP{;ka-jaiR zO84P>I}D9;JwbC$If?lz2yUzrGG$|hILt))&1pptWmXF_c$afbRUr0eQL+i^jQojf ztH~pE)bAwBfB1jN^+8-~Dhqz9H#L9QN=1@>l8}A#1^ZIq!exF{tmi@_{xJGEXq_HP zJfa}CZW6@Aqu$7YLpRAYqgoaf&<2Oyza`C?B`t5N65LBYow2T-SPy3cM=>0H(X}1C zWR>ff5^702#!*^Q8>tmPvu~E^uQd*rxnBDrAdRpfz5F6e42|+4DqmO8ptRb=X*M2q zkB|bBGt62m_oXgtj@xMYkXl>C__cp^-pe}f{TsaG{2di$M<8yG{rQcu5==HF&N1Z`G@cYb%2{gyjbCt*u>>$j3MLsaYq)X1 zY|%ItKzc0$x`yp*%1FAE?IC`ffZ0<5n5_DZibvRh!qan0I}uvTdt(KjYX zSMQ4Tj5Ol1NZ@dTC8=53^I)IKvR?=XEUp0^puIp#shP{cf*)^SAOi* zpkzJ5t9w@RpMVxi|MdFrCdMs`_3Ufh^d4U#%m+QF98=AH*T!_0Q&uAM65|%ddfdiM z$7%UD@{5VUbqT;);H(*3YL1QbI7sg6UnvF&{}gma)xP>z>51h=)kF=xIi|vIj%NjJ ze2qF*%^c%Ro^y)lPTujH@!ZR%U=TainB@ZUaH1d4dQ~zg>Xh zT~eg_=E`pMdwXS(5RS#xHtwYgkMl7-Q5TkV#YTA}U-(ynw)}&PrJLu3>40_2>_aN-?~O%Q7R#ybD1WSK8V#zyF91pbg+2c zc5L-09d5ojv`UOo=1)fR@44_NS}Mz_NOG&{SK5@*@=@w#QAwfc_xls`-RfJ` zllVM&gZdg|JuQ`uf|Tdx$|m)Ddu3Gp-c`9seoHTCqCYeuK8EPeU)6B6T|P(I&ZD-4FG@5}32dlX%e$GA6)@w$`Wr{%=BTT~Bx zn>TdSX9rwchJ8|7=NPZ#8=u}erhcE2EL92H3H$oeg z*D^u`tbM%8OZ;_XJ>gOrqi$NVB^~RTZ?rs5O$F2zs;Vwxj-g-cAqYsAg=f@OKDOT0 zpLmnw6j;-Z7V^9T)-{p3-XQH(?SY>tXocUP`3a>*lko;2;2u)=jRnfFK`KP^o+6$rLK3@w(*|(=!btOAFj?@|YY)45-mzVGY3^HX@?f8+HZ)fN&3f_ft-7~Ab z(Otvv{UZfZm(1Ufr;@$d@JYj!hU=K2jiM`-qzXfTN{KbrHBrht+Z#nO2d$}%q1v61Gtigi z{>1X^Yk6nl=HMJ@a}0L&1@j1G74R^d1pch0eNoc$7UWRw0qTyD3fhQE^b;<-@bQ74 zw2zd4uosOL;h{CYzqn$%_6-k@K9u~izi+~)bgfJnX3)(U`_!ALZ!bgE5Lb3a2kqmF ze&(ugUDQsQ6-Q}Rm8%u7kGGp zhxXxjDwk2O^|}06b46xHtwZQEVWhFl38HFmRNwh|zu(8!hyWCYj|UO~*52GD+)s=Y zsLtU!19oBU`l<3P<@)maLVsd^?M2s!Vk!!g6<_HCyYvmmFT9-%- z8EA{I-;#Eo6av_ff1O)=2@I`hz>c^bGIRpe;kja+6l@CRHg4Sdb* zqJf{_Hr7*Z#DC5tG-RC~h+SX7Y@O872*^0q={VaRhg*BlT(g zb7ZSrTq-s^iOuRqX&t&@p4;FgTn4D$+2S@hh(ZCB1=1v>r+W%-v?yKVlYWp~_8Ri+ zdMcnCjuel27p~r_>du8`c`mLos+UOMwNbrT#wVjXAtAp+$Ja=;v2}g~rABK%`#|9I zM&D;s<9#+HMz2UAqe_2Lr7Nh?)s@D(rATR_NQ#s$_NbpF6;dmrhx*IZ`glaf|GS0K z{0JkdSo$Uvi?%eX7PqUPC7V@^@u;dQu}J+aZc{%?mht0jUE3~nakQgD8q?>^x|K?O zHOpMB@lPn+8vj`R{fNJ^!R*2RlJPCRnOpzhHmc!VKzJKs*$ns_aG=KpL}q$EW6={c z=QFmoQ!2Y&W-S*+F!DX^6Ga^Fk`~Q*Zb;T+uYH~Ax>{k=ZTS;p@es!q#XJdd${3!-cgj!o6lTyN zuTkAV0d5-_oydx&UQh$>hWLkkLVxYB-+Xh6G7EYG7$l=aux>$3gb}_hP$tSdRAV>& z5p)s}CN^U+c9c;NG*3oAf9`hUjSMP-pnyi%))YCS>R`j&lcQ*+Lypyo2z|(*b#zWAdSSh<>NgonjPC_GDIuQ zXCGqA(3nw%B7F8(IO(Xn6UbG7Hy;NfNZQKJe&1 zU#-=GC$74FwX(G607?T?$CZ-s#6=OHzC>3f&juJxU|G4uDiH!_tr9&>CCYw^g^Lqo zr5L)2gbY`9&ylkKYs4l8Q6jn*o`3@bW;{BJeL3ft7z) zvG0=y$K*Y@OCB7mzumAQ?zBJryEJScmA5{s#_K7W9ljWne~MDy!X=_fybG6$a`Eq2 zB1~^8+pg4@3%i2E0|NT0m(ywQ_6@G^0ZRCH64s`)N3*(6LS-+eO!OTr3Snbz0YDEN zedDA0hes?DrRSDNe;cvg+qzr;%*e?lbHqT&70A5KE;nRb>$9HHe|soktqvP{3Uzo! z#rCc_8z0zzeFDFzz6`+2A_A~_(z~W!@w5HcrzntL;WR1)>war2h$rm7zC3)jj_%8; zMS1pOA9+#m2>ll>5xTW1Hf6Zrbmqsx3dFs0X#ns>*9fLXoF^os!-+47nvjawo0&h> z_7S&%mCBD_?4Mo>l~VFs2{nYLeHE>$hxKW1H}iu&^z*Mog~&fb$JEeIh>SzFGU9I3 z@?O5dwZ3mld*n~1!@6I{Db(JAw+HCXW@b;gMs*`15R-kf}aq+Ac5#)>5DRizffUUkrjOG10g*JY*YS%;6GKv!v1} zRo)cwGRs>R*X zcIgz`C=G4JM%}0+mT>uH*sUx1ZO?%mG#4y&@bFtW8tUd&i8(is(WUGlH~j(_5aD+~M+8{#4m%4S}$NT{cgtm0t?`SR>_wQ{Xx%6NF*uYaP57w9{A56bd6 zPKgSB$mAjwD}RLJn-G@;&NV+iLkudLw*|eBQC`@e9p$z3Cdy`V#1o_ZEPm*DBE4P@JMYvpfgZH*8Gtn#q9IqCtDnLhMhf`(IN77JV zEiu6Q(q+ewaiVu5zYSHT%l_djW`?2rL2uoW+h5ebzKpIBaEij;a2N`t(t+)H&xk%! zJnjSQp7oLXMtL|?MJG^EUoE*i|3n}CtHv)u4R#4fZQ~j>SgA*Sk&RM>jw1Ub`o}k~ zzR*(pEZi>)hW%ESQ<()-HGe2-HqZaz<<`-c9(g14CKc@viRl%g_}e(;IYcwS+F%>t z1y}=8y3&jn@d4eXMLkD%bPJ;N03HVkomEG0zQiY?#81&oGdQcX$sOo;uVlPca{PEJ zcs%ngl~v2ppX^mDHe%ycB@#!V+=Ob?-EkkPhf&_kL+vR<52#3o?JCk?gIfT&o)w}C z24O7_>F}w2-w&Lb#7Df$tP-hwh(o5!Dv|OlqK;I(Rm!2*YbK#19hA#LLXnbB37u3B zz(67F&WQXMj9iFvy?oTz2`ufXwr&C?H3uniGveO*1}~pAB(Y zjzbB5VVjnYNV%}^@#qCx;M4LMJPleukOlrg?FOUeR9#0EUuWt_B%0L2o%Zp=DV%87 z>gz1RCB$W@&DZHVgiAzT1}~h?Qr4bw0M}MRYVp_Z&q}3K&_5NGU;(veiFU#`j$wjY zHYrwrkY)9S)Y!Vte)438&%5&Z%!n>6iihgZ%LYctJa!)n{13ViX@$rOUE*qA++MM9 z6tN*s2yWK$JNZeMO+7t7Ch@4#ii?te-~~+f{2MruL_*2tR|x!0y>tNh1x@9F14r?|34X9iX}ZW2YN%F9p!o^W68S??QqC({3(Ja< zjp8MLTwN|>HB3K@V0_4o<_uv*9BS|vDgfaZ_A$75V?D*`D3mdMr`klR{)dz>r_5PeKpc~mM{9R^XlJ$-2wV6fYR#YGAak~r$#t3 z@nBXa@VVrP{*jjqKr~h=Y0&Z^9$HpiqHAgdd<-~#jQHoUJNb;zA+cPJR>og6Y}FB5 zd`^hPpnCICck+JTVu}h}N){O8)wM{(1|<jrUa9Tz;lu!kC^>uewa%cRi-Pf|g z0UG;7v?|FMMaO15S5IZ#=$nkzYBZu|)O&nwA6?_HX==XnJdaKDrYSZ_`wU3ZFn;42 z`N?x_t;FCfN}dD3cGp!NosSx~mW$4U#zuTTjXNS6WF?WbW3^gVsaXU!8B{DCUdM5u z_<}CvXLTj7?4y3xlTQAzq^L;u@w@xwJQ^kG0vhEH~d&j zLT3&nD($JDxiS5=!S+XF)5n?|fdALqd(5t|Z3=F$MvhgkmpO=1{Mdr_DD44;c%!mFK+HzI}- zY*XLN_hdrlWOUVZllAN5Z;3PaiEBy5aZW1U<=yojSvt+8L`m8CYR%jayY)*k8a5O=mGiYNj@5}X)he7wLsp7bL7LD z`LJQcyPb-uTuc5d^69|!bXooPi{%~6k)8R9g5>=^xtQTGGbkqi1?@GoHw>ixP31Xk zw?mgqo=Fca+r7(C7+RJNAT@-4si6!AUOUEGX zJSpEGz4gT6qTN@q`!{*}rTd?cM%M_qvhmKbB2Sp+Y#PWn9{ces4v;_SR8gPy(#QIn zhU+kl~KmIHy`QoFx@BB>UzphX3SCm~1v0An1=sGqX&4q$Wk_nMd zm-(1o`D53W7e(Y;Y}r#tTw(?J@pGlR^$WH!9!TNbY`jnY&{jas&BrtOF^c`Ml~LZH zYi>~k-AlN`y8WF|c}VYKA!wQUGP47cO3a3yU}9+-1=t43)GbmJX7GB|zIXPPbi%(Q z_Ql}YL*?GW_)2xfdMd)7o+j1JI?L?nNV;QR9C^KmGaxEsUmO%UBssxVfxGpuha8eSx4x~KH*YJI!ePQ4be8koU1EW1l*&aB zn>*Bz27%Z%(3ZWlD@A29I!Hp(=u5C)w!c`-i+IX$-tv+Uqx{T1p}w`!9dJ2y)i+;8}zo4V>-hmkk8-tD4jaVqAEzD3bZQD4W02l%4TbPGWB ztwA>-N%ihx$_z?gNW%^_ZB5P6hOJmUZBVrx$nldlY}V9m5flM<^~@~850d-eU=T8# zanj(c_QhAj{LRAr_x?TR-=AUrGrNZ6Gk=Y~73Q-qnCNmHJ{Gn~5&ulSRBtltg`r5}%xYMMeNJQG~k1a9zpA@-K?x zJ}Ft~bae+yr$`Jxj}z|f6K8U&rz{_jDAg9~kIrFCE>(}d={%aqqs*xMiXNQb68CBE z{b&7;FRDkUmD1}oCT4W1PJG@5s2sK?JN1fZ9^~xhmF?fKR^Gwd^&EyHySWl)mb2y1 zzKo~ziV#U7So@ens;5T7b8eID9H=m=&uucQc~C7c1{t35%u&v+U^S@RD4oDwjB`i& zE%v#X6Z~ol!>%;R`Z3m{8cwxlV3Xf^%T-@j9GM|;ojsoGiRPDByfkd`S)Kxdy9XXLJ!dORpBFv7++*UWbJi;z_Uj9P)+UoIlcy5r=Jl^a3gqAQ1f&|V5hDM1kpkvKZ@`*3DP)bC zIx#V_4aVQpef2NSn;iHJ70OQB$$*^W&ZG+$_X z18sMMtaI_ZP}aZrz0J=rp+Q}Q25r^~@LK3jl2bXMh2XWc(JJ`|{T!AQZj>-z7=3Sr zqc8r8KNar zl&1C!r5+$E&+AVNKI|h5ibSa0&q|k*c~26rxv5`Rf^cs1ryUe@&_Lp2viALQ~`~sia38~=IQkdVfnm=5oaK*__ z8qpW*ML%IRlpKPwo(qil?}d%lzF8ZhRhK1!so{yX2^Q=eLFT`(14ISTbuO0c5LLu_ zPK`{Kn;QM1L9S1hy4S~gE{+V7+cN#?dm$?Virnk(SZd*>hc*0`_Q?AoD+CDVVZ6K$ zIYxFeA-FQPr(H4^HWWQr+&Waf3`|WEv9xgSyxhK9Jgs z*!|p%iHE#pso1jS5O35dwogIEQVR=D8JeffaTx-B+FGc`gp&bNI|W zx4d<1O;Wbw1vt!WIG~-f*7${FaZC~REj#@Xsct#YQo1Q1iI2D9$C8e*r7{Yz&gvkD zJj9t?EDOrHma>B>Xn#e_P*w%WZdSEdH$V zd1_4-bagRBBhdWeW>}T8l;eJGQ5;xh>(wg%a}xFrCxhlwcI%@;KINHHra_N=Bb#p7 z*WtyZC(}IfwmkX32m6ZKP4t|@W!tREpRW>SXiF!R~{3L=#y}p&A>THwR)vkm2Q~hb# z?-tV?PC2;^PfXfn6~0_5&c2iBQ05&A)9RgaJTv+*CTRz`#4j*ZaVy1ngY@Zo%&|4H zc)gFDJ0^-r#w_}ikXETRaw{f=eyeHWRpesV6-sHZ=$s1Ylp4>@LXY2f9oz)QXbwA5ey zPELR>S}m9pzJ6uzIiVabRl_9ClypG$UE>QTga!L|xWw}K7CQX_RC}HJx zV$>sC6$Rs{=g`!Qb}nu3=WmuXS|=*$nBxv#qc_X_?ht1n`~_8J212#zdzW7stTh{7ZY?IHjMA(=k!ph7gvraUe z?o&*YIJZI$Us1c2q`i0X1p3Sk3_FML?o&DA#2E}ewKwvP!C)?0p@v`#%|5kpYy!O| zyRW$3VqbCeUjj)YG78t-f!XDdF{I5O<4L{nj=#{_J zJ*Zp>DqXyP9$_HINOp7y?bQi<*x^R=Dn%!xH?cVTLO~{GdVOmXN3xDX%0^c)y6#I> z<8t*|UFt9{(rlM6&ZsZsi|JU8XCU_@sqnoHc^8vF!YvPLU?}Zm|AkloCjL z69i}k@|soq@xX6xli7ngW@_?K@eo_uLu^{Av_}Q#u+u>%xw&uW1LX27a{7CB@>x1` zUr8#F#k$N6b?ZF0(JV78bIQp4u?EQzqG-%nP;hADb7nM2V+h zV_rQrm0@&E>@_2Q5uOPO@W3UEi`1w&1%f948N<%k6uMvRkT$#r2=-T79Fhxa^S#gakd(SK(V4-SEl`JUa;KOvwz{gzn(u(Aj zGy-u>HJoskd~By6*r7(u=SkTL8pKraLp>Q-g68G^+%83)3{>XU-Ln^&b9o(^n@bPK zlezQik-6cj`JLGXQ>JcjLzSS~;T`8ntnyC|aMaja>H#|~@aw4|Yy4<6WVOMLWpK4! zQ891Gk|k_s$dZ7V!XYcRMi`Al@(gwvr^|lL8kX|zvQ8mXNtaDKj1Z2ac&P#%Qmtwl zChKf>jbU@RSWZgW*a>b^WAik8Mqm?Vf7q%N{oVY~e?^$>%gO1JDwpLuCGE_^ccdkW z<4(JZdNOX3-TO!SoR>wA@*7L@Y@!SG#B_K5l|J8Vg?jBc?X*{BRi=u8>|c~1>5FJz z9DYJx5lZ%x-{+j1B21^qph>z4oJPgp5Vuqc}H5@iSbWE_?RS-n{(fAx?_0 zJQJng`E+0Sz;D6-{>St^v>*I(a~zqU>ls>w-zu)RT4gB1J(muD*O%_7H`RT;N%ru3 zmt2O{7+fqq%#st#jqk2$nwEWR|Fi|}?&S%`-8JXo+ zLa#rp6utn6!k57jh2Jhe)l(Q2LkyD*6;9a)_E1&^$8O4YZD{c9D`7ZX+yQ{0jA zP$N$$M!Zcu6tWg*{Dc@DO5>l!m1z90hB+GlX7wOXqcLi1y`sLWIbZ&P!9oSkj7v~ewlb1w*bz)VB1LE-p?JwF4%pxzK{sZ(Q41!E3V zC78L}hKEUGu?16$!qfa#q%mFggM%EkM6YAQEmE)5k={bYI^l;0QX-F}h%U2pucGN# zjOJWkf_z0FyV`qK#vFd}9|eG1f{G)6JZK(W-})1G@-n(tzp!O9b zre}=}je(y$JCcn6Sj|B<{plQc1zTXBpjtM>KCFI}hpiuyz6x@hq&IOTOs(3_Vd}f; zK^{|EPF1s!HmR_%vy_fG9Ht%%Q%AA=koV@8VE?iU+co>gOd>H^9{cGBMac-FT8Qqc z2z3_SnF5jZpP>5{t!Q+A$CaR4JJdm!1xg;|p}V;D|0BA?1>GB&tmx>>`s~$8%rE^c z1~K&245UE$oWnb`33B(Tm@*Od=o07AZSv?x+6A3iyioc5 zMx0*p?^}f>Sr1ObBpGZ1=F7@6$|}lePcZSvHYsDRQa`nwMtlkP&Kj(nVG!fGv;ile zTH@~34^Y#&jC&F`8n7;`WYJRM4Yl{B((MSvALXr+a!)NoL{Cv_rAy5$s-{qTZqdP? zTbE#^;y?kc`3b=xUwf>tHyi$j;qDJ6R*9l#xm*31Z22}rUT#HOQlP@G2J51>Vwmxk zee2mWzMXEgyv%EP5aj`LuR!gBqDY8dQ68w>H&V|9b%ZMXwQ78goWx9HT6k2w*&XZJ z7HeM{>p67R@xJC=f1(!ShTFiH1DEWRyI#hJLY_zNQwGN!y%_5mF}Ivtc=kdVX7Ah*ha^K3m^weE zV(&{Qi3V@zGCUY(p5C1`pH$xfg5(5LuLH*2fFS{KKo>B#2VVGiVq(;H#wSWRu%fGk z^m&6=l&K%&37Jm@s=o>vV>%h5s_ZLh&wnS0MT`bJ6#pn>O#Cufy**@pDJaifF)>lO zHqh~I$(dI0X!iuG{%HIa8~oL~7QE>i*e+E?S4%XF12HTRDDwwET zA&`i)g$7M;lH6L=-E+zUEJ;lg6oW(>2n&{+2u4-|CzO>`^2>=|^$5CoVI^lo{Jaw7 zJ_VCp&I&`c+=F>M9>Ot4q6x01kLlI zWC+v)5aWEr^k<0Zf*b_jyxU1>w+#8 z8_`FeuzMz8_nbS55yl)F)ZI-~`Pf`{vl=#XKSSd(wn_NoPkZTx`4U))1g6U#-Om{( zL#Ex&;DPBmb7*mds-;rNd!PNhG3nsueGCSU-32LoUfcT6cHOl$c`JUc*{5r6*}Ys8x3w-4f* zj7Q{se`4?&Ra`HHLUxw#Lku#;nanT6-7&y;lGp-&QJ8~G{uhiLk59wMbXn7o{)~sc z@7K>Rq3+#-TeVlFoVvIcbp_jZY3gB~Kg$r4x zra$hqAGljg@o8!gpB|jlYnJoFbF?P@XxB?BfBgJ{K{j-}^cr*nowJf@$~mOtEwGyM zyMc!mQ%BIaD>anAC8-kr4$ANPvH&<$EUJsi9xdcd-HyEe@IyMmvnOOb!E5$^b5pK-5aE!W%NTSUz>~E@@DMq|j^aKxv>$gM~JXBoul;pjh zXRP?Zs87nvF6=SZp?q@vhX&cnLf+jw+k}F3(>&oCdHzg5ttCQDj*OHXp79m(KK8^U zo!>Y)AOENNaGEFUA>n|?tm8z&gfgBJNlcsz_Nd6%4D%wgtuj1Sv*d?gX_j17z>?L+ zirqs8%}=_SZ^-7eM1tCKAZCdEQ0`Ik?r%{dG5oI|z=Oc?c|16j8(uUhg){gTepX92 zu){252yc4X`{Lcm+57Q!ilW-FYKW*+!hW+~c-18AdDXsN-App#JwWKU2IazV&t-O% z7k}$GH+XU?v^%tn&B{|x{XIN2Cn6-M*r|4Iz5#;8{q?pIMhoPB70>#>C4ewjhWY!i|u zPlrqO<_DRGTU$rms-}BI+^)|>+$MFzEkn(q!@DXX$y*cCff&oNpabPGEi zM{I~tw4YZ??`g<$E#vYy;JjqFf<>jEq(C9p=z@8CUdLHoil z92}NO31?;bHHl7IS*1*w3QS|Ph`7h{argmt3^>dY9F7F`rLT z8&FPo62V?7Rh2P^opH14*`1-{+V82E(7 zb3Dmkp&*1_Kbk!s5#qKw*Zca~!9t9B({ z=Q@PEMs+&r;{0!fzhu4xCAiOnL z{kq@vFMoP{YLMTxp8T%xaH#;K+M9J(vP&idRKg+Iu}cM}GzVsr|GrMuHtY};j&}w( zzJ;TVF{h4lhhN5YXBx0BQ2mtO^>pg~=z>#0`cA3Gl5K$@nQAmGY#6DcMrHeKpmwVf zdxneA(NV5;BO#0Y$OQE9=z3-YO5X~Gk_LqU=qpBblziaJ?%Md&+)Xi^=<7b zwpGwdO^74`6%%YVfFe+zLX+?wqMrLs;CPDPETX>zq z&r^;61}AnoaNMrQtNM@|D^o3+3X+1NAx|57s zplZlyOS$A^2^YnSu9}$7hap4A^MM{$>{EAjea-lmRaI!u>sv(mgYVE780fg;1>xN8 ztFgnDQyELj+ppQ>q$Wh$WsUrQF6IGo6W(c7Txc)e+lET}o&&0|8Fym|_;O-ue%Lr1 zE+cQ=Bf=5OzDVy3fA&5!y`Rb`rykRD>me$9NGkCgFtKP)$ib@_`+&&Mrpx${*3c=< zLVWK1&>q?gv%fFm^D4ei_2sML4vabL@%*6iZqV2r+bGj9z9r(iIe$+Et?MFcPUmXIvUe!zlE3YS0ic-z_XDjAUVrJ7KaK7^lA+*cp1=c%RRl<(2%qiSZ=_+?^M zURHXnCoc$#H%MfkVtWw=Hrv0&Ayoap-7K1{-eqC5!#q+0NhQiS(6rTObo*j^$HU{3 z&jwMOQh#)hw&ve>Z>sj>yt5s?*0+Ym_D%5@9Q4+wd$l$7uolnGJ3F7ZhWlFgex`Nb zFdt9&3bqFdw)&0j$$Qn1vIW$U4A&V4eH*GM)?Defm{i$@(6ZQ~^(J_-?pDQ&H&Wdj z{(LHC^h>3GjlZ!ZFV|Ps*K|RD>ZwP9|^vqND9CH zT=DA~%CPu#^>~|KuTz6Qi(f}ysQA_KN&MQeF{i4+uRp1#p2sNgRQ%e_V2oTTy!z#X zHm`oDWP$x{;nnX=IEhys$=Ni`ZpU9Cz$kyg*5nx4rWVEBZ-}@4Q8WMZe7c@bTcg;w z;VL2cNUU6sIwIc^m9}xa)*yaX5L}B%t|y3&Tk)Sbg79PdTN77~ON@bsxnoO%Hjw+| zg;IKA^mLwN%~;RR)2dfLORE*ApS)9gBUe{=R9YPtp#DHiCB8JveqSdXxKHu)vTP@P&%B=yR zR4SiLO#Q@8{>(Ecb@F--w7_I{%1-WLj6|xWljrniI+;uT0#Q2ovGIdDSv53??`fu= zx2wMW=ymDagXYB(_~I`pMqPcwzUr2%vROT7OYs2O(!|zxXb(#;H0V~E6|-O)$r--J zleVx`#r#MWbJW~YOfl2BY1w5gcb3!-k?HCJJ$*M%nm?1riU-QDo?f3_;xxO&^C2#FGr zdF(Ut*e~U=@A4S$b$5uI+hi)c)VI0N!v#Fh&DCOb`X(2Cr!I8MLwCuwYq|CZ`=Nz$ zfzT5!)xSnT7W13G9na-S*=_tPcV)PJU+ypw^b;w_4RaM&Gr-gz?bobEJ|}Jh^k4EZ z6v)i+n*+zGXR`dGvz#E*PIAAl7gEGFs(C{kS)6?i8fyhl%e|9E-!g7HitUg8_GdjG>ho&Gg@Po-MPfFhNPUUJ9xErtE@ zS{AYC+wLojrTvl1V(G6$E{LVCi!OLPpRFmszE+R>kLRac>l}|eQfEC* zdPg}<bu^kVDFhTYA74t(&h`#9X6$!uK?Aywt=GVS#;TP*1iMg-G zj#e)p6Woy5Knj(;tIpAunA^x^rArU5K2pz%brTXkv6N{Kwj}008#{U)k$|pE3EzKW zkK>xFE8?VGTVs1y#g5dFw85-9joPx=>Z}CcoTmG8=pY|UVGky@7LVg9!La|gi&*0LPf-~u7wDa_xNvhdsf zPH&WH<)pfD8$JadE5&-J>Wan2o7pArHmYUC_sRq)K<5#2iD}pQ`u;kL?!xr`;yI_U z^M-M%pA}{U=D}hDn-<8NCFIm*WpuQ5zp$)~sx>9(e#w}6X@~jomnpT7aYeoBMkd?%{!?|4TbF*x#n+s%-bg`b^b6~TCB;8LS9c=3pmTdY zJ92;d&P80NJ`HLN$5~@pozxulin?=RDg%hQIIJiY4%*(luI@eMjOm*k&mqjs|?={ci zRz}Of{5ASoN;g}vlMyU;`uvbtdMuhksSFLf z;11!sud54{NMbGo@~$(73s z!|{KS0!Rj>mk}`7H)Lr?YPfxo$ZD7D@@d^%dXcz3XkajPuKF6!v-deuXGh0`NmOwm zSW4aJSP2(Ad*5f7aECl*tMM{G4}FnX#dmba5ej!iN+jN|VIeiI_gtzqN;*9P?YT8V zmq7cHWSlF+#yfs5LE4vEYbdom=ai8loXaYyVmpENV|io~@$*L+al!=d@GmOos%~u*PQa@6BoB{%c?S>2ovj@9a;V?t zB%fHP9>;6z8er-f0C$^$>AeH|UF=tSOwia?aR|2%0M>9>-^_%Q?OXb^<>!Pv$09Wq z+r5=FZuXW|=?@|kQ@vKu_%d?Pv#1^yOpH25_w1+}=BunZD>6Rlcvbd=@EogqJVj-h zPqxx~#hKo-Y=>{FahCaSkiO-T@zn2s)>u!YkvhsA75|JLds;4_;m8In{-(fvC|0-Y z9c$z&Po+5&nJ<6z_?mU{BVJtwF&^$U4|9slq~F7kdZ&3!lal9)ZSxQ*W8?{B1g2i5 zZ#OV|8B-$jx{S>TdY)({Go^x@Pc8%f_FR$4|GC4w?TfaFNNs+`6W4Gdp?AfOj96N% z+`ul<*4{6g*;7;aj{LJWK3yu;c>Y43|Hn;AfyMpmma->3mJoYVn5(%tT`XhLIsL|@ zz~Yc$S&}Y*aG%bS)IOj&eUc^V#{+89X)Q?-IW8nr+sazI$_4O8SK01RBBkSq>y+$u zWr1?BwOV;UUlI%k(~H(1*^NaNIbgo^hCQt%xtX!M0`~QqwVImNaE`HJHz}8pqMW2B zA!9LS3zhU_gv9}iZEXZ?N*FT7fMi!xpiqgi039760z!WCOo#uTR(U?~C~`UaU(M)(qQkp6vDK5c4u?5MW< z3%E8FbV=S8&r8v6qjmKGnF3a~${euzNP0Mvz}f;@K)*mF)!*XPU(Wd+&I$b@JWXPE z`!O})gC-n7EUo4)>HfE0w;S%v)kJ&EsiQx!;kwbE^Ts6&KaK`dKjqTsc|@PnMI@WK zkBLfySyN*yRr+Br7iepaLl&XIRov3FwN)~Xv?tF*4!0H?%Tw7T*_1RX#wPSk4y`D{ zaHl;GHZYhWj6`vft*0#TF!~P+%o;i#ZqbbyrTljC3&Fzc_(cVj#PBnUjoQlg+M1!w zf%}?jugX@{@~wzXTMCBQZF~@I_do@uG0qp-#$U5(YoS(RFjN|2ule>!XzLDu1~9bT z^XHsmXl2nBb7NleVRUGVh8vit@*Y8J8+nPX_KnyoYTrS#dNgVuQaL*;_{m?W$$33L zi0_GJ)zkDw$i|hFYWTty>+O$6@%H7}O5^YCJAacqMcH?LWZ&7sos2eVDtD<*=`R&W z`ko1#VUim(zrp)i^P7by2$+yPxlLelqsPm$Cbm%GX{G*W&2I@cp)o|@fXr04XJDG^ zVtSm7L9+!qe~1AjUb8v_EmRz0My$kjHl{ILaF8t%>Gb__Yl8F3VC4KO7m9&axi**T z9t4&6=E;qF5nY4lH8E-qp4VQGYdk-L=l=)uT4gA{P9}4JWO0)F%l&Fzt336*cCO58 z>GrVWLxu-#uRoJFljq8a{8T;?&wcut?cYAd%qBkDj6-@x8R&~Fdp$!|ouXTay}nmb z*VxqWBFSd-mqRmanf)^*6T@C}|Kwcnm1Cztwm>k+h1QIi3X;2l=ran&$pSJv>)_qQF zIckB>8ht5efnd!I;}jj#TtMTP3l!l_L0UL9mzGC)Q;D(L=?bse_Npz%K9&+QE8h$a zKR5gzp`n^5`jdzWd6IV^x-H4}%lgVo*=CF+E~tKbBFN++37k`GY)DeEHTyVL)KQBU z=8X$r7Fjr*iBe1)hj}lDTF)k5?xg%!vrzUeTM+Tcy4_nB2dGJA~Xq zjmQm(`|Co*%u+n?577WeE=lK+x#1xl02rzLW> zWS1^vvs#y|if&34kF+CuB}3*C@@QW6hHZq9FgSSx@8b_%cVs8X%=T~9A#09*>-dXK z>)$&0-({)WYQ8=+*GF?8|CRF6ygd{TvNgq)NI?jjf4FgbbPN@_UHMAd?z>1IJOk&I zAfUhMQjwwCD&Dozr?G$)f4$fqCKg|F=uVO;O>@;Yk6Tf>qwceMdUM$Gk`~(~1Jm=@ zrGHI!b5z^Bas^%-WAF42~ z#>>37BT%_hTf1KVY+wEM+Q4k6t^3?u-6B_O6XQmt+w|7IxkCkQsX}?s2wDmiE z#_PV;cU{`ke{ zKj?XfTusQ3klcA+%K3((`pEOH#3-Zr z)+~USN2iR!eks0ui{x5j=nn0~VfQfj?6IpnOgY zfPR?(0nx7~43-JG`J7&GHT9G65dkFSR$YUOac>NR_B!5`v5u1O#&X4_>ye{jL*wK7#%{OR~zuEh-zgbTQDm$ZR`J3mQ@HZDRhU>0Q71UMP=M3{CBe9o( z@7Jb(u>>kyFf2$sIZOxJ{kc#geY)iv7gse|}VrjUVyzbQvX@7ZfpOVkZjg zW`q)xudp%@&q$0V%6Nyl2}TIUI`YGw6VX)icOrEXqrYAwLx>KQQB=&^FvYD>sx^vU zJ(uz%{lY=>1Ika{!(08Vq7E$lQq5JR+LH&o^(Vf%;Z`2irnYNO9>q)R-ly)B)7qCR zJC|SX+*9AW2ij>*?x^fBUe{_(ZF)~QzSteEE|1(AjC))VRG_3gz$wr>hnS4OUs0-DCH@HRzOI0P*)R>=4)Rb*4C zClZDGr-`=&(R&@HIPl>7l4_!x-pyQYH>=d;-qi0^`_y`oLAXJuugu-=?@Q}t&t)N^ zEx0p56sXjtcbh?@D_GXDA+O*nl=-9T2d)5Y4{FoUKl>{FTu$|MZECN6mF&7uSKi+E zEG0M?Pd@EIKdBQF1dTlL>-diKHB8g?*I2FukqKYmOXLZErC;0W8}wQ9o@0M; zSnjG7hf?=~O;yb}IRu)9lEV~;^ z!3+jLs9G|B#y-zFmi;2;@B^A36$G3adJa+`=;?r6J9QG{;;Gtg%IgdC?j*sVCHl<7 z*gU;#(+o+-j4pG#uKli?f312&*PrfF&Dz)#`(R3HRK+fPmi3n`2#RE16P0O+cl4m> z3{Wr#)>UfvlXLqaNP+Q)~ETQ=Fx^N(IIrIw*HzEiwrmOOZ@?CM_c&b zY(3U-f)eKhV=X5_p7$dKOpPbPB)tB0(4Y$2gJtMnN%Nz_@^$HH!uQet>1jpN8Ht*& z(?G;MamH)^hM3;~==sy)+Y=9XCR z6bJu(hi)wvi<&5Sh~cCzF}yvdI7_OEt0vfup;^h4{LF^IpUd%CpPHXhT~)A02Rm!=mP=fW@k zrR0redx}=1?}6xFXCy`igf|COAo){1ZPB-QLoxT&B$;6qi9z8S0~$r8$6U+dAXY)I zvI|ywkjp410|D7);DsEu2|@e`Jk(9Q%s1KIoEXKMwhns z*icG{9UD&A2V*1Z*4ExJOlUg{k~&Ljwe`-s7fm&scUlYxZsrP=y&v|xS9i(G#N-H` z;=o95d5mcDjzxI&OZ3A*^BLLYC)SP@_;K`g@-@^|@%Wuca5csd9E(Gax5JM2GH)+l zWDJ*eCH^0))vF!(vi$W#UD4O1$oPDW*#WotCPpezR)hdK_PMa}95Fx&t26?8tc|{W z&sxifH-rSS_Z-@qb+k6fY}1-V-W=6q`}#r-y1FxnZ6;jSDSsVIsA;beJ+8&pGeP;A zNBEns0jU_~YhH!`W5~QBjE`PW*=Y&c=L5|}zUBqoJmjt1&CPZhVm&g%kZ;Jss2hFU zTX`T_T+!kKcTmGNP`N{f4MVTXU)~+m#KVW#eRH_%qp*<-b|;%%&0a@S_=2Xucrv`~ zfi+gSB1C&ZhdsVZuS5I(CMnLPeZNKXZ^B63c(w>6&noo(H>o*;WhH_FtqjgU6WB_s z>tHN7#P>9`%L`+uBOU#Uah!U^56o0?I;Pzq>~&&+l59jMi#CsrJ7*abO`^C1?$5S8bK3su!CbIH2~{WO0& zr7m$U@*9(vGi&t)8d}IH#CsoV>+c!1$f&s~FrhE#=n>dW+PLN-86tEA@kY|aw##o{SujBSi2Ed*=PR9#X6h;8B9!OV6H+)9TCwjUbex+Y!?Y= z7P7u^nd18C`?HI0JuUwsrX?ZD4e-;<#HfE3xgJc^@Mwpdg3W_GBG-lFb`eG9>jN(z z5%-Mqc{%wzGKt!t-$w2;W8aOYf2X;Q6W^baV0p>!@<=K3dfNTFa9LOJ2JnU}>}bK30X{cB&pfn$pTb2db0(br zrJ6cW>oqco&i@J;n!nkHipIjxr*z$H9j%*t!4Cx1Zx_Uln8W!43o{GWuOoAu(F^`VHo^zz2bbG-umL zh{GAUSzsqJ{B0iN=Xp+hn#V2iHLon8Vu4Mx%4ZeJ;g;H}ao0<0D0k~Lv;iNZJU`H| zC1CXUHPU0)mue9T{@rqRJrA(2i#%!64zpD!0Z%Nt4$xB!DM8el?i74F2c3egGo5o~ zWU=55#`c|nLSurCtwEOJ!Na>M(tlFqYc2~kFA?(itClFz$n0EIMjhL!_ z9`PF=dFwx-N$aODMOFGH>}FbA!itD)Tr33ys+KzZ&E<+}Ldwfo@P7oeF5${^l=XI? z;Z1yxDC;1jb6e0@V_M@Pq!0DXKeWjaxu{}0ax%m& z9N!1idysv2w&_~!0d4&ih>LQ{zn+q#t zVnH^M5@S6ohyu;GJ#2J^ z4Wfz48Dr$mW!`)&)iGzp8{X4 z5nCmesvvw9T@jRQl=A1kkf&q$9TwUui1|^o`)`WLBD0k#y>S3vWl}r}PQZ{BK-W0H zaFD^Vgzu#bcL6W3m;@mN#mxnGL0KOH!c#nABef80XNe-1d~w~|0a);QFWLvg9WVeOWG-3%wnRQ3 zOw8>QQB>`dx0rc$`Ko>L8q<}3CmLpS8*91ZU_ndRa16kyr?STh?`PTLDhAu*&b94v zxK@wafml-gWq$M~taGwW?th5aF8*|Q?Sg**uU!C4+b4^ITXJDqU0_+Oq@&yVA=?T5AeeUXr-5m2w_w^j28tkNfX&XW*)T2Q z+zFPP1Jlmr;eQmS9U>w)1JiD@VA|WcX2G$U1n9x>qKtdc)_g+Q2?xVm?^pd^|Qrjm;?Qe3B+L`L(AddoWdIh_xRAkLXY9D86 zOwN`zp9-msYw_taGTC-d24+P|bq1+5T0v(U5Hj5;gfE5T1z}KH3#3K;+RO?IkXD@F zERdFn06^NWa!wxfPYu%kKEn#C_I5jHQF1P|W+>X!|Fj^jM6f9m3@&bz6elcqMv#_? zDFf2pE(-LBunijH4q7NJ;`~5#M>a~ERfFVz@a<2F(yrzUgE}`0rIiho{$HT9;?JN^+Jom= zipA%TDaFEG27WqxmSLTR&l0n=SL$wvhA;T+pM_T0_$+Abn*;bP-VxCvZS6JSvpW0G z0ME{dJKvjWIQRF1vu+!lEn`*wp#{zs@lYSwEXtpa&DLAktV^(2QW~A8^YHY3bYnHN z5EZ@s*sQ$VtM@~*B$ETx?QmJptULO;1sf{H@l?eni&Eeud0M{`d%g{2He(KFk-t2|)#yzbpy>x&&qwW%hbL5HIq@7jyHF z=L7Bul1XkPg)r_01S|rNt=ysDSkFOgfCfBggku4W5;Ce7I zs}%!yY~Nr!)^q(R+A4UgXD+;wjmP%dc&uxtQPUnmK7|eEYhXXF0Wj8c{aD@>FxE5I zZIMdASaUEK>$!fMP*lKJ&)gz;1!vAHM{$v*kT36Uc!_h zy}$xj+FKVqRa?`3PZkv0Hvq*VNoE-1+6RzWmyN`3${?}0DS^bwR(Hm{9!z;H`~!?a z5eA99AGwbR9_~kCtLKijkl5;=djN?w z2P3i7bH`aoY;~~6LSk{?a?>-w&nG4l$CtWG^urOX&oRVK2fMIEef?-=SFf5F)syA}J;(+*=pfUC}3x$;j1%+LGGA|VD z=tpAbT1YJH04E#>#^*hU{1zYWSAfT4{8ik1J&$v~{+`vGu$UxYY7 zERS}0WfgY>&XMa>I8($e=9^r!QCtPYmhf`2Z2*XUj{8i?@1e`@H`jAw1F;XE3W)79 zhkigahtnnn#CDubt3C;cy<{xlL*l@x@rIoIFIjl3n?>CakQ2~{`7ZP8uYMvRJAj8F z?EG;b+89espVDZv)v<2w6~%qyMBnv^02Dm78jR%(cjz62aw-H*n`uk^?7U-qob3E#+{$GHx@tOlZw0vg<-kx9Uz>2Sx9WWED&EJgz;A|QB+}8u0A~w8;(y2XJFU^EO+R=a({e^{OJIl!h7HGYnwfmUH{lIm>)S&@4mAaY%Z_GX*gFtDRMI6dY{{u%SUrA4 zP@%9pn54QhC@f0rDNxvTA7*QUr^K%Xk6mgjE^$x%dRo)3wlI&rWU*VDt+rIW>-j)| zu{`qzQ?cfMy|PC^v7)UgD7If)IU^J+c5Vg7zBQCistA7TNaZOISaY_}1N(Vm?3Zl# zHB8P34_ASlLXJZg{EBS|_*L$VS9db-s~A>uvxuT2lhyRH59+qJu@*5YU5QH zD%hj;koXny1s`K{2Rx#8X$_Ll%1Wj@`WJQx$pc&p8f3HoJ3>(fAoiGxUf!2(CVhxX z&R-TX?s0{TTis1~QX};QrL`Rinne9#dniuLQ7?(+iWNNrVE*a1{rDI#RpVn8Or__T zc&wn;K*hVMHK3-qehdx_Lg*ViRP-iPyStaGrdN?8seAD8)B%T+pT;!1HsxOb+UfVR8_ysFyBWx@sck_oC*OT{fIl2W5H&jyWZ}#88yCDC`uvYuLOnob}pTsp$w4%3+zY%+45j+F>6qX6kx{#)YVta`4j_tWXB7XO1yxtNTn;oWcnLT zJeNZTd13MYPcc!GPi>_H)qp^}W1j!6y7D4dQfv}GbR`EYiUd>7=hjK`Q|&o!cOa=i z;`d@HUgC~^NoSfurJmM2$~&!U)b!|u)0#um9n&g9UPtt^wnx>z43279e{jbY?`x6ewn2ofT#(oFi<+hurT(u} zQsRrwgts%4z}toK&BuF>rge45S-tM*RCxPu;?}Y_(ydyZ$)8_J)QU;~uNDZ^71*#6 zh1b;y{SKH{%Ak};p{AOCXY3HUhUMNa?h!wL0&e@}W`ViXcfJHb=wj>1k}})KTPm9s ziJb)Dpp9|#n@he+abig!>a2IbT%zA}V_Ww4l|u0x9yDqnU|%~MN=H=O@TiSw^KO6l z=FX3E1_CFdINDyF7omTrxfXQ*%u5`Lkdd~@khRj$TOBITG#3G36AE)IRSlu;zsDlf zS)?&cJ#*rDz4~fG31|?5MUzpq@-5 z4pYSn8C#`nC6Yb1R20tf7Z|hS7?Bn<5lUP&gHHq#v#i?4E(o>Fp~dNXc69tFwNcMn zb!qHkyce%M(RyMlxFRY4y_HFyv0s~>B)DQPwZ&Zqhk&M%1>UAR7vOxaY8Ubxj{YJk z!BB9HT{E~XOL|!GKE=j1mDImti@9-&Rc@_47rA6!okP(& zT{VZ^(2KR}T8IWNU8LRJzDQf#lJ|jjpSRLjtS{>Dh8%hA-dQrViutB;?3e@f&A-0b z|4kVPnUBq}KUV#TALE0SEIueJFXuC**njorKy5`w_X;O2>*&uoarCsA{4)acdlEY2bEN6*5&CbC@0$^Q#j#ySUO=pnIEc57Ce?4w0qQ4}#^!#$?g% z-(Kjao$$!D*FnKbwO{8}J+ZQclGS?akC(_cLQ^u;`>4aJ-V|^BVMm6%RKo7b#o0ZX zMO<&w3RN$Ma89K#&Oj%+RYm&k;a(*pwX$e0+L+{=AQpwK_qN6FbsyB+mp9)q_UUrE z3!b{euFIDt1qJ`?%}up2b4c~5yR|WSq;1pAzM|tLOhKM=9`jWv{qEIw2xl2y2EN;99Iu~ z5U&v)D_oc!rz~xJ{Q&*#`j=xT&VD{!_|d~woBL}$Uk#|i6h*i12=uD* z$UIK>@4-7fDq+^%o23)eWC`MWVo5nWs+s0`P&j6Y)b>RW*!?S`)TUr`kA7*iH-go7 zl}UrmW_dW)!JC|?w?*Hk)M6=B^|Qob#gh3?i(Z7T%KG=Hvu;R53qF3Ej&qVUn|Kogu<}5~J?Z zTlaDZ1VAQgwI!L?9NjKi@6xMEyCf86`}I#Osco}W5}VH^ zub`AH|GR!)f^U}dA?mFf9GRuQs_HElt*`w9b)Rd0(XKnBlOenfd(2^;;Dr$S1v&<_l{^Lx%^h@;h@p!yj;xn0ig5*s z&*wbcL-OXxQubQ#2BCAx6N9ouUM`Vgv(@SL%VrMsccaG>zYQMmQ)2qj4ahdmJ*{g4m zi81v%mGr@NpDf^?LlI;-itHndDP`L2$&Qj|NN-UQuo-4D} zVn`{^<%E66kY;MZ^nQ&bNeCJzD&Cda6w7LxDz7Z5RB^!tK*GMb{~c#IzQ8p#KKYoZ zw~lmsn}Z%e;*Vrns7AIfeL0!rczXQKV=UK3z2oz|Sa&5ctkLtuRUlFL=Q~*nPauPj ztb$7=R<2l;XH5QJx^d?RPIP4nZpHeS`XzB@)3*6NCK`#tZILr1H9m2jK27x94S!14m0M4rvCPk2I$9Z)CQS~2tfDKBqKp1LZ5 zp1x=D_K@)_oyLL@8JF%b`UbK<`i$dOsXQM!!(gBbyVEkS8NLv~wGlo-($+J0} zj~KgCuV#_!@HZjXL9*NoCfB$RrWz~z$(8y!+mD#d)QlZZ1|B5_%F}MNX|=lv$cB>d zYio-5SipFJobho!P9@}H=URR9Gx=C!&c{^Xu`#)KnsH}uR^LbjSYtT zP}Cd=0mn}fhYD-i=0jSIQOOg8dt|+AcI}jD1fB&cu<`+L%WK0T`7$k%Tk2b^j}k)* zVL&U5!pNO!f%TJ*N9LJt>`=!Wh$P|}2aT~(D!k2g7G4WZj6~nG0gAJEkB9v7tQ8Et zb(gx5&y|6c3e26Q8-$fs9}%{STtKdp@#!tb*3}19V!2I{SkCB_twP>UFU3g1_I_0J zqvKR(j#Zs*IreibL%v@>UMxz?;*63O%H;U&_ZQuSzo<+3i(2_lCAn^c_y&Q!OtHK` z%b!t7yw)HKdjTGF11Hy97to))Cp2X?LzW<-lnba2{RFE--1)q3bzdIuk}D)0dfw@y zjhtyQaUAkD`Ddj4O`~SmE}>ngcL{y;&rGf-xr8pZ73$cEETH`wT{4HE1re&gX6Vr|4>;EEY3kn$NgwPfln8{^{{d z*T`KmfZ6RuUOzSS+N7#LLs*v^1) z%y>CNCr<)#a=21C@GN9^Y{9NN9VN{IA7+ zC?r8U3V6nC)f&aSniwZm&G`K)vwce_exbyrHoh78=McPE>Bp0?oPU$`cp01Pg8AL# z#=I1dkPZPri^xXFZ}V?MneLtBYZWAjn4=!Q5$SPe0IgVuGw3-U-HPm;2#!3Nk;e?0 zDEu4=ll&I2%$EX8cnzbeu@HDDzsVO6)4tWm#_qNQJBdUAG1kO}imIN>7lM zY!7MElNB>$DrV8 z(NvB%I$*mZK53lMRNX2gM=;ivmwboz+d5>9;v>60uz7HiWH|O4KximmL4$SE{_FEqVR5>GjDxa%_jG9%;5Mw zKTiu_VE!A|ZSBp%uL-4Co8k`az51whkm?_T>{~)s*UW|p6jAx3VR=(MV~Jpx*2*2} zA-R)vNqQ*vlD=@z`J_ST=L|X@Ip}=Ypz|Sv&K+ku$9U)U#hoqaZU5SeLiVpM#S(R) zrnrA^Q*`+QKTlsEbXmO}y5#ty4MxfpUS{mEA|3?N#bo_=ezGDSh%?h-zm`iG^nSoZ zCv!Kj=o9v=_W(}~Hqo`MKZA*`MHLISdel_u8Eg~XJs-kZ*(SQ82eW1Pz6Y#1V6cf! z78My2-Jhcj`HH9Pzy_&hJ|{$c(Tr2(haZIW|MGj;UtDZ|@&6b5oNps+NJCC(ppzIH zG0=UEXT;VuEnc&yHXe};(lOGpFo@54$LaTw5N-MqOvJSZeV)V1FUK|~3k9*66@HZ| zrSJ2i`DWY9rWrN8wMN8NMs35LXxF-N0yk8(0Xv4fxIanhoA8*i4R?&G7sYUQsTl4& zo4ERSBw%u|;ZAm`V!YjsrjS~B3e#NAnM`vtPH&nM|7G+@_lKfK+NQbZUs77*Sf!OD zg}2sViQ?;*bH%pEEw*e^A~e)|ia*0A+2i7)TBcQx>cAcs4|O=Fc|tADGuz{oAGmFk zyAo@P*yM1iv4+=xUG8Up%(2VeMY_$wcDeuR7j9BtTT^1b?f`{RMss(_wx5T26i)zFj-f3VxDUk_xmfX*G;WCw6=U0E^T&8H z5yovB*eSzR@c#!M)f1Dw zG6fzqul#R&3jFB^nF4X3Y3$-@-KfN{1Or-&ZnlOZ1v5}q4LB=-kPck28^O1Et`S=@ zKZ$kfXQQmd^u&z>I6;#qdgaX1r!~k%j^tm!V)cZ2K29@_jL;f>q23a>R|i>|S**Fe zF3qhMX=7$$tr?=U;Q77g-igv(52@nfjeSyB{I_}1o_L~2equ)pXl^NoTH`aqCPt!M zHTRgzJMkx6a*`Oe%tDEAd-$y?%V?BBIFllI$9gQ$rOpnTJ5xf>en6Sz96jpO8~5;o zmx2PFg=h}&jCaiM{Z0fTVV>$frK;kL69UEGTqF@~1t2oEVMA>Rn=X8*$-(z~#mg3| zC10WoHFu-+;zK`DEopq1A4+?aA8m}ao3fE;k&D$ErK-^hndT;}swWB`{R)HY(*KZ= z|A^FiX2MBj_c$qA3f0_dXJ5^&wn_zso#!m(|B%zo|4wina-rFc=uK8rr}oAv5DFDM zA-!&X?;My#4D<~TQJUHV;4lXjEqdaidLGb?e7&RA#Sw?K?m=%4c|$c)N}?j`IoAFibP?QqDe=6M%LwKP0jK>+c|G)gbYA0TLF3IBykXr5bKg32C}GPN?Rgfdkgy(?eHvK6*BUd2;VIia$-|4j>f z?&P8X5_VGA8`~;&F>0hrI%|gxuS;RX#sd6UETT&gwW0dkx6xAdNILd*Y|0Q~b$Kgf zVCI;O1^7M;xkt^f3vCTHtdQJCB9wiSkgM^J>PgvV^9vg|%!^zoY}0C9sumv+Ff}(y!~il2lcwCRQ&8A8JL!PfVR14iTt#^*8|i=I%!D%OSt2*XkJ zMj1w0<7|;EarLek0T1_R^}3X64>M~_(#TSt);EY8;tzZKv}rz{KNmVd0s+GkZK8UQWpOCK-+%rAy zyx(v5yN~+~XLl%33n0;UJo*;G&aIQADyG_!7a5x_Tz$Vi4)HHa7tUFf1~=gBnQAKx>pR-d|$Tp8S*WVQizY2DVYe zkhCCOI3)9RWu1Jn!GX?vD3nmog^eqN9n)R%Mi?gx<>#g+uF_|NrW$|u#a89PH7mIt zjIDBGwXlXlqXf*tN5Od5q1>Rij!#*(zg2O$X-RSZmr3$eAPwJ@^s$5XBz;+J*)w{3sNySa7x?z~nZv#RG$ z>Qd0eR(gs~rN&Y(I(1sJa|i(9TmVGpT=XL* z>R$`ec;-HpUdZaxV_%?8-N)diW#YL|Hmm~eV51ZST&`C?q{d={@Pr=Emyxcm6@SxE;+y4c zX@sGt7Gqj14i|XkZ!#Zymg1`wS1rDMkkBksT&$I;_Nx$*qvm7iYjCT4&f?ZbIZ7AK zhmr%T?s%HVT$j9?@eQhi`^f>bju++H4eHuPX@ONhlPX|rP64}DpG+TlA$Oio^x4&O zGJRC(kY={fXSmSk2}PgkM=av}l(LA`E3v2}Aa__S{E%mCF!mhP#RGSr$!=x%knB%& z5)o12CQznCh-UuU?5CJkpWxjyQ%#(C&9`1TCDnvZ15`^w6TX+6FH*6zQ7D8Ud4M0B zdpl1fMdC_tGaE00>y}7(L+m8dJ_Rucz7nHcSaXjQD_QBr*^|F7R#W1No)rWqEE4Qr zZG4b<&}b}{+PIb42Sd2!?f64-5sga9qQY{KdtK^YqK6-QSeU;ml*be5oBdOC5wFOz zwrDJ{y0XJYS8YW~An&F7s=$rLKHgL!`m&0ork)@C$S^?+HEGY5up|ua^5;QbSdmh4#iO`!R=l?4a2!&z!?Ed`&gZNG#@~L4Z{7 zyTt7r3vQ)63e+UNf-4*Nrxxvxi0nDkiWc+}X<=N6MwuR~6Y`wa@En(8WH)R47iL5~ zp_kj@Go<_ilurP7L!T(+hkI-Z8|>H&lOSTAP+yNLu^V!j^k_OV4ux2Bg#QB952iO0 zxqzv>qnzB6ucU?$Mg6#A1D|Aoz8`LUS8Ke5f|6&;x8tft`lVJCTa&qN7u~p=)SZ`U zX{I6KOwpOFp$yUM5_5zYhQp`K(N?N*K+Z&>N7`;UYzw#2!PVUkRdcBhGdh~hBlQ%( zj|c^rPv}gOAF$4ZUYz}ipI~B|i$ja{tT_zpQCpYdv`bo8{fI?kb|$t)I0~|qY>$1G z7J}gO^uy|+*xKV(e;PhiUA6)i&xBA3(>G2Jc-h7qTdWt{bSh`^9+0B~q>Gp_Klr&Yk9G%*$ij$(s6=LGH>O5{W7KJ|%>qA#^KUd{jL z@8LNzHpT#>(MA!OdUd1pAZrM_E3vOkXYugf_tYbMxCa%5)1iiXL3|w4QX()1SL9pR z0E3ywT6>L|mtV{>A|Hx6N%aK-*~_qmDdogA-a?g_t@)O;-~6{7N)9K#sK$q4F|(0t z)J-VGhvfxChCB_?=I|qO^kWpO_D0ztX6+u0YmjG$z3PoMqB!@N4C% zV~?3^E&26(v*)&7-GjrgtzHi0A`=c-lZK(uI2wTBmEp1D`-2t9*)mj;g9jzrWaKiaiAdf1G(xtuwx^zAZB#&kpLEEPuAs z(ogy~TQ9sSr}W`xXxXRhpZfmtMULbDDvh$T|FA~;)$-F*?$eb&xc;kh%AZd851d4o zQ}~yimOj=(g#K5$i0c2$7w9PIJ^Fvy>09wh{cn{o{ZCah{cjaZR@YPZf964}|JApp za{rI|Kd1EJXK2}{>z|YQUm7*g|7_E8x{>qg%0H?9bIPAi`Tv{#w`ZXhEcG%I)8IjN zrtw|BQOy_ZXKYVA_ifM2a3}Yc^?{SG{{#E~{lU@nQ_%=SAuw<2PN(hD!F8s{LH^pO z;r}yC*w(~ya&^y452+nKQqZGZCYFDujwkoesRrz)tFMiN-ToQdUp{B1%8sWxb$jbK zit>?1Dm+VTGG7u?pQR+5Z5&&?dUB&rcm4GCU2A?!B!0yA%nihVolJ&LuCK6_kgf&YVe$@b3QFU)o&CeEl-VyF4g}MOK0P;gPHVn*Z+a> zP`^<@y=u#_L0U^ZAyyRgJ&9l2`)TW+p?Bx`$8A;+@2Ei~pW2?U`dh}QNCd`bvDt=h^)XpvMi=9J zM|qj50=04|)%}rFtbY>uDt%t$RPiMsCAm zd#3mcItw~ezvskX&~0?49&Oz_%2%+(&*4v5Bvk#&@I3RQ|F(UQ#6MLM&d3e|f>`=C zNOSEBmG?a{C}I|)GtAh=O5(XnSxJxr@?W!@nZ(|YxzhGA)Z-4HiZcn~K}gIA-WFR! z@qF11CYF-3onZnz8y|q!_^+M4X;j|q+eS5q9o@e4UOe-u)-|QgzED+dNNfBS4>kM3 zRkdNQ@n&^AtEzUE*7y}U&X2L*YvZ*XiW{MqUpU{TSF=oNyqvS7h!w^{b#0N>IDzA4 z-?*yUaav=c9M`&H_qcffOPt92vT`QxMs@8dt?@&Mk-UHlejLmi-{S01fFGP~SlauF zLaIQKRN{5ppaYu7c7(DMA!!mSTBbISyMAibxEr*_|K^#g%?odEOs!maJ>U8d&V%W; zFu9!?B>Xe=7b-0EZ5Sfx%_?q_l%`0pzJVGmPdrI8@U{YV*l0{*S*&f1RCZ}|EjOg< z0eMd>I6y>t`gxXlz!O@7>}8cATLFMfb*)=#yg(ISi}6Xqy0(Q3jKZ%9c>Mf>l0!xu zoTNP~cr7VevE#nt>e^!3&#^R6AZPYm)EZvk0(iJ}FhCJW2bNQAU3R(3Q8IaPP7?*t zR+$u>r)%ObSp4H0zvvXr>*7|5-36=;iB46WAy$~&&WKOmF|~T~&gex`H_wKz)%jzWOfE=d#}0HO{f`Bo>T(vM6lBN(N|NS;U>Zp(n6Hf zKXKL;_f=NcR!096_tjL_)hgOt1XXyuer8Z zg^+qFyn)N5TrMSYK&1xYoSp)Pz>|dF34-V8sfQ#bljT07NnyXqj^tE+vL=WD zO-AiOwm^bIyn5sI4dp^|_Fn*AOpLt-Qk90|4iy$WF-UZsGV`Q9kBv&Z?vVEhhi^TJ znBTW-~Ae+T2&7YAin zS#4oj=h^ z4`}TNRs=>a)qT9CHQp)%_i|r-RbJ$xFdY>1^s;L}tH0qTs*2o)I(Z!7715Gf$7VDS zQfx&!^@w~Xb}y1#lE-6al{C=d_>3YIu@UxkhY3461eG0Ol51ws5}BelUk?$p(I4Y{ z=XVuQC`ooJRs1b&1#u?8O2UJU1;r8&!5y98tXs+@JlJn6*8Rlcwi6yqobW6O3G%}3 z3v%3IvjTIMKaeHjC4Lb379y%5RtXUvD*&ng75!!NTxLHwqSQo#%G&G2%g{z!4qVor z2P+ZaKL6p6@tF*=jO>%RZ){mcZE?uBrW99#a-m>|ZG6MVm@sh(VUk}E--fy(I|nHJ zhVy_#HfarWMWFQOt`0-ZdtBm<673;bxv{EPufDN7;tLwPgRO53of)5ZrE7NFeA2zq(r!V1m(x0|SlxR*id^e)Sr~>DH3FP?2 zM-_1Rz`*)0ANGG~P`_F@^Xt-2H18dH zynl71iaoWypIbg9m#eVlOEaa?jN)|RhhGD-2u$f${Ij;^QzK-MJZ4m~Io=C;yh4wC z$DOA&Y=$Qgy11#8s^sk#2|vbX70)7T7A`k%FdCz)zLEq`!FZ&E5INHBe#edfANk#7 z2;koqGHUvi0{tDgn#imT9{aaL7FD839%TyKLhCZjzYIwnS;ifobi&}o$uT|`W74VR(1lU6tFSiTFX zif$nt?etepbVsLz;t@Ba=2{x}iiX;zDlCobRsKZdVQQ*ObjCw1I_a;-OwV!SO44LdM5>>)%;q z+>R*e4VU#T`z-$7Fo9%gbLu#Abs1tx>GL<;#lz&alf9hTeA9R<6o*Jjk@(UxkOmB3 zu0uDjWoByEVv-hw8^tq>QN8ON$tKZaWOjbltdVL;{{Qx5sa#DI=9i1+e89}7XOm&| zJWbNUn+3VU^vKg@Kf4#BM4liJWv z!tC{un^!aIC8>is`_a>`mtOm#wO$%+WKE`&Dv`?w(pNHTFexXe%wxYATxRZm$j>z8 z6qsGVqQPbT?xeE%*K z=!bVKK~SZJaIW=j;PzTR zgg5>S*e4|M&c31`6Hw66!Y;p0&@9pu1xL%Sy-o7K_?X8>Dcw2wd8OIxKQsZq35LvqL_q=0|w^IzLJ1Oc^ z11cxJX7&C@rQV6hO6uh|vmal4LWm%n!#zu6gFtyAYf#?Umhs|8jNb$0TEw~Jp;oQo zT#>=D)ixTUOcbTQrcNJ(6i;qaA){=_t#BNbqcf;Y1rlf}CPQuXU8TO=hLR!ry7+d8 zbo?W3Qla?8RzIwg5$q1`M)g<$C^8<&Kcp~C8mouV|M3XY?c-bsRnI3~^>39sq9oFpkLu`U29f9xv?|!n*c?3ky56yg zI;6=Hc}XyKG#x4QH!pPKeR7Q>P_=LjOtL-lx73iZv5B>VQtZQx+oR1$ljL1AiKaD5 zzCkonU@a=k!d$gmm-(H%vl5W0CxXS%WKadv(7gJPaaRwd9HHI+MW|!H*nl>BS5f53 ziY>v|%Cp?VmTD+-XTjDT{dDH3jTAZQ+}xGo*t>KNyw4aFfy-KiRz$W zt}*VROV4WekD+ZH{xNO=nD8H?dR^dpRBxL&k!4lyYU@oQ69*O9nW@+bk=(Mu$Ql7~PF*o)cEuoXZpFSlsA9p~iaD2FcB+c8=b7W< z>CJveI?$vx4isE%j61vZjhQ;$&|k+nIdxo~MZ6)|b%eyZb^IQiiDeUSRVcCQ(M-0< zK65D?9gbhdLUy`K8xz=*{4E%V5d98uX51j;~FFthx{f-mt zHf7O1yGAHVA~Ll4H53Z%M=o7S(7;f*;R?~pkoK{aE_c2(2pJ4nTyC1pldW)rY#2nv zS`JuaUKkZlP;bTOxrABsg%dI_O1-J5%Vo1E3%EhWb$Zu3f`?yQJd08YZ*GZ9mFCH~ zBXf0P=-XdFw}O@6F=mqy%o5Ra)o!(lzra}wrqDWEKJz3V3|!UA`XWY@pVpk2fplx{ynt-W+r!ii+b-tX05by`DRxucrit!{sbrnm~gQ> zRCaV(2@1x=MR_wj{1=OAm^U*Xy4VHy#Zt*!wrXE`wz2YJSnfIc@$D$#Z? zaSF{``lW#)i)fqcSm*qGC>M)xElfJ45azz+chSQ9r6iEA#fz;kfB6_}3V2u*wo+1k zjk{ynNM^CH@oMrHELNEB$*jZFGmOD3Qx6nlh8Sj#W}#ZEntD#5Iwb!^T9Fvt^Z8+U z3a8}wxEzP112YM+67wImJ?mlWUUS1w(QiMcJzAM(_(r|%2^6hT$ux3Q7d1-0d5C^{ zGo#QC=w}KaWwCNSoqsI9&U)M0v+hQpZ15+LHo9BTcq0hsu>RTOdqzYc2q#d|r1II- z{z>lWXJLm)u9@+blS(B7XvMeprI9~p;dhVv_FUNWesp{47gL-4lPafH`6m@cMqwvt zk~97*ni*R;saQF-|7Cu^cE@V!Kjz^|OiCdVt-Pki;zGuqswjo$PV=w zh{LKbP`)057SM2v<#u25EXmp4i9Wava%~_**8j)cyT?aWor~WyA%OsiJ5i!hsf-#c zv08(mCI)2&GO!0`07VoP6pJEOt4K0}#mK}-G&|F2J+1cgYi(&g?eTU_v8@{MmVhP! zs|KkGSS8?XkK-kRauw(OK5Or}B>`#A`QzpDAv3f0x;|^IXFd04rLYCljEjd9O%jRR zq-OsRC`qtoNBkZR1t6BlS#lE)bg;0{?TQq{yy-p>uVu-*JhLUPdA2B|bcWHOOLqTtg{}`wDw1Q)_JH>qtnrEE^cvEx+ z(apMpudAYerKn6&fWnxf^W3^INbj7aWG=cf3E|(To|XxomZeU2~~e5H`~i*};@*W|~Hu3g=(ZntAkzT^w@)=R|<*e1OG z=;_13#N8fskNS*{pOfMN1N5nABH3)hUB1p^NYkFs57{o!i{Q$Tbu)D@t69%#Zo}l9Yh*(2aIiIq?oD^u0SvW!u?(bR!yM21|)HyaBsK2Do(~#Q)|Sgf`NW6 ztJx4kYMfrXzp}J}$owLNs~COvO)XN2gU-U{f&Tg!X}%^1wYP z%zVaYl()d9{G){l$%Ncq^FoNGfgmSbtsb3GLHan(!K-zbAb!zzZ^8XtYY2ib;$G|c zsj~;zEAhw_KV~#wMX}>xZL)?9_L{=06-6q=c*ZNAF|N!vzDb?<5E5N)B=sgB);U z)Ku*!v=Sk$*GhcP#&V9R!VUy;R2wxC-~tI$dIS|QXbIy;%tt#y2qz}SZr4I3>~D{V z*0(8zkA3Fukt){yVYx4I)x~NMuSMAYyElVF?bCPd%=F$~jAu*?ELzE(y~@0EHxokX z#nqe7ZQUc{Afk%(K;K}(uh4CU98#YVGe0O~;E^BLhxA(eka`Fp*zhic^CHu4nhtGKXC_hGM@sB9zVqMP1?1eSFGChj z4ZRzP5z~^PdfR-k{t<7Ngt&x=D)qKZW=7Odk=MA54h*4Fxx3t2=y&*U0eE*zEOL^= zd*%oB@V4;qDQgo-{^(bb^;(Y9YU|)gEeKqNh9R+nY_?zU0{p@JWw5|g?X}Tad#$qH zUVDfo=)c$Q?zh)yuHqXv+GsXfrFpD)a2{%-aU$(~cE|ASeTGt)tKbG^;zdK%bSd+< z4@JW%JoG8SA!7^0KIg9-5bj;kQam1`PsoZ$eP!$k_K0kJR208ek2l5M=I9^tnto2= zdB|NI8BykeAIOE=C(h?5V#yF3SG8|xMNRaFP6B7V36juizOLGbDZ`63+9a_cGM64N z`!z?(C0>(b5{_1N-YmFy~-OR%x1P`}E1%eSPUMCnPmrUMj7B9mOXZ6d;j?0VAJ{++jB1_C?aqQ zTMecZ@o6|oga5+#ZW%z1002&={rLO$r0pI0^JCWh4pRT!_rI~en#a?W>(9rr*kaiv z$8x~k{w7ScL!gHpGDJ)&wz(iGII<}pcxdYp;y-x7u624C=P?~7GCcr&PLK6 z$Buzz$ER)hxK}o3nzLUdoP9v74IXdf4LO+ohJ+N+BZF@_QEX~=seJxGK>KHW}ra~@$e`L1XADO4q z1XnXeWd!ob@VZ31NK**Hz4`v{AWRbxwTz^^Js|A%&xB@V5D=yn2;JO}SgR<@5Reg- zL%~D6Vzt#u*HXUeyJ}`{a{5>K4Kfc;E;2i?#f5pV9?Y1u&{lPSsi~i@f)$bDkvD5# zinP!gUizv?cyX6RWPvD{&lu-$t?kfIdPMW472zCO1ANTl2K?ZsS%ZVPn_M(KIudi5 zjoMw(1_F7kdh)~|Qftg*Na!=`+(^wJ8(y0cnOnrZ*`K%M6lC7Sm6_IAQ>3;Tg3ltt z{LLLjJeE=FDLex5;x#TT8-oZ%Ff@KiiB?2noS~KZH&uSIbu=%eh0@(8DsP=$sy3WO*r66{ea+lN6soN-YUb51-&V> z;;tjaKpQCm+~Hq&Q2Ek@B?`-O8cybiEZ|7Sl6CQU*>{NPTM_uo-GH9K( z@Zj`JI$pB6nH1)m!;HeIyeSai^UYV@0q1=*!2R5(zEB{4335au-ub%72-)H3rqa^J ze)7gj*>owaq{3>ktQ-?;fdZ|9FuaQd2@aPL4%Ql;hM&PogdIZ&Y-4sCmfFotj{q() zx6fm}8TKLxOi}hW5EY5xVAyrBDif0)@aXREfyc<;(?&1k1oH4gNxNaMl??nc;qF`E zl;oe1eBV7;9*L1&t1wfDFt?a@&9}LxQ>69C4B8Czu!DzyOJL6?_>gIc+?yAo;8Qjc z(<$_(+zKjin^>HpcQlklyHwfQg1I6;*o4HfhgigU@T>Eg7nn^rj`~$Za6=fgNNaS$ zsrsXCmmZ<|2F1XC!NB~4aiBOYE`znDbz#Zo6t$3quBlmG$kK3*i0{BJF=;gJ5AjVh z<0<*tq|ohWmm<#| zTF!Cm65)6~<^9G7bheVmf)0?jituFT)grN;H*-ehnzJ$Zm0rrXO0I&thk^JA7GRaP zKB5Ki728Ey_YBqiPQu8|n~4mMj1FJyQj>!DRg(zj(zQ%chO^j55HDZ#grFv}pJ>Up ze3+5HX|hmLfQuzqj1Vuu7{SuqXZ3h-K0=AvGfDiW6{EbyT+@e4O0MGA7Iq}0&wNL) zcUq*55ySm9e~m~+poG!Nj~y0pc9=I`X#?j21spG3vb*hZkw^)B`sXxJfN@{5}1=9A(<4bYx{Y!o2C(W^X^npZWh6>=V}8m|(ZzGMCQ90>+Z-dK}hF2PBxC^$*}3K=}+ zHCfHiLVZw@*3_+yyMBwGDdBkFR1INIWY_ge1k>8H`#sOr+i& z>lwI9&Yf(9<^B6yE`8b^#-5kjHWC=MneT!GoU9i1sAw{*5Fmtl5j@b5#se6Rb;{vP z;(_l|BNGpFYIk2Mk3@?1j7W0SX}Dvqz2N8YE&v~oq;Ldun!gMZ#};3rjV&tzY|tTS zDVM<>?!l1Q(j9+w#U8Qnr&g&tP|E$bv3vn$03 z1-OQ&AsW&aPieDvnJ68`u|hr+)9PA)R^&X)M_=!+s-MqJ<>l1K?H5=_`&mw$*0`4@ ztjRofg*}-O^u^KUKSWihR}H?yi{xF7Hc?i2(X>)}mUDeyh;OnPO0QH$8x6$U(<9eh zkUu?AcR`WA{4*btmAgBnR@UhzmhEVDx_ixc=55C!?MsA;MPR>*iJ{vsAR0bL8hM3S z&8s6Vu&o|nCWm?(hx*Z64$M}>Im-U}(5D(F?%rf0k`LvQ8U|2o&USvMO`)iO*8 zXJ8_(N1}p|W5t43B9ANN%oQK5uS5oF?S+Wi3tHo+>UhpMH+4Llq@P5|3FpX@&ttC) za8!(#bvQ4o?{_#KQaBc>IP!xcPA0c#(@NTtrN~&w8FM9q=G(Fy*5SNC4Yb}7E0ZsM zkbz2HDj7nz-`=l3@e*VORev$dmCUN`#d{_`GTQ z-jJ_-Y&jE1m)W)v`$Ty47Vok$XLHk^nGZBjFh|U1_nF_F2Tgr9!%zW}Q1Z^8UF-X< z*i5J{)rN%^*=Z4VIkMr1;Gg#&b{ikfrHx6np|D>(Vtp`N`@+qt2VviEEb^)^q|y;o z3V>HYn37%CT%o81F+94Y2wk|!P>L)JBWE$5!P>|m-xd;G1Dk5X9-3F(s7R_sdUXZJ zYVoB2#C+==NHW}jyz;rNd+7?m zFoa4LH5<(cZ&p)FW-O=38_1;QCVL}%O-N1ZBznw1cKy5hSKw(~KG14OAbw2i zHYwP&QuX(jGgJMg&)>fV&zAe8fzY#ZfE}2!C?h6l!eD-)q%PU7g6akI8G4uS3xdx3 z&G6uF79R3Egr1e=9BMtuaS3$4rk~_&L%brc57M6hv-K3YcLZXpe}gHO*!HJUM*PYM zLYc>4ICJtviW;jswwY`C0xL(|9YvWLeiV{b#m#FjN!s*S_FlFjl3T)1h~{$-7q1LhWd(`**n0?aenc1Yx!O2>Dz)-d&N|$*F^%? z`M_1#&mkx5^s1=-4f|vh)n3y)`zy<67!0nGl4J$qZgn{vJ>cCgxmih?rbqLp|9Ci~ zfTWMk{>rSHw^5=8H2qYq4d6iHh^!KU*kF747a?>ty2~aMgp3XCvB8q8jBblV>)M(F zUp0FVSaC7p4WVrlLhC{vqubMN7NAVTz;EfXo={g$O|$o_=D>kw@7JDI_NPPfkDgG^ z1YU;PKRPnBzLz;r>Ogbg>t=7l3Yrl+Ll!KWS3$z-WNxpINra8r=*vt1CF}mx=hB*a z_Y%uG4zZ?nKPB_y&gabcSeVpIl!O3wa?2%3rhdmhd0F`z`ubx5yKH}~8K& zSf|fQ9u2jEN)wl|(-ZmkWss-0l={lwsXLb_+&EyZ<-z&yF&Z3!9zTsChL?-SogS(7 zB#@RW%)dvR@03@Q@&LkBl;|mua}p(wQZG5DG~(hIaf%kvSOzK(8&)g-{IX>3IBP#e zpa3yjY--~`^lD9Erc5w)U{6%~95Q*b8!mEb<+GKvTBO&wFcJTNr`Yu*g6AES1P|7|sx&Dh;f71~hB9KuXVNm?=1+@NY_WhVHkI>z0ri6kU zRV;kD7;`86X*B>Y6tplwPPGdDLS)wU<}YGzU`um?gybJZSCYAItuIpSZE?Gk#mtjE zn6qtBKc6CMrDLc5$N0u%J~rBCrC({8ST;U~1d{pfa*!`Bn++yui;9|3O`k z;Go~8hs~jWZ4v{?+h1Scn7$x4gm~GL=#kuWZk2m3Z+fA$hO~x43w|NF=VX*Ixpr}0 zU{eStE@fSR!+G_z%DiL8F$59QXEbxE65?3RY`9NKs?l8ErnI>dGqp#tDA*15awz?enJX}Zs-ok{UltN5I!WM~qe0~yg=*-n00*pjPR5vI70 zQpqW{oA13LplWzQ#&%`KmBs!+SmX><=HPvwHOCf`EL!`6IaV@9JBJ|#mU(v(t|hrD z3)AJSRf(;$Rz;;TRQnSdmB4~@wYo8k3CJa<2S{}J&82dFpQe(f44{Q5@E6uL% zL%BKqCoqqj^yQ2u~~dKAwK$J10_d z^HM=TcDV(zE7e|B=aX)o8?0^@Wq>OqUJ`SGUJ~C>$O;>B(UOnz3mCba+Qdu;K$M&#Vk*lPv8i)o0x8tj!FN|VLlS)| zIMT{R9FY?$n71*rBf)-(B9lAAXkX=QTvzvMJjSk6`D&ak`7JY@F*PFJ{&dyKBTmZ&d%CH#)P&6WTi% zGwk(VZBkcw4e1a3WoKCft6E=M)^3(kj$)M3o@k>S#V9h?I#Ln=r%jShyX9E08TXnw z4{cOQr@tqg+RZ&I%TiOe7`Fs}^hagFiHS8Ieg-on&mqL1zy;blns+yMiqEiOp8Lpv z7{H#I&r)Bf+eI~p`9WA9o`lz0iL9+lH;akS&#}w9pjqfkh0qHp<|vA7dDC!*m5Fup zq6`Wtg)f}Jvr!ji;DpzLL}9kt$h&A)3U^pI;q@1-C9i~d$V8;4qzhU|=3m4YvwouR z#kq{%x`YH@{POSi{$g*@-oW@`?Gp#Z7xVt(oAAYHQX*RTT|PXmNqn)v?)G287tiD# z5?@?{Qh*$rXJ5-I%67>{82M?0aWQ8Kgt6z~2xC@ePX|R97QTq&M`q?Ke37ybS*1qs zXjw=;JG~Md13rz+uu;!$Jb$&YSV`(p?<%=~C0vYb)mNUBQz(2(-bSu@o7qw55z>g^ zEt?iuXqFLSty38%#+L(w=vD#EdBT?@QMkTLSS#AC>-R6qJYqQ9_i#B1AiXeu2 zAVFP7v_w}Fh}`Cav(@0oG<)(pJVP1L*~7N&WDY_+MoT8Xm&dvXx-6_`-u$dg z&w6z_ucR)odn`0y&Xm_YGT(e|qvU+cv_Z%Hu$m^paU}l9A zlwT#~6H;Egvzx!h9;=S_lLz=E^-Qat*7O(;C`#SfulWiOZ|R4^dn$s(B;5tg!qcNt zY8pbLGMb;ZMK5d!?>iB1k^D7UQ!l!QPHzu&$8Fh-vYh(E7IK**(qPZBIk;I$|!)hOtML+AI8bLY2Bs@!v(w-s0z_6zuo* z38D3{--KO&{l-cd7~TC7UcqGx3*OT_dt0-2`_ppSseHiN6YXrm4dk0^$t_Z5vDTC4 zttZ`P4Do)#;_8ik?H?61Fc5h91)=q{Rn#0PZuTDeylPI^MYr|@x`)CBRXacSBz5ga zH(8Hp@DDspG5)b5L+g53K*qMMdG_{Z@4HVc{-Hv8Rg-D|>_~U$)n0*c^X%g0z>&?~ zqn=k~?xBn=_TOUuV^YfDY@gZ55Al@?F-_pF>?8Zyk7OR5>qllDow3JTOmiw_w}?0U z*^BmXFMZaI&1&ym_#MHH$@Wr|z4ZmcGxp#YJ5wHV@|!K-NEWm2N0_l3i*m48vfnJu zWXZBG!OPN=dh!yqcp!*>$mYCKRxEk54r-7qM=@sNdu`vpQfdicPL}#dNJ++xNE_4*bMAa*3!ZW|M~h}mex8{?|sw< z#MiAJ7{pJe3noF#dhXPofpRHqA&tF1lFJQKs0~JdyCAoLD4^;XT?Fu_!p*MnCAOt@ zuJxra{>zk~>T)6x#HCK+&>zV_GfrY99F`mA*h9}tG45DV8lK<`dQ`}|8PV}~a3miA z8geAr&&W7D+LMD9GVO9IjRx9DetCAQoXZY8QNIqp6`v>#oG+v^{w1`bl-Q{@rbTj5 zB~YI>Dl*zAR&BhHk2h=ZEp@!zHrtJaMA%Qr*pd%hGNvHgSWjsJ)S9L7k<0RnCc%z* zD(Z5#M6V8>rrj9tQ1tLeMfoC6Ocx|tB_!6DhZk%-pmE? ziLd-+?an#UlJTP6{)x-yd?kFKP`mq|!0Rc;w;>lFh%LF|DMzXLriCYSv!^$h1NJ$VD^-h;S1J)0=<(Fw(Bb9 z46&4WCNiCq!utjZ%duW-l9DP+L-@eASIiYqHLjz6_`pe8lh8pTB^o{Vq?k0_^hw>a z@PVOPaEsvE1wn(CxeWZoVApFm-t8QUSTv2oLW~OJ}@`vwrb6d zDI@=ANr4oy8C=g!(*YCuzFU#C9&Gn_fuonrM}n2u8{V)BP!YZ3%(~wu`VvF)SjG}FDSD@Cmki9 zqg$p9YneD)WenyHT5zi@(?>qTG<#>Nh&0#pMD0=)fxz6t(=^gY2IeXBHS7riwOfyr z%NcQw+z%67ay|6$y1-XXFwl1CPQ8(vW4$m`a(VPQ->#Y#AO9~rv8Ls+liV%WpWJd; zSxw6=rx4O+7hUb=|N98p;{3+L@rm|;@Ti^i?Ke&@lSrufaui|L>dHz3H}qC|{^s=j zH3vsYX6CyV(aK+PJWuAhAJ6$~j%QWQMD2;X(<*!m#y#eDzLNOBYrGpDS!28(KgMfp zk00qZK8zQNLt=gnF9vyy9zqXP2C6;{c6vhla~Q@;xLS63Li^kt@s}l;glm>RyG&B8Xrr*r; zo3B5)ndvv*atfgJ~P^ly+qIp zs0{@8H7)Kk=?~TW8gKp@kN6^e%M!iHy)_Ov>jmz~?B3Q!LvmL=B zJPmu`A012cyyQC=CKYR_8Gj+P>{LfkemiTLJwxMv6U~tXX5>b7p`2V}3Q-w!;w8MsTy>O?0^s)BY=Mj2Rp)f>RwoC*x&3a$d`n zq!L-Q$K!D!5^6wOy>|jf!AfAF>FshXJXq2oZ<81=;xa;rI>;eRh`NsAg8mInWBLNA zI*X$?NgYM7B#{8{2gi^#wvz(Hn&@m=$rt&Tl*)+}YIAfYPpqRN!BwI6&akCoPeGlj zu*>&J5ymFQywfTW&MC81%PQU2Cr>9ZkVMHk;G&>}N!l-|k|_DfP@dp?(GtLrY)@`* zMRQ<)U&CzUDzuod5Djb{76UgKjyQN2}Z|w=UW>#pSF61#C9o zS|UOHc3D5Zd%IkK!3UMbo&>8X?U9tQVqy6l00WGp0l4@s z{F$HlY*EY$AN#DpTLobuzdCYQPiO*gowrD9jH-p$?{0ba_k2UxCLT5xM<1>q&2h#F zrXo?|7O=~9r|m?^FhcEc+GPp1O7!@X(r+sg z#&%H|6gfwEs)hF!YCk4nodw;-path*t#PIG?PwaO;!cltv-+bCUZ~X-t}byp_{>|Q zKHq9zsJ+>CzLKRjeIi4N1{TZSTyO$oy^rp!rTdEUe8bW;y`-v_d@_27YQ@t!Mdtem zPY0CTiqoYfxouiW!RGsZFMpfzOjkNP0GQTbk1mM0fMWS?d}3&MXW&t zu>RO%J}y0TavC+>TXL(UFM{|ETnksFoSWxh5+--L$VSvDAD@?r0|v84EgZm6*BTdL z@|P$%HeIAQHiJic>#S>Us=M|kSpiVmf@@{@uf8FP(wcs**bM7f&E-hPE})V+m5}J} zqJ`Q`U9yQiN2-Ha=u@9>@$AiZ`(O%^N$#5;%J%yT?FWnCINNg_J41Uy&k28i?LygN zOn0j91CG z#PjM!k^AQ2<)Q~C;}?~E6{YOckH_0amIgcVK`9`DD%*3!^iPcje>7Lj&DaGmy!I4IUY$QLh=;B?&|ChDY01Sv6quT3^>&40jVAwq@!)5GUEg3}1f%IOBbpkIf0oT4YXMAt5CS~7_| zMkcvp_UU(s-RH#)n5YZ+Z{=F=y$@+WCA9(Rn(ZkYkScR*T|=ACQnW z2!FCHo?ptcc-F!U*MY^bV#V|@0Wq3L!-7C*kTt|fGDOZ$uLOQxo*G~H_95NF2-4+5 zO*vzexNV>D0M@*b89n--8KxLR0}S)|Q^Z+xDXf;aHx^-RqSoDE=A3L3u+Tj$3Qf%Z zinWm%QK?}Bfk%BepPQhb+T>c%BemGc*5(H#LUgZf;=1E_X5KUcX^OCN3VH>%622f8 zey)x95Z&Y#?-|%)mP<(4x-NqH9LOU3sFX#vMM`Z4*9~NoO*F+!n{11ic$~titG2&M zwspIT)|J(pEOT(Cm99I?i@vR#jqb7VfwhR7+wafk(6*W99F@+vI&W=%eQIWTfs|#@ zt7e&GgzQhXKN<$kEhW~~IY=pN8(P>Ot?>ZMpj_5A%3V?+5!7IMu>Fsg+<&4X0ajTW zlQ>y;OD-Cfd?ch<98>v{@J(X1K@_{zki4tO?`lXyK~TA!vv4Ht?}}G>w_Z zoZpZC&x#WjuJ5*Z_)UqDX+SWICrhAnlX!ccC@50)JS%B9&6#>j*(lI5XL(vC%X&0! z;I$Zci2T&zR?*~mTJ(yxZG%?lVbs6zBcQOy{0&$lbcYR;J?6YwvMKL4)q#Xtf>}ed zAhC6}>4UtWl06tpBd84y4lPSKmVGA;nHfNDN(S_FV+b&jAqwBd*-0*;C1B!S5w>>a zC$hP1ZckXfa6N|j#2^fEXHR10X*d+_XL~#fYzvN2usxfP)#bErK3y%a?Te55+Y8XL zU}9R1(N?6mq+E3rQD|^Mv0HPW3jf3tksm!Rq47fcK{a%eR-8 zz0dMmvc}{BUy(izV!D+nl#`$`xb28$=gk`9W%K<}>>F_vCK$qI*fny!WRx%mU&!W6 zzKi|Py4GNmFG@)qk$Dn8#*7kQCw^bXgi`tK!XM9(Wss!1Nw1vHn*Hc0z8@Rzz&ulr zjPLSC&;AX+0t?3fSdWgJV3{bb9%^am&-ElGH;?cHqPo*hVujcI9F_$4 z3ZlcPcyJ)I=fY;UFQE@P%5&6_!0&3UBJRYBs>#&{KUk}13ADxEwX=9 z+}M6VYdA-M#_a(yUIp}+@Q8K-RppLZR};y7sV3roDc4)oeCJo)80r9iLg&; zAEd8HoSo}kx1LbPPhef25mVyRN{}|tS9*qn%<_vg`S2B z7A&kAA)mDi>I&rZ#syl_)4XE|HepED%iP7Tt%F-HRKLj?Jh#QW86$7KbFlDINMU-J zJp$nsiISY;%sGx}VB)6K{w3{2fI62m0qa?}&cTccFwu}Py(r!)y$Q7>T`kYIx~jV` zS*OshBlKl_eaB?%Rjlq+*D{7+L%PGYwhAsf4+2nyw0wwrJyh)s9+@?Em7u`xLTfBg zC_)X5UQ$Dgoxt;f=y`jSC)Xbc;1=y*wbj~-hZJ(nFZwRNTCbD=(y}C)xADuH2;Mjy zziQK(!@vh*$12uc-n>TGz*B*KrTCb(G3z9t$LCsDs1bd&)5QlML-CZW zadI$V@9~89PFPy#*B)43JA|T3-i-%%{5&@8$JHK9a5*i!jB!DBy1dP~6L6l4Zx$8M zKX|nS?RtH0hc_WK%IrI!wj@q8L5+i^x%3=d?dMXHUFqa%XzZ#x%hJ?`CM*b^>ggDA zy-ZDOe2oElI;J>l`I)2L^`Z4MXMr+Kq?4s*BI#{Y3r;S+J?8tjk*>Si5xm52oJ0Ns z_8B=8MXf62fncrlm*d7|Re9EQ2#D7RQ6UVKi$~kA){}RQ5YdFG;E?6En(~QbtaJQe&tx=SUgUTPXk+s9sY5KAQIuBcLz6lG=nq!!Ne*{qeiJ z31^UfT#4vEV;?(r^hNoH(Oz0f^byt581ZkPizGK;-R{Z7$Utdn$$+H;OkW%ZDJ(u4 zWLdwE1g?|ZGptY5{rL`a=P~eSzievrYhJSP?!ubK^UU4ADWJ{xK(c4l)EFkQYy8pk z?|UGhh&2V3(<3#NEZ&QH`2h?rarNC|{*T>=PV{z6G6LH4_oePhR^5YCx^3V}#eTz- z$chK4HK}i{86O9t*D{`-LsUAVUnMm@jBO6p)uy8@(4=Oiy2?3pR}b{7q`D#r+M&Ao zLBCouD=HmoR+arKy)V(qrbP#w`%+H3TxoS>JNy|@Z0wQKxD-YvL(Y>qUL zO9R(S{gWv2x)f1%lj7TeE_X~@vz&lRg^ox(L(Xp~TdwSqdy9m0pIhegv=#{lLSyCQ zQ|>RVrKape?gCHqWalbpoM@PSENKWO&ZUY^5NJ=B95I%s5Ck#)we)L#^j%1o)W7uk z5^B$talFXP@abSrD>uEvI$rP4LJ7k$?;VjkUL>v{kEr(BHpn-(KZ-+Q_=TJrqsKa3 zqfQu_K3$SlFMYaZrrVHZ<8*xyh%R(mRa3_#yUxh|b!t=^7b!ngPO!w_D*q~Dcf^iL z4YfxCNq-AHpiO32yFyW7b{LJd9+fJ(<^r~l|ANx^>p&^BKT?okQ8Z1MK>Rjr@Brq& zDQU_D;7eH*wIa=;iccl=>s|OyKxR%kBeg{7^|A0D zarK&Bvov^q<0Xp$g0m)73dvG2J_#5Hd>cNQ79Dpw(bWWd=#hdUBu^V+VYj!zZj#`| z>^?FJ5BRhhUj&GyWqhF$`96gKiPSt7r@?c9YNxM!D^P_5g#6oN{>-k-ncE|#l1EFl zKOyq6&lpoZ7p9@^+@g3-a>MnVk7dT8OdVg5r0&L70pm+%5O97bktD1M3}ym@`=Dnn zdjg>LuL9+t3U#n_wM0T=Ph7yBxPZ}j_{zV|*b}c8r}hL{hNRZ2aM?as;pB`D5e@f>v)$8usorn-wuSgi8|{Q_H3Kw=8VFBtP!A^c^55 zTiQ(KJmFjkAj8~f{;V<9l}SG1VkX@1vQ?^=Sx!Dnaibtb0wQCpxj|J>d(E)EeJ{8io!hW=jzX zRkWf@T(I^lwQ>n(L0Ah|{Aj>s=5zIOB}&yos**FFs*h5Y9o@^0<`WODeihy3t1!8= z&?_}J5)a<08T!VW-R6DNR5mBab$A!z*~loqH&Y_us~>K2Hb2OndA#<-S|zSdzF-uL zcPe~-S=OUdF5yve)}z0Wq1b-Fsh#aM+etUUjL13pugZ z-10QrDj9&P9!;4KZptRmG5a{`1Ac|;UFy)*k4FBJ_4 zR_JPB3%_xN1|x>EtKL9W3(kb!`oM}vs z&lw{+o1Qdr5GX&>CgZ5Z_jOEefC$37Siqg_1%A?y-@vij=Jx# zEz^37pJlZ=uTQIjVr^;OVUE|@@M`{9Ef4C`vTCj$KYhsg(?Z7lxBpx7U)XQ{S*_0N z(`v^2GcGT_4y0cgepvd2HBYf2ZT*7t@bn85GpkQJq<+EM8?GFl)Gvrg-27VI|UH2`c)L52l3*xOFk$~E(m1)AeJ>OypEP1iynJ#l7 z8MWy=j}lCq&!5^iRu$o<5E&zAd(^=a5!;~NZYMd!4E=^K@<(@4zX5#Jh#`)Z&Vm%s zm}|==jlu}aFLOIt(M9xrI#;q8AmO+zsUkiHZ^$sJWb@>+Y#s^eUcX0Ayc+x`&tTkD zyfNrTp){5MlM=ycqiUq}qsy8IDe5sB$7pBFvi%U3oH(Q#P5BN?o|Kx^D01!XTq3szX_`gClp?D$sEOEJj4 zgjFML^>T@J$F~wK{IxWIZ>TQ5p}V&}T_L}tBTf)y%Wus_W1b( zz#FYs-&R^zP0TG9CFr^bOM%R;2eU!_gV77*4%SuI7hPv@vs7XH)Wu+q)$ia$1HojrOM=8qon(%E9(kt^6&#l($o(?+>@*zde4 z3Lx~XOxzI^QzsczqU5Y}&nPp#dTZcwXW^$Dy?SDIumD@3Qh)VCb4h-DQSCzYD>@Z= z6y0?>LCg69U7m{{&U#2fC;xpyv|s2#WPagH{`lPd@l=o$y$*Zksokp8T-74#-yChU zGy+BI$1X`5om<9t7n@~tihD$Uld`lze$w!9{vc7LtnrEQd{>HYm2mUBcLH!0nnf`h z%bJRu+57V*U;{e)H%NXRv12?Hsy7{5~(qx(^-cN;_?IudteN>FA!b#eJBY3|VEU>NmHeVTw3!*1Gy&16b#vRT+OKIe;c6#PXDjtNE(CAB(XZQ=5 z)bbxh-eYZiYv(rKJMIa_=c{^2yGwbtCa^8Kk#l05JJN`bMPwp~936bEMxJzndc~Jm z{${KFk;^Ll)yK-_@#uQBr?hsw^5$Wycvd-m-1v3p>w_*XTNE(1_#>B_fvSx`B)v!a zt1s%VJy}w*gx3Jx&fwM<2Gs0!tf!jZU_7c7NtTt`4HnM0^Y0kBqovgve#43m0f zWAmqYn*5n4KPUCdGyW7$lRp#X=OF$MJaT~G|3*bOhp9h0SN5_Em2J?0mRN$oLwOdRoNxUbJX7bgAs zW3oscA$Kf#Cuus|FrZx|N)zQAhHc3{^h4fCE&MBm`0ypYbGdxuCfg8~ov+aII6=?j z{LW7a?+PKhm+O>NpW!PIin0#k+yJXo#NUficxc75teD|%Bm8OOW6lHGi7-HIcM^B`27k~V&BK}_Na!tYt_7wT+Kc$GjHK%Zr zW9GwTV(>u$`rsd4AlV0|?xSljM5cQyqbKgl6-fKpah=nm`$eZav=ssLTkb~O4}OKtZbv}#y-uGQC>%)56qpGrBo<$!*k4s7 zjm(5Ly0Fxv{bG$Lw8i0W`)mlVzsPmQuMoo9`L(xs=ZxscD?IJ*g7V+y#;BkpZ=+li z5W}zPnr}}A{ApVePC`NzJ4t~ibxDH9J-Er!wr@y4d+xOv(GeHP`Sd$C$n^BYOIp*n z6}{hHvCCVbG)U_(MDkU=OgdO@qMt%3?F?uW-)2T~D5nWHXUSwTW;7$3dyz+==6sQ_ zTv05Gvx7FYrp8=BB(OM=V0o$hXh>SBB4)R}=>ihsBPudPNKO9w$eK=oHJ9HI16a1C zu{HduQ@b`wZ{fQUqkb}JJ|1hH*kIXOu46=J)C1V);|?SkllMTg#(cSfaq&$9@@5%3T?*@3ZduSAOz1=De2AT0TYiNhk;+!{x? zfo>!<)tw6%E2(NY8;~6D<+2kiNtxnOIkX6X(oHA|KQI=?!sqOTo2Z@Zj|}%$<;yP8 z*+tV*<3~-=jg_U(Snt>L*_G@8^0~hY1IbZ^h#)qz9J1roAv;bES?+NjhzU%4)&-oe z$Wq0Br&sN(JBve#k^1(`np7mmX#TPYj4WY9X&Fo#}{e(+6Th+-0Vrqa5ZVq0|QS3u5h z?Bp6(hV*{tHp}!Cf*=wcEdllL&B5;pQ=Gl#dT_Jf*p0g9L@oSR?&#PK_2k{y7?8hO zfbFWiZJ7(;clIdwzcMvC;shu`^;z(aTLU~AM~?2lk>IY<^@5)0sA0e;4X+XnF4 ze4um98vytt0KS0GDV&WkHUj)&1^i+K{9*v#7I1a|%Zm7a2^Ci@jiiB}swu8}9J`B) zWub&J!B&|xjYCOjPmSceoU$0OKY zhpyn8V!So>DFKEa-hZOc_y@q&!k0nA#D0ellO#@p#hj{cn6iIGL5fgQD8?W0%=cF{2rm~L?vFGGi^E1)22yQ@_-Jec zjkj4uuODfFV0o}7pK{2%^yn?~^{A??j`I$7RJX2qJElhqjzzV7tgmXAkl$0mPnd`P zv^@|h^;eb3ew+hBo5Q2Ejc?QBTMPazbEy-qFJx~o4AockH|TO6{h8^qulOiauHv0x)`KlYD@*XgEMxR=B15nSNXyI;SYftlyYY zgrKv6X;uJVkt#1`Lmj&(XSy0XU5IcvIo&@KjR~RSL3*>Y} zqny%kJvUI}Zi|I7hs>6cLTj;P!CgTo-7FU%p&#z~1SctJ5O&JU=8_Z9R(JxK2J)h;GtR>TAeeGUzvi;0Wp2S^elUYr)@A$0MMhFZrO zMe2Z1dd;rSz>5*@B3`-Vmd2%h#(HVh60YIbx=yhEPUbjM@R?y z&(sAw-a#RTuR7G7o57NxLh}eZn;ISW9bC`m+x{GT%~`4_c~Qx$+L4<-jBIf7o}X^L z8V97XuqEtdA5ZukiJ*IutgqI1E;~v@l7U6Y{ui^!fk9vyc0KrV^GnHh#K7lsy;|~v z<_msLbkK*34wm`IB>irxt;?yPN3I}x9;RT>GCt=&{l?eC(~%PX=;B16>dV^i`gXq# zhc6~Ws>KJS%Sd2xN3PRl4SSg{@p5ph)WI4EDhvTPGV=0v&vO(-WIO3|G4%0;-+=D> z(r!n5N>m%f^OmX8#w&~rnNZccS|iYR#Fom@5ynm?=}{9)rJQ6R>@e>*qL1)dYx=F4 zk#`v)^F!6F>0eWT$I32K;apd;uc-G8sQ}Ulw~t zO_6OL3FM1D3FSPOhot=$L}npkn>&ybj@J704+lHUGY6x?o@HsvBC~b#&q*CrZLu?FDEL=!5&bmFc_A2Jry;`z-nh%$Z>ofI;}F$+p=J7zp&P9cc2I@rKe; zc-yBa*PAM0!G)(=$PbjDu!=)zFyvmx!JI3?$BOm z@DUw4AARW`Nk5tx7W^&ZC$Mg!t8OR{zAn_Y8u+iyuQA}|>mD77P2nqlba@2^#I=!ouk~e)Evm}YPnYsKiDiW_H%ATaixN`$=`Y4uC;08y zu1s>Mue_^SaB7+!61Q-nha_@?WUP%`$kFzc)9517hWuDd1f`ZpG&%k!Rr3>@kkPl@=3ag$u7#%Udg;8B+$K=ruLc-ov314 zHWsPrJu5wOv0xs>wt9RMKN2Nxv`II~S+0DZ>!p(WTph?(7y7qq8n%OsWy{o{Q)?};eru$`DVGG1+6ItM0n$@`w zQAAgIQtn_wm9?jQc%Zz~?(?-#YPwCuY9Rw%5`L!1VED{QtyVN|lr<+CoVT2DSaUkb zZhwj0{$pxRfK%O+fbt>6p9W>^v;2}n1M^{RsSsm`VUWizsV^GymL6?t6`&fViE!r& z9@33D@JZe_Kl(FE$M@oM@*Jz;x2JP>qvs#3hWf{q>fz!Fe-&D-nqJLHXBZWq>Y3aD zZphL$7fK1g(R2?*p}*MhL{BkhkLI&NE?Yj`jKF&Bg)ga}X#*X0P5=XlSa7+Sn|kDH zXOqc?U{=2N@*)333=+Lhpla@4%{i>TU#291jg;KfybFmIhpCN+koZ?S8A=Xx-N)B|r+o#r$ND0D%o3aTnR+ft5#=*(6;v4fSD9 zHkwy)nV20D-D4`bs->Wkz|8YI_XsM2;LYjQ2un>y~~ z(ZrcWP@%vnQSunFqV&2i$1OEE{STkok%$>Wk6IO;wJLu6x?gzjBW*lkwEkzi4&p_mCKYPrB(6i63WM^5| z?SpEM1+v;d=6~5f$I7f8Ine$|Nqi6^Zf$|RR&iiN`afnmceuAaSv^s+M0fPt4wY|y4EAAtr95(MoQMbK}y||{v8z%h0?!URIOup5DTZD zzNiO!;05w%p8eC6CJNNAIcTkB~>j z_9H_*8pR_pH`sa+fxIQkco_jL(z|O?O=@?UR8V2@$zhTtCw#`t{&a+8Y3eJnvQ;cv zYj?Or0de8#IFE3NS;zFXY!lW*99?OS*xf^R`-2=5GUE2s(i zfyzjxOInwLwa|&)y;+s_ZW25R z-y~?(o$OY~A#sg04hSJhU=1bz-UOyKz5|b+k7$5i*On?ADg10_@R9g2o@er@hwL`K zPUxyjmE0|kQ6~eE2}EXh>&8(Ej~kP$HVoK+h_}m!A_6?yijq=N@h;24vQJB^44Nil z`-Had^mg%t@RYCBtx1%;^cS^Hl&BGo_uj`?#YZS3a}aPw^BQ13WqNyJ(K{a^2#dJv+!W_-uD-W>Ip&?@tPzQ4_7KGXmNg` zgXxb&#RFu3cnVqaLkXQE_m3A%Q$0>A2&uNym?C8mQZdm-R`FBRDaZYJ2VO_%hzKcZ zq9O{i_9wZ2WJ4W99&#J<5V_N_9t*c)5H1pr+eP9rw~TML#KVUKSKZI_y;2DVE@yqv z?`lg&$#viOdjUJLjv>S9P86fEst6 zEQts4!uv@))(ap~B=Ws~PD?y`k359LW4AiX$qvq@gT4}vh9Ls0`@3bY*%FT*zn7MH z{FK(SBpw&~QxcDbB(wYmiN_5GazP4~#N){#OA;W2M3NovBk_2Td8KFhKmP*?5{XBa zq@#OUO48wFc8ABFzxx&AfU6p7jlmKLMAMRvU%yK)eI*@tk$pumenvV8=m3(AyY05$ z)cQ#}B<%*|9PIh9teO4eznR&wyi7|vBp^6!1m|q~m$U zpPr5JD8K&CBpo}?=g>yaKV1#=k1JUW)N}v8l5`Y5Jb(BVls zChM7!j@IM;1xd%Oy=)>|(($_jV15{qj?PCi*Zn{6Cf99N`oMz&N;-a?u7IRteny4A zO9hd191i~=@{UO1K>TVSfBu8HZwQKu&Owbbo0~q4cYZBIT0Z><%G}B4^3^qS48}9R^z2KKP^8042$3?=e2{ z?0(yG;wNL;JPijDl-GU|WlElCfMmfFw7Wl&*{+U+93j4hbRyAdn1e`o^Jh?U6*e=x zNNxkmQ6?G2%EZBnmh*0WM=&{yyd{Se4qBYHDYsI9085w--9aZvW1w;ICi}h3nr8V9{Io>!NIsCXL`NN4n79^4* zc9HcY0XekdJSm5aL~9&xmqP=fHQg=cPP3lSB(J|^zXl+|8)KUN3zA)HlyKeB4CH+9 z!q^uaCHdu&S0CCx+`Kv`wpnN=$-6}?h=|0dE6E=&A`GPe5Ew5k%G7w143OATIh?{i zFKinXYKN!hSJfy`v-Il%r+l8JrS zUwy9DD2`n^+S-YoxxJ1ahhw5~V=u08(=kJvQS_V?1Q{4##@AHEwYx=B8Q#BQ=^4+l zc%*q-aqG#dkdesu9LVLjx7hw|gE4F^KBq}@q^ zV25nz@cV7vs?UNylAeD8spPg5nDoxjyl@evG23&&rP7luC){Ds;OT$ zYv?;n(_%a*wNgsuQsudX=8%5*8+_A)=Qo8-x^_6b_!IDW=z`6G+j zbRO-;kC*N)r6Cy>w&eWsNwZQ@JP=2BIC7OpAj_)4df{lE<8(JK%89>YY&zSqN$JKu zOPue>{|qDfyMdu$_IrFgj~n)fm{skPG3zXAgE6m-X_I5;bXb1zKC&V5n?s_)q~qQD zIkAF0L`wIB){#H^Bafuwwia@Zhb%StSr7peEKwBJ_rvl$?-P2rg?Dll_W{KB&T`upql3Cxy_g4xts48+&q0q zP4kucF<}|f6WPK<3hbR&MQ1(MnI5ywSW{yV{dS|;1MQ!XWBcV^Pv`>%^h(HUyi{Yn z=_QVw@sU!Sw#SbQy~JyKyvoYMXsOoL5$L%w@(jM0W#A!Vu%>m(E`!KH?zQ07v;5b$k7|lv=xaAm zA);tSP4h7C4QGp!Av?mMng~n7T8jT4kE(VeKdGF9$zs>8%(yxbEZ@Y5V zcI2Ev7-eaG_vZL-LhCA;t#^qwg~5{XBy@sQi-=8Iy=MYMf(1ByDB1|xz+ArEHQX_E zK|zSTgo$lC#DiHTRE+C8MKxkYYQ04v@vHeOYLUI>$MNt3>;Dczy&oAi>yF74T!zDQMHmxhm?NtdpYE)Azk`}=k2Pl?+kd`GC~ z#uXEd_L!M5R*>nks8!*x+gfibX{+J5p-X_mJgV?cKAqgXm_-svt7k}cUa)QAjQaVL z&p=0%&}8UR$Y~WqQ?~lb8O_egXN*ty((Qcr+uH%g7tSQe_icEQHb&mx!rN0!ZC%<6`m>B22A7Ae)Mf z0nB8-Jww{hn%g&!#E(_=@jr@igLpsWbvJjt*sC?_G1qgGiYErqCY0m}$mk?$4$;Qg zG^_J%{x2|QL&~{`b0p1WsMmxNIQ20B1>#~z@wiwiSn@{+;NTt*Da2?C?a34Zp@)#Y zje*7W?cyhI5GG4ZvJ3)#gc0sW{SvpCXM~XRnaOsjW&B=O<;}8c(r}G7n3xp-0BgE$)ZArla^#=@iu6t>rXfN`<|(ORLfYs($LnQuS^9s!kSM zn5wfl9db_M`_+6BWw`y=k|`iPR)-Ve{gxjWS3&>lb`LIYVrql3RQlr`&?z`Jhs z6|aJ+m`n*LKxHb&2QwlNDt%JC%%%BwC5&g&iK!v|KV<$%-m@oh+QD?OA56*SLRmgn zkVUd!A?ui4Rlzqf&a$;m`EMRGI8lF{0v_pt)UXFG);8padd~A_hkC{bE>P&@n21K# z;CVFVynt60J9OwoU&I3mO9VO0)f@7IJKA#_Mv=>)}1>Nx77f6}+q7oN!Qd8to!xRt9uZLz9E z)m)epzfB5414|v$>VMaLTL(b^9%?+Q!mvz$jO9MLFbE0|_1fFM|4Li}nx=a$6+HGY zD!4RVf!~Je{8Cu|J4Ua$%5?`gjbqbT^>X@m6jptmM^YPDb)fxTs{L|7zXR|oYd;X5rul_p zmDFe(n0zJF+{<2E1l{56**_?-iCT0=vK`y|QSOo*-bfYRp*>Z@pqJaHoFE!(7H=|w z#@Uf9kVp1eeV>2=yd^kV?Wc>%+;9nz+wz`PU-4AP#K;>1xF>7==gNE_ymDFdAC`nZ zu1@jIB?FVkV23b)h&h#&?&rV-~T}vhp{(ICcAB^U_xTM{sSU{K7@V%=e#@ zq4mj&#Qb8e75-Hug2fQZsY#F%Ndlk~=Nv(vbhw|Ovx)fIC1n!>EJp>Q)G7+KkUF@+ zvqv;!*@ZZ&Uac5XC@@9zVC+7tn^k@`>-Dmnl`GxhB^=W$ian+8RnH~Q?g;n6orsKP zHQaPjQiq3?3XmJFK!|mh74lBbnQXzONIb|bm+!16M`ZFPFG6ChMJ^Br0p!on-hoY) zT=A$L$G0<{qq{U5vOaz$we}aLi9C(Sl1h?VF7#-421A@tSbe=jL&UkYykQ(>a8XkJ z6#K%OU>i?UH0|=ljPCGeP9^{vsk^N(D+D@HBotNYWd*4Jzt2 zud$3Jxf{^m*6R~_m+(g6IjqVeD1%|=dm?ivItMr554F$}%=)Z`ap&uVn<(RSL%Yf< z+=e#b&f?x0#;Y3A>pBi8AwI1$tm`CN!1RAl+Jo>_`@@sm6jL6E- z>PrRPj<$I^ySy+uCr((nm zZNuo|(BbjWO^4455Fhl$p*vG(QhkH?bi=y z{kR-=5>M5;@(G=AvD(TlYAZjVxNp+V_&u`iSqIMYUS#q;Vi&;Q$FEhJ*NQ(m*K2RA z0`Bdc6U2}q*4L~?{D~ZvMu}*H?z#i3hbXWYT!v?KG(f!fm)UtIE0;4*jtI^XM>>n# z$|f~sA6K5^j@%0vSP>MGuOCW=F0lvTre(KErU8=HscSHnC`J${RK$lxR13HQpgD8nDpZcEP?cngRjB%S%zi}k$=?=dyA2Y!C4DKB^rbR*3 z@?#z^;Bn%vfkj`FqGB&P@bQE4xZ;?{U(;TK*!2BXF0bJ5rf(c^yzV_tE&9e$$9wf> z_0_4zd-W-=;-WQBdYE4~a?B5C@K>tV;m7;*uzFQ=yjNAK!I8&%73ZtO;(?94Nb!Vw z;4`IT@rv(LHH|yot6A!+(bg-q1+)z@ zq-l5Wh9<2p`r@!PHI8|8YHb^U?rhIBVR-+JCyLdh&?WUu0c>LPW8+C`hTlQ`K{_)RSwyHRUa$4S73;w~3it{GNx2 zsa$+6^`zbk5vy-R8)S>OTjiyt zo8mlIPrj?F9VP|N;Q4Lo0&mL2`8?U93MlANv`xHVBa+%k_M@t10m8&yZkMZKr^xNL z6vFJK#|m8r867&@;d_ggJB_Hm@l{HAw7*2rM4V-hBGzykJ4>2^FHa<~R#6LOU(9ua)FgSIvO~-(t%rwX+YILI6y92tvAKd*s)zCA>i9g`|K&*r+fOiC z2z|q0OWO9AgR66GD*MSawee&+g)qi0i9lMkyTduB$rr&VMo!Rr8`$-j9>G zrpXz;z$KR4gQ<=9b?#-+>%SOzGYiUMAJj`)^sS%kL>Y~Jp5rvujMi(8+(E&rMTkIY zOays$faX@r)7|0-1Hc1LSe-q|iP&e?&VhKWzv^ir#u+~2X5jRiC-Do=|1K}ZJ3x%C z_#FWNujMPTz2deQPjLhb*vafLZw_`4c^@&Ji-1zI`JZ6uhA-dzoEk8j_8{K#8FE6r z_Gh6MVW%S5H>#=#v(&GFmYIco!3HlljjqcoN%xn%FY`}$m(ZFVY!K$b0wfE5jr=q% z70XW++)=|oE)w3vDm02R$%1tQ3%R9`jTgtr)BCuhqx`9Il&Stj1M9I-j|e=JjAo#D z{wpH;Fj_?obPpldJ$88iR$Y4`2OakiPf0X%Xrg~l;s)4&d_upukB~4kx@IhwbHCAp zJ<&BqTweLLClvi!54}H_pkRaa(4I?Njva{;d3Zz*?LH%M5?9~wSkq&Bc)gp~TlLuP zLD(}8#?R^4lK8Jl9qABSN)u8He;gwC;CT0qYuOdE^Ubkey`9uH%+7T$+ami#+psVX zX=xdOCMt${>?rWM6X&RcUw`>F*ek|!%0`b{*4`>PhnWru+~sVTkt?X!f6;n7vGDx2 zI>UBncnEoTRa7*71B;wtJ>sq={&ZF%M$E_}7_;XT1t4Qw4f7op z`OZAg#@7#C@&0dq{vyq`dk7JIkVAk26ibCz&tM4zzO2y%MS2Kjv<#0-j+IETe1=At zpo}Jk3dER!ff3;9iK6{gU)3cWvRfAmTlg4(t``{jECb@{2 zgWa2&Jma>V^-^Jmdc4&W`#7IqpC=H6J$S)xdv(^Nj>ILt$W>s$_uR41GARF5@!|&? zzXH6WbM^=w5c@pC6H8>dH+_HlkZn&apFYHD#7zP?0yiG)@GNWWJHp=(ONFfo-A>}a zL=H9!*74dnBa(HZZtu{Ojry{!C5sVP$J#QqXFF-5>$JBf z24R^K>dc(fQHeV3;YMkguy8_}f&$EL;3C3era7^hbH7 zUOpg&PgKuP-Px+o;Dh?q2idl`p#SMIE7ha*P~$C$6Q*xS-z<|k7-Wkdq~FtpA5ujw zrN~?9o6DrgU|al6De_hN>3J0SGJP{nisaao{nd0))u>u>DI&49=}xFIPl`Bf@gGVp zlDt8U@-u2k44p3Sqv~FcNGUi39iJ4On|>j>3JT7V`%@X6Fk4a(7ORYcJP~ziVlWr@ zsHs=Eu!6iw?NsYW^gZPkDkLN1K2z9W5Py~&(Xl=GvE33!a8fjMaRw1CV$dHRN4wV{ z=)7EsaxMAQbwXle2er7U%-td+9%t`6$pY z3}UCi+Nd1rO`wcm?A$YF-@q=6xi|e|#@!#j_3&n_yop~XmQ1IB7K8uwQyX?8n1B83 z(MLx@{1u8h*<2zM=4R-YO&QlYP}I^1%(FR@ZJ}uy0S6Ml^7@LbL|7zUdMX0Dw+KTi zXVG{pdX)tRzcO@NT{3VH#ipRK6}gx(h`-~EiY$I6BFm<($@LYv+Oy803oDI^Jnk>5 zuh8P(5p;*34^)GlT(>Eqdg7-ESf(;Pp%TE14jYcwTn&1zN)9Svblyc6sLRoFipVAD zW$(mH5l&-CQ|7%z6RQU?W#=S55P@BBO;XN-s!@oDmqkPGojMcL_#L+8@}0|~@}{Jv zxANuKR8YAs@PrIyy6n~Jzsc#O8_`WdYNxoj^PJ1tDpR z?Ssby*N%1F)>!5&i8{lX&hQmkF5?ZsicVvYvwmR~hJ_>e9bD-&mSkh6Qok@4Ys9?z zilL+{QvUHNs7ud>8y@)Jb{zw{>Fem%+TqQ5*02_P3M$;z;Db}KT;Roti4R4}8M!o{ zDRdgm=T&84cy9(jd7EwDN2PFWktq;K7MXJ6+k&u&Hg9iqk*Y@^X3B9O#$SZ}_datj zn*%^6@jKI1KQpT(Q@Rtson>SKCmX~=6lj3J&1uPGfo;Y;S#i;r_uEnIryl!?>$MGb z%o_aHVa(va%^M-&SF#PSTONDyb;Kq&can=E`?ba0mD>F2nQLvf{n}O2@8O_JoT-ZZ{iq_HYpfzyQdAZAUkdDZ zYvZDo+WFa2dFp&IRy{c}}mi^kbt(aJ5k5nyQ6C?KR zxG0POoCXPvwPJd&6*CT}co->r;(hV&?FTYma zod3GKRl|}J+IOk5g%uS7hbwQ^Xq-6jZ#My|9#7DHV^@Md@;m!lRVjf@_g zHr0O`v31c6V3t8tT3vgj(P!U*-ZQYL+3rYeMqe;wMRv3Oti)f%6b0QcXCf3lU&Q?dW+Gjj80$xtA84@$uE9|Ld6CxX8*}+PiL8;H$d#Fl?rZIV z7*BXFdk7O*HqT||(?8ptEUy=p0(ymsg7VxQA4BE!%(p3-=82s(-O{s7sP`S`= zA49mYO%=5a`DAa5?a3tSInoaMYs;Die>v^#PGh72^8o3=ve@D`(Kagbb?2U7d(M(P z03zGXoB!IYCAZEmTyi=ZGP2sA9*xRpwa;jRV1Ge&IP+i+O!JZHr=-hc-!Hc-#^}MR zg#m14H(YKHwH1bXZVG7bmPVRN>dy{xlb zez5cDG0TT*8xGsMtMUj+B87%qJ2s{{A*lTq#WCaS4g3th~I%ETN(jXb8-s4@Z=4?CF~S3n;r)Q21rHY@dED?t=*T#@C3}0|Bo)6~ z7#i7VM8RO1h(Ar?5U^_V=Qd}al}M-$ z6M{VO_%WtwC(X>FoGso!xfE9Han6=>e>9Fsnw=*?|xc+FOK$=Lh-=BDSRi)3095uM;$OY3d@cCUsFzn7TOa z0dOf?;v{k|fIKkk`gGE#Ga9lo%jO5hqL|eWylB_|irBYO+KJ5KY{{JldcYr{YJ2>1 zKoLbJn(KMIb{hx1M4Q|Y)h*pM8D*+2nAI?Pm=0X(0+?g3 z4)r*-T9ZWx_4u^91-yFhbnfE2)uTmP?HgP?Ck$4o=PIqXP2Nqgsx0F=F_^jq*%++{ z_h>=nqc-Cur~OmyJ_+r?YH-&2SGtV%v_%K@Yv=Bhp?#@NnLj@w2c~s=@nGA2?V7D} zbbYML*B9|MXHJ)t?^5Nf29|H3d`umdPGeuD5T!3!z@&xjfN%T&ox^X)X}l9=LabNu zkC5nDGm$M`^|ph%wcx8#(B7imC+r}-)oOpPKK;aLyn9Ti4?TRGPIF?zhf>3Re3+y_3-q>&r(-sBpym#6(;T%gix9ioBrT-_nF9qKEgoKvq`GwU(i?5<}GbkDP?jx{6kf^ zluffyx!nISt~zyFphUNzsYJj9YtV{m7-BMCr`M3^-%6L@#rKtTe8i^r8C%T>)QNec z-Onc&zrr7he*y%T*fT2ovG4-oz-KR#CeES>iC^EB`u283W~y-cuX{qPk)@u+4{ise zec?&Tg59?Z+QK@JXfzOZ$%6IR7T|tM0GkmKk9@zm?!j#mnOp=TF*jKYpo4gRExlNY z=u4v~g^DUm8wau!ocFRr2Th8~5i8aMB>J=n9B+8u2-0R{RgX>F-D}Sow#}U89QHL? z;uve?#v{qfH=>pLnNj}>U+CK3TOrJbVEHi$N29MjrA^gL&T9kg#r5#CX%`2YNm7Md zTXPm=sy<2lq0hdtUzJ*|nB}gw`w$w{F5yzO0F5+yh->P|z+3bU!M}?aJX<`(?wWd) zJ+N64eQC85)XCdJR)vS5T^0|?(5GIN!L^f=)Q`o*Fn7IO2CVEcE$BkVevy)~V*^O| z9Pp1=c6Y-1Ss5~j2^T3CD<#B;@7I5@NT%NPgZ2}nPUAIrnlkv;=YByWl@ERKkhWnE z_k-)UL_GFD7qZ%dryzy9wDm&+C$J(y+UNovku_}A({5r-z2OVrT}G>t-?c2mpR+#W z{y~UMJBV_Vp(~~Z?u=M6y2Ty50qFZP_2k=DORuVy)Aom|{m4A&(qHSg7+V9MCH}Af z4pjEF#nSh}gF;eWqSgJF5gY9Xw|~EgWQAM@yR@f<1q!;7I!hK4Z$!L5Fid^wRykN| zdMFb0pQ3)t19Po!%H-t;V0lX!>3k_ER@38U%vRUogog;~5* ziUT!2d0pd0jgvi$Sg)IksM5Ua_bh@~)TUPu&lLl%b^-h2L?Q4eic=z*m+U+gnQ~qD z6b5bNqS$J__eZsW1N`fW?ItsEUE0zZ;DxLR+p(Um75NgXo>mqo%Hnv#(@Vipi4g+b z{q!TDHoF@7HM$W)*N|y6hW2E+B08#w?u@G47>3&e0eICDdC``o7E?`3dm_VVG#0d4 zL87hv3D)|uu&D*!<~4Tf;jE&>6I4UOEYO|d>rRD(a@MpVlt%xMm6?h%6P-$Z@gKM3d4ZLLe#1T^HT&QIzm@9 zm^n9QJ>au<%lML=jD(ocTT%mYYEL-=Z#ao+Weo$e6dSnoFy2fJgEWipIKwAca$F@B z&casd0k6GV*^b;zTvRk;tt>)&Y7=hn+k~C$K8ChnxjE){EZ{@`B3{L<*C~7X-Z{XM z$cHib0S0%hCh9mg+1Pep4MM0~QovDS56lr8DrKM>x*iWKDD??l?quErHx}5!c~9|o zsW+UZ4lqwR7YT&HT-uszmh)GHdJ|=P=Q)floB7yp#X8t@{b*bA6|3)nZy~-Z6V0#w zEYPeJGS^vPC=r5%DhX%%q>a8qlC;Y$_g}{wH9_GQ)X|BkuEZVrp>>RAzkfpk7=+fl zlVX>)%HHMHo|^tDPXnZ~E8R4auVGOk9>m|$KMz|~YqraCQokc8!Ah*kZ!Rx}xXhch zg@p;{^>7R^c-z{gGrdYv3~=5LX-StilajJY7fX$s`~Co`wFN+zOj zTi=49m8+=LyyQ1BSt*yAX4ltj!0gMgPWsl*aX(=jm_HfCz%Y}(Z1lFIqV--a(M~uj zUrgweD`leRBGDxU*mmt#-Upfx`t>=L36nvXweRc376MxsO_R2$9otv-ZQW=^0zVj- zhs$2@Wz}qo2xUnUHtkpL2M+7x?K0ZbBSm<+jh*s*r*0&jVmjm7j!FR+IrwnRGkwRgT6?2O~#Inh#3fV}pi5*Ed#tz|r`d?HZ`I4t_#1iA4DrJ-QccjhPRK3^V4$ur+{(dXF5Bk8x@ z=Xg`+Or&j_t&skmDi2~N3Jp^2IbL)jN{N{#a#zS5D$R2|GHdcL=sh!rkNHV@&E6=t z9>;4Q2R0+!F;fe5=A^Il$Jz?zWwXz**C$iiJr>=NEs}MggbJ*AMds|FTAd)OfzE?X zRBZE~%{q*fN>kv)RIBOFmTu_;DAXNM`r`~Q0De$x6%w@YA{udT)C2xomfq=K=AP6g zkW#bnM&0LRvHYjvSMGk!z53?6?wqysPWPmJ?h6CU?p*42v<6C49b|+>OSYwEHxprF zq{V!tbH|#v>|1<}R~VtuO>_kMm8;c#!YIs}o|f$b^uHq|QTQBee{zsk_ljM(s2$8| zCxv~+`<~Ft_RyLyb5~rrQM>^ZOsB`@3B8i}q@9qu2l)SeBNp175!;=?6p}RA(du!$ zn8@@QYM%TJsT52FPs#ib8t|V|#|U9X+HF>UJ4lpy5Zq z`F@c{U~Ipvb5K6hybkiYx=glbs>IoVdFUf%@*@;zow6=O_C3Sn=qBAzw;tMyoxt9F zkK=7t(dTGpGR6`Eq|obV*XsT$W8(jyT3(=ze#G_+RzPKsWDypC+iZ24<=_q&$r=kN z+GLaTNLU2ARcK4S%HdUh`jx6A$SYbVp1514kF>zAd$bv(xm~ke2AmPwGs-v=+Fc&o zeTrji>?4^Es$h7X)*fUz7&4|)oicicHPj1B0r(5VpN`^~e}nkncjmhu$EzO4Hy+1Z zKF3Qw$6Fr$8lMTA={1L>kQGORqqNg#r=PY=AnzpUez`PpirdjBXJ#)DjdVMIYL)_njUqQl!-5f&^=A!sPY|kMuB|Cod zrbV_5Rx1z3WJ&ddQJGDoWI1h~7x;{Sg|Y=}JG`2!OTC6mI-fmO#H)1M`hnQ!*}LEHV+xz zdMgB5IG{4KpSilgMy6%*P;%-iVRtWG)t|oZvuD@t6H%iN1%z<0KTrZRvLce26B1(w zT3GtxD4)dCk)1@5l&YTFpFX{V?3fc8k#UsW%0qY$p1 zkNeE3q0p!1N;+L?`rk<`G)PK*hPL4(jCRU{-|Sj3PTO#q9Wx!QbR1iG(p7b~wgDd# zyhK8sgJYd1Vz(3e@Dj(Xj+YXD!}9}7=V&)xO8lM@8L`e>N6dIN@tCyCEDF188Cv$O z$U;0DhC#{Y=o@Wkv(lv<{)xWGrMPi8kiBXfnrfq~&JK0wtsJClPeiNy(`~k4I2*ET z*41lQFKOc37-mZx&=tZtgRgPSa4^6sduZ<^WxG~X@CZXKc{C#i41}Ldx`F7#99DwOw?HQ|3FzYIljQSG=3Yf$Zf9Eu|4G{ksi?i z`D}j+8U#@cP zRkEYJlKvd#vCI5>a5qWOad1H`o_LAr@)@SLG~v&QKZfj4rVlFeXipo3cZspHnF9$$ z$}U^{Jciwu5-dd@?z1AhdyE!yGp;p)W9Uc9btc<8S;${T!Z8YmCixK$J*qfa3nB*a zvo)Vg5ip4SUr~@I$&ay~A3B&M4I}ADg*}S|%Dq-f3ZF5^XD~<Aq5%|~YmPy^=e-z4(B)_|o1q-b!L_YoZOn8=+Vzo1zBE^a-bm5GSk*tE2OJ}{>-FkCVaPa)n`adX{Y z=r(aelIZ7EB_l3{)g;z)q{f z>gXEXm|==-M+qiv-Gj9I4`EF24o9pS^qdxFe&*7t6DG7|am2^+Tdr+D9palKwtmkp@HyJTYsgjanv28#br4{; zaDW#>QRP6Jxg9M^opUuE@*0t!%1D_E^0Yi8m!yHJ{6f5GkkURUo0xw=nG`qni*=Xr zgc!f_QF?x~+8qLv1-2{YYvul|62K7GWFZjp4_Hef|9po@>8uVJ4Ts>IIs!eK-xC&jh9{?>ZS8AYw z`wE$&!W5{J!d&b<25(Qs_fkr2TyjrXvo0yVN?Ii)`2*8|GfyUoza%;0v-glVBGX@# zF992AyIRJWRm310X3ediIakY{RnEA|!?Vip-elO9jYt_RhvyUvgmU%pw$j6d%GvoXQVJ^+I%f-MCzChDm*!(CAB?<mjLxGeP{GtegNUNh%ha7`h7ctk)b zP?p{Yk?gOLwf61=UCA#bm%Q<&If`D%_AvE3JCd6PVgXbT;W4dAp}q}Ny*IsqwA$xc zxNqGh_}G(yX{LVkZgH#NYSJb~M{JnMa%tQ%#ki-;S$|J?Jf!OONTj?9^t1Jznloa>26q~G4DQ& z)f5%adz?bSDHF81x400md@&J=TJr@w&&v^*=68hG&{?o~#5|fn< zNgu`9MB>sU3r?A*HccNMe{YUF_#i%p~jT zp6Jp-*K_mlPEvJ-LPMBmHUB5a=pB3d;Qenzk@!}42MZMb=UAY6ict*~s4kB`PY@Dt zQv44b#%}AtfTlKoRG?t6_RlQFQP2%N(F8I2{|h}a>ZSi=B5vBfEgAnKQD1z<=MYYE zsKp~`jv+?JnkONm;>15wwmsz7)KVz9h3ajp`$L+fc1x{`Zjj zag}d6kDi*h%4yfY)iE6d9i&I1GMBt!p065!!ltkB2+(`%H+?fEqyOfU^ynMuPP%j? z?{8xvgB}W#kmjVmha2VLJv`J-NI&dd2{lR72n4#Vgo@_>Qa2b)2qSBPzu~k$=EIEx zm*e){4r$=p|6oq1sSm8>i0|l!pVM7Sb;nZ7Td+buCH9By=nih^HwVXjE}YVU&tr++ z@u>qTg%BR4l0JKh6@_R>xo1$ule?jHP zD!37e93>AC-DW>|h|CiB6(38K(l2|%f9vLfv*9;g{177^>8|TKuQ7;7inn-?jfheF z^J-NtMka&Y;o`OPLfw~WwfiWKn8Ck52?@12;f(drT9JkPk#&V0V~ryffiy7t!@}KIqR3MCGXXhUgM7Cn8b(gxWyY@O23xU zzdM+OedgJ8O4`rnn*bT7coV+EmTXGw2pzU-5BxXP>ft42Rv)Ng>2j?$i<+%|Y}f9W z0R+oNA(Z))t7g|ahM%`yY2pV`$M2X84}dSa+2-n0l0Ip*PfJ}#2_4GiL`e%B>Yz?i zCsdG25jx0w7@zJwmhUrR`CRK@%Urjls8fsQ^D)>vmYa{mea6KzsJCUA6|GhThj=|( z9VnztX!W%)%<#NTyz-WQq}@N>>cH8IuvupMEbg_slVt6~B3h6QE=(>qo~H}tZ_)JI z&5qkS3WXeW+uuv^xm_Mb7LJo*d(GZF7 z@esiyrCj<<1fG{Oa#wgZr{Qc)!-brNOE?Wz$Z5D%PQw-Fs(I->3OV%TB=mpFNf`D4 zFO4pIZ{B%%n+h2tus=Yiq(}s(Z<(JLqGV(J8E0$2OKF z>{?FLK#}rz8eCr=E#>imK(*TSYMKOl&T;kOAcS^DPcSx8*-j*(zAWTHU;B)hkL)@9 zWI??X5JL}7qHhonF}m7V874k zG__k{1MExlUE#_ynFy~D2NLDYU2G^9N$yI|BI6F*cr-LH{1$?R05e2HxHas<)j4L% zUU3_cd6|IadzkjzIcX>tHB+&gPO@k@jgNht`loE#My9#G62bxltn7nyiLag$0byWy z|9$YSdjRxx)E;mmwVzwbPWac0`AD45KZMhJ_3U|+OnCmN$w&zw-#3PH&mUoRsVIoQW zu`V4(+ROwd3l^8d9PVVSCh7_no{zhf@`06nIy2d>TxSGDi$J~ZXKJu$YTC>{vfs)w z0%uwKMleh2{L*vG2j9m-RVhnqe*;u_jZRsmt-5qY8X@$KW5D1Mo9!{* z+9i!-3L1{@W~qAZt-qDt26qJ4tg{VF!MW+;{%~Cj{2fae|Ht%pxs~7Coh-O7jCTlCS`*Og&?72ZO<}ROsir47&m15DpSQ=_}X4}q^Sc=flK4>>kstVg;HnBpU z@X5X~ZnNP27e#=M>5W_RkXPj(cpyekVPHN{Me`dL&8=UUQh!vGhZo^~4GXb?LbDOU z&4M1P7|~LpBn-xqqVTL@qavjYsTgN0EK`c({&u>}6*-Qy6^j+s8w`d!d3#xErG+UL zZF9empgjz1JBYcs9VDXFb_h<35jae{n&s69KZX8+1+ zSTt>eo}q`js@K~qbw|7ZW%Z`g4;`_=lM&jtywb5XuqE+VE57Uel+DaU(n&x?f9WfE zamDREqglAn*NOIu)|TuOVDJk7`d@L@%#M^@04{n8O?;2}`l>pR{~6xW<`sjfFLU$Si@h8+K+D8b6woF5 zwFJ=a@|Hxc6486-p$X3jydsWuMZ2;#myKK*oe{h@(>^t@G0{u|dq;^BDSM1i6%*;4 zX|9&MHrZQF5!h14g+v|(C`Flawe|9!179Xm=0oCtf&nxdu*E_pak5+?d&yh?IEX#b zJLY9_)ht)KT*YdV>Og%snleMcHmuQ~J1JVkDX*L#O zk*S!Jg^t{d?k}e`@kS^)s`?dfVVI9h4K#*g?}iRdt=@zHJRgHS?DE`in2A4$Ma5D0 zY?a`%<$d^!sS_6gcgZ%b_D#Vxm=aBjKBr8JHd2u-Cuj>QMeYGyYF!N{VmO2Q`OZ~k zSQJ^urXD&>dbVFs)`fAT_QY;2B+@wiUhJ=7+UqGLgvcW?pB*v(j=(?SO;$k+X~ia| zgdACy;I6o9g_FCh?0W1&Okmz8#8CoIX(+{7DXwi;h7W2ClcNu?ef;1=D^AjflzP|Y z_>i8sj70oS4t|^^c|XYI_(VN?KYkStecBV9RdeX(V!sE>sMj10QmJ;|V&3UW!OtUQ zrE{N09tlC$Kb2Jc0;xF^!(QlvT$khhxLxiA)+IN>HC+<4Pplz`r%T*jQav;`734@^2``HK**L>RI-AS~?^edJBW~~eh z1A~gf)R1ahwAx8bbh6<0-%Vjg>zEiYIF5-MF0|SDh6X>J_<3L|J;TvG{vc>O^)7K= zN(8&K6EoWF&iXa5gxO=k1=7=n*FZgv!9;MEwTjuJhxZ}_i(T4h&I`yXqugb_o&G4s z9b)+bQhFn-46W(3NRaKxf=+tchvNS*`FJSaiq{{`@TlH0Z9$JchNYt?)_sZZ%+|mJ zcj#`o5f&X^eCBp7Ty7P|M{U2lfq=p#%#52B#IG=L5}~vtz?5BbjS+K-#dYrpUd`UWj~ zWt|^sQr?I^ZgkeZ;U5gq!wY>*BsbGT94KQRlnQB4P<~=U=ryjAR71s>BQon)8^)Ar zTD$pkzaZnhkC^{W=QI99E_Z_qxEsfv&uBGEDbd?skZ&=ui|v8)+!0-jh6px>xrXKK zLO8LN_qsTXreRaKVlt3x+q`Zi5_j%Cp|C ztBa%TAB%&lb(??WB(ef@aaO7s8sM)g=j-<|sQ&&4Z+Ka;ukbK<%3 zCXzS)WC;3p<|IzRVR%Ad zn5^O$S;bSWRXmv$TLo05#2YcQ`uhixfsY5SD=Q@JDbO(5d?k$mE3-juN8mzfR^TO9 z;ANt;7QL6K3OyNtQ56kjQ9(zqqol{&bmYn$=ntEHs$Xm>i{s=y5D4$c?Q31&W&d&+ zYKpQdmQ_{;rB+<_s?qA0z)3L&<5EqW740@iRmAaPp`7rP*h(KcdnF@chsubkDzDa5Mnt}G)q8FB#7lZQF`x<% zlv@J}Nv_M`dhq2=SN&*8&9~X5Xhz~^dhmTJd^s5V_{3mam$d7uUo3Cu+cKm`rV0Ue z4Bh>*oTdBaSoq;qNTiQBBi!Mc`SFW@35hWW@`9wpM-&``3DToOiHYU>QHR<|N9~_g zR+sfLkXu~Lu4ux6N-p&M^-O-xelSv{9*NR?c3In;QmGWJpql4!Oqe-{^x`9fQ( zXH{ySZ>iMoYOmC;+qz#{-uBcN+VU+=Rcbf$^ljoTiPUafC4magCsM>qt&q&xTF{t; zZ^LyLNmb>+9okO_ES>9P2uYrkPDw%>=t_*`DQUx4G!-Yqqj`wL(4ilEN7sJRNUWJh z)F;&2o}ubXLY8@~a3RQURt?vmm+j#zdD&C?hDVzt|8G&<$OOi=io!`;%vsf-xHiOsC$+wN(3Np(T< z#SxE_9(Y+6I6%R^uk@3^bcy6|DJPYQ&VD`lCgQ)kU(zX`#76!l?UL0wM~g_>Rd4tv zs+HT&ecWCe$+`(&?m}s83N-#d8j17Fbvf5Hnbr~S7DdNgNqB)&5Iw!zUME0$3pLwl z6yTJ=_HOg_A9f_m|7MrwB?g-(^z~q^_P1R1?_YA^2r2L*DUf_IK83;ce@*v|m++$Y z)5*c>?o_evB&=ZV+afm65AFnTypiEhs%<)^Cr@=n)@~*RF=>cf zhUk$y+jY1rU7PuN=o@Wier#`+<1>-ymL3jZbhZmzTYWmt{8K}RvA(*3DdeTcI4n50 zR%g`{ncUI(VC{i(n3qb!?<~YDOnP{qLK%mo z=o8jZmjEiY|0_FEya|9C*$Cc<8}j`SK>sfN0LwXx&gZY!dAh=Fpee)YJe|-po+Kzj zf}sFj!jgp!(YxRCjeIh$g1=rtgj`GJNiRn@WnxFP+ETvh{Xjyp$Oq^4`{3OEAAF;2$Env*US_4}Zx{|7z( z)xCv9ej|m)^ea5ZDl7r1LeWEhug8wHZ4a|kpDJ7^h38wdQz(V!7h;o_162{pK0hN3 z;nr?3|K~RG81Bx|>MoLPtpNKjIb^iEwpMDlv~#L-$f?r7sd60wjF!jbE-GhC;}_aG z9VR@U$(NzS=WBIeehqC@x{L4+0!`)GPnyef-V=!UNmF^w7h2t$yq|QS?!ekpLPxT+ z&`aD3xbx*EE&(mIDgG>v8%B?^;#O%7{15j8t+HNwjh#fv67GUNhkn3PXwNQo7RKJs zvG2lI$ysO|485KaN@fN!fm3VB&>NJ%BS`Q{qP+V`t(A(&@TYOw7r=??+M}CGQw0zeU&~+%#-wi>r%eWe>T?WXKUG{ZrE2H*^(_ z9y2yURzGa(Re-!p3EgN~b zc7~Knk!46Pk?iIp#e^*vChDY&~AhmTs&*yteVm?^LaqiMx{*gjLI~z2R zx~o2ym5TB-@R{2nZ8T=Q!n#V}lfLP&rUDQ{ST8L$HZvO{@YsjjPJZH#7LbN|vID0c zEszZqRDzN!H$87}5(eS~CCv5v;9NdO*c-U$STU_CFM`^(;|Xe;D>oI`63-C(Ch)u^ z4-PzIwJ_I~c&y)U>5bo0^NB!ZpJkDiT2AR*FMh zA*aBMq?4!Ro=tXE(Gj$v1Kq~M14J-7Wx!x@~iJ4Jd(+`oeed>5Z*U>G6cWbW|x!za-a5`H0G ziQ{>Ohh=kS=%c~0kCbo_38K@n(?Rrtor#CBZHaw^*WN+hIGnhjf*G-o@Y*{ZUkQjZ znC$+!Dec%n1nIF_T*6)u<|X2LlGqT)E&#ji7r!0?r0Q@|=&A_}pb|R>DnVDBzp;?H zK>P=enSrnaM~LiC>_TMD$T4T$d?*Rox5C<9Dk<)ElHw*F#I8b}${{L&u0gaW44eqk z37|&cJrvT^hkb{#p(HrOoE!--JFH!2_e;8GXpxb0aSTMXmiri*CNJad`SqC~R0*jhpf7ZNTyO}awyV3)eZ^xmLk<*)vW zBIY>WztS(BOiKTk3KE5!Tv_%Z7Ta!##mIELWlaCg|C2MV&7Y1dGyq!D@lEL&B6Xth zrQ%FY@<{SQB3%@F!VcNe%-5a~R`Tt0$lr!Tl@&v3FdMg!wMB_e)G67Uq%)X8$pqen z*XAh2j$Cd}Y_S?98WQt06#EIUg!YQ$T_L6vR;nPC_ULkyd6!a?B&6b#G=6cDghb>N zf!sdb){-W=tio)H6E)5#Z<``EC&Fd`G>b*B%};FfF459US_Sc#a!MxawD8Fx!l%)J zQTT{v1#&C}kN@$sP=mJ!HL{c2vod`8>lo0^~r*Kj?wpW(Efl%l`drqsi zp`ExB0$UsC1_mJWfRv-=TjU?O0hfbOBQ+=VCFN?iXD03r&(NFgcI1kQyAUVpB2H|! zXC!Vw+=yuAQbaRw?uZaY4tKVQW*ADNlA|Gq%SxPde6h^#6e=&|L@@t(ZJ$`CS<+kR zIYi4>__s;AI^evo`Q)dvb$b0pUHMSV#3^Z3pb}hNY!3`S&?Itlc5G$o%5wulRk9}a zOz7xJBQVq%zPU_P38ulDNwvC;TVZ6aIdm`C5U3N!)m#Z#~9KKKn<=)e-a|+BVN|?M{Yg zF==y993w)s%pyh zSlM~uiU+A=b7$gU3rS~rp`PR1o%GsQ0wZg>#K7e#@f;DNfGJKE+;f^N&$Y#s#>#WS z(X!A3v>Z;R&MBRVWSd{6@fWC5DT;f{qPU#K`%LeY4koz_f4=adDJAX3qOuS(npt9X zH}H#+Sw)GTvdwcrjpjO+LUyg``glH{i2`%xsUKI=GC}|7MzjZOWty=WgBr>HbH6Xf zSYI6G;IK+RC#6Z>3WAjtNz)C71O_56fUBAJ^t{C-)pJU5vEO{vsYJ?Sk4PV~N79I; zz&r=-g`{kC%7kI6KVVa^fzw!5NV;jRZht|tU_R5SCKqc4JbF$WeLRxu*!}gStXkjx zQu&xXDpnSdgxB|ndsDF|V zMf16IICJy5vCXbCq{H_mQ_!S3453T@Sn2Iq(%YTjYgEs$O_^1M_`ZgaKqc%~_d*8mIvALTpQ{gPQb1NE7TV@{vJSOsv$7WWQbl z%xiB~aBR9dz1XQm@*cw&mMp$P0mr)3)?V*1aukHHt=Zb*vFYyh*tEt_PZNz4K}AxW_8E6PG^N1)sA5n-LX(PE&ku8P2p0@Uk9 z^#L_HG51IT>f_}3nzTiLku7vKJ4w`ki*y$Ba=MXP^Vv+T1*DO@8<;zG{Hf~4wcgsp zUxD#e9zHhxdfD`;56AcWu*CW>gCFaosC@JZJE-4B?56C(ejk0=ty+7PAM2yAeDo|I z(ZaE&Wcy^IuG}O@1Am@pK^Ceby|_i~oiv7l5#4W|rwX4;+GCF93PCja@mt}$zwJBo zz;n_CI-cXV;iuplFhtmuZ`p&1ql6eK z|6xRGQI(yeAIIs3(%e^X#F~Grk5yD>!!>76y)BIb=cOwK1=7waY7V|{ufIm(#~fpK zlO~IV9#Z&d9nC8CV-aJcnp9hV5T;}&X12b)0clqD{Mox4%Wc+oV<>$##i z5~ZST^V+P$41YO$xzH^?TG&1B#L;qAixa z9E>0g6zT5m0nX)Fqr)gIS2F&aq1AW#bx-L(S4>4qeEQ~f7qSgTs@4?S0i^DMj29#2 zoeK^mgX=7PEobxJ6-0{-!_|S8g)|WDBS*!mTdZS3tH+4*khwJ1BL0_<*1B#dj3_}) zM7+VIg2B7Z=ci#lSNczsr_Mr?*rJ2TtFd|Qba()TZoFcaAck^a9}zzHGfb06h@S)K z<_*&iq)+A^^8#*o5k8Zo%0|deIK@NP~tf+fU~M9UpN8fFSYBtQw6d6BT96J~^u@2-;`lI_Q_;E`hQ2&pU|&U<{;@&3SJWrvG!{| zX5!=&kD50Q05YZD!`@8H5>|!3KMqd^p)%az)%oN}3XEQ#gSD_CyMH1(_!mSVUjgxb!RB?_s1trJ+cU6EWs|tiJc~NvNC8Hz_CC;eu=MJ{ zn&7>|lGg-Q5Qc!TGIfs%F=e$hmX;*^{X|Y_#SV0q5e4{vDPZpSvsh{lbt@%}RMdb_ zu5_zbtHIlNi6BxcrWzm*Qa4C+2d^>1;WmcU&j5V)nPo@~)(?rl&&gmu&es^;RR9U= zvz5#GD?Fx$a5&Xs^5EFK_C^*zzE~s%j8n5L_(pIWzk)wnU7lRJ`4gDR#3;)s^EsR< zkK4gJrS<_Gye|GdzGcq-5l^iHwFsm7)w~pDN%POe3U|Cb=>U>g&NyF57t*E+EDHs1 z=|O+lq>f-&{#3D0Ak2Kbe_W#LDI{}^=54z=#JX^_Cz5-zyYx`?Al9FZ9UlAJxW4mc z^-~EZy-O0Q^vdv5YKTN!P}%@|c6@#kLq{chNJ)nFo873yRjef|dA1dwPh6s;%>EhF98kYB!bEq@R`@==k14(+obQ}4R8MNw^- zYkRW`{X8a?Ym}{*^d>kBx4rFLa8^d4#oC2TLm#KzACT(9uGVH}env$lA%(_%hrp?s zkoqLAAeHTq;63)J_5)Q6DSz^{xF|sx+KNkLXjt=~$m%Di_}G`1^Mo!xI7*&e20^5W zyA9Y{g?14$IL7aP+vqQA zc#vIz^~r(@uwG0J5%-dB@{V^H{cHJtTFMu-qfN(eF=4G4GBK`<80yr)sG#=Eqv9uLZ65lGlm^Ru%#~ypj&O%Y5a}VzaVc zjQbM?dEYZ|f^*R8$R$NbArZ zZr5w}rw;AKb`I??G5l7PHXAvHDlOgXje(KT6#p?KJ) z453732pe>lfSm|@<@~+XYP}>Tx!a7^#P0+x_WpybBk3p-qX+MRkH0au!EN7~gjOtY z0Mu4;oCHyl3%uMW#&WS&Jx8OX5<(Z`sawgsoyg2 z;@m#RKG8RxDYvAEDHx>QLc7}%q!266)a|Kq`*&`g>h=P;Rrb$UC_;%T7>$t>D#`rX zj#Zo)tyq?Ok(D7NGup3CMMOLZnzQ@A@!#U**ynQ8BOlxAZFLGr@u&1*cy>b+#;7I9RXwMm`D22LXE1?YIbL0RO z1NS^B(W0Xsq`3yVO4gp9&FiM~@i*uVFsW3-Q{53$>X6tOkVQ7OCs%?VN_0c2l#qxn zM;mb)<6jB(v|3gNyIS*p_8D%a47pc$lS5|hLmf#1ZwAQxCuS&|rEV)$rI_Pm{D*!` z?0e{F)r^KA!9({1t``;38m;aR6vym{#w_w#4x$pu%AZ0H2T1Ku8g(}H&ozA11@@a~+cfnjuvs1QlzvKGIAs{t*0QFyV_I8P&Y z6JH*?t)1G2QRuVCx^=`;g4(YK<8eBsg+!trJUl*7%-+qa&Yo>7ezTB_I6nIq1e+>t zEY}{v@^KqiTCK>`63<5NX@^P}QuVH}t33D-|F>-Beo*!D#LLFJp$|n5b_upAmxvl{ zDmN=pgMEY=Y%j}qBzXAq6&GUBi5jdWGxXu$*oUaW2;3=ZurDyBe?g3g;@2=9)R~yr zJ00I(F)z8H_#h+pA?mQtoW>XN3wh$Tzk}6h%OJk68B4O1T^Et*2E|9PWRlC`;YR(y zR=swsR=1KTGQPkK%HC7VAp&<;s~_sg)9U^o_TB_euByr(f9x@A4Kj!*@CYH@f$mOc zrPC7V&PD=R+H?YF0#()Bue-}sR~5A+-H8k(B4z-g2RFuLjEWl3!Jv$wqPEM(qN5Q< z%&7k{ZVU{L#sx)3?f>^|?^WHdN@r>P{XhTty-!!)ch9}|-2L2h&pr1%(gY_j#=##> zKlKfyd_&$=cwchr8~%>GuOEd<(idL(=K zoX(S|NnZcLarj;m2HEXPZvoej4_}hZAIa!69M(_aIqrDmwGz|=7IP`eoNOO!xxow3M!T!$niB;HJEaBU1+-H-yw-a}oI| zKTKg8x9IilDD-=+yWdcZa?aF89q1)@FBVUz_~bA!JWn1Hw-{_ z8h_^77YHVN)qyZ^in))!t`&u*5AWRm1;9}`d8YnNC%^paRB`{T?n!mxf4RCpJ45_? z)O|$V52|~cx>fW#Jm(~5g zx`yYwM@xPWs{4ex7XGsrOSt)GsQ+Abo7Fv2-OJRSr|v20TKXTU|9*9!Q1=dXbLz&` zU9Rprbq&vmQ_gm+*BYmOzn!A(`66-8R<}{z%hX-3Zd%

          h4tcL3N){cdxq7sC(>G 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%0AMf0KaOoFo!S_ER@ooQT{{32R+aK=! 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%0Ds5{-Hj1 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 BltT#?SF)+}DPWtSrX; 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

        fg$RuJo?SZe> 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 KIpb@JVgA3^pJ9Li literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/typing.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/typing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f21c56e26502cf39dfad93d7e62d7f0dfbad1022 GIT binary patch literal 22629 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 literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/validators.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..938517d29693922ccc00242ef6314d580bde08ed GIT binary patch literal 30894 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 a^?qpg4qb&*w?XnPN!y$5+gTze(fz;F5-YF( literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/version.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic/v1/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11d1fbe925717018044b6304f772fa311ddee1ad GIT binary patch literal 1957 zcmZt`OKclObY}l{ogZ-`=hN1uEs@p6NvKejG^B#Gh|&`JMIpGdHr`3P?%KPW-8!{v zqX<=^ph%PpX+=>vrV1bs2qaDw9J$0wtE3YuRpJ6SLwYFX!W-M0M8K0~-kbMk-n{?M z4GlpAaPG^~W|M@_ul(QxoU5>21T>G%Ap=by15e-pG6X}kgb5*lh>%w5_qL!3(NKss zB^c^eX(EspcOxS0K~%=bkS4^p&|LEjx(s**gG2^NuqGi2Q4M(*G{K!`{W~!&CNeE$ zXB^Wa22CR1_PZe>x+ov~i5vA)EZt}qD`k^Qp>Mfiv#D9NeLz8dy z8MGUDjs6SBJVX|9y||I<;24!b9K)=^%s4jnk{R2$WD#IUCw1>aOk$cra-MBlE>jHK zBiUS`iDY!s>donvY3QC!3oTyWF|*UXO~5ToR1`O+*pOu>dbTUa(at3VtZlJWl@t-k2MuS1-Yj z@jS+8?x2M7(ih?kj>(0sP0~Y5#u5*E{Y?cT>v) zudTElhueR-e9*mn=tUfBp}aD|`Mk>lwd%9XNy>A_R9*@E6o31P97T0p)H~w`L&R?_irnYf|f))c8>9c_?*13b)U`zSeO3 z8mraHaJ>iN7_^HdsztQ%kQJZer}@<=rsbO)$l(j*KC)&#Gz zS=-Zjqq^{#&(&(2?x1xbQ8ju@8?Mcn5!w$t-n#A-Y+w?`tEg`&*f*;_3bxLw6-mP# zYf?)^6XlN8){gnZA057?Rf6q!3SUn>MjSt>1W>3G+~PMPA84RO?)V$RskH(VcdfQ{ p&c1rhxG!~b{asJp2z>RPv>(ldcB0#AOkBV*@$=9j@dtcJ{0Gx`*{T2l literal 0 HcmV?d00001 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/_hypothesis_plugin.py b/backend/venv/Lib/site-packages/pydantic/v1/_hypothesis_plugin.py new file mode 100644 index 0000000..b62234d --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/_hypothesis_plugin.py @@ -0,0 +1,391 @@ +""" +Register Hypothesis strategies for Pydantic custom types. + +This enables fully-automatic generation of test data for most Pydantic classes. + +Note that this module has *no* runtime impact on Pydantic itself; instead it +is registered as a setuptools entry point and Hypothesis will import it if +Pydantic is installed. See also: + +https://hypothesis.readthedocs.io/en/latest/strategies.html#registering-strategies-via-setuptools-entry-points +https://hypothesis.readthedocs.io/en/latest/data.html#hypothesis.strategies.register_type_strategy +https://hypothesis.readthedocs.io/en/latest/strategies.html#interaction-with-pytest-cov +https://docs.pydantic.dev/usage/types/#pydantic-types + +Note that because our motivation is to *improve user experience*, the strategies +are always sound (never generate invalid data) but sacrifice completeness for +maintainability (ie may be unable to generate some tricky but valid data). + +Finally, this module makes liberal use of `# type: ignore[]` pragmas. +This is because Hypothesis annotates `register_type_strategy()` with +`(T, SearchStrategy[T])`, but in most cases we register e.g. `ConstrainedInt` +to generate instances of the builtin `int` type which match the constraints. +""" + +import contextlib +import datetime +import ipaddress +import json +import math +from fractions import Fraction +from typing import Callable, Dict, Type, Union, cast, overload + +import hypothesis.strategies as st + +import pydantic +import pydantic.color +import pydantic.types +from pydantic.v1.utils import lenient_issubclass + +# FilePath and DirectoryPath are explicitly unsupported, as we'd have to create +# them on-disk, and that's unsafe in general without being told *where* to do so. +# +# URLs are unsupported because it's easy for users to define their own strategy for +# "normal" URLs, and hard for us to define a general strategy which includes "weird" +# URLs but doesn't also have unpredictable performance problems. +# +# conlist() and conset() are unsupported for now, because the workarounds for +# Cython and Hypothesis to handle parametrized generic types are incompatible. +# We are rethinking Hypothesis compatibility in Pydantic v2. + +# Emails +try: + import email_validator +except ImportError: # pragma: no cover + pass +else: + + def is_valid_email(s: str) -> bool: + # Hypothesis' st.emails() occasionally generates emails like 0@A0--0.ac + # that are invalid according to email-validator, so we filter those out. + try: + email_validator.validate_email(s, check_deliverability=False) + return True + except email_validator.EmailNotValidError: # pragma: no cover + return False + + # Note that these strategies deliberately stay away from any tricky Unicode + # or other encoding issues; we're just trying to generate *something* valid. + st.register_type_strategy(pydantic.EmailStr, st.emails().filter(is_valid_email)) # type: ignore[arg-type] + st.register_type_strategy( + pydantic.NameEmail, + st.builds( + '{} <{}>'.format, # type: ignore[arg-type] + st.from_regex('[A-Za-z0-9_]+( [A-Za-z0-9_]+){0,5}', fullmatch=True), + st.emails().filter(is_valid_email), + ), + ) + +# PyObject - dotted names, in this case taken from the math module. +st.register_type_strategy( + pydantic.PyObject, # type: ignore[arg-type] + st.sampled_from( + [cast(pydantic.PyObject, f'math.{name}') for name in sorted(vars(math)) if not name.startswith('_')] + ), +) + +# CSS3 Colors; as name, hex, rgb(a) tuples or strings, or hsl strings +_color_regexes = ( + '|'.join( + ( + pydantic.color.r_hex_short, + pydantic.color.r_hex_long, + pydantic.color.r_rgb, + pydantic.color.r_rgba, + pydantic.color.r_hsl, + pydantic.color.r_hsla, + ) + ) + # Use more precise regex patterns to avoid value-out-of-range errors + .replace(pydantic.color._r_sl, r'(?:(\d\d?(?:\.\d+)?|100(?:\.0+)?)%)') + .replace(pydantic.color._r_alpha, r'(?:(0(?:\.\d+)?|1(?:\.0+)?|\.\d+|\d{1,2}%))') + .replace(pydantic.color._r_255, r'(?:((?:\d|\d\d|[01]\d\d|2[0-4]\d|25[0-4])(?:\.\d+)?|255(?:\.0+)?))') +) +st.register_type_strategy( + pydantic.color.Color, + st.one_of( + st.sampled_from(sorted(pydantic.color.COLORS_BY_NAME)), + st.tuples( + st.integers(0, 255), + st.integers(0, 255), + st.integers(0, 255), + st.none() | st.floats(0, 1) | st.floats(0, 100).map('{}%'.format), + ), + st.from_regex(_color_regexes, fullmatch=True), + ), +) + + +# Card numbers, valid according to the Luhn algorithm + + +def add_luhn_digit(card_number: str) -> str: + # See https://en.wikipedia.org/wiki/Luhn_algorithm + for digit in '0123456789': + with contextlib.suppress(Exception): + pydantic.PaymentCardNumber.validate_luhn_check_digit(card_number + digit) + return card_number + digit + raise AssertionError('Unreachable') # pragma: no cover + + +card_patterns = ( + # Note that these patterns omit the Luhn check digit; that's added by the function above + '4[0-9]{14}', # Visa + '5[12345][0-9]{13}', # Mastercard + '3[47][0-9]{12}', # American Express + '[0-26-9][0-9]{10,17}', # other (incomplete to avoid overlap) +) +st.register_type_strategy( + pydantic.PaymentCardNumber, + st.from_regex('|'.join(card_patterns), fullmatch=True).map(add_luhn_digit), # type: ignore[arg-type] +) + +# UUIDs +st.register_type_strategy(pydantic.UUID1, st.uuids(version=1)) +st.register_type_strategy(pydantic.UUID3, st.uuids(version=3)) +st.register_type_strategy(pydantic.UUID4, st.uuids(version=4)) +st.register_type_strategy(pydantic.UUID5, st.uuids(version=5)) + +# Secrets +st.register_type_strategy(pydantic.SecretBytes, st.binary().map(pydantic.SecretBytes)) +st.register_type_strategy(pydantic.SecretStr, st.text().map(pydantic.SecretStr)) + +# IP addresses, networks, and interfaces +st.register_type_strategy(pydantic.IPvAnyAddress, st.ip_addresses()) # type: ignore[arg-type] +st.register_type_strategy( + pydantic.IPvAnyInterface, + st.from_type(ipaddress.IPv4Interface) | st.from_type(ipaddress.IPv6Interface), # type: ignore[arg-type] +) +st.register_type_strategy( + pydantic.IPvAnyNetwork, + st.from_type(ipaddress.IPv4Network) | st.from_type(ipaddress.IPv6Network), # type: ignore[arg-type] +) + +# We hook into the con***() functions and the ConstrainedNumberMeta metaclass, +# so here we only have to register subclasses for other constrained types which +# don't go via those mechanisms. Then there are the registration hooks below. +st.register_type_strategy(pydantic.StrictBool, st.booleans()) +st.register_type_strategy(pydantic.StrictStr, st.text()) + + +# FutureDate, PastDate +st.register_type_strategy(pydantic.FutureDate, st.dates(min_value=datetime.date.today() + datetime.timedelta(days=1))) +st.register_type_strategy(pydantic.PastDate, st.dates(max_value=datetime.date.today() - datetime.timedelta(days=1))) + + +# Constrained-type resolver functions +# +# For these ones, we actually want to inspect the type in order to work out a +# satisfying strategy. First up, the machinery for tracking resolver functions: + +RESOLVERS: Dict[type, Callable[[type], st.SearchStrategy]] = {} # type: ignore[type-arg] + + +@overload +def _registered(typ: Type[pydantic.types.T]) -> Type[pydantic.types.T]: + pass + + +@overload +def _registered(typ: pydantic.types.ConstrainedNumberMeta) -> pydantic.types.ConstrainedNumberMeta: + pass + + +def _registered( + typ: Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta] +) -> Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta]: + # This function replaces the version in `pydantic.types`, in order to + # effect the registration of new constrained types so that Hypothesis + # can generate valid examples. + pydantic.types._DEFINED_TYPES.add(typ) + for supertype, resolver in RESOLVERS.items(): + if issubclass(typ, supertype): + st.register_type_strategy(typ, resolver(typ)) # type: ignore + return typ + raise NotImplementedError(f'Unknown type {typ!r} has no resolver to register') # pragma: no cover + + +def resolves( + typ: Union[type, pydantic.types.ConstrainedNumberMeta] +) -> Callable[[Callable[..., st.SearchStrategy]], Callable[..., st.SearchStrategy]]: # type: ignore[type-arg] + def inner(f): # type: ignore + assert f not in RESOLVERS + RESOLVERS[typ] = f + return f + + return inner + + +# Type-to-strategy resolver functions + + +@resolves(pydantic.JsonWrapper) +def resolve_json(cls): # type: ignore[no-untyped-def] + try: + inner = st.none() if cls.inner_type is None else st.from_type(cls.inner_type) + except Exception: # pragma: no cover + finite = st.floats(allow_infinity=False, allow_nan=False) + inner = st.recursive( + base=st.one_of(st.none(), st.booleans(), st.integers(), finite, st.text()), + extend=lambda x: st.lists(x) | st.dictionaries(st.text(), x), # type: ignore + ) + inner_type = getattr(cls, 'inner_type', None) + return st.builds( + cls.inner_type.json if lenient_issubclass(inner_type, pydantic.BaseModel) else json.dumps, + inner, + ensure_ascii=st.booleans(), + indent=st.none() | st.integers(0, 16), + sort_keys=st.booleans(), + ) + + +@resolves(pydantic.ConstrainedBytes) +def resolve_conbytes(cls): # type: ignore[no-untyped-def] # pragma: no cover + min_size = cls.min_length or 0 + max_size = cls.max_length + if not cls.strip_whitespace: + return st.binary(min_size=min_size, max_size=max_size) + # Fun with regex to ensure we neither start nor end with whitespace + repeats = '{{{},{}}}'.format( + min_size - 2 if min_size > 2 else 0, + max_size - 2 if (max_size or 0) > 2 else '', + ) + if min_size >= 2: + pattern = rf'\W.{repeats}\W' + elif min_size == 1: + pattern = rf'\W(.{repeats}\W)?' + else: + assert min_size == 0 + pattern = rf'(\W(.{repeats}\W)?)?' + return st.from_regex(pattern.encode(), fullmatch=True) + + +@resolves(pydantic.ConstrainedDecimal) +def resolve_condecimal(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt + s = st.decimals(min_value, max_value, allow_nan=False, places=cls.decimal_places) + if cls.lt is not None: + s = s.filter(lambda d: d < cls.lt) + if cls.gt is not None: + s = s.filter(lambda d: cls.gt < d) + return s + + +@resolves(pydantic.ConstrainedFloat) +def resolve_confloat(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + exclude_min = False + exclude_max = False + + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + exclude_min = True + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt + exclude_max = True + + if cls.multiple_of is None: + return st.floats(min_value, max_value, exclude_min=exclude_min, exclude_max=exclude_max, allow_nan=False) + + if min_value is not None: + min_value = math.ceil(min_value / cls.multiple_of) + if exclude_min: + min_value = min_value + 1 + if max_value is not None: + assert max_value >= cls.multiple_of, 'Cannot build model with max value smaller than multiple of' + max_value = math.floor(max_value / cls.multiple_of) + if exclude_max: + max_value = max_value - 1 + + return st.integers(min_value, max_value).map(lambda x: x * cls.multiple_of) + + +@resolves(pydantic.ConstrainedInt) +def resolve_conint(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + 1 + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt - 1 + + if cls.multiple_of is None or cls.multiple_of == 1: + return st.integers(min_value, max_value) + + # These adjustments and the .map handle integer-valued multiples, while the + # .filter handles trickier cases as for confloat. + if min_value is not None: + min_value = math.ceil(Fraction(min_value) / Fraction(cls.multiple_of)) + if max_value is not None: + max_value = math.floor(Fraction(max_value) / Fraction(cls.multiple_of)) + return st.integers(min_value, max_value).map(lambda x: x * cls.multiple_of) + + +@resolves(pydantic.ConstrainedDate) +def resolve_condate(cls): # type: ignore[no-untyped-def] + if cls.ge is not None: + assert cls.gt is None, 'Set `gt` or `ge`, but not both' + min_value = cls.ge + elif cls.gt is not None: + min_value = cls.gt + datetime.timedelta(days=1) + else: + min_value = datetime.date.min + if cls.le is not None: + assert cls.lt is None, 'Set `lt` or `le`, but not both' + max_value = cls.le + elif cls.lt is not None: + max_value = cls.lt - datetime.timedelta(days=1) + else: + max_value = datetime.date.max + return st.dates(min_value, max_value) + + +@resolves(pydantic.ConstrainedStr) +def resolve_constr(cls): # type: ignore[no-untyped-def] # pragma: no cover + min_size = cls.min_length or 0 + max_size = cls.max_length + + if cls.regex is None and not cls.strip_whitespace: + return st.text(min_size=min_size, max_size=max_size) + + if cls.regex is not None: + strategy = st.from_regex(cls.regex) + if cls.strip_whitespace: + strategy = strategy.filter(lambda s: s == s.strip()) + elif cls.strip_whitespace: + repeats = '{{{},{}}}'.format( + min_size - 2 if min_size > 2 else 0, + max_size - 2 if (max_size or 0) > 2 else '', + ) + if min_size >= 2: + strategy = st.from_regex(rf'\W.{repeats}\W') + elif min_size == 1: + strategy = st.from_regex(rf'\W(.{repeats}\W)?') + else: + assert min_size == 0 + strategy = st.from_regex(rf'(\W(.{repeats}\W)?)?') + + if min_size == 0 and max_size is None: + return strategy + elif max_size is None: + return strategy.filter(lambda s: min_size <= len(s)) + return strategy.filter(lambda s: min_size <= len(s) <= max_size) + + +# Finally, register all previously-defined types, and patch in our new function +for typ in list(pydantic.types._DEFINED_TYPES): + _registered(typ) +pydantic.types._registered = _registered +st.register_type_strategy(pydantic.Json, resolve_json) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/annotated_types.py b/backend/venv/Lib/site-packages/pydantic/v1/annotated_types.py new file mode 100644 index 0000000..d9eaaaf --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/annotated_types.py @@ -0,0 +1,72 @@ +import sys +from typing import TYPE_CHECKING, Any, Dict, FrozenSet, NamedTuple, Type + +from pydantic.v1.fields import Required +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.typing import is_typeddict, is_typeddict_special + +if TYPE_CHECKING: + from typing_extensions import TypedDict + +if sys.version_info < (3, 11): + + def is_legacy_typeddict(typeddict_cls: Type['TypedDict']) -> bool: # type: ignore[valid-type] + return is_typeddict(typeddict_cls) and type(typeddict_cls).__module__ == 'typing' + +else: + + def is_legacy_typeddict(_: Any) -> Any: + return False + + +def create_model_from_typeddict( + # Mypy bug: `Type[TypedDict]` is resolved as `Any` https://github.com/python/mypy/issues/11030 + typeddict_cls: Type['TypedDict'], # type: ignore[valid-type] + **kwargs: Any, +) -> Type['BaseModel']: + """ + Create a `BaseModel` based on the fields of a `TypedDict`. + Since `typing.TypedDict` in Python 3.8 does not store runtime information about optional keys, + we raise an error if this happens (see https://bugs.python.org/issue38834). + """ + field_definitions: Dict[str, Any] + + # Best case scenario: with python 3.9+ or when `TypedDict` is imported from `typing_extensions` + if not hasattr(typeddict_cls, '__required_keys__'): + raise TypeError( + 'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.9.2. ' + 'Without it, there is no way to differentiate required and optional fields when subclassed.' + ) + + if is_legacy_typeddict(typeddict_cls) and any( + is_typeddict_special(t) for t in typeddict_cls.__annotations__.values() + ): + raise TypeError( + 'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.11. ' + 'Without it, there is no way to reflect Required/NotRequired keys.' + ) + + required_keys: FrozenSet[str] = typeddict_cls.__required_keys__ # type: ignore[attr-defined] + field_definitions = { + field_name: (field_type, Required if field_name in required_keys else None) + for field_name, field_type in typeddict_cls.__annotations__.items() + } + + return create_model(typeddict_cls.__name__, **kwargs, **field_definitions) + + +def create_model_from_namedtuple(namedtuple_cls: Type['NamedTuple'], **kwargs: Any) -> Type['BaseModel']: + """ + Create a `BaseModel` based on the fields of a named tuple. + A named tuple can be created with `typing.NamedTuple` and declared annotations + but also with `collections.namedtuple`, in this case we consider all fields + to have type `Any`. + """ + # With python 3.10+, `__annotations__` always exists but can be empty hence the `getattr... or...` logic + namedtuple_annotations: Dict[str, Type[Any]] = getattr(namedtuple_cls, '__annotations__', None) or { + k: Any for k in namedtuple_cls._fields + } + field_definitions: Dict[str, Any] = { + field_name: (field_type, Required) for field_name, field_type in namedtuple_annotations.items() + } + return create_model(namedtuple_cls.__name__, **kwargs, **field_definitions) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/class_validators.py b/backend/venv/Lib/site-packages/pydantic/v1/class_validators.py new file mode 100644 index 0000000..2f68fc8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/class_validators.py @@ -0,0 +1,361 @@ +import warnings +from collections import ChainMap +from functools import partial, partialmethod, wraps +from itertools import chain +from types import FunctionType +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Type, Union, overload + +from pydantic.v1.errors import ConfigError +from pydantic.v1.typing import AnyCallable +from pydantic.v1.utils import ROOT_KEY, in_ipython + +if TYPE_CHECKING: + from pydantic.v1.typing import AnyClassMethod + + +class Validator: + __slots__ = 'func', 'pre', 'each_item', 'always', 'check_fields', 'skip_on_failure' + + def __init__( + self, + func: AnyCallable, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool = False, + skip_on_failure: bool = False, + ): + self.func = func + self.pre = pre + self.each_item = each_item + self.always = always + self.check_fields = check_fields + self.skip_on_failure = skip_on_failure + + +if TYPE_CHECKING: + from inspect import Signature + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.types import ModelOrDc + + ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], ModelField, Type[BaseConfig]], Any] + ValidatorsList = List[ValidatorCallable] + ValidatorListDict = Dict[str, List[Validator]] + +_FUNCS: Set[str] = set() +VALIDATOR_CONFIG_KEY = '__validator_config__' +ROOT_VALIDATOR_CONFIG_KEY = '__root_validator_config__' + + +def validator( + *fields: str, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool = True, + whole: Optional[bool] = None, + allow_reuse: bool = False, +) -> Callable[[AnyCallable], 'AnyClassMethod']: + """ + Decorate methods on the class indicating that they should be used to validate fields + :param fields: which field(s) the method should be called on + :param pre: whether or not this validator should be called before the standard validators (else after) + :param each_item: for complex objects (sets, lists etc.) whether to validate individual elements rather than the + whole object + :param always: whether this method and other validators should be called even if the value is missing + :param check_fields: whether to check that the fields actually exist on the model + :param allow_reuse: whether to track and raise an error if another validator refers to the decorated function + """ + if not fields: + raise ConfigError('validator with no fields specified') + elif isinstance(fields[0], FunctionType): + raise ConfigError( + "validators should be used with fields and keyword arguments, not bare. " # noqa: Q000 + "E.g. usage should be `@validator('', ...)`" + ) + elif not all(isinstance(field, str) for field in fields): + raise ConfigError( + "validator fields should be passed as separate string args. " # noqa: Q000 + "E.g. usage should be `@validator('', '', ...)`" + ) + + if whole is not None: + warnings.warn( + 'The "whole" keyword argument is deprecated, use "each_item" (inverse meaning, default False) instead', + DeprecationWarning, + ) + assert each_item is False, '"each_item" and "whole" conflict, remove "whole"' + each_item = not whole + + def dec(f: AnyCallable) -> 'AnyClassMethod': + f_cls = _prepare_validator(f, allow_reuse) + setattr( + f_cls, + VALIDATOR_CONFIG_KEY, + ( + fields, + Validator(func=f_cls.__func__, pre=pre, each_item=each_item, always=always, check_fields=check_fields), + ), + ) + return f_cls + + return dec + + +@overload +def root_validator(_func: AnyCallable) -> 'AnyClassMethod': + ... + + +@overload +def root_validator( + *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False +) -> Callable[[AnyCallable], 'AnyClassMethod']: + ... + + +def root_validator( + _func: Optional[AnyCallable] = None, *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False +) -> Union['AnyClassMethod', Callable[[AnyCallable], 'AnyClassMethod']]: + """ + Decorate methods on a model indicating that they should be used to validate (and perhaps modify) data either + before or after standard model parsing/validation is performed. + """ + if _func: + f_cls = _prepare_validator(_func, allow_reuse) + setattr( + f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure) + ) + return f_cls + + def dec(f: AnyCallable) -> 'AnyClassMethod': + f_cls = _prepare_validator(f, allow_reuse) + setattr( + f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure) + ) + return f_cls + + return dec + + +def _prepare_validator(function: AnyCallable, allow_reuse: bool) -> 'AnyClassMethod': + """ + Avoid validators with duplicated names since without this, validators can be overwritten silently + which generally isn't the intended behaviour, don't run in ipython (see #312) or if allow_reuse is False. + """ + f_cls = function if isinstance(function, classmethod) else classmethod(function) + if not in_ipython() and not allow_reuse: + ref = ( + getattr(f_cls.__func__, '__module__', '') + + '.' + + getattr(f_cls.__func__, '__qualname__', f'') + ) + if ref in _FUNCS: + raise ConfigError(f'duplicate validator function "{ref}"; if this is intended, set `allow_reuse=True`') + _FUNCS.add(ref) + return f_cls + + +class ValidatorGroup: + def __init__(self, validators: 'ValidatorListDict') -> None: + self.validators = validators + self.used_validators = {'*'} + + def get_validators(self, name: str) -> Optional[Dict[str, Validator]]: + self.used_validators.add(name) + validators = self.validators.get(name, []) + if name != ROOT_KEY: + validators += self.validators.get('*', []) + if validators: + return {getattr(v.func, '__name__', f''): v for v in validators} + else: + return None + + def check_for_unused(self) -> None: + unused_validators = set( + chain.from_iterable( + ( + getattr(v.func, '__name__', f'') + for v in self.validators[f] + if v.check_fields + ) + for f in (self.validators.keys() - self.used_validators) + ) + ) + if unused_validators: + fn = ', '.join(unused_validators) + raise ConfigError( + f"Validators defined with incorrect fields: {fn} " # noqa: Q000 + f"(use check_fields=False if you're inheriting from the model and intended this)" + ) + + +def extract_validators(namespace: Dict[str, Any]) -> Dict[str, List[Validator]]: + validators: Dict[str, List[Validator]] = {} + for var_name, value in namespace.items(): + validator_config = getattr(value, VALIDATOR_CONFIG_KEY, None) + if validator_config: + fields, v = validator_config + for field in fields: + if field in validators: + validators[field].append(v) + else: + validators[field] = [v] + return validators + + +def extract_root_validators(namespace: Dict[str, Any]) -> Tuple[List[AnyCallable], List[Tuple[bool, AnyCallable]]]: + from inspect import signature + + pre_validators: List[AnyCallable] = [] + post_validators: List[Tuple[bool, AnyCallable]] = [] + for name, value in namespace.items(): + validator_config: Optional[Validator] = getattr(value, ROOT_VALIDATOR_CONFIG_KEY, None) + if validator_config: + sig = signature(validator_config.func) + args = list(sig.parameters.keys()) + if args[0] == 'self': + raise ConfigError( + f'Invalid signature for root validator {name}: {sig}, "self" not permitted as first argument, ' + f'should be: (cls, values).' + ) + if len(args) != 2: + raise ConfigError(f'Invalid signature for root validator {name}: {sig}, should be: (cls, values).') + # check function signature + if validator_config.pre: + pre_validators.append(validator_config.func) + else: + post_validators.append((validator_config.skip_on_failure, validator_config.func)) + return pre_validators, post_validators + + +def inherit_validators(base_validators: 'ValidatorListDict', validators: 'ValidatorListDict') -> 'ValidatorListDict': + for field, field_validators in base_validators.items(): + if field not in validators: + validators[field] = [] + validators[field] += field_validators + return validators + + +def make_generic_validator(validator: AnyCallable) -> 'ValidatorCallable': + """ + Make a generic function which calls a validator with the right arguments. + + Unfortunately other approaches (eg. return a partial of a function that builds the arguments) is slow, + hence this laborious way of doing things. + + It's done like this so validators don't all need **kwargs in their signature, eg. any combination of + the arguments "values", "fields" and/or "config" are permitted. + """ + from inspect import signature + + if not isinstance(validator, (partial, partialmethod)): + # This should be the default case, so overhead is reduced + sig = signature(validator) + args = list(sig.parameters.keys()) + else: + # Fix the generated argument lists of partial methods + sig = signature(validator.func) + args = [ + k + for k in signature(validator.func).parameters.keys() + if k not in validator.args | validator.keywords.keys() + ] + + first_arg = args.pop(0) + if first_arg == 'self': + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, "self" not permitted as first argument, ' + f'should be: (cls, value, values, config, field), "values", "config" and "field" are all optional.' + ) + elif first_arg == 'cls': + # assume the second argument is value + return wraps(validator)(_generic_validator_cls(validator, sig, set(args[1:]))) + else: + # assume the first argument was value which has already been removed + return wraps(validator)(_generic_validator_basic(validator, sig, set(args))) + + +def prep_validators(v_funcs: Iterable[AnyCallable]) -> 'ValidatorsList': + return [make_generic_validator(f) for f in v_funcs if f] + + +all_kwargs = {'values', 'field', 'config'} + + +def _generic_validator_cls(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': + # assume the first argument is value + has_kwargs = False + if 'kwargs' in args: + has_kwargs = True + args -= {'kwargs'} + + if not args.issubset(all_kwargs): + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, should be: ' + f'(cls, value, values, config, field), "values", "config" and "field" are all optional.' + ) + + if has_kwargs: + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) + elif args == set(): + return lambda cls, v, values, field, config: validator(cls, v) + elif args == {'values'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values) + elif args == {'field'}: + return lambda cls, v, values, field, config: validator(cls, v, field=field) + elif args == {'config'}: + return lambda cls, v, values, field, config: validator(cls, v, config=config) + elif args == {'values', 'field'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field) + elif args == {'values', 'config'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values, config=config) + elif args == {'field', 'config'}: + return lambda cls, v, values, field, config: validator(cls, v, field=field, config=config) + else: + # args == {'values', 'field', 'config'} + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) + + +def _generic_validator_basic(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': + has_kwargs = False + if 'kwargs' in args: + has_kwargs = True + args -= {'kwargs'} + + if not args.issubset(all_kwargs): + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, should be: ' + f'(value, values, config, field), "values", "config" and "field" are all optional.' + ) + + if has_kwargs: + return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) + elif args == set(): + return lambda cls, v, values, field, config: validator(v) + elif args == {'values'}: + return lambda cls, v, values, field, config: validator(v, values=values) + elif args == {'field'}: + return lambda cls, v, values, field, config: validator(v, field=field) + elif args == {'config'}: + return lambda cls, v, values, field, config: validator(v, config=config) + elif args == {'values', 'field'}: + return lambda cls, v, values, field, config: validator(v, values=values, field=field) + elif args == {'values', 'config'}: + return lambda cls, v, values, field, config: validator(v, values=values, config=config) + elif args == {'field', 'config'}: + return lambda cls, v, values, field, config: validator(v, field=field, config=config) + else: + # args == {'values', 'field', 'config'} + return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) + + +def gather_all_validators(type_: 'ModelOrDc') -> Dict[str, 'AnyClassMethod']: + all_attributes = ChainMap(*[cls.__dict__ for cls in type_.__mro__]) # type: ignore[arg-type,var-annotated] + return { + k: v + for k, v in all_attributes.items() + if hasattr(v, VALIDATOR_CONFIG_KEY) or hasattr(v, ROOT_VALIDATOR_CONFIG_KEY) + } diff --git a/backend/venv/Lib/site-packages/pydantic/v1/color.py b/backend/venv/Lib/site-packages/pydantic/v1/color.py new file mode 100644 index 0000000..b0bbf78 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/color.py @@ -0,0 +1,494 @@ +""" +Color definitions are used as per CSS3 specification: +http://www.w3.org/TR/css3-color/#svg-color + +A few colors have multiple names referring to the sames colors, eg. `grey` and `gray` or `aqua` and `cyan`. + +In these cases the LAST color when sorted alphabetically takes preferences, +eg. Color((0, 255, 255)).as_named() == 'cyan' because "cyan" comes after "aqua". +""" +import math +import re +from colorsys import hls_to_rgb, rgb_to_hls +from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union, cast + +from pydantic.v1.errors import ColorError +from pydantic.v1.utils import Representation, almost_equal_floats + +if TYPE_CHECKING: + from pydantic.v1.typing import CallableGenerator, ReprArgs + +ColorTuple = Union[Tuple[int, int, int], Tuple[int, int, int, float]] +ColorType = Union[ColorTuple, str] +HslColorTuple = Union[Tuple[float, float, float], Tuple[float, float, float, float]] + + +class RGBA: + """ + Internal use only as a representation of a color. + """ + + __slots__ = 'r', 'g', 'b', 'alpha', '_tuple' + + def __init__(self, r: float, g: float, b: float, alpha: Optional[float]): + self.r = r + self.g = g + self.b = b + self.alpha = alpha + + self._tuple: Tuple[float, float, float, Optional[float]] = (r, g, b, alpha) + + def __getitem__(self, item: Any) -> Any: + return self._tuple[item] + + +# these are not compiled here to avoid import slowdown, they'll be compiled the first time they're used, then cached +r_hex_short = r'\s*(?:#|0x)?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?\s*' +r_hex_long = r'\s*(?:#|0x)?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?\s*' +_r_255 = r'(\d{1,3}(?:\.\d+)?)' +_r_comma = r'\s*,\s*' +r_rgb = fr'\s*rgb\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}\)\s*' +_r_alpha = r'(\d(?:\.\d+)?|\.\d+|\d{1,2}%)' +r_rgba = fr'\s*rgba\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_alpha}\s*\)\s*' +_r_h = r'(-?\d+(?:\.\d+)?|-?\.\d+)(deg|rad|turn)?' +_r_sl = r'(\d{1,3}(?:\.\d+)?)%' +r_hsl = fr'\s*hsl\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}\s*\)\s*' +r_hsla = fr'\s*hsl\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}{_r_comma}{_r_alpha}\s*\)\s*' + +# colors where the two hex characters are the same, if all colors match this the short version of hex colors can be used +repeat_colors = {int(c * 2, 16) for c in '0123456789abcdef'} +rads = 2 * math.pi + + +class Color(Representation): + __slots__ = '_original', '_rgba' + + def __init__(self, value: ColorType) -> None: + self._rgba: RGBA + self._original: ColorType + if isinstance(value, (tuple, list)): + self._rgba = parse_tuple(value) + elif isinstance(value, str): + self._rgba = parse_str(value) + elif isinstance(value, Color): + self._rgba = value._rgba + value = value._original + else: + raise ColorError(reason='value must be a tuple, list or string') + + # if we've got here value must be a valid color + self._original = value + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='color') + + def original(self) -> ColorType: + """ + Original value passed to Color + """ + return self._original + + def as_named(self, *, fallback: bool = False) -> str: + if self._rgba.alpha is None: + rgb = cast(Tuple[int, int, int], self.as_rgb_tuple()) + try: + return COLORS_BY_VALUE[rgb] + except KeyError as e: + if fallback: + return self.as_hex() + else: + raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()') from e + else: + return self.as_hex() + + def as_hex(self) -> str: + """ + Hex string representing the color can be 3, 4, 6 or 8 characters depending on whether the string + a "short" representation of the color is possible and whether there's an alpha channel. + """ + values = [float_to_255(c) for c in self._rgba[:3]] + if self._rgba.alpha is not None: + values.append(float_to_255(self._rgba.alpha)) + + as_hex = ''.join(f'{v:02x}' for v in values) + if all(c in repeat_colors for c in values): + as_hex = ''.join(as_hex[c] for c in range(0, len(as_hex), 2)) + return '#' + as_hex + + def as_rgb(self) -> str: + """ + Color as an rgb(, , ) or rgba(, , , ) string. + """ + if self._rgba.alpha is None: + return f'rgb({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)})' + else: + return ( + f'rgba({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)}, ' + f'{round(self._alpha_float(), 2)})' + ) + + def as_rgb_tuple(self, *, alpha: Optional[bool] = None) -> ColorTuple: + """ + Color as an RGB or RGBA tuple; red, green and blue are in the range 0 to 255, alpha if included is + in the range 0 to 1. + + :param alpha: whether to include the alpha channel, options are + None - (default) include alpha only if it's set (e.g. not None) + True - always include alpha, + False - always omit alpha, + """ + r, g, b = (float_to_255(c) for c in self._rgba[:3]) + if alpha is None: + if self._rgba.alpha is None: + return r, g, b + else: + return r, g, b, self._alpha_float() + elif alpha: + return r, g, b, self._alpha_float() + else: + # alpha is False + return r, g, b + + def as_hsl(self) -> str: + """ + Color as an hsl(, , ) or hsl(, , , ) string. + """ + if self._rgba.alpha is None: + h, s, li = self.as_hsl_tuple(alpha=False) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%})' + else: + h, s, li, a = self.as_hsl_tuple(alpha=True) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%}, {round(a, 2)})' + + def as_hsl_tuple(self, *, alpha: Optional[bool] = None) -> HslColorTuple: + """ + Color as an HSL or HSLA tuple, e.g. hue, saturation, lightness and optionally alpha; all elements are in + the range 0 to 1. + + NOTE: this is HSL as used in HTML and most other places, not HLS as used in python's colorsys. + + :param alpha: whether to include the alpha channel, options are + None - (default) include alpha only if it's set (e.g. not None) + True - always include alpha, + False - always omit alpha, + """ + h, l, s = rgb_to_hls(self._rgba.r, self._rgba.g, self._rgba.b) + if alpha is None: + if self._rgba.alpha is None: + return h, s, l + else: + return h, s, l, self._alpha_float() + if alpha: + return h, s, l, self._alpha_float() + else: + # alpha is False + return h, s, l + + def _alpha_float(self) -> float: + return 1 if self._rgba.alpha is None else self._rgba.alpha + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls + + def __str__(self) -> str: + return self.as_named(fallback=True) + + def __repr_args__(self) -> 'ReprArgs': + return [(None, self.as_named(fallback=True))] + [('rgb', self.as_rgb_tuple())] # type: ignore + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Color) and self.as_rgb_tuple() == other.as_rgb_tuple() + + def __hash__(self) -> int: + return hash(self.as_rgb_tuple()) + + +def parse_tuple(value: Tuple[Any, ...]) -> RGBA: + """ + Parse a tuple or list as a color. + """ + if len(value) == 3: + r, g, b = (parse_color_value(v) for v in value) + return RGBA(r, g, b, None) + elif len(value) == 4: + r, g, b = (parse_color_value(v) for v in value[:3]) + return RGBA(r, g, b, parse_float_alpha(value[3])) + else: + raise ColorError(reason='tuples must have length 3 or 4') + + +def parse_str(value: str) -> RGBA: + """ + Parse a string to an RGBA tuple, trying the following formats (in this order): + * named color, see COLORS_BY_NAME below + * hex short eg. `fff` (prefix can be `#`, `0x` or nothing) + * hex long eg. `ffffff` (prefix can be `#`, `0x` or nothing) + * `rgb(, , ) ` + * `rgba(, , , )` + """ + value_lower = value.lower() + try: + r, g, b = COLORS_BY_NAME[value_lower] + except KeyError: + pass + else: + return ints_to_rgba(r, g, b, None) + + m = re.fullmatch(r_hex_short, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v * 2, 16) for v in rgb) + if a: + alpha: Optional[float] = int(a * 2, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_hex_long, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v, 16) for v in rgb) + if a: + alpha = int(a, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_rgb, value_lower) + if m: + return ints_to_rgba(*m.groups(), None) # type: ignore + + m = re.fullmatch(r_rgba, value_lower) + if m: + return ints_to_rgba(*m.groups()) # type: ignore + + m = re.fullmatch(r_hsl, value_lower) + if m: + h, h_units, s, l_ = m.groups() + return parse_hsl(h, h_units, s, l_) + + m = re.fullmatch(r_hsla, value_lower) + if m: + h, h_units, s, l_, a = m.groups() + return parse_hsl(h, h_units, s, l_, parse_float_alpha(a)) + + raise ColorError(reason='string not recognised as a valid color') + + +def ints_to_rgba(r: Union[int, str], g: Union[int, str], b: Union[int, str], alpha: Optional[float]) -> RGBA: + return RGBA(parse_color_value(r), parse_color_value(g), parse_color_value(b), parse_float_alpha(alpha)) + + +def parse_color_value(value: Union[int, str], max_val: int = 255) -> float: + """ + Parse a value checking it's a valid int in the range 0 to max_val and divide by max_val to give a number + in the range 0 to 1 + """ + try: + color = float(value) + except ValueError: + raise ColorError(reason='color values must be a valid number') + if 0 <= color <= max_val: + return color / max_val + else: + raise ColorError(reason=f'color values must be in the range 0 to {max_val}') + + +def parse_float_alpha(value: Union[None, str, float, int]) -> Optional[float]: + """ + Parse a value checking it's a valid float in the range 0 to 1 + """ + if value is None: + return None + try: + if isinstance(value, str) and value.endswith('%'): + alpha = float(value[:-1]) / 100 + else: + alpha = float(value) + except ValueError: + raise ColorError(reason='alpha values must be a valid float') + + if almost_equal_floats(alpha, 1): + return None + elif 0 <= alpha <= 1: + return alpha + else: + raise ColorError(reason='alpha values must be in the range 0 to 1') + + +def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: Optional[float] = None) -> RGBA: + """ + Parse raw hue, saturation, lightness and alpha values and convert to RGBA. + """ + s_value, l_value = parse_color_value(sat, 100), parse_color_value(light, 100) + + h_value = float(h) + if h_units in {None, 'deg'}: + h_value = h_value % 360 / 360 + elif h_units == 'rad': + h_value = h_value % rads / rads + else: + # turns + h_value = h_value % 1 + + r, g, b = hls_to_rgb(h_value, l_value, s_value) + return RGBA(r, g, b, alpha) + + +def float_to_255(c: float) -> int: + return int(round(c * 255)) + + +COLORS_BY_NAME = { + 'aliceblue': (240, 248, 255), + 'antiquewhite': (250, 235, 215), + 'aqua': (0, 255, 255), + 'aquamarine': (127, 255, 212), + 'azure': (240, 255, 255), + 'beige': (245, 245, 220), + 'bisque': (255, 228, 196), + 'black': (0, 0, 0), + 'blanchedalmond': (255, 235, 205), + 'blue': (0, 0, 255), + 'blueviolet': (138, 43, 226), + 'brown': (165, 42, 42), + 'burlywood': (222, 184, 135), + 'cadetblue': (95, 158, 160), + 'chartreuse': (127, 255, 0), + 'chocolate': (210, 105, 30), + 'coral': (255, 127, 80), + 'cornflowerblue': (100, 149, 237), + 'cornsilk': (255, 248, 220), + 'crimson': (220, 20, 60), + 'cyan': (0, 255, 255), + 'darkblue': (0, 0, 139), + 'darkcyan': (0, 139, 139), + 'darkgoldenrod': (184, 134, 11), + 'darkgray': (169, 169, 169), + 'darkgreen': (0, 100, 0), + 'darkgrey': (169, 169, 169), + 'darkkhaki': (189, 183, 107), + 'darkmagenta': (139, 0, 139), + 'darkolivegreen': (85, 107, 47), + 'darkorange': (255, 140, 0), + 'darkorchid': (153, 50, 204), + 'darkred': (139, 0, 0), + 'darksalmon': (233, 150, 122), + 'darkseagreen': (143, 188, 143), + 'darkslateblue': (72, 61, 139), + 'darkslategray': (47, 79, 79), + 'darkslategrey': (47, 79, 79), + 'darkturquoise': (0, 206, 209), + 'darkviolet': (148, 0, 211), + 'deeppink': (255, 20, 147), + 'deepskyblue': (0, 191, 255), + 'dimgray': (105, 105, 105), + 'dimgrey': (105, 105, 105), + 'dodgerblue': (30, 144, 255), + 'firebrick': (178, 34, 34), + 'floralwhite': (255, 250, 240), + 'forestgreen': (34, 139, 34), + 'fuchsia': (255, 0, 255), + 'gainsboro': (220, 220, 220), + 'ghostwhite': (248, 248, 255), + 'gold': (255, 215, 0), + 'goldenrod': (218, 165, 32), + 'gray': (128, 128, 128), + 'green': (0, 128, 0), + 'greenyellow': (173, 255, 47), + 'grey': (128, 128, 128), + 'honeydew': (240, 255, 240), + 'hotpink': (255, 105, 180), + 'indianred': (205, 92, 92), + 'indigo': (75, 0, 130), + 'ivory': (255, 255, 240), + 'khaki': (240, 230, 140), + 'lavender': (230, 230, 250), + 'lavenderblush': (255, 240, 245), + 'lawngreen': (124, 252, 0), + 'lemonchiffon': (255, 250, 205), + 'lightblue': (173, 216, 230), + 'lightcoral': (240, 128, 128), + 'lightcyan': (224, 255, 255), + 'lightgoldenrodyellow': (250, 250, 210), + 'lightgray': (211, 211, 211), + 'lightgreen': (144, 238, 144), + 'lightgrey': (211, 211, 211), + 'lightpink': (255, 182, 193), + 'lightsalmon': (255, 160, 122), + 'lightseagreen': (32, 178, 170), + 'lightskyblue': (135, 206, 250), + 'lightslategray': (119, 136, 153), + 'lightslategrey': (119, 136, 153), + 'lightsteelblue': (176, 196, 222), + 'lightyellow': (255, 255, 224), + 'lime': (0, 255, 0), + 'limegreen': (50, 205, 50), + 'linen': (250, 240, 230), + 'magenta': (255, 0, 255), + 'maroon': (128, 0, 0), + 'mediumaquamarine': (102, 205, 170), + 'mediumblue': (0, 0, 205), + 'mediumorchid': (186, 85, 211), + 'mediumpurple': (147, 112, 219), + 'mediumseagreen': (60, 179, 113), + 'mediumslateblue': (123, 104, 238), + 'mediumspringgreen': (0, 250, 154), + 'mediumturquoise': (72, 209, 204), + 'mediumvioletred': (199, 21, 133), + 'midnightblue': (25, 25, 112), + 'mintcream': (245, 255, 250), + 'mistyrose': (255, 228, 225), + 'moccasin': (255, 228, 181), + 'navajowhite': (255, 222, 173), + 'navy': (0, 0, 128), + 'oldlace': (253, 245, 230), + 'olive': (128, 128, 0), + 'olivedrab': (107, 142, 35), + 'orange': (255, 165, 0), + 'orangered': (255, 69, 0), + 'orchid': (218, 112, 214), + 'palegoldenrod': (238, 232, 170), + 'palegreen': (152, 251, 152), + 'paleturquoise': (175, 238, 238), + 'palevioletred': (219, 112, 147), + 'papayawhip': (255, 239, 213), + 'peachpuff': (255, 218, 185), + 'peru': (205, 133, 63), + 'pink': (255, 192, 203), + 'plum': (221, 160, 221), + 'powderblue': (176, 224, 230), + 'purple': (128, 0, 128), + 'red': (255, 0, 0), + 'rosybrown': (188, 143, 143), + 'royalblue': (65, 105, 225), + 'saddlebrown': (139, 69, 19), + 'salmon': (250, 128, 114), + 'sandybrown': (244, 164, 96), + 'seagreen': (46, 139, 87), + 'seashell': (255, 245, 238), + 'sienna': (160, 82, 45), + 'silver': (192, 192, 192), + 'skyblue': (135, 206, 235), + 'slateblue': (106, 90, 205), + 'slategray': (112, 128, 144), + 'slategrey': (112, 128, 144), + 'snow': (255, 250, 250), + 'springgreen': (0, 255, 127), + 'steelblue': (70, 130, 180), + 'tan': (210, 180, 140), + 'teal': (0, 128, 128), + 'thistle': (216, 191, 216), + 'tomato': (255, 99, 71), + 'turquoise': (64, 224, 208), + 'violet': (238, 130, 238), + 'wheat': (245, 222, 179), + 'white': (255, 255, 255), + 'whitesmoke': (245, 245, 245), + 'yellow': (255, 255, 0), + 'yellowgreen': (154, 205, 50), +} + +COLORS_BY_VALUE = {v: k for k, v in COLORS_BY_NAME.items()} diff --git a/backend/venv/Lib/site-packages/pydantic/v1/config.py b/backend/venv/Lib/site-packages/pydantic/v1/config.py new file mode 100644 index 0000000..18f7c99 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/config.py @@ -0,0 +1,191 @@ +import json +from enum import Enum +from typing import TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Optional, Tuple, Type, Union + +from typing_extensions import Literal, Protocol + +from pydantic.v1.typing import AnyArgTCallable, AnyCallable +from pydantic.v1.utils import GetterDict +from pydantic.v1.version import compiled + +if TYPE_CHECKING: + from typing import overload + + from pydantic.v1.fields import ModelField + from pydantic.v1.main import BaseModel + + ConfigType = Type['BaseConfig'] + + class SchemaExtraCallable(Protocol): + @overload + def __call__(self, schema: Dict[str, Any]) -> None: + pass + + @overload + def __call__(self, schema: Dict[str, Any], model_class: Type[BaseModel]) -> None: + pass + +else: + SchemaExtraCallable = Callable[..., None] + +__all__ = 'BaseConfig', 'ConfigDict', 'get_config', 'Extra', 'inherit_config', 'prepare_config' + + +class Extra(str, Enum): + allow = 'allow' + ignore = 'ignore' + forbid = 'forbid' + + +# https://github.com/cython/cython/issues/4003 +# Fixed in Cython 3 and Pydantic v1 won't support Cython 3. +# Pydantic v2 doesn't depend on Cython at all. +if not compiled: + from typing_extensions import TypedDict + + class ConfigDict(TypedDict, total=False): + title: Optional[str] + anystr_lower: bool + anystr_strip_whitespace: bool + min_anystr_length: int + max_anystr_length: Optional[int] + validate_all: bool + extra: Extra + allow_mutation: bool + frozen: bool + allow_population_by_field_name: bool + use_enum_values: bool + fields: Dict[str, Union[str, Dict[str, str]]] + validate_assignment: bool + error_msg_templates: Dict[str, str] + arbitrary_types_allowed: bool + orm_mode: bool + getter_dict: Type[GetterDict] + alias_generator: Optional[Callable[[str], str]] + keep_untouched: Tuple[type, ...] + schema_extra: Union[Dict[str, object], 'SchemaExtraCallable'] + json_loads: Callable[[str], object] + json_dumps: AnyArgTCallable[str] + json_encoders: Dict[Type[object], AnyCallable] + underscore_attrs_are_private: bool + allow_inf_nan: bool + copy_on_model_validation: Literal['none', 'deep', 'shallow'] + # whether dataclass `__post_init__` should be run after validation + post_init_call: Literal['before_validation', 'after_validation'] + +else: + ConfigDict = dict # type: ignore + + +class BaseConfig: + title: Optional[str] = None + anystr_lower: bool = False + anystr_upper: bool = False + anystr_strip_whitespace: bool = False + min_anystr_length: int = 0 + max_anystr_length: Optional[int] = None + validate_all: bool = False + extra: Extra = Extra.ignore + allow_mutation: bool = True + frozen: bool = False + allow_population_by_field_name: bool = False + use_enum_values: bool = False + fields: Dict[str, Union[str, Dict[str, str]]] = {} + validate_assignment: bool = False + error_msg_templates: Dict[str, str] = {} + arbitrary_types_allowed: bool = False + orm_mode: bool = False + getter_dict: Type[GetterDict] = GetterDict + alias_generator: Optional[Callable[[str], str]] = None + keep_untouched: Tuple[type, ...] = () + schema_extra: Union[Dict[str, Any], 'SchemaExtraCallable'] = {} + json_loads: Callable[[str], Any] = json.loads + json_dumps: Callable[..., str] = json.dumps + json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable] = {} + underscore_attrs_are_private: bool = False + allow_inf_nan: bool = True + + # whether inherited models as fields should be reconstructed as base model, + # and whether such a copy should be shallow or deep + copy_on_model_validation: Literal['none', 'deep', 'shallow'] = 'shallow' + + # whether `Union` should check all allowed types before even trying to coerce + smart_union: bool = False + # whether dataclass `__post_init__` should be run before or after validation + post_init_call: Literal['before_validation', 'after_validation'] = 'before_validation' + + @classmethod + def get_field_info(cls, name: str) -> Dict[str, Any]: + """ + Get properties of FieldInfo from the `fields` property of the config class. + """ + + fields_value = cls.fields.get(name) + + if isinstance(fields_value, str): + field_info: Dict[str, Any] = {'alias': fields_value} + elif isinstance(fields_value, dict): + field_info = fields_value + else: + field_info = {} + + if 'alias' in field_info: + field_info.setdefault('alias_priority', 2) + + if field_info.get('alias_priority', 0) <= 1 and cls.alias_generator: + alias = cls.alias_generator(name) + if not isinstance(alias, str): + raise TypeError(f'Config.alias_generator must return str, not {alias.__class__}') + field_info.update(alias=alias, alias_priority=1) + return field_info + + @classmethod + def prepare_field(cls, field: 'ModelField') -> None: + """ + Optional hook to check or modify fields during model creation. + """ + pass + + +def get_config(config: Union[ConfigDict, Type[object], None]) -> Type[BaseConfig]: + if config is None: + return BaseConfig + + else: + config_dict = ( + config + if isinstance(config, dict) + else {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} + ) + + class Config(BaseConfig): + ... + + for k, v in config_dict.items(): + setattr(Config, k, v) + return Config + + +def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType': + if not self_config: + base_classes: Tuple['ConfigType', ...] = (parent_config,) + elif self_config == parent_config: + base_classes = (self_config,) + else: + base_classes = self_config, parent_config + + namespace['json_encoders'] = { + **getattr(parent_config, 'json_encoders', {}), + **getattr(self_config, 'json_encoders', {}), + **namespace.get('json_encoders', {}), + } + + return type('Config', base_classes, namespace) + + +def prepare_config(config: Type[BaseConfig], cls_name: str) -> None: + if not isinstance(config.extra, Extra): + try: + config.extra = Extra(config.extra) + except ValueError: + raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"') diff --git a/backend/venv/Lib/site-packages/pydantic/v1/dataclasses.py b/backend/venv/Lib/site-packages/pydantic/v1/dataclasses.py new file mode 100644 index 0000000..bd16702 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/dataclasses.py @@ -0,0 +1,500 @@ +""" +The main purpose is to enhance stdlib dataclasses by adding validation +A pydantic dataclass can be generated from scratch or from a stdlib one. + +Behind the scene, a pydantic dataclass is just like a regular one on which we attach +a `BaseModel` and magic methods to trigger the validation of the data. +`__init__` and `__post_init__` are hence overridden and have extra logic to be +able to validate input data. + +When a pydantic dataclass is generated from scratch, it's just a plain dataclass +with validation triggered at initialization + +The tricky part if for stdlib dataclasses that are converted after into pydantic ones e.g. + +```py +@dataclasses.dataclass +class M: + x: int + +ValidatedM = pydantic.dataclasses.dataclass(M) +``` + +We indeed still want to support equality, hashing, repr, ... as if it was the stdlib one! + +```py +assert isinstance(ValidatedM(x=1), M) +assert ValidatedM(x=1) == M(x=1) +``` + +This means we **don't want to create a new dataclass that inherits from it** +The trick is to create a wrapper around `M` that will act as a proxy to trigger +validation without altering default `M` behaviour. +""" +import copy +import dataclasses +import sys +from contextlib import contextmanager +from functools import wraps + +try: + from functools import cached_property +except ImportError: + # cached_property available only for python3.8+ + pass + +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Generator, Optional, Type, TypeVar, Union, overload + +from typing_extensions import dataclass_transform + +from pydantic.v1.class_validators import gather_all_validators +from pydantic.v1.config import BaseConfig, ConfigDict, Extra, get_config +from pydantic.v1.error_wrappers import ValidationError +from pydantic.v1.errors import DataclassTypeError +from pydantic.v1.fields import Field, FieldInfo, Required, Undefined +from pydantic.v1.main import create_model, validate_model +from pydantic.v1.utils import ClassAttribute + +if TYPE_CHECKING: + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import CallableGenerator, NoArgAnyCallable + + DataclassT = TypeVar('DataclassT', bound='Dataclass') + + DataclassClassOrWrapper = Union[Type['Dataclass'], 'DataclassProxy'] + + class Dataclass: + # stdlib attributes + __dataclass_fields__: ClassVar[Dict[str, Any]] + __dataclass_params__: ClassVar[Any] # in reality `dataclasses._DataclassParams` + __post_init__: ClassVar[Callable[..., None]] + + # Added by pydantic + __pydantic_run_validation__: ClassVar[bool] + __post_init_post_parse__: ClassVar[Callable[..., None]] + __pydantic_initialised__: ClassVar[bool] + __pydantic_model__: ClassVar[Type[BaseModel]] + __pydantic_validate_values__: ClassVar[Callable[['Dataclass'], None]] + __pydantic_has_field_info_default__: ClassVar[bool] # whether a `pydantic.Field` is used as default value + + def __init__(self, *args: object, **kwargs: object) -> None: + pass + + @classmethod + def __get_validators__(cls: Type['Dataclass']) -> 'CallableGenerator': + pass + + @classmethod + def __validate__(cls: Type['DataclassT'], v: Any) -> 'DataclassT': + pass + + +__all__ = [ + 'dataclass', + 'set_validation', + 'create_pydantic_model_from_dataclass', + 'is_builtin_dataclass', + 'make_dataclass_validator', +] + +_T = TypeVar('_T') + +if sys.version_info >= (3, 10): + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = ..., + ) -> Callable[[Type[_T]], 'DataclassClassOrWrapper']: + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + _cls: Type[_T], + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = ..., + ) -> 'DataclassClassOrWrapper': + ... + +else: + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + ) -> Callable[[Type[_T]], 'DataclassClassOrWrapper']: + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + _cls: Type[_T], + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + ) -> 'DataclassClassOrWrapper': + ... + + +@dataclass_transform(field_specifiers=(dataclasses.field, Field)) +def dataclass( + _cls: Optional[Type[_T]] = None, + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = False, +) -> Union[Callable[[Type[_T]], 'DataclassClassOrWrapper'], 'DataclassClassOrWrapper']: + """ + Like the python standard lib dataclasses but with type validation. + The result is either a pydantic dataclass that will validate input data + or a wrapper that will trigger validation around a stdlib dataclass + to avoid modifying it directly + """ + the_config = get_config(config) + + def wrap(cls: Type[Any]) -> 'DataclassClassOrWrapper': + should_use_proxy = ( + use_proxy + if use_proxy is not None + else ( + is_builtin_dataclass(cls) + and (cls.__bases__[0] is object or set(dir(cls)) == set(dir(cls.__bases__[0]))) + ) + ) + if should_use_proxy: + dc_cls_doc = '' + dc_cls = DataclassProxy(cls) + default_validate_on_init = False + else: + dc_cls_doc = cls.__doc__ or '' # needs to be done before generating dataclass + if sys.version_info >= (3, 10): + dc_cls = dataclasses.dataclass( + cls, + init=init, + repr=repr, + eq=eq, + order=order, + unsafe_hash=unsafe_hash, + frozen=frozen, + kw_only=kw_only, + ) + else: + dc_cls = dataclasses.dataclass( # type: ignore + cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen + ) + default_validate_on_init = True + + should_validate_on_init = default_validate_on_init if validate_on_init is None else validate_on_init + _add_pydantic_validation_attributes(cls, the_config, should_validate_on_init, dc_cls_doc) + dc_cls.__pydantic_model__.__try_update_forward_refs__(**{cls.__name__: cls}) + return dc_cls + + if _cls is None: + return wrap + + return wrap(_cls) + + +@contextmanager +def set_validation(cls: Type['DataclassT'], value: bool) -> Generator[Type['DataclassT'], None, None]: + original_run_validation = cls.__pydantic_run_validation__ + try: + cls.__pydantic_run_validation__ = value + yield cls + finally: + cls.__pydantic_run_validation__ = original_run_validation + + +class DataclassProxy: + __slots__ = '__dataclass__' + + def __init__(self, dc_cls: Type['Dataclass']) -> None: + object.__setattr__(self, '__dataclass__', dc_cls) + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + with set_validation(self.__dataclass__, True): + return self.__dataclass__(*args, **kwargs) + + def __getattr__(self, name: str) -> Any: + return getattr(self.__dataclass__, name) + + def __setattr__(self, __name: str, __value: Any) -> None: + return setattr(self.__dataclass__, __name, __value) + + def __instancecheck__(self, instance: Any) -> bool: + return isinstance(instance, self.__dataclass__) + + def __copy__(self) -> 'DataclassProxy': + return DataclassProxy(copy.copy(self.__dataclass__)) + + def __deepcopy__(self, memo: Any) -> 'DataclassProxy': + return DataclassProxy(copy.deepcopy(self.__dataclass__, memo)) + + +def _add_pydantic_validation_attributes( # noqa: C901 (ignore complexity) + dc_cls: Type['Dataclass'], + config: Type[BaseConfig], + validate_on_init: bool, + dc_cls_doc: str, +) -> None: + """ + We need to replace the right method. If no `__post_init__` has been set in the stdlib dataclass + it won't even exist (code is generated on the fly by `dataclasses`) + By default, we run validation after `__init__` or `__post_init__` if defined + """ + init = dc_cls.__init__ + + @wraps(init) + def handle_extra_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + if config.extra == Extra.ignore: + init(self, *args, **{k: v for k, v in kwargs.items() if k in self.__dataclass_fields__}) + + elif config.extra == Extra.allow: + for k, v in kwargs.items(): + self.__dict__.setdefault(k, v) + init(self, *args, **{k: v for k, v in kwargs.items() if k in self.__dataclass_fields__}) + + else: + init(self, *args, **kwargs) + + if hasattr(dc_cls, '__post_init__'): + try: + post_init = dc_cls.__post_init__.__wrapped__ # type: ignore[attr-defined] + except AttributeError: + post_init = dc_cls.__post_init__ + + @wraps(post_init) + def new_post_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + if config.post_init_call == 'before_validation': + post_init(self, *args, **kwargs) + + if self.__class__.__pydantic_run_validation__: + self.__pydantic_validate_values__() + if hasattr(self, '__post_init_post_parse__'): + self.__post_init_post_parse__(*args, **kwargs) + + if config.post_init_call == 'after_validation': + post_init(self, *args, **kwargs) + + setattr(dc_cls, '__init__', handle_extra_init) + setattr(dc_cls, '__post_init__', new_post_init) + + else: + + @wraps(init) + def new_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + handle_extra_init(self, *args, **kwargs) + + if self.__class__.__pydantic_run_validation__: + self.__pydantic_validate_values__() + + if hasattr(self, '__post_init_post_parse__'): + # We need to find again the initvars. To do that we use `__dataclass_fields__` instead of + # public method `dataclasses.fields` + + # get all initvars and their default values + initvars_and_values: Dict[str, Any] = {} + for i, f in enumerate(self.__class__.__dataclass_fields__.values()): + if f._field_type is dataclasses._FIELD_INITVAR: # type: ignore[attr-defined] + try: + # set arg value by default + initvars_and_values[f.name] = args[i] + except IndexError: + initvars_and_values[f.name] = kwargs.get(f.name, f.default) + + self.__post_init_post_parse__(**initvars_and_values) + + setattr(dc_cls, '__init__', new_init) + + setattr(dc_cls, '__pydantic_run_validation__', ClassAttribute('__pydantic_run_validation__', validate_on_init)) + setattr(dc_cls, '__pydantic_initialised__', False) + setattr(dc_cls, '__pydantic_model__', create_pydantic_model_from_dataclass(dc_cls, config, dc_cls_doc)) + setattr(dc_cls, '__pydantic_validate_values__', _dataclass_validate_values) + setattr(dc_cls, '__validate__', classmethod(_validate_dataclass)) + setattr(dc_cls, '__get_validators__', classmethod(_get_validators)) + + if dc_cls.__pydantic_model__.__config__.validate_assignment and not dc_cls.__dataclass_params__.frozen: + setattr(dc_cls, '__setattr__', _dataclass_validate_assignment_setattr) + + +def _get_validators(cls: 'DataclassClassOrWrapper') -> 'CallableGenerator': + yield cls.__validate__ + + +def _validate_dataclass(cls: Type['DataclassT'], v: Any) -> 'DataclassT': + with set_validation(cls, True): + if isinstance(v, cls): + v.__pydantic_validate_values__() + return v + elif isinstance(v, (list, tuple)): + return cls(*v) + elif isinstance(v, dict): + return cls(**v) + else: + raise DataclassTypeError(class_name=cls.__name__) + + +def create_pydantic_model_from_dataclass( + dc_cls: Type['Dataclass'], + config: Type[Any] = BaseConfig, + dc_cls_doc: Optional[str] = None, +) -> Type['BaseModel']: + field_definitions: Dict[str, Any] = {} + for field in dataclasses.fields(dc_cls): + default: Any = Undefined + default_factory: Optional['NoArgAnyCallable'] = None + field_info: FieldInfo + + if field.default is not dataclasses.MISSING: + default = field.default + elif field.default_factory is not dataclasses.MISSING: + default_factory = field.default_factory + else: + default = Required + + if isinstance(default, FieldInfo): + field_info = default + dc_cls.__pydantic_has_field_info_default__ = True + else: + field_info = Field(default=default, default_factory=default_factory, **field.metadata) + + field_definitions[field.name] = (field.type, field_info) + + validators = gather_all_validators(dc_cls) + model: Type['BaseModel'] = create_model( + dc_cls.__name__, + __config__=config, + __module__=dc_cls.__module__, + __validators__=validators, + __cls_kwargs__={'__resolve_forward_refs__': False}, + **field_definitions, + ) + model.__doc__ = dc_cls_doc if dc_cls_doc is not None else dc_cls.__doc__ or '' + return model + + +if sys.version_info >= (3, 8): + + def _is_field_cached_property(obj: 'Dataclass', k: str) -> bool: + return isinstance(getattr(type(obj), k, None), cached_property) + +else: + + def _is_field_cached_property(obj: 'Dataclass', k: str) -> bool: + return False + + +def _dataclass_validate_values(self: 'Dataclass') -> None: + # validation errors can occur if this function is called twice on an already initialised dataclass. + # for example if Extra.forbid is enabled, it would consider __pydantic_initialised__ an invalid extra property + if getattr(self, '__pydantic_initialised__'): + return + if getattr(self, '__pydantic_has_field_info_default__', False): + # We need to remove `FieldInfo` values since they are not valid as input + # It's ok to do that because they are obviously the default values! + input_data = { + k: v + for k, v in self.__dict__.items() + if not (isinstance(v, FieldInfo) or _is_field_cached_property(self, k)) + } + else: + input_data = {k: v for k, v in self.__dict__.items() if not _is_field_cached_property(self, k)} + d, _, validation_error = validate_model(self.__pydantic_model__, input_data, cls=self.__class__) + if validation_error: + raise validation_error + self.__dict__.update(d) + object.__setattr__(self, '__pydantic_initialised__', True) + + +def _dataclass_validate_assignment_setattr(self: 'Dataclass', name: str, value: Any) -> None: + if self.__pydantic_initialised__: + d = dict(self.__dict__) + d.pop(name, None) + known_field = self.__pydantic_model__.__fields__.get(name, None) + if known_field: + value, error_ = known_field.validate(value, d, loc=name, cls=self.__class__) + if error_: + raise ValidationError([error_], self.__class__) + + object.__setattr__(self, name, value) + + +def is_builtin_dataclass(_cls: Type[Any]) -> bool: + """ + Whether a class is a stdlib dataclass + (useful to discriminated a pydantic dataclass that is actually a wrapper around a stdlib dataclass) + + we check that + - `_cls` is a dataclass + - `_cls` is not a processed pydantic dataclass (with a basemodel attached) + - `_cls` is not a pydantic dataclass inheriting directly from a stdlib dataclass + e.g. + ``` + @dataclasses.dataclass + class A: + x: int + + @pydantic.dataclasses.dataclass + class B(A): + y: int + ``` + In this case, when we first check `B`, we make an extra check and look at the annotations ('y'), + which won't be a superset of all the dataclass fields (only the stdlib fields i.e. 'x') + """ + return ( + dataclasses.is_dataclass(_cls) + and not hasattr(_cls, '__pydantic_model__') + and set(_cls.__dataclass_fields__).issuperset(set(getattr(_cls, '__annotations__', {}))) + ) + + +def make_dataclass_validator(dc_cls: Type['Dataclass'], config: Type[BaseConfig]) -> 'CallableGenerator': + """ + Create a pydantic.dataclass from a builtin dataclass to add type validation + and yield the validators + It retrieves the parameters of the dataclass and forwards them to the newly created dataclass + """ + yield from _get_validators(dataclass(dc_cls, config=config, use_proxy=True)) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/datetime_parse.py b/backend/venv/Lib/site-packages/pydantic/v1/datetime_parse.py new file mode 100644 index 0000000..a7598fc --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/datetime_parse.py @@ -0,0 +1,248 @@ +""" +Functions to parse datetime objects. + +We're using regular expressions rather than time.strptime because: +- They provide both validation and parsing. +- They're more flexible for datetimes. +- The date/datetime/time constructors produce friendlier error messages. + +Stolen from https://raw.githubusercontent.com/django/django/main/django/utils/dateparse.py at +9718fa2e8abe430c3526a9278dd976443d4ae3c6 + +Changed to: +* use standard python datetime types not django.utils.timezone +* raise ValueError when regex doesn't match rather than returning None +* support parsing unix timestamps for dates and datetimes +""" +import re +from datetime import date, datetime, time, timedelta, timezone +from typing import Dict, Optional, Type, Union + +from pydantic.v1 import errors + +date_expr = r'(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})' +time_expr = ( + r'(?P\d{1,2}):(?P\d{1,2})' + r'(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?' + r'(?PZ|[+-]\d{2}(?::?\d{2})?)?$' +) + +date_re = re.compile(f'{date_expr}$') +time_re = re.compile(time_expr) +datetime_re = re.compile(f'{date_expr}[T ]{time_expr}') + +standard_duration_re = re.compile( + r'^' + r'(?:(?P-?\d+) (days?, )?)?' + r'((?:(?P-?\d+):)(?=\d+:\d+))?' + r'(?:(?P-?\d+):)?' + r'(?P-?\d+)' + r'(?:\.(?P\d{1,6})\d{0,6})?' + r'$' +) + +# Support the sections of ISO 8601 date representation that are accepted by timedelta +iso8601_duration_re = re.compile( + r'^(?P[-+]?)' + r'P' + r'(?:(?P\d+(.\d+)?)D)?' + r'(?:T' + r'(?:(?P\d+(.\d+)?)H)?' + r'(?:(?P\d+(.\d+)?)M)?' + r'(?:(?P\d+(.\d+)?)S)?' + r')?' + r'$' +) + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) +StrBytesIntFloat = Union[str, bytes, int, float] + + +def get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f'invalid type; expected {native_expected_type}, string, bytes, int or float') + + +def from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str], error: Type[Exception]) -> Union[None, int, timezone]: + if value == 'Z': + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == '-': + offset = -offset + try: + return timezone(timedelta(minutes=offset)) + except ValueError: + raise error() + else: + return None + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = get_numeric(value, 'date') + if number is not None: + return from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + match = date_re.match(value) # type: ignore + if match is None: + raise errors.DateError() + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise errors.DateError() + + +def parse_time(value: Union[time, StrBytesIntFloat]) -> time: + """ + Parse a time/string and return a datetime.time. + + Raise ValueError if the input is well formatted but not a valid time. + Raise ValueError if the input isn't well formatted, in particular if it contains an offset. + """ + if isinstance(value, time): + return value + + number = get_numeric(value, 'time') + if number is not None: + if number >= 86400: + # doesn't make sense since the time time loop back around to 0 + raise errors.TimeError() + return (datetime.min + timedelta(seconds=number)).time() + + if isinstance(value, bytes): + value = value.decode() + + match = time_re.match(value) # type: ignore + if match is None: + raise errors.TimeError() + + kw = match.groupdict() + if kw['microsecond']: + kw['microsecond'] = kw['microsecond'].ljust(6, '0') + + tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.TimeError) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_['tzinfo'] = tzinfo + + try: + return time(**kw_) # type: ignore + except ValueError: + raise errors.TimeError() + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = get_numeric(value, 'datetime') + if number is not None: + return from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + match = datetime_re.match(value) # type: ignore + if match is None: + raise errors.DateTimeError() + + kw = match.groupdict() + if kw['microsecond']: + kw['microsecond'] = kw['microsecond'].ljust(6, '0') + + tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.DateTimeError) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_['tzinfo'] = tzinfo + + try: + return datetime(**kw_) # type: ignore + except ValueError: + raise errors.DateTimeError() + + +def parse_duration(value: StrBytesIntFloat) -> timedelta: + """ + Parse a duration int/float/string and return a datetime.timedelta. + + The preferred format for durations in Django is '%d %H:%M:%S.%f'. + + Also supports ISO 8601 representation. + """ + if isinstance(value, timedelta): + return value + + if isinstance(value, (int, float)): + # below code requires a string + value = f'{value:f}' + elif isinstance(value, bytes): + value = value.decode() + + try: + match = standard_duration_re.match(value) or iso8601_duration_re.match(value) + except TypeError: + raise TypeError('invalid type; expected timedelta, string, bytes, int or float') + + if not match: + raise errors.DurationError() + + kw = match.groupdict() + sign = -1 if kw.pop('sign', '+') == '-' else 1 + if kw.get('microseconds'): + kw['microseconds'] = kw['microseconds'].ljust(6, '0') + + if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'): + kw['microseconds'] = '-' + kw['microseconds'] + + kw_ = {k: float(v) for k, v in kw.items() if v is not None} + + return sign * timedelta(**kw_) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/decorator.py b/backend/venv/Lib/site-packages/pydantic/v1/decorator.py new file mode 100644 index 0000000..2c7c2c2 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/decorator.py @@ -0,0 +1,264 @@ +from functools import wraps +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, TypeVar, Union, overload + +from pydantic.v1 import validator +from pydantic.v1.config import Extra +from pydantic.v1.errors import ConfigError +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.typing import get_all_type_hints +from pydantic.v1.utils import to_camel + +__all__ = ('validate_arguments',) + +if TYPE_CHECKING: + from pydantic.v1.typing import AnyCallable + + AnyCallableT = TypeVar('AnyCallableT', bound=AnyCallable) + ConfigType = Union[None, Type[Any], Dict[str, Any]] + + +@overload +def validate_arguments(func: None = None, *, config: 'ConfigType' = None) -> Callable[['AnyCallableT'], 'AnyCallableT']: + ... + + +@overload +def validate_arguments(func: 'AnyCallableT') -> 'AnyCallableT': + ... + + +def validate_arguments(func: Optional['AnyCallableT'] = None, *, config: 'ConfigType' = None) -> Any: + """ + Decorator to validate the arguments passed to a function. + """ + + def validate(_func: 'AnyCallable') -> 'AnyCallable': + vd = ValidatedFunction(_func, config) + + @wraps(_func) + def wrapper_function(*args: Any, **kwargs: Any) -> Any: + return vd.call(*args, **kwargs) + + wrapper_function.vd = vd # type: ignore + wrapper_function.validate = vd.init_model_instance # type: ignore + wrapper_function.raw_function = vd.raw_function # type: ignore + wrapper_function.model = vd.model # type: ignore + return wrapper_function + + if func: + return validate(func) + else: + return validate + + +ALT_V_ARGS = 'v__args' +ALT_V_KWARGS = 'v__kwargs' +V_POSITIONAL_ONLY_NAME = 'v__positional_only' +V_DUPLICATE_KWARGS = 'v__duplicate_kwargs' + + +class ValidatedFunction: + def __init__(self, function: 'AnyCallableT', config: 'ConfigType'): # noqa C901 + from inspect import Parameter, signature + + parameters: Mapping[str, Parameter] = signature(function).parameters + + if parameters.keys() & {ALT_V_ARGS, ALT_V_KWARGS, V_POSITIONAL_ONLY_NAME, V_DUPLICATE_KWARGS}: + raise ConfigError( + f'"{ALT_V_ARGS}", "{ALT_V_KWARGS}", "{V_POSITIONAL_ONLY_NAME}" and "{V_DUPLICATE_KWARGS}" ' + f'are not permitted as argument names when using the "{validate_arguments.__name__}" decorator' + ) + + self.raw_function = function + self.arg_mapping: Dict[int, str] = {} + self.positional_only_args = set() + self.v_args_name = 'args' + self.v_kwargs_name = 'kwargs' + + type_hints = get_all_type_hints(function) + takes_args = False + takes_kwargs = False + fields: Dict[str, Tuple[Any, Any]] = {} + for i, (name, p) in enumerate(parameters.items()): + if p.annotation is p.empty: + annotation = Any + else: + annotation = type_hints[name] + + default = ... if p.default is p.empty else p.default + if p.kind == Parameter.POSITIONAL_ONLY: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_POSITIONAL_ONLY_NAME] = List[str], None + self.positional_only_args.add(name) + elif p.kind == Parameter.POSITIONAL_OR_KEYWORD: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_DUPLICATE_KWARGS] = List[str], None + elif p.kind == Parameter.KEYWORD_ONLY: + fields[name] = annotation, default + elif p.kind == Parameter.VAR_POSITIONAL: + self.v_args_name = name + fields[name] = Tuple[annotation, ...], None + takes_args = True + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + self.v_kwargs_name = name + fields[name] = Dict[str, annotation], None # type: ignore + takes_kwargs = True + + # these checks avoid a clash between "args" and a field with that name + if not takes_args and self.v_args_name in fields: + self.v_args_name = ALT_V_ARGS + + # same with "kwargs" + if not takes_kwargs and self.v_kwargs_name in fields: + self.v_kwargs_name = ALT_V_KWARGS + + if not takes_args: + # we add the field so validation below can raise the correct exception + fields[self.v_args_name] = List[Any], None + + if not takes_kwargs: + # same with kwargs + fields[self.v_kwargs_name] = Dict[Any, Any], None + + self.create_model(fields, takes_args, takes_kwargs, config) + + def init_model_instance(self, *args: Any, **kwargs: Any) -> BaseModel: + values = self.build_values(args, kwargs) + return self.model(**values) + + def call(self, *args: Any, **kwargs: Any) -> Any: + m = self.init_model_instance(*args, **kwargs) + return self.execute(m) + + def build_values(self, args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Dict[str, Any]: + values: Dict[str, Any] = {} + if args: + arg_iter = enumerate(args) + while True: + try: + i, a = next(arg_iter) + except StopIteration: + break + arg_name = self.arg_mapping.get(i) + if arg_name is not None: + values[arg_name] = a + else: + values[self.v_args_name] = [a] + [a for _, a in arg_iter] + break + + var_kwargs: Dict[str, Any] = {} + wrong_positional_args = [] + duplicate_kwargs = [] + fields_alias = [ + field.alias + for name, field in self.model.__fields__.items() + if name not in (self.v_args_name, self.v_kwargs_name) + ] + non_var_fields = set(self.model.__fields__) - {self.v_args_name, self.v_kwargs_name} + for k, v in kwargs.items(): + if k in non_var_fields or k in fields_alias: + if k in self.positional_only_args: + wrong_positional_args.append(k) + if k in values: + duplicate_kwargs.append(k) + values[k] = v + else: + var_kwargs[k] = v + + if var_kwargs: + values[self.v_kwargs_name] = var_kwargs + if wrong_positional_args: + values[V_POSITIONAL_ONLY_NAME] = wrong_positional_args + if duplicate_kwargs: + values[V_DUPLICATE_KWARGS] = duplicate_kwargs + return values + + def execute(self, m: BaseModel) -> Any: + d = {k: v for k, v in m._iter() if k in m.__fields_set__ or m.__fields__[k].default_factory} + var_kwargs = d.pop(self.v_kwargs_name, {}) + + if self.v_args_name in d: + args_: List[Any] = [] + in_kwargs = False + kwargs = {} + for name, value in d.items(): + if in_kwargs: + kwargs[name] = value + elif name == self.v_args_name: + args_ += value + in_kwargs = True + else: + args_.append(value) + return self.raw_function(*args_, **kwargs, **var_kwargs) + elif self.positional_only_args: + args_ = [] + kwargs = {} + for name, value in d.items(): + if name in self.positional_only_args: + args_.append(value) + else: + kwargs[name] = value + return self.raw_function(*args_, **kwargs, **var_kwargs) + else: + return self.raw_function(**d, **var_kwargs) + + def create_model(self, fields: Dict[str, Any], takes_args: bool, takes_kwargs: bool, config: 'ConfigType') -> None: + pos_args = len(self.arg_mapping) + + class CustomConfig: + pass + + if not TYPE_CHECKING: # pragma: no branch + if isinstance(config, dict): + CustomConfig = type('Config', (), config) # noqa: F811 + elif config is not None: + CustomConfig = config # noqa: F811 + + if hasattr(CustomConfig, 'fields') or hasattr(CustomConfig, 'alias_generator'): + raise ConfigError( + 'Setting the "fields" and "alias_generator" property on custom Config for ' + '@validate_arguments is not yet supported, please remove.' + ) + + class DecoratorBaseModel(BaseModel): + @validator(self.v_args_name, check_fields=False, allow_reuse=True) + def check_args(cls, v: Optional[List[Any]]) -> Optional[List[Any]]: + if takes_args or v is None: + return v + + raise TypeError(f'{pos_args} positional arguments expected but {pos_args + len(v)} given') + + @validator(self.v_kwargs_name, check_fields=False, allow_reuse=True) + def check_kwargs(cls, v: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: + if takes_kwargs or v is None: + return v + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v.keys())) + raise TypeError(f'unexpected keyword argument{plural}: {keys}') + + @validator(V_POSITIONAL_ONLY_NAME, check_fields=False, allow_reuse=True) + def check_positional_only(cls, v: Optional[List[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}') + + @validator(V_DUPLICATE_KWARGS, check_fields=False, allow_reuse=True) + def check_duplicate_kwargs(cls, v: Optional[List[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'multiple values for argument{plural}: {keys}') + + class Config(CustomConfig): + extra = getattr(CustomConfig, 'extra', Extra.forbid) + + self.model = create_model(to_camel(self.raw_function.__name__), __base__=DecoratorBaseModel, **fields) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/env_settings.py b/backend/venv/Lib/site-packages/pydantic/v1/env_settings.py new file mode 100644 index 0000000..5f6f217 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/env_settings.py @@ -0,0 +1,350 @@ +import os +import warnings +from pathlib import Path +from typing import AbstractSet, Any, Callable, ClassVar, Dict, List, Mapping, Optional, Tuple, Type, Union + +from pydantic.v1.config import BaseConfig, Extra +from pydantic.v1.fields import ModelField +from pydantic.v1.main import BaseModel +from pydantic.v1.types import JsonWrapper +from pydantic.v1.typing import StrPath, display_as_type, get_origin, is_union +from pydantic.v1.utils import deep_update, lenient_issubclass, path_type, sequence_like + +env_file_sentinel = str(object()) + +SettingsSourceCallable = Callable[['BaseSettings'], Dict[str, Any]] +DotenvType = Union[StrPath, List[StrPath], Tuple[StrPath, ...]] + + +class SettingsError(ValueError): + pass + + +class BaseSettings(BaseModel): + """ + Base class for settings, allowing values to be overridden by environment variables. + + This is useful in production for secrets you do not wish to save in code, it plays nicely with docker(-compose), + Heroku and any 12 factor app design. + """ + + def __init__( + __pydantic_self__, + _env_file: Optional[DotenvType] = env_file_sentinel, + _env_file_encoding: Optional[str] = None, + _env_nested_delimiter: Optional[str] = None, + _secrets_dir: Optional[StrPath] = None, + **values: Any, + ) -> None: + # Uses something other than `self` the first arg to allow "self" as a settable attribute + super().__init__( + **__pydantic_self__._build_values( + values, + _env_file=_env_file, + _env_file_encoding=_env_file_encoding, + _env_nested_delimiter=_env_nested_delimiter, + _secrets_dir=_secrets_dir, + ) + ) + + def _build_values( + self, + init_kwargs: Dict[str, Any], + _env_file: Optional[DotenvType] = None, + _env_file_encoding: Optional[str] = None, + _env_nested_delimiter: Optional[str] = None, + _secrets_dir: Optional[StrPath] = None, + ) -> Dict[str, Any]: + # Configure built-in sources + init_settings = InitSettingsSource(init_kwargs=init_kwargs) + env_settings = EnvSettingsSource( + env_file=(_env_file if _env_file != env_file_sentinel else self.__config__.env_file), + env_file_encoding=( + _env_file_encoding if _env_file_encoding is not None else self.__config__.env_file_encoding + ), + env_nested_delimiter=( + _env_nested_delimiter if _env_nested_delimiter is not None else self.__config__.env_nested_delimiter + ), + env_prefix_len=len(self.__config__.env_prefix), + ) + file_secret_settings = SecretsSettingsSource(secrets_dir=_secrets_dir or self.__config__.secrets_dir) + # Provide a hook to set built-in sources priority and add / remove sources + sources = self.__config__.customise_sources( + init_settings=init_settings, env_settings=env_settings, file_secret_settings=file_secret_settings + ) + if sources: + return deep_update(*reversed([source(self) for source in sources])) + else: + # no one should mean to do this, but I think returning an empty dict is marginally preferable + # to an informative error and much better than a confusing error + return {} + + class Config(BaseConfig): + env_prefix: str = '' + env_file: Optional[DotenvType] = None + env_file_encoding: Optional[str] = None + env_nested_delimiter: Optional[str] = None + secrets_dir: Optional[StrPath] = None + validate_all: bool = True + extra: Extra = Extra.forbid + arbitrary_types_allowed: bool = True + case_sensitive: bool = False + + @classmethod + def prepare_field(cls, field: ModelField) -> None: + env_names: Union[List[str], AbstractSet[str]] + field_info_from_config = cls.get_field_info(field.name) + + env = field_info_from_config.get('env') or field.field_info.extra.get('env') + if env is None: + if field.has_alias: + warnings.warn( + 'aliases are no longer used by BaseSettings to define which environment variables to read. ' + 'Instead use the "env" field setting. ' + 'See https://pydantic-docs.helpmanual.io/usage/settings/#environment-variable-names', + FutureWarning, + ) + env_names = {cls.env_prefix + field.name} + elif isinstance(env, str): + env_names = {env} + elif isinstance(env, (set, frozenset)): + env_names = env + elif sequence_like(env): + env_names = list(env) + else: + raise TypeError(f'invalid field env: {env!r} ({display_as_type(env)}); should be string, list or set') + + if not cls.case_sensitive: + env_names = env_names.__class__(n.lower() for n in env_names) + field.field_info.extra['env_names'] = env_names + + @classmethod + def customise_sources( + cls, + init_settings: SettingsSourceCallable, + env_settings: SettingsSourceCallable, + file_secret_settings: SettingsSourceCallable, + ) -> Tuple[SettingsSourceCallable, ...]: + return init_settings, env_settings, file_secret_settings + + @classmethod + def parse_env_var(cls, field_name: str, raw_val: str) -> Any: + return cls.json_loads(raw_val) + + # populated by the metaclass using the Config class defined above, annotated here to help IDEs only + __config__: ClassVar[Type[Config]] + + +class InitSettingsSource: + __slots__ = ('init_kwargs',) + + def __init__(self, init_kwargs: Dict[str, Any]): + self.init_kwargs = init_kwargs + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: + return self.init_kwargs + + def __repr__(self) -> str: + return f'InitSettingsSource(init_kwargs={self.init_kwargs!r})' + + +class EnvSettingsSource: + __slots__ = ('env_file', 'env_file_encoding', 'env_nested_delimiter', 'env_prefix_len') + + def __init__( + self, + env_file: Optional[DotenvType], + env_file_encoding: Optional[str], + env_nested_delimiter: Optional[str] = None, + env_prefix_len: int = 0, + ): + self.env_file: Optional[DotenvType] = env_file + self.env_file_encoding: Optional[str] = env_file_encoding + self.env_nested_delimiter: Optional[str] = env_nested_delimiter + self.env_prefix_len: int = env_prefix_len + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: # noqa C901 + """ + Build environment variables suitable for passing to the Model. + """ + d: Dict[str, Any] = {} + + if settings.__config__.case_sensitive: + env_vars: Mapping[str, Optional[str]] = os.environ + else: + env_vars = {k.lower(): v for k, v in os.environ.items()} + + dotenv_vars = self._read_env_files(settings.__config__.case_sensitive) + if dotenv_vars: + env_vars = {**dotenv_vars, **env_vars} + + for field in settings.__fields__.values(): + env_val: Optional[str] = None + for env_name in field.field_info.extra['env_names']: + env_val = env_vars.get(env_name) + if env_val is not None: + break + + is_complex, allow_parse_failure = self.field_is_complex(field) + if is_complex: + if env_val is None: + # field is complex but no value found so far, try explode_env_vars + env_val_built = self.explode_env_vars(field, env_vars) + if env_val_built: + d[field.alias] = env_val_built + else: + # field is complex and there's a value, decode that as JSON, then add explode_env_vars + try: + env_val = settings.__config__.parse_env_var(field.name, env_val) + except ValueError as e: + if not allow_parse_failure: + raise SettingsError(f'error parsing env var "{env_name}"') from e + + if isinstance(env_val, dict): + d[field.alias] = deep_update(env_val, self.explode_env_vars(field, env_vars)) + else: + d[field.alias] = env_val + elif env_val is not None: + # simplest case, field is not complex, we only need to add the value if it was found + d[field.alias] = env_val + + return d + + def _read_env_files(self, case_sensitive: bool) -> Dict[str, Optional[str]]: + env_files = self.env_file + if env_files is None: + return {} + + if isinstance(env_files, (str, os.PathLike)): + env_files = [env_files] + + dotenv_vars = {} + for env_file in env_files: + env_path = Path(env_file).expanduser() + if env_path.is_file(): + dotenv_vars.update( + read_env_file(env_path, encoding=self.env_file_encoding, case_sensitive=case_sensitive) + ) + + return dotenv_vars + + def field_is_complex(self, field: ModelField) -> Tuple[bool, bool]: + """ + Find out if a field is complex, and if so whether JSON errors should be ignored + """ + if lenient_issubclass(field.annotation, JsonWrapper): + return False, False + + if field.is_complex(): + allow_parse_failure = False + elif is_union(get_origin(field.type_)) and field.sub_fields and any(f.is_complex() for f in field.sub_fields): + allow_parse_failure = True + else: + return False, False + + return True, allow_parse_failure + + def explode_env_vars(self, field: ModelField, env_vars: Mapping[str, Optional[str]]) -> Dict[str, Any]: + """ + Process env_vars and extract the values of keys containing env_nested_delimiter into nested dictionaries. + + This is applied to a single field, hence filtering by env_var prefix. + """ + prefixes = [f'{env_name}{self.env_nested_delimiter}' for env_name in field.field_info.extra['env_names']] + result: Dict[str, Any] = {} + for env_name, env_val in env_vars.items(): + if not any(env_name.startswith(prefix) for prefix in prefixes): + continue + # we remove the prefix before splitting in case the prefix has characters in common with the delimiter + env_name_without_prefix = env_name[self.env_prefix_len :] + _, *keys, last_key = env_name_without_prefix.split(self.env_nested_delimiter) + env_var = result + for key in keys: + env_var = env_var.setdefault(key, {}) + env_var[last_key] = env_val + + return result + + def __repr__(self) -> str: + return ( + f'EnvSettingsSource(env_file={self.env_file!r}, env_file_encoding={self.env_file_encoding!r}, ' + f'env_nested_delimiter={self.env_nested_delimiter!r})' + ) + + +class SecretsSettingsSource: + __slots__ = ('secrets_dir',) + + def __init__(self, secrets_dir: Optional[StrPath]): + self.secrets_dir: Optional[StrPath] = secrets_dir + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: + """ + Build fields from "secrets" files. + """ + secrets: Dict[str, Optional[str]] = {} + + if self.secrets_dir is None: + return secrets + + secrets_path = Path(self.secrets_dir).expanduser() + + if not secrets_path.exists(): + warnings.warn(f'directory "{secrets_path}" does not exist') + return secrets + + if not secrets_path.is_dir(): + raise SettingsError(f'secrets_dir must reference a directory, not a {path_type(secrets_path)}') + + for field in settings.__fields__.values(): + for env_name in field.field_info.extra['env_names']: + path = find_case_path(secrets_path, env_name, settings.__config__.case_sensitive) + if not path: + # path does not exist, we currently don't return a warning for this + continue + + if path.is_file(): + secret_value = path.read_text().strip() + if field.is_complex(): + try: + secret_value = settings.__config__.parse_env_var(field.name, secret_value) + except ValueError as e: + raise SettingsError(f'error parsing env var "{env_name}"') from e + + secrets[field.alias] = secret_value + else: + warnings.warn( + f'attempted to load secret file "{path}" but found a {path_type(path)} instead.', + stacklevel=4, + ) + return secrets + + def __repr__(self) -> str: + return f'SecretsSettingsSource(secrets_dir={self.secrets_dir!r})' + + +def read_env_file( + file_path: StrPath, *, encoding: str = None, case_sensitive: bool = False +) -> Dict[str, Optional[str]]: + try: + from dotenv import dotenv_values + except ImportError as e: + raise ImportError('python-dotenv is not installed, run `pip install pydantic[dotenv]`') from e + + file_vars: Dict[str, Optional[str]] = dotenv_values(file_path, encoding=encoding or 'utf8') + if not case_sensitive: + return {k.lower(): v for k, v in file_vars.items()} + else: + return file_vars + + +def find_case_path(dir_path: Path, file_name: str, case_sensitive: bool) -> Optional[Path]: + """ + Find a file within path's directory matching filename, optionally ignoring case. + """ + for f in dir_path.iterdir(): + if f.name == file_name: + return f + elif not case_sensitive and f.name.lower() == file_name.lower(): + return f + return None diff --git a/backend/venv/Lib/site-packages/pydantic/v1/error_wrappers.py b/backend/venv/Lib/site-packages/pydantic/v1/error_wrappers.py new file mode 100644 index 0000000..bc7f263 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/error_wrappers.py @@ -0,0 +1,161 @@ +import json +from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Sequence, Tuple, Type, Union + +from pydantic.v1.json import pydantic_encoder +from pydantic.v1.utils import Representation + +if TYPE_CHECKING: + from typing_extensions import TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import ReprArgs + + Loc = Tuple[Union[int, str], ...] + + class _ErrorDictRequired(TypedDict): + loc: Loc + msg: str + type: str + + class ErrorDict(_ErrorDictRequired, total=False): + ctx: Dict[str, Any] + + +__all__ = 'ErrorWrapper', 'ValidationError' + + +class ErrorWrapper(Representation): + __slots__ = 'exc', '_loc' + + def __init__(self, exc: Exception, loc: Union[str, 'Loc']) -> None: + self.exc = exc + self._loc = loc + + def loc_tuple(self) -> 'Loc': + if isinstance(self._loc, tuple): + return self._loc + else: + return (self._loc,) + + def __repr_args__(self) -> 'ReprArgs': + return [('exc', self.exc), ('loc', self.loc_tuple())] + + +# ErrorList is something like Union[List[Union[List[ErrorWrapper], ErrorWrapper]], ErrorWrapper] +# but recursive, therefore just use: +ErrorList = Union[Sequence[Any], ErrorWrapper] + + +class ValidationError(Representation, ValueError): + __slots__ = 'raw_errors', 'model', '_error_cache' + + def __init__(self, errors: Sequence[ErrorList], model: 'ModelOrDc') -> None: + self.raw_errors = errors + self.model = model + self._error_cache: Optional[List['ErrorDict']] = None + + def errors(self) -> List['ErrorDict']: + if self._error_cache is None: + try: + config = self.model.__config__ # type: ignore + except AttributeError: + config = self.model.__pydantic_model__.__config__ # type: ignore + self._error_cache = list(flatten_errors(self.raw_errors, config)) + return self._error_cache + + def json(self, *, indent: Union[None, int, str] = 2) -> str: + return json.dumps(self.errors(), indent=indent, default=pydantic_encoder) + + def __str__(self) -> str: + errors = self.errors() + no_errors = len(errors) + return ( + f'{no_errors} validation error{"" if no_errors == 1 else "s"} for {self.model.__name__}\n' + f'{display_errors(errors)}' + ) + + def __repr_args__(self) -> 'ReprArgs': + return [('model', self.model.__name__), ('errors', self.errors())] + + +def display_errors(errors: List['ErrorDict']) -> str: + return '\n'.join(f'{_display_error_loc(e)}\n {e["msg"]} ({_display_error_type_and_ctx(e)})' for e in errors) + + +def _display_error_loc(error: 'ErrorDict') -> str: + return ' -> '.join(str(e) for e in error['loc']) + + +def _display_error_type_and_ctx(error: 'ErrorDict') -> str: + t = 'type=' + error['type'] + ctx = error.get('ctx') + if ctx: + return t + ''.join(f'; {k}={v}' for k, v in ctx.items()) + else: + return t + + +def flatten_errors( + errors: Sequence[Any], config: Type['BaseConfig'], loc: Optional['Loc'] = None +) -> Generator['ErrorDict', None, None]: + for error in errors: + if isinstance(error, ErrorWrapper): + if loc: + error_loc = loc + error.loc_tuple() + else: + error_loc = error.loc_tuple() + + if isinstance(error.exc, ValidationError): + yield from flatten_errors(error.exc.raw_errors, config, error_loc) + else: + yield error_dict(error.exc, config, error_loc) + elif isinstance(error, list): + yield from flatten_errors(error, config, loc=loc) + else: + raise RuntimeError(f'Unknown error object: {error}') + + +def error_dict(exc: Exception, config: Type['BaseConfig'], loc: 'Loc') -> 'ErrorDict': + type_ = get_exc_type(exc.__class__) + msg_template = config.error_msg_templates.get(type_) or getattr(exc, 'msg_template', None) + ctx = exc.__dict__ + if msg_template: + msg = msg_template.format(**ctx) + else: + msg = str(exc) + + d: 'ErrorDict' = {'loc': loc, 'msg': msg, 'type': type_} + + if ctx: + d['ctx'] = ctx + + return d + + +_EXC_TYPE_CACHE: Dict[Type[Exception], str] = {} + + +def get_exc_type(cls: Type[Exception]) -> str: + # slightly more efficient than using lru_cache since we don't need to worry about the cache filling up + try: + return _EXC_TYPE_CACHE[cls] + except KeyError: + r = _get_exc_type(cls) + _EXC_TYPE_CACHE[cls] = r + return r + + +def _get_exc_type(cls: Type[Exception]) -> str: + if issubclass(cls, AssertionError): + return 'assertion_error' + + base_name = 'type_error' if issubclass(cls, TypeError) else 'value_error' + if cls in (TypeError, ValueError): + # just TypeError or ValueError, no extra code + return base_name + + # if it's not a TypeError or ValueError, we just take the lowercase of the exception name + # no chaining or snake case logic, use "code" for more complex error types. + code = getattr(cls, 'code', None) or cls.__name__.replace('Error', '').lower() + return base_name + '.' + code diff --git a/backend/venv/Lib/site-packages/pydantic/v1/errors.py b/backend/venv/Lib/site-packages/pydantic/v1/errors.py new file mode 100644 index 0000000..6e86442 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/errors.py @@ -0,0 +1,646 @@ +from decimal import Decimal +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, Sequence, Set, Tuple, Type, Union + +from pydantic.v1.typing import display_as_type + +if TYPE_CHECKING: + from pydantic.v1.typing import DictStrAny + +# explicitly state exports to avoid "from pydantic.v1.errors import *" also importing Decimal, Path etc. +__all__ = ( + 'PydanticTypeError', + 'PydanticValueError', + 'ConfigError', + 'MissingError', + 'ExtraError', + 'NoneIsNotAllowedError', + 'NoneIsAllowedError', + 'WrongConstantError', + 'NotNoneError', + 'BoolError', + 'BytesError', + 'DictError', + 'EmailError', + 'UrlError', + 'UrlSchemeError', + 'UrlSchemePermittedError', + 'UrlUserInfoError', + 'UrlHostError', + 'UrlHostTldError', + 'UrlPortError', + 'UrlExtraError', + 'EnumError', + 'IntEnumError', + 'EnumMemberError', + 'IntegerError', + 'FloatError', + 'PathError', + 'PathNotExistsError', + 'PathNotAFileError', + 'PathNotADirectoryError', + 'PyObjectError', + 'SequenceError', + 'ListError', + 'SetError', + 'FrozenSetError', + 'TupleError', + 'TupleLengthError', + 'ListMinLengthError', + 'ListMaxLengthError', + 'ListUniqueItemsError', + 'SetMinLengthError', + 'SetMaxLengthError', + 'FrozenSetMinLengthError', + 'FrozenSetMaxLengthError', + 'AnyStrMinLengthError', + 'AnyStrMaxLengthError', + 'StrError', + 'StrRegexError', + 'NumberNotGtError', + 'NumberNotGeError', + 'NumberNotLtError', + 'NumberNotLeError', + 'NumberNotMultipleError', + 'DecimalError', + 'DecimalIsNotFiniteError', + 'DecimalMaxDigitsError', + 'DecimalMaxPlacesError', + 'DecimalWholeDigitsError', + 'DateTimeError', + 'DateError', + 'DateNotInThePastError', + 'DateNotInTheFutureError', + 'TimeError', + 'DurationError', + 'HashableError', + 'UUIDError', + 'UUIDVersionError', + 'ArbitraryTypeError', + 'ClassError', + 'SubclassError', + 'JsonError', + 'JsonTypeError', + 'PatternError', + 'DataclassTypeError', + 'CallableError', + 'IPvAnyAddressError', + 'IPvAnyInterfaceError', + 'IPvAnyNetworkError', + 'IPv4AddressError', + 'IPv6AddressError', + 'IPv4NetworkError', + 'IPv6NetworkError', + 'IPv4InterfaceError', + 'IPv6InterfaceError', + 'ColorError', + 'StrictBoolError', + 'NotDigitError', + 'LuhnValidationError', + 'InvalidLengthForBrand', + 'InvalidByteSize', + 'InvalidByteSizeUnit', + 'MissingDiscriminator', + 'InvalidDiscriminator', +) + + +def cls_kwargs(cls: Type['PydanticErrorMixin'], ctx: 'DictStrAny') -> 'PydanticErrorMixin': + """ + For built-in exceptions like ValueError or TypeError, we need to implement + __reduce__ to override the default behaviour (instead of __getstate__/__setstate__) + By default pickle protocol 2 calls `cls.__new__(cls, *args)`. + Since we only use kwargs, we need a little constructor to change that. + Note: the callable can't be a lambda as pickle looks in the namespace to find it + """ + return cls(**ctx) + + +class PydanticErrorMixin: + code: str + msg_template: str + + def __init__(self, **ctx: Any) -> None: + self.__dict__ = ctx + + def __str__(self) -> str: + return self.msg_template.format(**self.__dict__) + + def __reduce__(self) -> Tuple[Callable[..., 'PydanticErrorMixin'], Tuple[Type['PydanticErrorMixin'], 'DictStrAny']]: + return cls_kwargs, (self.__class__, self.__dict__) + + +class PydanticTypeError(PydanticErrorMixin, TypeError): + pass + + +class PydanticValueError(PydanticErrorMixin, ValueError): + pass + + +class ConfigError(RuntimeError): + pass + + +class MissingError(PydanticValueError): + msg_template = 'field required' + + +class ExtraError(PydanticValueError): + msg_template = 'extra fields not permitted' + + +class NoneIsNotAllowedError(PydanticTypeError): + code = 'none.not_allowed' + msg_template = 'none is not an allowed value' + + +class NoneIsAllowedError(PydanticTypeError): + code = 'none.allowed' + msg_template = 'value is not none' + + +class WrongConstantError(PydanticValueError): + code = 'const' + + def __str__(self) -> str: + permitted = ', '.join(repr(v) for v in self.permitted) # type: ignore + return f'unexpected value; permitted: {permitted}' + + +class NotNoneError(PydanticTypeError): + code = 'not_none' + msg_template = 'value is not None' + + +class BoolError(PydanticTypeError): + msg_template = 'value could not be parsed to a boolean' + + +class BytesError(PydanticTypeError): + msg_template = 'byte type expected' + + +class DictError(PydanticTypeError): + msg_template = 'value is not a valid dict' + + +class EmailError(PydanticValueError): + msg_template = 'value is not a valid email address' + + +class UrlError(PydanticValueError): + code = 'url' + + +class UrlSchemeError(UrlError): + code = 'url.scheme' + msg_template = 'invalid or missing URL scheme' + + +class UrlSchemePermittedError(UrlError): + code = 'url.scheme' + msg_template = 'URL scheme not permitted' + + def __init__(self, allowed_schemes: Set[str]): + super().__init__(allowed_schemes=allowed_schemes) + + +class UrlUserInfoError(UrlError): + code = 'url.userinfo' + msg_template = 'userinfo required in URL but missing' + + +class UrlHostError(UrlError): + code = 'url.host' + msg_template = 'URL host invalid' + + +class UrlHostTldError(UrlError): + code = 'url.host' + msg_template = 'URL host invalid, top level domain required' + + +class UrlPortError(UrlError): + code = 'url.port' + msg_template = 'URL port invalid, port cannot exceed 65535' + + +class UrlExtraError(UrlError): + code = 'url.extra' + msg_template = 'URL invalid, extra characters found after valid URL: {extra!r}' + + +class EnumMemberError(PydanticTypeError): + code = 'enum' + + def __str__(self) -> str: + permitted = ', '.join(repr(v.value) for v in self.enum_values) # type: ignore + return f'value is not a valid enumeration member; permitted: {permitted}' + + +class IntegerError(PydanticTypeError): + msg_template = 'value is not a valid integer' + + +class FloatError(PydanticTypeError): + msg_template = 'value is not a valid float' + + +class PathError(PydanticTypeError): + msg_template = 'value is not a valid path' + + +class _PathValueError(PydanticValueError): + def __init__(self, *, path: Path) -> None: + super().__init__(path=str(path)) + + +class PathNotExistsError(_PathValueError): + code = 'path.not_exists' + msg_template = 'file or directory at path "{path}" does not exist' + + +class PathNotAFileError(_PathValueError): + code = 'path.not_a_file' + msg_template = 'path "{path}" does not point to a file' + + +class PathNotADirectoryError(_PathValueError): + code = 'path.not_a_directory' + msg_template = 'path "{path}" does not point to a directory' + + +class PyObjectError(PydanticTypeError): + msg_template = 'ensure this value contains valid import path or valid callable: {error_message}' + + +class SequenceError(PydanticTypeError): + msg_template = 'value is not a valid sequence' + + +class IterableError(PydanticTypeError): + msg_template = 'value is not a valid iterable' + + +class ListError(PydanticTypeError): + msg_template = 'value is not a valid list' + + +class SetError(PydanticTypeError): + msg_template = 'value is not a valid set' + + +class FrozenSetError(PydanticTypeError): + msg_template = 'value is not a valid frozenset' + + +class DequeError(PydanticTypeError): + msg_template = 'value is not a valid deque' + + +class TupleError(PydanticTypeError): + msg_template = 'value is not a valid tuple' + + +class TupleLengthError(PydanticValueError): + code = 'tuple.length' + msg_template = 'wrong tuple length {actual_length}, expected {expected_length}' + + def __init__(self, *, actual_length: int, expected_length: int) -> None: + super().__init__(actual_length=actual_length, expected_length=expected_length) + + +class ListMinLengthError(PydanticValueError): + code = 'list.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class ListMaxLengthError(PydanticValueError): + code = 'list.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class ListUniqueItemsError(PydanticValueError): + code = 'list.unique_items' + msg_template = 'the list has duplicated items' + + +class SetMinLengthError(PydanticValueError): + code = 'set.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class SetMaxLengthError(PydanticValueError): + code = 'set.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class FrozenSetMinLengthError(PydanticValueError): + code = 'frozenset.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class FrozenSetMaxLengthError(PydanticValueError): + code = 'frozenset.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class AnyStrMinLengthError(PydanticValueError): + code = 'any_str.min_length' + msg_template = 'ensure this value has at least {limit_value} characters' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class AnyStrMaxLengthError(PydanticValueError): + code = 'any_str.max_length' + msg_template = 'ensure this value has at most {limit_value} characters' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class StrError(PydanticTypeError): + msg_template = 'str type expected' + + +class StrRegexError(PydanticValueError): + code = 'str.regex' + msg_template = 'string does not match regex "{pattern}"' + + def __init__(self, *, pattern: str) -> None: + super().__init__(pattern=pattern) + + +class _NumberBoundError(PydanticValueError): + def __init__(self, *, limit_value: Union[int, float, Decimal]) -> None: + super().__init__(limit_value=limit_value) + + +class NumberNotGtError(_NumberBoundError): + code = 'number.not_gt' + msg_template = 'ensure this value is greater than {limit_value}' + + +class NumberNotGeError(_NumberBoundError): + code = 'number.not_ge' + msg_template = 'ensure this value is greater than or equal to {limit_value}' + + +class NumberNotLtError(_NumberBoundError): + code = 'number.not_lt' + msg_template = 'ensure this value is less than {limit_value}' + + +class NumberNotLeError(_NumberBoundError): + code = 'number.not_le' + msg_template = 'ensure this value is less than or equal to {limit_value}' + + +class NumberNotFiniteError(PydanticValueError): + code = 'number.not_finite_number' + msg_template = 'ensure this value is a finite number' + + +class NumberNotMultipleError(PydanticValueError): + code = 'number.not_multiple' + msg_template = 'ensure this value is a multiple of {multiple_of}' + + def __init__(self, *, multiple_of: Union[int, float, Decimal]) -> None: + super().__init__(multiple_of=multiple_of) + + +class DecimalError(PydanticTypeError): + msg_template = 'value is not a valid decimal' + + +class DecimalIsNotFiniteError(PydanticValueError): + code = 'decimal.not_finite' + msg_template = 'value is not a valid decimal' + + +class DecimalMaxDigitsError(PydanticValueError): + code = 'decimal.max_digits' + msg_template = 'ensure that there are no more than {max_digits} digits in total' + + def __init__(self, *, max_digits: int) -> None: + super().__init__(max_digits=max_digits) + + +class DecimalMaxPlacesError(PydanticValueError): + code = 'decimal.max_places' + msg_template = 'ensure that there are no more than {decimal_places} decimal places' + + def __init__(self, *, decimal_places: int) -> None: + super().__init__(decimal_places=decimal_places) + + +class DecimalWholeDigitsError(PydanticValueError): + code = 'decimal.whole_digits' + msg_template = 'ensure that there are no more than {whole_digits} digits before the decimal point' + + def __init__(self, *, whole_digits: int) -> None: + super().__init__(whole_digits=whole_digits) + + +class DateTimeError(PydanticValueError): + msg_template = 'invalid datetime format' + + +class DateError(PydanticValueError): + msg_template = 'invalid date format' + + +class DateNotInThePastError(PydanticValueError): + code = 'date.not_in_the_past' + msg_template = 'date is not in the past' + + +class DateNotInTheFutureError(PydanticValueError): + code = 'date.not_in_the_future' + msg_template = 'date is not in the future' + + +class TimeError(PydanticValueError): + msg_template = 'invalid time format' + + +class DurationError(PydanticValueError): + msg_template = 'invalid duration format' + + +class HashableError(PydanticTypeError): + msg_template = 'value is not a valid hashable' + + +class UUIDError(PydanticTypeError): + msg_template = 'value is not a valid uuid' + + +class UUIDVersionError(PydanticValueError): + code = 'uuid.version' + msg_template = 'uuid version {required_version} expected' + + def __init__(self, *, required_version: int) -> None: + super().__init__(required_version=required_version) + + +class ArbitraryTypeError(PydanticTypeError): + code = 'arbitrary_type' + msg_template = 'instance of {expected_arbitrary_type} expected' + + def __init__(self, *, expected_arbitrary_type: Type[Any]) -> None: + super().__init__(expected_arbitrary_type=display_as_type(expected_arbitrary_type)) + + +class ClassError(PydanticTypeError): + code = 'class' + msg_template = 'a class is expected' + + +class SubclassError(PydanticTypeError): + code = 'subclass' + msg_template = 'subclass of {expected_class} expected' + + def __init__(self, *, expected_class: Type[Any]) -> None: + super().__init__(expected_class=display_as_type(expected_class)) + + +class JsonError(PydanticValueError): + msg_template = 'Invalid JSON' + + +class JsonTypeError(PydanticTypeError): + code = 'json' + msg_template = 'JSON object must be str, bytes or bytearray' + + +class PatternError(PydanticValueError): + code = 'regex_pattern' + msg_template = 'Invalid regular expression' + + +class DataclassTypeError(PydanticTypeError): + code = 'dataclass' + msg_template = 'instance of {class_name}, tuple or dict expected' + + +class CallableError(PydanticTypeError): + msg_template = '{value} is not callable' + + +class EnumError(PydanticTypeError): + code = 'enum_instance' + msg_template = '{value} is not a valid Enum instance' + + +class IntEnumError(PydanticTypeError): + code = 'int_enum_instance' + msg_template = '{value} is not a valid IntEnum instance' + + +class IPvAnyAddressError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 address' + + +class IPvAnyInterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 interface' + + +class IPvAnyNetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 network' + + +class IPv4AddressError(PydanticValueError): + msg_template = 'value is not a valid IPv4 address' + + +class IPv6AddressError(PydanticValueError): + msg_template = 'value is not a valid IPv6 address' + + +class IPv4NetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv4 network' + + +class IPv6NetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv6 network' + + +class IPv4InterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv4 interface' + + +class IPv6InterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv6 interface' + + +class ColorError(PydanticValueError): + msg_template = 'value is not a valid color: {reason}' + + +class StrictBoolError(PydanticValueError): + msg_template = 'value is not a valid boolean' + + +class NotDigitError(PydanticValueError): + code = 'payment_card_number.digits' + msg_template = 'card number is not all digits' + + +class LuhnValidationError(PydanticValueError): + code = 'payment_card_number.luhn_check' + msg_template = 'card number is not luhn valid' + + +class InvalidLengthForBrand(PydanticValueError): + code = 'payment_card_number.invalid_length_for_brand' + msg_template = 'Length for a {brand} card must be {required_length}' + + +class InvalidByteSize(PydanticValueError): + msg_template = 'could not parse value and unit from byte string' + + +class InvalidByteSizeUnit(PydanticValueError): + msg_template = 'could not interpret byte unit: {unit}' + + +class MissingDiscriminator(PydanticValueError): + code = 'discriminated_union.missing_discriminator' + msg_template = 'Discriminator {discriminator_key!r} is missing in value' + + +class InvalidDiscriminator(PydanticValueError): + code = 'discriminated_union.invalid_discriminator' + msg_template = ( + 'No match for discriminator {discriminator_key!r} and value {discriminator_value!r} ' + '(allowed values: {allowed_values})' + ) + + def __init__(self, *, discriminator_key: str, discriminator_value: Any, allowed_values: Sequence[Any]) -> None: + super().__init__( + discriminator_key=discriminator_key, + discriminator_value=discriminator_value, + allowed_values=', '.join(map(repr, allowed_values)), + ) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/fields.py b/backend/venv/Lib/site-packages/pydantic/v1/fields.py new file mode 100644 index 0000000..002b60c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/fields.py @@ -0,0 +1,1253 @@ +import copy +import re +from collections import Counter as CollectionCounter, defaultdict, deque +from collections.abc import Callable, Hashable as CollectionsHashable, Iterable as CollectionsIterable +from typing import ( + TYPE_CHECKING, + Any, + Counter, + DefaultDict, + Deque, + Dict, + ForwardRef, + FrozenSet, + Generator, + Iterable, + Iterator, + List, + Mapping, + Optional, + Pattern, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from typing_extensions import Annotated, Final + +from pydantic.v1 import errors as errors_ +from pydantic.v1.class_validators import Validator, make_generic_validator, prep_validators +from pydantic.v1.error_wrappers import ErrorWrapper +from pydantic.v1.errors import ConfigError, InvalidDiscriminator, MissingDiscriminator, NoneIsNotAllowedError +from pydantic.v1.types import Json, JsonWrapper +from pydantic.v1.typing import ( + NoArgAnyCallable, + convert_generics, + display_as_type, + get_args, + get_origin, + is_finalvar, + is_literal_type, + is_new_type, + is_none_type, + is_typeddict, + is_typeddict_special, + is_union, + new_type_supertype, +) +from pydantic.v1.utils import ( + PyObjectStr, + Representation, + ValueItems, + get_discriminator_alias_and_values, + get_unique_discriminator_alias, + lenient_isinstance, + lenient_issubclass, + sequence_like, + smart_deepcopy, +) +from pydantic.v1.validators import constant_validator, dict_validator, find_validators, validate_json + +Required: Any = Ellipsis + +T = TypeVar('T') + + +class UndefinedType: + def __repr__(self) -> str: + return 'PydanticUndefined' + + def __copy__(self: T) -> T: + return self + + def __reduce__(self) -> str: + return 'Undefined' + + def __deepcopy__(self: T, _: Any) -> T: + return self + + +Undefined = UndefinedType() + +if TYPE_CHECKING: + from pydantic.v1.class_validators import ValidatorsList + from pydantic.v1.config import BaseConfig + from pydantic.v1.error_wrappers import ErrorList + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import AbstractSetIntStr, MappingIntStrAny, ReprArgs + + ValidateReturn = Tuple[Optional[Any], Optional[ErrorList]] + LocStr = Union[Tuple[Union[int, str], ...], str] + BoolUndefined = Union[bool, UndefinedType] + + +class FieldInfo(Representation): + """ + Captures extra information about a field. + """ + + __slots__ = ( + 'default', + 'default_factory', + 'alias', + 'alias_priority', + 'title', + 'description', + 'exclude', + 'include', + 'const', + 'gt', + 'ge', + 'lt', + 'le', + 'multiple_of', + 'allow_inf_nan', + 'max_digits', + 'decimal_places', + 'min_items', + 'max_items', + 'unique_items', + 'min_length', + 'max_length', + 'allow_mutation', + 'repr', + 'regex', + 'discriminator', + 'extra', + ) + + # field constraints with the default value, it's also used in update_from_config below + __field_constraints__ = { + 'min_length': None, + 'max_length': None, + 'regex': None, + 'gt': None, + 'lt': None, + 'ge': None, + 'le': None, + 'multiple_of': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'min_items': None, + 'max_items': None, + 'unique_items': None, + 'allow_mutation': True, + } + + def __init__(self, default: Any = Undefined, **kwargs: Any) -> None: + self.default = default + self.default_factory = kwargs.pop('default_factory', None) + self.alias = kwargs.pop('alias', None) + self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias is not None else None) + self.title = kwargs.pop('title', None) + self.description = kwargs.pop('description', None) + self.exclude = kwargs.pop('exclude', None) + self.include = kwargs.pop('include', None) + self.const = kwargs.pop('const', None) + self.gt = kwargs.pop('gt', None) + self.ge = kwargs.pop('ge', None) + self.lt = kwargs.pop('lt', None) + self.le = kwargs.pop('le', None) + self.multiple_of = kwargs.pop('multiple_of', None) + self.allow_inf_nan = kwargs.pop('allow_inf_nan', None) + self.max_digits = kwargs.pop('max_digits', None) + self.decimal_places = kwargs.pop('decimal_places', None) + self.min_items = kwargs.pop('min_items', None) + self.max_items = kwargs.pop('max_items', None) + self.unique_items = kwargs.pop('unique_items', None) + self.min_length = kwargs.pop('min_length', None) + self.max_length = kwargs.pop('max_length', None) + self.allow_mutation = kwargs.pop('allow_mutation', True) + self.regex = kwargs.pop('regex', None) + self.discriminator = kwargs.pop('discriminator', None) + self.repr = kwargs.pop('repr', True) + self.extra = kwargs + + def __repr_args__(self) -> 'ReprArgs': + field_defaults_to_hide: Dict[str, Any] = { + 'repr': True, + **self.__field_constraints__, + } + + attrs = ((s, getattr(self, s)) for s in self.__slots__) + return [(a, v) for a, v in attrs if v != field_defaults_to_hide.get(a, None)] + + def get_constraints(self) -> Set[str]: + """ + Gets the constraints set on the field by comparing the constraint value with its default value + + :return: the constraints set on field_info + """ + return {attr for attr, default in self.__field_constraints__.items() if getattr(self, attr) != default} + + def update_from_config(self, from_config: Dict[str, Any]) -> None: + """ + Update this FieldInfo based on a dict from get_field_info, only fields which have not been set are dated. + """ + for attr_name, value in from_config.items(): + try: + current_value = getattr(self, attr_name) + except AttributeError: + # attr_name is not an attribute of FieldInfo, it should therefore be added to extra + # (except if extra already has this value!) + self.extra.setdefault(attr_name, value) + else: + if current_value is self.__field_constraints__.get(attr_name, None): + setattr(self, attr_name, value) + elif attr_name == 'exclude': + self.exclude = ValueItems.merge(value, current_value) + elif attr_name == 'include': + self.include = ValueItems.merge(value, current_value, intersect=True) + + def _validate(self) -> None: + if self.default is not Undefined and self.default_factory is not None: + raise ValueError('cannot specify both default and default_factory') + + +def Field( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, + alias: Optional[str] = None, + title: Optional[str] = None, + description: Optional[str] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny', Any]] = None, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny', Any]] = None, + const: Optional[bool] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + multiple_of: Optional[float] = None, + allow_inf_nan: Optional[bool] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + min_items: Optional[int] = None, + max_items: Optional[int] = None, + unique_items: Optional[bool] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + allow_mutation: bool = True, + regex: Optional[str] = None, + discriminator: Optional[str] = None, + repr: bool = True, + **extra: Any, +) -> Any: + """ + Used to provide extra information about a field, either for the model schema or complex validation. Some arguments + apply only to number fields (``int``, ``float``, ``Decimal``) and some apply only to ``str``. + + :param default: since this is replacing the field’s default, its first argument is used + to set the default, use ellipsis (``...``) to indicate the field is required + :param default_factory: callable that will be called when a default value is needed for this field + If both `default` and `default_factory` are set, an error is raised. + :param alias: the public name of the field + :param title: can be any string, used in the schema + :param description: can be any string, used in the schema + :param exclude: exclude this field while dumping. + Takes same values as the ``include`` and ``exclude`` arguments on the ``.dict`` method. + :param include: include this field while dumping. + Takes same values as the ``include`` and ``exclude`` arguments on the ``.dict`` method. + :param const: this field is required and *must* take it's default value + :param gt: only applies to numbers, requires the field to be "greater than". The schema + will have an ``exclusiveMinimum`` validation keyword + :param ge: only applies to numbers, requires the field to be "greater than or equal to". The + schema will have a ``minimum`` validation keyword + :param lt: only applies to numbers, requires the field to be "less than". The schema + will have an ``exclusiveMaximum`` validation keyword + :param le: only applies to numbers, requires the field to be "less than or equal to". The + schema will have a ``maximum`` validation keyword + :param multiple_of: only applies to numbers, requires the field to be "a multiple of". The + schema will have a ``multipleOf`` validation keyword + :param allow_inf_nan: only applies to numbers, allows the field to be NaN or infinity (+inf or -inf), + which is a valid Python float. Default True, set to False for compatibility with JSON. + :param max_digits: only applies to Decimals, requires the field to have a maximum number + of digits within the decimal. It does not include a zero before the decimal point or trailing decimal zeroes. + :param decimal_places: only applies to Decimals, requires the field to have at most a number of decimal places + allowed. It does not include trailing decimal zeroes. + :param min_items: only applies to lists, requires the field to have a minimum number of + elements. The schema will have a ``minItems`` validation keyword + :param max_items: only applies to lists, requires the field to have a maximum number of + elements. The schema will have a ``maxItems`` validation keyword + :param unique_items: only applies to lists, requires the field not to have duplicated + elements. The schema will have a ``uniqueItems`` validation keyword + :param min_length: only applies to strings, requires the field to have a minimum length. The + schema will have a ``minLength`` validation keyword + :param max_length: only applies to strings, requires the field to have a maximum length. The + schema will have a ``maxLength`` validation keyword + :param allow_mutation: a boolean which defaults to True. When False, the field raises a TypeError if the field is + assigned on an instance. The BaseModel Config must set validate_assignment to True + :param regex: only applies to strings, requires the field match against a regular expression + pattern string. The schema will have a ``pattern`` validation keyword + :param discriminator: only useful with a (discriminated a.k.a. tagged) `Union` of sub models with a common field. + The `discriminator` is the name of this common field to shorten validation and improve generated schema + :param repr: show this field in the representation + :param **extra: any additional keyword arguments will be added as is to the schema + """ + field_info = FieldInfo( + default, + default_factory=default_factory, + alias=alias, + title=title, + description=description, + exclude=exclude, + include=include, + const=const, + gt=gt, + ge=ge, + lt=lt, + le=le, + multiple_of=multiple_of, + allow_inf_nan=allow_inf_nan, + max_digits=max_digits, + decimal_places=decimal_places, + min_items=min_items, + max_items=max_items, + unique_items=unique_items, + min_length=min_length, + max_length=max_length, + allow_mutation=allow_mutation, + regex=regex, + discriminator=discriminator, + repr=repr, + **extra, + ) + field_info._validate() + return field_info + + +# used to be an enum but changed to int's for small performance improvement as less access overhead +SHAPE_SINGLETON = 1 +SHAPE_LIST = 2 +SHAPE_SET = 3 +SHAPE_MAPPING = 4 +SHAPE_TUPLE = 5 +SHAPE_TUPLE_ELLIPSIS = 6 +SHAPE_SEQUENCE = 7 +SHAPE_FROZENSET = 8 +SHAPE_ITERABLE = 9 +SHAPE_GENERIC = 10 +SHAPE_DEQUE = 11 +SHAPE_DICT = 12 +SHAPE_DEFAULTDICT = 13 +SHAPE_COUNTER = 14 +SHAPE_NAME_LOOKUP = { + SHAPE_LIST: 'List[{}]', + SHAPE_SET: 'Set[{}]', + SHAPE_TUPLE_ELLIPSIS: 'Tuple[{}, ...]', + SHAPE_SEQUENCE: 'Sequence[{}]', + SHAPE_FROZENSET: 'FrozenSet[{}]', + SHAPE_ITERABLE: 'Iterable[{}]', + SHAPE_DEQUE: 'Deque[{}]', + SHAPE_DICT: 'Dict[{}]', + SHAPE_DEFAULTDICT: 'DefaultDict[{}]', + SHAPE_COUNTER: 'Counter[{}]', +} + +MAPPING_LIKE_SHAPES: Set[int] = {SHAPE_DEFAULTDICT, SHAPE_DICT, SHAPE_MAPPING, SHAPE_COUNTER} + + +class ModelField(Representation): + __slots__ = ( + 'type_', + 'outer_type_', + 'annotation', + 'sub_fields', + 'sub_fields_mapping', + 'key_field', + 'validators', + 'pre_validators', + 'post_validators', + 'default', + 'default_factory', + 'required', + 'final', + 'model_config', + 'name', + 'alias', + 'has_alias', + 'field_info', + 'discriminator_key', + 'discriminator_alias', + 'validate_always', + 'allow_none', + 'shape', + 'class_validators', + 'parse_json', + ) + + def __init__( + self, + *, + name: str, + type_: Type[Any], + class_validators: Optional[Dict[str, Validator]], + model_config: Type['BaseConfig'], + default: Any = None, + default_factory: Optional[NoArgAnyCallable] = None, + required: 'BoolUndefined' = Undefined, + final: bool = False, + alias: Optional[str] = None, + field_info: Optional[FieldInfo] = None, + ) -> None: + self.name: str = name + self.has_alias: bool = alias is not None + self.alias: str = alias if alias is not None else name + self.annotation = type_ + self.type_: Any = convert_generics(type_) + self.outer_type_: Any = type_ + self.class_validators = class_validators or {} + self.default: Any = default + self.default_factory: Optional[NoArgAnyCallable] = default_factory + self.required: 'BoolUndefined' = required + self.final: bool = final + self.model_config = model_config + self.field_info: FieldInfo = field_info or FieldInfo(default) + self.discriminator_key: Optional[str] = self.field_info.discriminator + self.discriminator_alias: Optional[str] = self.discriminator_key + + self.allow_none: bool = False + self.validate_always: bool = False + self.sub_fields: Optional[List[ModelField]] = None + self.sub_fields_mapping: Optional[Dict[str, 'ModelField']] = None # used for discriminated union + self.key_field: Optional[ModelField] = None + self.validators: 'ValidatorsList' = [] + self.pre_validators: Optional['ValidatorsList'] = None + self.post_validators: Optional['ValidatorsList'] = None + self.parse_json: bool = False + self.shape: int = SHAPE_SINGLETON + self.model_config.prepare_field(self) + self.prepare() + + def get_default(self) -> Any: + return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() + + @staticmethod + def _get_field_info( + field_name: str, annotation: Any, value: Any, config: Type['BaseConfig'] + ) -> Tuple[FieldInfo, Any]: + """ + Get a FieldInfo from a root typing.Annotated annotation, value, or config default. + + The FieldInfo may be set in typing.Annotated or the value, but not both. If neither contain + a FieldInfo, a new one will be created using the config. + + :param field_name: name of the field for use in error messages + :param annotation: a type hint such as `str` or `Annotated[str, Field(..., min_length=5)]` + :param value: the field's assigned value + :param config: the model's config object + :return: the FieldInfo contained in the `annotation`, the value, or a new one from the config. + """ + field_info_from_config = config.get_field_info(field_name) + + field_info = None + if get_origin(annotation) is Annotated: + field_infos = [arg for arg in get_args(annotation)[1:] if isinstance(arg, FieldInfo)] + if len(field_infos) > 1: + raise ValueError(f'cannot specify multiple `Annotated` `Field`s for {field_name!r}') + field_info = next(iter(field_infos), None) + if field_info is not None: + field_info = copy.copy(field_info) + field_info.update_from_config(field_info_from_config) + if field_info.default not in (Undefined, Required): + raise ValueError(f'`Field` default cannot be set in `Annotated` for {field_name!r}') + if value is not Undefined and value is not Required: + # check also `Required` because of `validate_arguments` that sets `...` as default value + field_info.default = value + + if isinstance(value, FieldInfo): + if field_info is not None: + raise ValueError(f'cannot specify `Annotated` and value `Field`s together for {field_name!r}') + field_info = value + field_info.update_from_config(field_info_from_config) + elif field_info is None: + field_info = FieldInfo(value, **field_info_from_config) + value = None if field_info.default_factory is not None else field_info.default + field_info._validate() + return field_info, value + + @classmethod + def infer( + cls, + *, + name: str, + value: Any, + annotation: Any, + class_validators: Optional[Dict[str, Validator]], + config: Type['BaseConfig'], + ) -> 'ModelField': + from pydantic.v1.schema import get_annotation_from_field_info + + field_info, value = cls._get_field_info(name, annotation, value, config) + required: 'BoolUndefined' = Undefined + if value is Required: + required = True + value = None + elif value is not Undefined: + required = False + annotation = get_annotation_from_field_info(annotation, field_info, name, config.validate_assignment) + + return cls( + name=name, + type_=annotation, + alias=field_info.alias, + class_validators=class_validators, + default=value, + default_factory=field_info.default_factory, + required=required, + model_config=config, + field_info=field_info, + ) + + def set_config(self, config: Type['BaseConfig']) -> None: + self.model_config = config + info_from_config = config.get_field_info(self.name) + config.prepare_field(self) + new_alias = info_from_config.get('alias') + new_alias_priority = info_from_config.get('alias_priority') or 0 + if new_alias and new_alias_priority >= (self.field_info.alias_priority or 0): + self.field_info.alias = new_alias + self.field_info.alias_priority = new_alias_priority + self.alias = new_alias + new_exclude = info_from_config.get('exclude') + if new_exclude is not None: + self.field_info.exclude = ValueItems.merge(self.field_info.exclude, new_exclude) + new_include = info_from_config.get('include') + if new_include is not None: + self.field_info.include = ValueItems.merge(self.field_info.include, new_include, intersect=True) + + @property + def alt_alias(self) -> bool: + return self.name != self.alias + + def prepare(self) -> None: + """ + Prepare the field but inspecting self.default, self.type_ etc. + + Note: this method is **not** idempotent (because _type_analysis is not idempotent), + e.g. calling it it multiple times may modify the field and configure it incorrectly. + """ + self._set_default_and_type() + if self.type_.__class__ is ForwardRef or self.type_.__class__ is DeferredType: + # self.type_ is currently a ForwardRef and there's nothing we can do now, + # user will need to call model.update_forward_refs() + return + + self._type_analysis() + if self.required is Undefined: + self.required = True + if self.default is Undefined and self.default_factory is None: + self.default = None + self.populate_validators() + + def _set_default_and_type(self) -> None: + """ + Set the default value, infer the type if needed and check if `None` value is valid. + """ + if self.default_factory is not None: + if self.type_ is Undefined: + raise errors_.ConfigError( + f'you need to set the type of field {self.name!r} when using `default_factory`' + ) + return + + default_value = self.get_default() + + if default_value is not None and self.type_ is Undefined: + self.type_ = default_value.__class__ + self.outer_type_ = self.type_ + self.annotation = self.type_ + + if self.type_ is Undefined: + raise errors_.ConfigError(f'unable to infer type for attribute "{self.name}"') + + if self.required is False and default_value is None: + self.allow_none = True + + def _type_analysis(self) -> None: # noqa: C901 (ignore complexity) + # typing interface is horrible, we have to do some ugly checks + if lenient_issubclass(self.type_, JsonWrapper): + self.type_ = self.type_.inner_type + self.parse_json = True + elif lenient_issubclass(self.type_, Json): + self.type_ = Any + self.parse_json = True + elif isinstance(self.type_, TypeVar): + if self.type_.__bound__: + self.type_ = self.type_.__bound__ + elif self.type_.__constraints__: + self.type_ = Union[self.type_.__constraints__] + else: + self.type_ = Any + elif is_new_type(self.type_): + self.type_ = new_type_supertype(self.type_) + + if self.type_ is Any or self.type_ is object: + if self.required is Undefined: + self.required = False + self.allow_none = True + return + elif self.type_ is Pattern or self.type_ is re.Pattern: + # python 3.7 only, Pattern is a typing object but without sub fields + return + elif is_literal_type(self.type_): + return + elif is_typeddict(self.type_): + return + + if is_finalvar(self.type_): + self.final = True + + if self.type_ is Final: + self.type_ = Any + else: + self.type_ = get_args(self.type_)[0] + + self._type_analysis() + return + + origin = get_origin(self.type_) + + if origin is Annotated or is_typeddict_special(origin): + self.type_ = get_args(self.type_)[0] + self._type_analysis() + return + + if self.discriminator_key is not None and not is_union(origin): + raise TypeError('`discriminator` can only be used with `Union` type with more than one variant') + + # add extra check for `collections.abc.Hashable` for python 3.10+ where origin is not `None` + if origin is None or origin is CollectionsHashable: + # field is not "typing" object eg. Union, Dict, List etc. + # allow None for virtual superclasses of NoneType, e.g. Hashable + if isinstance(self.type_, type) and isinstance(None, self.type_): + self.allow_none = True + return + elif origin is Callable: + return + elif is_union(origin): + types_ = [] + for type_ in get_args(self.type_): + if is_none_type(type_) or type_ is Any or type_ is object: + if self.required is Undefined: + self.required = False + self.allow_none = True + if is_none_type(type_): + continue + types_.append(type_) + + if len(types_) == 1: + # Optional[] + self.type_ = types_[0] + # this is the one case where the "outer type" isn't just the original type + self.outer_type_ = self.type_ + # re-run to correctly interpret the new self.type_ + self._type_analysis() + else: + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{display_as_type(t)}') for t in types_] + + if self.discriminator_key is not None: + self.prepare_discriminated_union_sub_fields() + return + elif issubclass(origin, Tuple): # type: ignore + # origin == Tuple without item type + args = get_args(self.type_) + if not args: # plain tuple + self.type_ = Any + self.shape = SHAPE_TUPLE_ELLIPSIS + elif len(args) == 2 and args[1] is Ellipsis: # e.g. Tuple[int, ...] + self.type_ = args[0] + self.shape = SHAPE_TUPLE_ELLIPSIS + self.sub_fields = [self._create_sub_type(args[0], f'{self.name}_0')] + elif args == ((),): # Tuple[()] means empty tuple + self.shape = SHAPE_TUPLE + self.type_ = Any + self.sub_fields = [] + else: + self.shape = SHAPE_TUPLE + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{i}') for i, t in enumerate(args)] + return + elif issubclass(origin, List): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'list_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_LIST + elif issubclass(origin, Set): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'set_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_SET + elif issubclass(origin, FrozenSet): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'frozenset_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_FROZENSET + elif issubclass(origin, Deque): + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_DEQUE + elif issubclass(origin, Sequence): + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_SEQUENCE + # priority to most common mapping: dict + elif origin is dict or origin is Dict: + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_DICT + elif issubclass(origin, DefaultDict): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_DEFAULTDICT + elif issubclass(origin, Counter): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = int + self.shape = SHAPE_COUNTER + elif issubclass(origin, Mapping): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_MAPPING + # Equality check as almost everything inherits form Iterable, including str + # check for Iterable and CollectionsIterable, as it could receive one even when declared with the other + elif origin in {Iterable, CollectionsIterable}: + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_ITERABLE + self.sub_fields = [self._create_sub_type(self.type_, f'{self.name}_type')] + elif issubclass(origin, Type): # type: ignore + return + elif hasattr(origin, '__get_validators__') or self.model_config.arbitrary_types_allowed: + # Is a Pydantic-compatible generic that handles itself + # or we have arbitrary_types_allowed = True + self.shape = SHAPE_GENERIC + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{i}') for i, t in enumerate(get_args(self.type_))] + self.type_ = origin + return + else: + raise TypeError(f'Fields of type "{origin}" are not supported.') + + # type_ has been refined eg. as the type of a List and sub_fields needs to be populated + self.sub_fields = [self._create_sub_type(self.type_, '_' + self.name)] + + def prepare_discriminated_union_sub_fields(self) -> None: + """ + Prepare the mapping -> and update `sub_fields` + Note that this process can be aborted if a `ForwardRef` is encountered + """ + assert self.discriminator_key is not None + + if self.type_.__class__ is DeferredType: + return + + assert self.sub_fields is not None + sub_fields_mapping: Dict[str, 'ModelField'] = {} + all_aliases: Set[str] = set() + + for sub_field in self.sub_fields: + t = sub_field.type_ + if t.__class__ is ForwardRef: + # Stopping everything...will need to call `update_forward_refs` + return + + alias, discriminator_values = get_discriminator_alias_and_values(t, self.discriminator_key) + all_aliases.add(alias) + for discriminator_value in discriminator_values: + sub_fields_mapping[discriminator_value] = sub_field + + self.sub_fields_mapping = sub_fields_mapping + self.discriminator_alias = get_unique_discriminator_alias(all_aliases, self.discriminator_key) + + def _create_sub_type(self, type_: Type[Any], name: str, *, for_keys: bool = False) -> 'ModelField': + if for_keys: + class_validators = None + else: + # validators for sub items should not have `each_item` as we want to check only the first sublevel + class_validators = { + k: Validator( + func=v.func, + pre=v.pre, + each_item=False, + always=v.always, + check_fields=v.check_fields, + skip_on_failure=v.skip_on_failure, + ) + for k, v in self.class_validators.items() + if v.each_item + } + + field_info, _ = self._get_field_info(name, type_, None, self.model_config) + + return self.__class__( + type_=type_, + name=name, + class_validators=class_validators, + model_config=self.model_config, + field_info=field_info, + ) + + def populate_validators(self) -> None: + """ + Prepare self.pre_validators, self.validators, and self.post_validators based on self.type_'s __get_validators__ + and class validators. This method should be idempotent, e.g. it should be safe to call multiple times + without mis-configuring the field. + """ + self.validate_always = getattr(self.type_, 'validate_always', False) or any( + v.always for v in self.class_validators.values() + ) + + class_validators_ = self.class_validators.values() + if not self.sub_fields or self.shape == SHAPE_GENERIC: + get_validators = getattr(self.type_, '__get_validators__', None) + v_funcs = ( + *[v.func for v in class_validators_ if v.each_item and v.pre], + *(get_validators() if get_validators else list(find_validators(self.type_, self.model_config))), + *[v.func for v in class_validators_ if v.each_item and not v.pre], + ) + self.validators = prep_validators(v_funcs) + + self.pre_validators = [] + self.post_validators = [] + + if self.field_info and self.field_info.const: + self.post_validators.append(make_generic_validator(constant_validator)) + + if class_validators_: + self.pre_validators += prep_validators(v.func for v in class_validators_ if not v.each_item and v.pre) + self.post_validators += prep_validators(v.func for v in class_validators_ if not v.each_item and not v.pre) + + if self.parse_json: + self.pre_validators.append(make_generic_validator(validate_json)) + + self.pre_validators = self.pre_validators or None + self.post_validators = self.post_validators or None + + def validate( + self, v: Any, values: Dict[str, Any], *, loc: 'LocStr', cls: Optional['ModelOrDc'] = None + ) -> 'ValidateReturn': + assert self.type_.__class__ is not DeferredType + + if self.type_.__class__ is ForwardRef: + assert cls is not None + raise ConfigError( + f'field "{self.name}" not yet prepared so type is still a ForwardRef, ' + f'you might need to call {cls.__name__}.update_forward_refs().' + ) + + errors: Optional['ErrorList'] + if self.pre_validators: + v, errors = self._apply_validators(v, values, loc, cls, self.pre_validators) + if errors: + return v, errors + + if v is None: + if is_none_type(self.type_): + # keep validating + pass + elif self.allow_none: + if self.post_validators: + return self._apply_validators(v, values, loc, cls, self.post_validators) + else: + return None, None + else: + return v, ErrorWrapper(NoneIsNotAllowedError(), loc) + + if self.shape == SHAPE_SINGLETON: + v, errors = self._validate_singleton(v, values, loc, cls) + elif self.shape in MAPPING_LIKE_SHAPES: + v, errors = self._validate_mapping_like(v, values, loc, cls) + elif self.shape == SHAPE_TUPLE: + v, errors = self._validate_tuple(v, values, loc, cls) + elif self.shape == SHAPE_ITERABLE: + v, errors = self._validate_iterable(v, values, loc, cls) + elif self.shape == SHAPE_GENERIC: + v, errors = self._apply_validators(v, values, loc, cls, self.validators) + else: + # sequence, list, set, generator, tuple with ellipsis, frozen set + v, errors = self._validate_sequence_like(v, values, loc, cls) + + if not errors and self.post_validators: + v, errors = self._apply_validators(v, values, loc, cls, self.post_validators) + return v, errors + + def _validate_sequence_like( # noqa: C901 (ignore complexity) + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + """ + Validate sequence-like containers: lists, tuples, sets and generators + Note that large if-else blocks are necessary to enable Cython + optimization, which is why we disable the complexity check above. + """ + if not sequence_like(v): + e: errors_.PydanticTypeError + if self.shape == SHAPE_LIST: + e = errors_.ListError() + elif self.shape in (SHAPE_TUPLE, SHAPE_TUPLE_ELLIPSIS): + e = errors_.TupleError() + elif self.shape == SHAPE_SET: + e = errors_.SetError() + elif self.shape == SHAPE_FROZENSET: + e = errors_.FrozenSetError() + else: + e = errors_.SequenceError() + return v, ErrorWrapper(e, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result = [] + errors: List[ErrorList] = [] + for i, v_ in enumerate(v): + v_loc = *loc, i + r, ee = self._validate_singleton(v_, values, v_loc, cls) + if ee: + errors.append(ee) + else: + result.append(r) + + if errors: + return v, errors + + converted: Union[List[Any], Set[Any], FrozenSet[Any], Tuple[Any, ...], Iterator[Any], Deque[Any]] = result + + if self.shape == SHAPE_SET: + converted = set(result) + elif self.shape == SHAPE_FROZENSET: + converted = frozenset(result) + elif self.shape == SHAPE_TUPLE_ELLIPSIS: + converted = tuple(result) + elif self.shape == SHAPE_DEQUE: + converted = deque(result, maxlen=getattr(v, 'maxlen', None)) + elif self.shape == SHAPE_SEQUENCE: + if isinstance(v, tuple): + converted = tuple(result) + elif isinstance(v, set): + converted = set(result) + elif isinstance(v, Generator): + converted = iter(result) + elif isinstance(v, deque): + converted = deque(result, maxlen=getattr(v, 'maxlen', None)) + return converted, None + + def _validate_iterable( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + """ + Validate Iterables. + + This intentionally doesn't validate values to allow infinite generators. + """ + + try: + iterable = iter(v) + except TypeError: + return v, ErrorWrapper(errors_.IterableError(), loc) + return iterable, None + + def _validate_tuple( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + e: Optional[Exception] = None + if not sequence_like(v): + e = errors_.TupleError() + else: + actual_length, expected_length = len(v), len(self.sub_fields) # type: ignore + if actual_length != expected_length: + e = errors_.TupleLengthError(actual_length=actual_length, expected_length=expected_length) + + if e: + return v, ErrorWrapper(e, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result = [] + errors: List[ErrorList] = [] + for i, (v_, field) in enumerate(zip(v, self.sub_fields)): # type: ignore + v_loc = *loc, i + r, ee = field.validate(v_, values, loc=v_loc, cls=cls) + if ee: + errors.append(ee) + else: + result.append(r) + + if errors: + return v, errors + else: + return tuple(result), None + + def _validate_mapping_like( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + try: + v_iter = dict_validator(v) + except TypeError as exc: + return v, ErrorWrapper(exc, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result, errors = {}, [] + for k, v_ in v_iter.items(): + v_loc = *loc, '__key__' + key_result, key_errors = self.key_field.validate(k, values, loc=v_loc, cls=cls) # type: ignore + if key_errors: + errors.append(key_errors) + continue + + v_loc = *loc, k + value_result, value_errors = self._validate_singleton(v_, values, v_loc, cls) + if value_errors: + errors.append(value_errors) + continue + + result[key_result] = value_result + if errors: + return v, errors + elif self.shape == SHAPE_DICT: + return result, None + elif self.shape == SHAPE_DEFAULTDICT: + return defaultdict(self.type_, result), None + elif self.shape == SHAPE_COUNTER: + return CollectionCounter(result), None + else: + return self._get_mapping_value(v, result), None + + def _get_mapping_value(self, original: T, converted: Dict[Any, Any]) -> Union[T, Dict[Any, Any]]: + """ + When type is `Mapping[KT, KV]` (or another unsupported mapping), we try to avoid + coercing to `dict` unwillingly. + """ + original_cls = original.__class__ + + if original_cls == dict or original_cls == Dict: + return converted + elif original_cls in {defaultdict, DefaultDict}: + return defaultdict(self.type_, converted) + else: + try: + # Counter, OrderedDict, UserDict, ... + return original_cls(converted) # type: ignore + except TypeError: + raise RuntimeError(f'Could not convert dictionary to {original_cls.__name__!r}') from None + + def _validate_singleton( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + if self.sub_fields: + if self.discriminator_key is not None: + return self._validate_discriminated_union(v, values, loc, cls) + + errors = [] + + if self.model_config.smart_union and is_union(get_origin(self.type_)): + # 1st pass: check if the value is an exact instance of one of the Union types + # (e.g. to avoid coercing a bool into an int) + for field in self.sub_fields: + if v.__class__ is field.outer_type_: + return v, None + + # 2nd pass: check if the value is an instance of any subclass of the Union types + for field in self.sub_fields: + # This whole logic will be improved later on to support more complex `isinstance` checks + # It will probably be done once a strict mode is added and be something like: + # ``` + # value, error = field.validate(v, values, strict=True) + # if error is None: + # return value, None + # ``` + try: + if isinstance(v, field.outer_type_): + return v, None + except TypeError: + # compound type + if lenient_isinstance(v, get_origin(field.outer_type_)): + value, error = field.validate(v, values, loc=loc, cls=cls) + if not error: + return value, None + + # 1st pass by default or 3rd pass with `smart_union` enabled: + # check if the value can be coerced into one of the Union types + for field in self.sub_fields: + value, error = field.validate(v, values, loc=loc, cls=cls) + if error: + errors.append(error) + else: + return value, None + return v, errors + else: + return self._apply_validators(v, values, loc, cls, self.validators) + + def _validate_discriminated_union( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + assert self.discriminator_key is not None + assert self.discriminator_alias is not None + + try: + try: + discriminator_value = v[self.discriminator_alias] + except KeyError: + if self.model_config.allow_population_by_field_name: + discriminator_value = v[self.discriminator_key] + else: + raise + except KeyError: + return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc) + except TypeError: + try: + # BaseModel or dataclass + discriminator_value = getattr(v, self.discriminator_key) + except (AttributeError, TypeError): + return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc) + + if self.sub_fields_mapping is None: + assert cls is not None + raise ConfigError( + f'field "{self.name}" not yet prepared so type is still a ForwardRef, ' + f'you might need to call {cls.__name__}.update_forward_refs().' + ) + + try: + sub_field = self.sub_fields_mapping[discriminator_value] + except (KeyError, TypeError): + # KeyError: `discriminator_value` is not in the dictionary. + # TypeError: `discriminator_value` is unhashable. + assert self.sub_fields_mapping is not None + return v, ErrorWrapper( + InvalidDiscriminator( + discriminator_key=self.discriminator_key, + discriminator_value=discriminator_value, + allowed_values=list(self.sub_fields_mapping), + ), + loc, + ) + else: + if not isinstance(loc, tuple): + loc = (loc,) + return sub_field.validate(v, values, loc=(*loc, display_as_type(sub_field.type_)), cls=cls) + + def _apply_validators( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'], validators: 'ValidatorsList' + ) -> 'ValidateReturn': + for validator in validators: + try: + v = validator(cls, v, values, self, self.model_config) + except (ValueError, TypeError, AssertionError) as exc: + return v, ErrorWrapper(exc, loc) + return v, None + + def is_complex(self) -> bool: + """ + Whether the field is "complex" eg. env variables should be parsed as JSON. + """ + from pydantic.v1.main import BaseModel + + return ( + self.shape != SHAPE_SINGLETON + or hasattr(self.type_, '__pydantic_model__') + or lenient_issubclass(self.type_, (BaseModel, list, set, frozenset, dict)) + ) + + def _type_display(self) -> PyObjectStr: + t = display_as_type(self.type_) + + if self.shape in MAPPING_LIKE_SHAPES: + t = f'Mapping[{display_as_type(self.key_field.type_)}, {t}]' # type: ignore + elif self.shape == SHAPE_TUPLE: + t = 'Tuple[{}]'.format(', '.join(display_as_type(f.type_) for f in self.sub_fields)) # type: ignore + elif self.shape == SHAPE_GENERIC: + assert self.sub_fields + t = '{}[{}]'.format( + display_as_type(self.type_), ', '.join(display_as_type(f.type_) for f in self.sub_fields) + ) + elif self.shape != SHAPE_SINGLETON: + t = SHAPE_NAME_LOOKUP[self.shape].format(t) + + if self.allow_none and (self.shape != SHAPE_SINGLETON or not self.sub_fields): + t = f'Optional[{t}]' + return PyObjectStr(t) + + def __repr_args__(self) -> 'ReprArgs': + args = [('name', self.name), ('type', self._type_display()), ('required', self.required)] + + if not self.required: + if self.default_factory is not None: + args.append(('default_factory', f'')) + else: + args.append(('default', self.default)) + + if self.alt_alias: + args.append(('alias', self.alias)) + return args + + +class ModelPrivateAttr(Representation): + __slots__ = ('default', 'default_factory') + + def __init__(self, default: Any = Undefined, *, default_factory: Optional[NoArgAnyCallable] = None) -> None: + self.default = default + self.default_factory = default_factory + + def get_default(self) -> Any: + return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and (self.default, self.default_factory) == ( + other.default, + other.default_factory, + ) + + +def PrivateAttr( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, +) -> Any: + """ + Indicates that attribute is only used internally and never mixed with regular fields. + + Types or values of private attrs are not checked by pydantic and it's up to you to keep them relevant. + + Private attrs are stored in model __slots__. + + :param default: the attribute’s default value + :param default_factory: callable that will be called when a default value is needed for this attribute + If both `default` and `default_factory` are set, an error is raised. + """ + if default is not Undefined and default_factory is not None: + raise ValueError('cannot specify both default and default_factory') + + return ModelPrivateAttr( + default, + default_factory=default_factory, + ) + + +class DeferredType: + """ + Used to postpone field preparation, while creating recursive generic models. + """ + + +def is_finalvar_with_default_val(type_: Type[Any], val: Any) -> bool: + return is_finalvar(type_) and val is not Undefined and not isinstance(val, FieldInfo) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/generics.py b/backend/venv/Lib/site-packages/pydantic/v1/generics.py new file mode 100644 index 0000000..9a69f2b --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/generics.py @@ -0,0 +1,400 @@ +import sys +import types +import typing +from typing import ( + TYPE_CHECKING, + Any, + ClassVar, + Dict, + ForwardRef, + Generic, + Iterator, + List, + Mapping, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, +) +from weakref import WeakKeyDictionary, WeakValueDictionary + +from typing_extensions import Annotated, Literal as ExtLiteral + +from pydantic.v1.class_validators import gather_all_validators +from pydantic.v1.fields import DeferredType +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.types import JsonWrapper +from pydantic.v1.typing import display_as_type, get_all_type_hints, get_args, get_origin, typing_base +from pydantic.v1.utils import all_identical, lenient_issubclass + +if sys.version_info >= (3, 10): + from typing import _UnionGenericAlias +if sys.version_info >= (3, 8): + from typing import Literal + +GenericModelT = TypeVar('GenericModelT', bound='GenericModel') +TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type + +CacheKey = Tuple[Type[Any], Any, Tuple[Any, ...]] +Parametrization = Mapping[TypeVarType, Type[Any]] + +# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected +# once they are no longer referenced by the caller. +if sys.version_info >= (3, 9): # Typing for weak dictionaries available at 3.9 + GenericTypesCache = WeakValueDictionary[CacheKey, Type[BaseModel]] + AssignedParameters = WeakKeyDictionary[Type[BaseModel], Parametrization] +else: + GenericTypesCache = WeakValueDictionary + AssignedParameters = WeakKeyDictionary + +# _generic_types_cache is a Mapping from __class_getitem__ arguments to the parametrized version of generic models. +# This ensures multiple calls of e.g. A[B] return always the same class. +_generic_types_cache = GenericTypesCache() + +# _assigned_parameters is a Mapping from parametrized version of generic models to assigned types of parametrizations +# as captured during construction of the class (not instances). +# E.g., for generic model `Model[A, B]`, when parametrized model `Model[int, str]` is created, +# `Model[int, str]`: {A: int, B: str}` will be stored in `_assigned_parameters`. +# (This information is only otherwise available after creation from the class name string). +_assigned_parameters = AssignedParameters() + + +class GenericModel(BaseModel): + __slots__ = () + __concrete__: ClassVar[bool] = False + + if TYPE_CHECKING: + # Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with + # `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of + # `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below. + __parameters__: ClassVar[Tuple[TypeVarType, ...]] + + # Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings + def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]: + """Instantiates a new class from a generic class `cls` and type variables `params`. + + :param params: Tuple of types the class . Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + :return: New model class inheriting from `cls` with instantiated + types described by `params`. If no parameters are given, `cls` is + returned as is. + + """ + + def _cache_key(_params: Any) -> CacheKey: + args = get_args(_params) + # python returns a list for Callables, which is not hashable + if len(args) == 2 and isinstance(args[0], list): + args = (tuple(args[0]), args[1]) + return cls, _params, args + + cached = _generic_types_cache.get(_cache_key(params)) + if cached is not None: + return cached + if cls.__concrete__ and Generic not in cls.__bases__: + raise TypeError('Cannot parameterize a concrete instantiation of a generic model') + if not isinstance(params, tuple): + params = (params,) + if cls is GenericModel and any(isinstance(param, TypeVar) for param in params): + raise TypeError('Type parameters should be placed on typing.Generic, not GenericModel') + if not hasattr(cls, '__parameters__'): + raise TypeError(f'Type {cls.__name__} must inherit from typing.Generic before being parameterized') + + check_parameters_count(cls, params) + # Build map from generic typevars to passed params + typevars_map: Dict[TypeVarType, Type[Any]] = dict(zip(cls.__parameters__, params)) + if all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map: + return cls # if arguments are equal to parameters it's the same object + + # Create new model with original model as parent inserting fields with DeferredType. + model_name = cls.__concrete_name__(params) + validators = gather_all_validators(cls) + + type_hints = get_all_type_hints(cls).items() + instance_type_hints = {k: v for k, v in type_hints if get_origin(v) is not ClassVar} + + fields = {k: (DeferredType(), cls.__fields__[k].field_info) for k in instance_type_hints if k in cls.__fields__} + + model_module, called_globally = get_caller_frame_info() + created_model = cast( + Type[GenericModel], # casting ensures mypy is aware of the __concrete__ and __parameters__ attributes + create_model( + model_name, + __module__=model_module or cls.__module__, + __base__=(cls,) + tuple(cls.__parameterized_bases__(typevars_map)), + __config__=None, + __validators__=validators, + __cls_kwargs__=None, + **fields, + ), + ) + + _assigned_parameters[created_model] = typevars_map + + if called_globally: # create global reference and therefore allow pickling + object_by_reference = None + reference_name = model_name + reference_module_globals = sys.modules[created_model.__module__].__dict__ + while object_by_reference is not created_model: + object_by_reference = reference_module_globals.setdefault(reference_name, created_model) + reference_name += '_' + + created_model.Config = cls.Config + + # Find any typevars that are still present in the model. + # If none are left, the model is fully "concrete", otherwise the new + # class is a generic class as well taking the found typevars as + # parameters. + new_params = tuple( + {param: None for param in iter_contained_typevars(typevars_map.values())} + ) # use dict as ordered set + created_model.__concrete__ = not new_params + if new_params: + created_model.__parameters__ = new_params + + # Save created model in cache so we don't end up creating duplicate + # models that should be identical. + _generic_types_cache[_cache_key(params)] = created_model + if len(params) == 1: + _generic_types_cache[_cache_key(params[0])] = created_model + + # Recursively walk class type hints and replace generic typevars + # with concrete types that were passed. + _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map) + + return created_model + + @classmethod + def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str: + """Compute class name for child classes. + + :param params: Tuple of types the class . Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + :return: String representing a the new class where `params` are + passed to `cls` as type variables. + + This method can be overridden to achieve a custom naming scheme for GenericModels. + """ + param_names = [display_as_type(param) for param in params] + params_component = ', '.join(param_names) + return f'{cls.__name__}[{params_component}]' + + @classmethod + def __parameterized_bases__(cls, typevars_map: Parametrization) -> Iterator[Type[Any]]: + """ + Returns unbound bases of cls parameterised to given type variables + + :param typevars_map: Dictionary of type applications for binding subclasses. + Given a generic class `Model` with 2 type variables [S, T] + and a concrete model `Model[str, int]`, + the value `{S: str, T: int}` would be passed to `typevars_map`. + :return: an iterator of generic sub classes, parameterised by `typevars_map` + and other assigned parameters of `cls` + + e.g.: + ``` + class A(GenericModel, Generic[T]): + ... + + class B(A[V], Generic[V]): + ... + + assert A[int] in B.__parameterized_bases__({V: int}) + ``` + """ + + def build_base_model( + base_model: Type[GenericModel], mapped_types: Parametrization + ) -> Iterator[Type[GenericModel]]: + base_parameters = tuple(mapped_types[param] for param in base_model.__parameters__) + parameterized_base = base_model.__class_getitem__(base_parameters) + if parameterized_base is base_model or parameterized_base is cls: + # Avoid duplication in MRO + return + yield parameterized_base + + for base_model in cls.__bases__: + if not issubclass(base_model, GenericModel): + # not a class that can be meaningfully parameterized + continue + elif not getattr(base_model, '__parameters__', None): + # base_model is "GenericModel" (and has no __parameters__) + # or + # base_model is already concrete, and will be included transitively via cls. + continue + elif cls in _assigned_parameters: + if base_model in _assigned_parameters: + # cls is partially parameterised but not from base_model + # e.g. cls = B[S], base_model = A[S] + # B[S][int] should subclass A[int], (and will be transitively via B[int]) + # but it's not viable to consistently subclass types with arbitrary construction + # So don't attempt to include A[S][int] + continue + else: # base_model not in _assigned_parameters: + # cls is partially parameterized, base_model is original generic + # e.g. cls = B[str, T], base_model = B[S, T] + # Need to determine the mapping for the base_model parameters + mapped_types: Parametrization = { + key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items() + } + yield from build_base_model(base_model, mapped_types) + else: + # cls is base generic, so base_class has a distinct base + # can construct the Parameterised base model using typevars_map directly + yield from build_base_model(base_model, typevars_map) + + +def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any: + """Return type with all occurrences of `type_map` keys recursively replaced with their values. + + :param type_: Any type, class or generic alias + :param type_map: Mapping from `TypeVar` instance to concrete types. + :return: New type representing the basic structure of `type_` with all + `typevar_map` keys recursively replaced. + + >>> replace_types(Tuple[str, Union[List[str], float]], {str: int}) + Tuple[int, Union[List[int], float]] + + """ + if not type_map: + return type_ + + type_args = get_args(type_) + origin_type = get_origin(type_) + + if origin_type is Annotated: + annotated_type, *annotations = type_args + return Annotated[replace_types(annotated_type, type_map), tuple(annotations)] + + if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal): + return type_map.get(type_, type_) + # Having type args is a good indicator that this is a typing module + # class instantiation or a generic alias of some sort. + if type_args: + resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args) + if all_identical(type_args, resolved_type_args): + # If all arguments are the same, there is no need to modify the + # type or create a new object at all + return type_ + if ( + origin_type is not None + and isinstance(type_, typing_base) + and not isinstance(origin_type, typing_base) + and getattr(type_, '_name', None) is not None + ): + # In python < 3.9 generic aliases don't exist so any of these like `list`, + # `type` or `collections.abc.Callable` need to be translated. + # See: https://www.python.org/dev/peps/pep-0585 + origin_type = getattr(typing, type_._name) + assert origin_type is not None + # PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__. + # We also cannot use isinstance() since we have to compare types. + if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721 + return _UnionGenericAlias(origin_type, resolved_type_args) + return origin_type[resolved_type_args] + + # We handle pydantic generic models separately as they don't have the same + # semantics as "typing" classes or generic aliases + if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__: + type_args = type_.__parameters__ + resolved_type_args = tuple(replace_types(t, type_map) for t in type_args) + if all_identical(type_args, resolved_type_args): + return type_ + return type_[resolved_type_args] + + # Handle special case for typehints that can have lists as arguments. + # `typing.Callable[[int, str], int]` is an example for this. + if isinstance(type_, (List, list)): + resolved_list = list(replace_types(element, type_map) for element in type_) + if all_identical(type_, resolved_list): + return type_ + return resolved_list + + # For JsonWrapperValue, need to handle its inner type to allow correct parsing + # of generic Json arguments like Json[T] + if not origin_type and lenient_issubclass(type_, JsonWrapper): + type_.inner_type = replace_types(type_.inner_type, type_map) + return type_ + + # If all else fails, we try to resolve the type directly and otherwise just + # return the input with no modifications. + new_type = type_map.get(type_, type_) + # Convert string to ForwardRef + if isinstance(new_type, str): + return ForwardRef(new_type) + else: + return new_type + + +def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None: + actual = len(parameters) + expected = len(cls.__parameters__) + if actual != expected: + description = 'many' if actual > expected else 'few' + raise TypeError(f'Too {description} parameters for {cls.__name__}; actual {actual}, expected {expected}') + + +DictValues: Type[Any] = {}.values().__class__ + + +def iter_contained_typevars(v: Any) -> Iterator[TypeVarType]: + """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found.""" + if isinstance(v, TypeVar): + yield v + elif hasattr(v, '__parameters__') and not get_origin(v) and lenient_issubclass(v, GenericModel): + yield from v.__parameters__ + elif isinstance(v, (DictValues, list)): + for var in v: + yield from iter_contained_typevars(var) + else: + args = get_args(v) + for arg in args: + yield from iter_contained_typevars(arg) + + +def get_caller_frame_info() -> Tuple[Optional[str], bool]: + """ + Used inside a function to check whether it was called globally + + Will only work against non-compiled code, therefore used only in pydantic.generics + + :returns Tuple[module_name, called_globally] + """ + try: + previous_caller_frame = sys._getframe(2) + except ValueError as e: + raise RuntimeError('This function must be used inside another function') from e + except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it + return None, False + frame_globals = previous_caller_frame.f_globals + return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals + + +def _prepare_model_fields( + created_model: Type[GenericModel], + fields: Mapping[str, Any], + instance_type_hints: Mapping[str, type], + typevars_map: Mapping[Any, type], +) -> None: + """ + Replace DeferredType fields with concrete type hints and prepare them. + """ + + for key, field in created_model.__fields__.items(): + if key not in fields: + assert field.type_.__class__ is not DeferredType + # https://github.com/nedbat/coveragepy/issues/198 + continue # pragma: no cover + + assert field.type_.__class__ is DeferredType, field.type_.__class__ + + field_type_hint = instance_type_hints[key] + concrete_type = replace_types(field_type_hint, typevars_map) + field.type_ = concrete_type + field.outer_type_ = concrete_type + field.prepare() + created_model.__annotations__[key] = concrete_type diff --git a/backend/venv/Lib/site-packages/pydantic/v1/json.py b/backend/venv/Lib/site-packages/pydantic/v1/json.py new file mode 100644 index 0000000..41d0d5f --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/json.py @@ -0,0 +1,112 @@ +import datetime +from collections import deque +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from re import Pattern +from types import GeneratorType +from typing import Any, Callable, Dict, Type, Union +from uuid import UUID + +from pydantic.v1.color import Color +from pydantic.v1.networks import NameEmail +from pydantic.v1.types import SecretBytes, SecretStr + +__all__ = 'pydantic_encoder', 'custom_pydantic_encoder', 'timedelta_isoformat' + + +def isoformat(o: Union[datetime.date, datetime.time]) -> str: + return o.isoformat() + + +def decimal_encoder(dec_value: Decimal) -> Union[int, float]: + """ + Encodes a Decimal as int of there's no exponent, otherwise float + + This is useful when we use ConstrainedDecimal to represent Numeric(x,0) + where a 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 + """ + if dec_value.as_tuple().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, + 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, +} + + +def pydantic_encoder(obj: Any) -> Any: + from dataclasses import asdict, is_dataclass + + from pydantic.v1.main import BaseModel + + if isinstance(obj, BaseModel): + return obj.dict() + elif is_dataclass(obj): + return asdict(obj) + + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = ENCODERS_BY_TYPE[base] + except KeyError: + continue + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable") + + +def custom_pydantic_encoder(type_encoders: Dict[Any, Callable[[Type[Any]], Any]], obj: Any) -> Any: + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = type_encoders[base] + except KeyError: + continue + + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + return pydantic_encoder(obj) + + +def timedelta_isoformat(td: datetime.timedelta) -> str: + """ + ISO 8601 encoding for Python timedelta object. + """ + minutes, seconds = divmod(td.seconds, 60) + hours, minutes = divmod(minutes, 60) + return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' diff --git a/backend/venv/Lib/site-packages/pydantic/v1/main.py b/backend/venv/Lib/site-packages/pydantic/v1/main.py new file mode 100644 index 0000000..8000967 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/main.py @@ -0,0 +1,1113 @@ +import warnings +from abc import ABCMeta +from copy import deepcopy +from enum import Enum +from functools import partial +from pathlib import Path +from types import FunctionType, prepare_class, resolve_bases +from typing import ( + TYPE_CHECKING, + AbstractSet, + Any, + Callable, + ClassVar, + Dict, + List, + Mapping, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, + no_type_check, + overload, +) + +from typing_extensions import dataclass_transform + +from pydantic.v1.class_validators import ValidatorGroup, extract_root_validators, extract_validators, inherit_validators +from pydantic.v1.config import BaseConfig, Extra, inherit_config, prepare_config +from pydantic.v1.error_wrappers import ErrorWrapper, ValidationError +from pydantic.v1.errors import ConfigError, DictError, ExtraError, MissingError +from pydantic.v1.fields import ( + MAPPING_LIKE_SHAPES, + Field, + ModelField, + ModelPrivateAttr, + PrivateAttr, + Undefined, + is_finalvar_with_default_val, +) +from pydantic.v1.json import custom_pydantic_encoder, pydantic_encoder +from pydantic.v1.parse import Protocol, load_file, load_str_bytes +from pydantic.v1.schema import default_ref_template, model_schema +from pydantic.v1.types import PyObject, StrBytes +from pydantic.v1.typing import ( + AnyCallable, + get_args, + get_origin, + is_classvar, + is_namedtuple, + is_union, + resolve_annotations, + update_model_forward_refs, +) +from pydantic.v1.utils import ( + DUNDER_ATTRIBUTES, + ROOT_KEY, + ClassAttribute, + GetterDict, + Representation, + ValueItems, + generate_model_signature, + is_valid_field, + is_valid_private_name, + lenient_issubclass, + sequence_like, + smart_deepcopy, + unique_list, + validate_field_name, +) + +if TYPE_CHECKING: + from inspect import Signature + + from pydantic.v1.class_validators import ValidatorListDict + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import ( + AbstractSetIntStr, + AnyClassMethod, + CallableGenerator, + DictAny, + DictStrAny, + MappingIntStrAny, + ReprArgs, + SetStr, + TupleGenerator, + ) + + Model = TypeVar('Model', bound='BaseModel') + +__all__ = 'BaseModel', 'create_model', 'validate_model' + +_T = TypeVar('_T') + + +def validate_custom_root_type(fields: Dict[str, ModelField]) -> None: + if len(fields) > 1: + raise ValueError(f'{ROOT_KEY} cannot be mixed with other fields') + + +def generate_hash_function(frozen: bool) -> Optional[Callable[[Any], int]]: + def hash_function(self_: Any) -> int: + return hash(self_.__class__) + hash(tuple(self_.__dict__.values())) + + return hash_function if frozen else None + + +# If a field is of type `Callable`, its default value should be a function and cannot to ignored. +ANNOTATED_FIELD_UNTOUCHED_TYPES: Tuple[Any, ...] = (property, type, classmethod, staticmethod) +# When creating a `BaseModel` instance, we bypass all the methods, properties... added to the model +UNTOUCHED_TYPES: Tuple[Any, ...] = (FunctionType,) + ANNOTATED_FIELD_UNTOUCHED_TYPES +# Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we need to add this extra +# (somewhat hacky) boolean to keep track of whether we've created the `BaseModel` class yet, and therefore whether it's +# safe to refer to it. If it *hasn't* been created, we assume that the `__new__` call we're in the middle of is for +# the `BaseModel` class, since that's defined immediately after the metaclass. +_is_base_model_class_defined = False + + +@dataclass_transform(kw_only_default=True, field_specifiers=(Field,)) +class ModelMetaclass(ABCMeta): + @no_type_check # noqa C901 + def __new__(mcs, name, bases, namespace, **kwargs): # noqa C901 + fields: Dict[str, ModelField] = {} + config = BaseConfig + validators: 'ValidatorListDict' = {} + + pre_root_validators, post_root_validators = [], [] + private_attributes: Dict[str, ModelPrivateAttr] = {} + base_private_attributes: Dict[str, ModelPrivateAttr] = {} + slots: SetStr = namespace.get('__slots__', ()) + slots = {slots} if isinstance(slots, str) else set(slots) + class_vars: SetStr = set() + hash_func: Optional[Callable[[Any], int]] = None + + for base in reversed(bases): + if _is_base_model_class_defined and issubclass(base, BaseModel) and base != BaseModel: + fields.update(smart_deepcopy(base.__fields__)) + config = inherit_config(base.__config__, config) + validators = inherit_validators(base.__validators__, validators) + pre_root_validators += base.__pre_root_validators__ + post_root_validators += base.__post_root_validators__ + base_private_attributes.update(base.__private_attributes__) + class_vars.update(base.__class_vars__) + hash_func = base.__hash__ + + resolve_forward_refs = kwargs.pop('__resolve_forward_refs__', True) + allowed_config_kwargs: SetStr = { + key + for key in dir(config) + if not (key.startswith('__') and key.endswith('__')) # skip dunder methods and attributes + } + config_kwargs = {key: kwargs.pop(key) for key in kwargs.keys() & allowed_config_kwargs} + config_from_namespace = namespace.get('Config') + if config_kwargs and config_from_namespace: + raise TypeError('Specifying config in two places is ambiguous, use either Config attribute or class kwargs') + config = inherit_config(config_from_namespace, config, **config_kwargs) + + validators = inherit_validators(extract_validators(namespace), validators) + vg = ValidatorGroup(validators) + + for f in fields.values(): + f.set_config(config) + extra_validators = vg.get_validators(f.name) + if extra_validators: + f.class_validators.update(extra_validators) + # re-run prepare to add extra validators + f.populate_validators() + + prepare_config(config, name) + + untouched_types = ANNOTATED_FIELD_UNTOUCHED_TYPES + + def is_untouched(v: Any) -> bool: + return isinstance(v, untouched_types) or v.__class__.__name__ == 'cython_function_or_method' + + if (namespace.get('__module__'), namespace.get('__qualname__')) != ('pydantic.main', 'BaseModel'): + annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None)) + # annotation only fields need to come first in fields + for ann_name, ann_type in annotations.items(): + if is_classvar(ann_type): + class_vars.add(ann_name) + elif is_finalvar_with_default_val(ann_type, namespace.get(ann_name, Undefined)): + class_vars.add(ann_name) + elif is_valid_field(ann_name): + validate_field_name(bases, ann_name) + value = namespace.get(ann_name, Undefined) + allowed_types = get_args(ann_type) if is_union(get_origin(ann_type)) else (ann_type,) + if ( + is_untouched(value) + and ann_type != PyObject + and not any( + lenient_issubclass(get_origin(allowed_type), Type) for allowed_type in allowed_types + ) + ): + continue + fields[ann_name] = ModelField.infer( + name=ann_name, + value=value, + annotation=ann_type, + class_validators=vg.get_validators(ann_name), + config=config, + ) + elif ann_name not in namespace and config.underscore_attrs_are_private: + private_attributes[ann_name] = PrivateAttr() + + untouched_types = UNTOUCHED_TYPES + config.keep_untouched + for var_name, value in namespace.items(): + can_be_changed = var_name not in class_vars and not is_untouched(value) + if isinstance(value, ModelPrivateAttr): + if not is_valid_private_name(var_name): + raise NameError( + f'Private attributes "{var_name}" must not be a valid field name; ' + f'Use sunder or dunder names, e. g. "_{var_name}" or "__{var_name}__"' + ) + private_attributes[var_name] = value + elif config.underscore_attrs_are_private and is_valid_private_name(var_name) and can_be_changed: + private_attributes[var_name] = PrivateAttr(default=value) + elif is_valid_field(var_name) and var_name not in annotations and can_be_changed: + validate_field_name(bases, var_name) + inferred = ModelField.infer( + name=var_name, + value=value, + annotation=annotations.get(var_name, Undefined), + class_validators=vg.get_validators(var_name), + config=config, + ) + if var_name in fields: + if lenient_issubclass(inferred.type_, fields[var_name].type_): + inferred.type_ = fields[var_name].type_ + else: + raise TypeError( + f'The type of {name}.{var_name} differs from the new default value; ' + f'if you wish to change the type of this field, please use a type annotation' + ) + fields[var_name] = inferred + + _custom_root_type = ROOT_KEY in fields + if _custom_root_type: + validate_custom_root_type(fields) + vg.check_for_unused() + if config.json_encoders: + json_encoder = partial(custom_pydantic_encoder, config.json_encoders) + else: + json_encoder = pydantic_encoder + pre_rv_new, post_rv_new = extract_root_validators(namespace) + + if hash_func is None: + hash_func = generate_hash_function(config.frozen) + + exclude_from_namespace = fields | private_attributes.keys() | {'__slots__'} + new_namespace = { + '__config__': config, + '__fields__': fields, + '__exclude_fields__': { + name: field.field_info.exclude for name, field in fields.items() if field.field_info.exclude is not None + } + or None, + '__include_fields__': { + name: field.field_info.include for name, field in fields.items() if field.field_info.include is not None + } + or None, + '__validators__': vg.validators, + '__pre_root_validators__': unique_list( + pre_root_validators + pre_rv_new, + name_factory=lambda v: v.__name__, + ), + '__post_root_validators__': unique_list( + post_root_validators + post_rv_new, + name_factory=lambda skip_on_failure_and_v: skip_on_failure_and_v[1].__name__, + ), + '__schema_cache__': {}, + '__json_encoder__': staticmethod(json_encoder), + '__custom_root_type__': _custom_root_type, + '__private_attributes__': {**base_private_attributes, **private_attributes}, + '__slots__': slots | private_attributes.keys(), + '__hash__': hash_func, + '__class_vars__': class_vars, + **{n: v for n, v in namespace.items() if n not in exclude_from_namespace}, + } + + cls = super().__new__(mcs, name, bases, new_namespace, **kwargs) + # set __signature__ attr only for model class, but not for its instances + cls.__signature__ = ClassAttribute('__signature__', generate_model_signature(cls.__init__, fields, config)) + + if not _is_base_model_class_defined: + # Cython does not understand the `if TYPE_CHECKING:` condition in the + # BaseModel's body (where annotations are set), so clear them manually: + getattr(cls, '__annotations__', {}).clear() + + if resolve_forward_refs: + cls.__try_update_forward_refs__() + + # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487 + # for attributes not in `new_namespace` (e.g. private attributes) + for name, obj in namespace.items(): + if name not in new_namespace: + set_name = getattr(obj, '__set_name__', None) + if callable(set_name): + set_name(cls, name) + + return cls + + def __instancecheck__(self, instance: Any) -> bool: + """ + Avoid calling ABC _abc_subclasscheck unless we're pretty sure. + + See #3829 and python/cpython#92810 + """ + return hasattr(instance, '__post_root_validators__') and super().__instancecheck__(instance) + + +object_setattr = object.__setattr__ + + +class BaseModel(Representation, metaclass=ModelMetaclass): + if TYPE_CHECKING: + # populated by the metaclass, defined here to help IDEs only + __fields__: ClassVar[Dict[str, ModelField]] = {} + __include_fields__: ClassVar[Optional[Mapping[str, Any]]] = None + __exclude_fields__: ClassVar[Optional[Mapping[str, Any]]] = None + __validators__: ClassVar[Dict[str, AnyCallable]] = {} + __pre_root_validators__: ClassVar[List[AnyCallable]] + __post_root_validators__: ClassVar[List[Tuple[bool, AnyCallable]]] + __config__: ClassVar[Type[BaseConfig]] = BaseConfig + __json_encoder__: ClassVar[Callable[[Any], Any]] = lambda x: x + __schema_cache__: ClassVar['DictAny'] = {} + __custom_root_type__: ClassVar[bool] = False + __signature__: ClassVar['Signature'] + __private_attributes__: ClassVar[Dict[str, ModelPrivateAttr]] + __class_vars__: ClassVar[SetStr] + __fields_set__: ClassVar[SetStr] = set() + + Config = BaseConfig + __slots__ = ('__dict__', '__fields_set__') + __doc__ = '' # Null out the Representation docstring + + def __init__(__pydantic_self__, **data: Any) -> None: + """ + Create a new model by parsing and validating input data from keyword arguments. + + Raises ValidationError if the input data cannot be parsed to form a valid model. + """ + # Uses something other than `self` the first arg to allow "self" as a settable attribute + values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data) + if validation_error: + raise validation_error + try: + object_setattr(__pydantic_self__, '__dict__', values) + except TypeError as e: + raise TypeError( + 'Model values must be a dict; you may not have returned a dictionary from a root validator' + ) from e + object_setattr(__pydantic_self__, '__fields_set__', fields_set) + __pydantic_self__._init_private_attributes() + + @no_type_check + def __setattr__(self, name, value): # noqa: C901 (ignore complexity) + if name in self.__private_attributes__ or name in DUNDER_ATTRIBUTES: + return object_setattr(self, name, value) + + if self.__config__.extra is not Extra.allow and name not in self.__fields__: + raise ValueError(f'"{self.__class__.__name__}" object has no field "{name}"') + elif not self.__config__.allow_mutation or self.__config__.frozen: + raise TypeError(f'"{self.__class__.__name__}" is immutable and does not support item assignment') + elif name in self.__fields__ and self.__fields__[name].final: + raise TypeError( + f'"{self.__class__.__name__}" object "{name}" field is final and does not support reassignment' + ) + elif self.__config__.validate_assignment: + new_values = {**self.__dict__, name: value} + + for validator in self.__pre_root_validators__: + try: + new_values = validator(self.__class__, new_values) + except (ValueError, TypeError, AssertionError) as exc: + raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], self.__class__) + + known_field = self.__fields__.get(name, None) + if known_field: + # We want to + # - make sure validators are called without the current value for this field inside `values` + # - keep other values (e.g. submodels) untouched (using `BaseModel.dict()` will change them into dicts) + # - keep the order of the fields + if not known_field.field_info.allow_mutation: + raise TypeError(f'"{known_field.name}" has allow_mutation set to False and cannot be assigned') + dict_without_original_value = {k: v for k, v in self.__dict__.items() if k != name} + value, error_ = known_field.validate(value, dict_without_original_value, loc=name, cls=self.__class__) + if error_: + raise ValidationError([error_], self.__class__) + else: + new_values[name] = value + + errors = [] + for skip_on_failure, validator in self.__post_root_validators__: + if skip_on_failure and errors: + continue + try: + new_values = validator(self.__class__, new_values) + except (ValueError, TypeError, AssertionError) as exc: + errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) + if errors: + raise ValidationError(errors, self.__class__) + + # update the whole __dict__ as other values than just `value` + # may be changed (e.g. with `root_validator`) + object_setattr(self, '__dict__', new_values) + else: + self.__dict__[name] = value + + self.__fields_set__.add(name) + + def __getstate__(self) -> 'DictAny': + private_attrs = ((k, getattr(self, k, Undefined)) for k in self.__private_attributes__) + return { + '__dict__': self.__dict__, + '__fields_set__': self.__fields_set__, + '__private_attribute_values__': {k: v for k, v in private_attrs if v is not Undefined}, + } + + def __setstate__(self, state: 'DictAny') -> None: + object_setattr(self, '__dict__', state['__dict__']) + object_setattr(self, '__fields_set__', state['__fields_set__']) + for name, value in state.get('__private_attribute_values__', {}).items(): + object_setattr(self, name, value) + + def _init_private_attributes(self) -> None: + for name, private_attr in self.__private_attributes__.items(): + default = private_attr.get_default() + if default is not Undefined: + object_setattr(self, name, default) + + def dict( + self, + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + by_alias: bool = False, + skip_defaults: Optional[bool] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> 'DictStrAny': + """ + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + """ + if skip_defaults is not None: + warnings.warn( + f'{self.__class__.__name__}.dict(): "skip_defaults" is deprecated and replaced by "exclude_unset"', + DeprecationWarning, + ) + exclude_unset = skip_defaults + + return dict( + self._iter( + to_dict=True, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + ) + + def json( + self, + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + by_alias: bool = False, + skip_defaults: Optional[bool] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + encoder: Optional[Callable[[Any], Any]] = None, + models_as_dict: bool = True, + **dumps_kwargs: Any, + ) -> str: + """ + Generate a JSON representation of the model, `include` and `exclude` arguments as per `dict()`. + + `encoder` is an optional function to supply as `default` to json.dumps(), other arguments as per `json.dumps()`. + """ + if skip_defaults is not None: + warnings.warn( + f'{self.__class__.__name__}.json(): "skip_defaults" is deprecated and replaced by "exclude_unset"', + DeprecationWarning, + ) + exclude_unset = skip_defaults + encoder = cast(Callable[[Any], Any], encoder or self.__json_encoder__) + + # We don't directly call `self.dict()`, which does exactly this with `to_dict=True` + # because we want to be able to keep raw `BaseModel` instances and not as `dict`. + # This allows users to write custom JSON encoders for given `BaseModel` classes. + data = dict( + self._iter( + to_dict=models_as_dict, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + ) + if self.__custom_root_type__: + data = data[ROOT_KEY] + return self.__config__.json_dumps(data, default=encoder, **dumps_kwargs) + + @classmethod + def _enforce_dict_if_root(cls, obj: Any) -> Any: + if cls.__custom_root_type__ and ( + not (isinstance(obj, dict) and obj.keys() == {ROOT_KEY}) + and not (isinstance(obj, BaseModel) and obj.__fields__.keys() == {ROOT_KEY}) + or cls.__fields__[ROOT_KEY].shape in MAPPING_LIKE_SHAPES + ): + return {ROOT_KEY: obj} + else: + return obj + + @classmethod + def parse_obj(cls: Type['Model'], obj: Any) -> 'Model': + obj = cls._enforce_dict_if_root(obj) + if not isinstance(obj, dict): + try: + obj = dict(obj) + except (TypeError, ValueError) as e: + exc = TypeError(f'{cls.__name__} expected dict not {obj.__class__.__name__}') + raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls) from e + return cls(**obj) + + @classmethod + def parse_raw( + cls: Type['Model'], + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + ) -> 'Model': + try: + obj = load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=cls.__config__.json_loads, + ) + except (ValueError, TypeError, UnicodeDecodeError) as e: + raise ValidationError([ErrorWrapper(e, loc=ROOT_KEY)], cls) + return cls.parse_obj(obj) + + @classmethod + def parse_file( + cls: Type['Model'], + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + ) -> 'Model': + obj = load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=cls.__config__.json_loads, + ) + return cls.parse_obj(obj) + + @classmethod + def from_orm(cls: Type['Model'], obj: Any) -> 'Model': + if not cls.__config__.orm_mode: + raise ConfigError('You must have the config attribute orm_mode=True to use from_orm') + obj = {ROOT_KEY: obj} if cls.__custom_root_type__ else cls._decompose_class(obj) + m = cls.__new__(cls) + values, fields_set, validation_error = validate_model(cls, obj) + if validation_error: + raise validation_error + object_setattr(m, '__dict__', values) + object_setattr(m, '__fields_set__', fields_set) + m._init_private_attributes() + return m + + @classmethod + def construct(cls: Type['Model'], _fields_set: Optional['SetStr'] = None, **values: Any) -> 'Model': + """ + Creates a new model setting __dict__ and __fields_set__ from trusted or pre-validated data. + Default values are respected, but no other validation is performed. + Behaves as if `Config.extra = 'allow'` was set since it adds all passed values + """ + m = cls.__new__(cls) + fields_values: Dict[str, Any] = {} + for name, field in cls.__fields__.items(): + if field.alt_alias and field.alias in values: + fields_values[name] = values[field.alias] + elif name in values: + fields_values[name] = values[name] + elif not field.required: + fields_values[name] = field.get_default() + fields_values.update(values) + object_setattr(m, '__dict__', fields_values) + if _fields_set is None: + _fields_set = set(values.keys()) + object_setattr(m, '__fields_set__', _fields_set) + m._init_private_attributes() + return m + + def _copy_and_set_values(self: 'Model', values: 'DictStrAny', fields_set: 'SetStr', *, deep: bool) -> 'Model': + if deep: + # chances of having empty dict here are quite low for using smart_deepcopy + values = deepcopy(values) + + cls = self.__class__ + m = cls.__new__(cls) + object_setattr(m, '__dict__', values) + object_setattr(m, '__fields_set__', fields_set) + for name in self.__private_attributes__: + value = getattr(self, name, Undefined) + if value is not Undefined: + if deep: + value = deepcopy(value) + object_setattr(m, name, value) + + return m + + def copy( + self: 'Model', + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + update: Optional['DictStrAny'] = None, + deep: bool = False, + ) -> 'Model': + """ + Duplicate a model, optionally choose which fields to include, exclude and change. + + :param include: fields to include in new model + :param exclude: fields to exclude from new model, as with values this takes precedence over include + :param update: values to change/add in the new model. Note: the data is not validated before creating + the new model: you should trust this data + :param deep: set to `True` to make a deep copy of the model + :return: new model instance + """ + + values = dict( + self._iter(to_dict=False, by_alias=False, include=include, exclude=exclude, exclude_unset=False), + **(update or {}), + ) + + # new `__fields_set__` can have unset optional fields with a set value in `update` kwarg + if update: + fields_set = self.__fields_set__ | update.keys() + else: + fields_set = set(self.__fields_set__) + + return self._copy_and_set_values(values, fields_set, deep=deep) + + @classmethod + def schema(cls, by_alias: bool = True, ref_template: str = default_ref_template) -> 'DictStrAny': + cached = cls.__schema_cache__.get((by_alias, ref_template)) + if cached is not None: + return cached + s = model_schema(cls, by_alias=by_alias, ref_template=ref_template) + cls.__schema_cache__[(by_alias, ref_template)] = s + return s + + @classmethod + def schema_json( + cls, *, by_alias: bool = True, ref_template: str = default_ref_template, **dumps_kwargs: Any + ) -> str: + from pydantic.v1.json import pydantic_encoder + + return cls.__config__.json_dumps( + cls.schema(by_alias=by_alias, ref_template=ref_template), default=pydantic_encoder, **dumps_kwargs + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls: Type['Model'], value: Any) -> 'Model': + if isinstance(value, cls): + copy_on_model_validation = cls.__config__.copy_on_model_validation + # whether to deep or shallow copy the model on validation, None means do not copy + deep_copy: Optional[bool] = None + if copy_on_model_validation not in {'deep', 'shallow', 'none'}: + # Warn about deprecated behavior + warnings.warn( + "`copy_on_model_validation` should be a string: 'deep', 'shallow' or 'none'", DeprecationWarning + ) + if copy_on_model_validation: + deep_copy = False + + if copy_on_model_validation == 'shallow': + # shallow copy + deep_copy = False + elif copy_on_model_validation == 'deep': + # deep copy + deep_copy = True + + if deep_copy is None: + return value + else: + return value._copy_and_set_values(value.__dict__, value.__fields_set__, deep=deep_copy) + + value = cls._enforce_dict_if_root(value) + + if isinstance(value, dict): + return cls(**value) + elif cls.__config__.orm_mode: + return cls.from_orm(value) + else: + try: + value_as_dict = dict(value) + except (TypeError, ValueError) as e: + raise DictError() from e + return cls(**value_as_dict) + + @classmethod + def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict: + if isinstance(obj, GetterDict): + return obj + return cls.__config__.getter_dict(obj) + + @classmethod + @no_type_check + def _get_value( + cls, + v: Any, + to_dict: bool, + by_alias: bool, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], + exclude_unset: bool, + exclude_defaults: bool, + exclude_none: bool, + ) -> Any: + if isinstance(v, BaseModel): + if to_dict: + v_dict = v.dict( + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=include, + exclude=exclude, + exclude_none=exclude_none, + ) + if ROOT_KEY in v_dict: + return v_dict[ROOT_KEY] + return v_dict + else: + return v.copy(include=include, exclude=exclude) + + value_exclude = ValueItems(v, exclude) if exclude else None + value_include = ValueItems(v, include) if include else None + + if isinstance(v, dict): + return { + k_: cls._get_value( + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(k_), + exclude=value_exclude and value_exclude.for_element(k_), + exclude_none=exclude_none, + ) + for k_, v_ in v.items() + if (not value_exclude or not value_exclude.is_excluded(k_)) + and (not value_include or value_include.is_included(k_)) + } + + elif sequence_like(v): + seq_args = ( + cls._get_value( + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(i), + exclude=value_exclude and value_exclude.for_element(i), + exclude_none=exclude_none, + ) + for i, v_ in enumerate(v) + if (not value_exclude or not value_exclude.is_excluded(i)) + and (not value_include or value_include.is_included(i)) + ) + + return v.__class__(*seq_args) if is_namedtuple(v.__class__) else v.__class__(seq_args) + + elif isinstance(v, Enum) and getattr(cls.Config, 'use_enum_values', False): + return v.value + + else: + return v + + @classmethod + def __try_update_forward_refs__(cls, **localns: Any) -> None: + """ + Same as update_forward_refs but will not raise exception + when forward references are not defined. + """ + update_model_forward_refs(cls, cls.__fields__.values(), cls.__config__.json_encoders, localns, (NameError,)) + + @classmethod + def update_forward_refs(cls, **localns: Any) -> None: + """ + Try to update ForwardRefs on fields based on this Model, globalns and localns. + """ + update_model_forward_refs(cls, cls.__fields__.values(), cls.__config__.json_encoders, localns) + + def __iter__(self) -> 'TupleGenerator': + """ + so `dict(model)` works + """ + yield from self.__dict__.items() + + def _iter( + self, + to_dict: bool = False, + by_alias: bool = False, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> 'TupleGenerator': + # Merge field set excludes with explicit exclude parameter with explicit overriding field set options. + # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case. + if exclude is not None or self.__exclude_fields__ is not None: + exclude = ValueItems.merge(self.__exclude_fields__, exclude) + + if include is not None or self.__include_fields__ is not None: + include = ValueItems.merge(self.__include_fields__, include, intersect=True) + + allowed_keys = self._calculate_keys( + include=include, exclude=exclude, exclude_unset=exclude_unset # type: ignore + ) + if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): + # huge boost for plain _iter() + yield from self.__dict__.items() + return + + value_exclude = ValueItems(self, exclude) if exclude is not None else None + value_include = ValueItems(self, include) if include is not None else None + + for field_key, v in self.__dict__.items(): + if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): + continue + + if exclude_defaults: + model_field = self.__fields__.get(field_key) + if not getattr(model_field, 'required', True) and getattr(model_field, 'default', _missing) == v: + continue + + if by_alias and field_key in self.__fields__: + dict_key = self.__fields__[field_key].alias + else: + dict_key = field_key + + if to_dict or value_include or value_exclude: + v = self._get_value( + v, + to_dict=to_dict, + by_alias=by_alias, + include=value_include and value_include.for_element(field_key), + exclude=value_exclude and value_exclude.for_element(field_key), + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + yield dict_key, v + + def _calculate_keys( + self, + include: Optional['MappingIntStrAny'], + exclude: Optional['MappingIntStrAny'], + exclude_unset: bool, + update: Optional['DictStrAny'] = None, + ) -> Optional[AbstractSet[str]]: + if include is None and exclude is None and exclude_unset is False: + return None + + keys: AbstractSet[str] + if exclude_unset: + keys = self.__fields_set__.copy() + else: + keys = self.__dict__.keys() + + if include is not None: + keys &= include.keys() + + if update: + keys -= update.keys() + + if exclude: + keys -= {k for k, v in exclude.items() if ValueItems.is_true(v)} + + return keys + + def __eq__(self, other: Any) -> bool: + if isinstance(other, BaseModel): + return self.dict() == other.dict() + else: + return self.dict() == other + + def __repr_args__(self) -> 'ReprArgs': + return [ + (k, v) + for k, v in self.__dict__.items() + if k not in DUNDER_ATTRIBUTES and (k not in self.__fields__ or self.__fields__[k].field_info.repr) + ] + + +_is_base_model_class_defined = True + + +@overload +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: None = None, + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + **field_definitions: Any, +) -> Type['BaseModel']: + ... + + +@overload +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: Union[Type['Model'], Tuple[Type['Model'], ...]], + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + **field_definitions: Any, +) -> Type['Model']: + ... + + +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: Union[None, Type['Model'], Tuple[Type['Model'], ...]] = None, + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + __slots__: Optional[Tuple[str, ...]] = None, + **field_definitions: Any, +) -> Type['Model']: + """ + Dynamically create a model. + :param __model_name: name of the created model + :param __config__: config class to use for the new model + :param __base__: base class for the new model to inherit from + :param __module__: module of the created model + :param __validators__: a dict of method names and @validator class methods + :param __cls_kwargs__: a dict for class creation + :param __slots__: Deprecated, `__slots__` should not be passed to `create_model` + :param field_definitions: fields of the model (or extra fields if a base is supplied) + in the format `=(, )` or `=, e.g. + `foobar=(str, ...)` or `foobar=123`, or, for complex use-cases, in the format + `=` or `=(, )`, e.g. + `foo=Field(datetime, default_factory=datetime.utcnow, alias='bar')` or + `foo=(str, FieldInfo(title='Foo'))` + """ + if __slots__ is not None: + # __slots__ will be ignored from here on + warnings.warn('__slots__ should not be passed to create_model', RuntimeWarning) + + if __base__ is not None: + if __config__ is not None: + raise ConfigError('to avoid confusion __config__ and __base__ cannot be used together') + if not isinstance(__base__, tuple): + __base__ = (__base__,) + else: + __base__ = (cast(Type['Model'], BaseModel),) + + __cls_kwargs__ = __cls_kwargs__ or {} + + fields = {} + annotations = {} + + for f_name, f_def in field_definitions.items(): + if not is_valid_field(f_name): + warnings.warn(f'fields may not start with an underscore, ignoring "{f_name}"', RuntimeWarning) + if isinstance(f_def, tuple): + try: + f_annotation, f_value = f_def + except ValueError as e: + raise ConfigError( + 'field definitions should either be a tuple of (, ) or just a ' + 'default value, unfortunately this means tuples as ' + 'default values are not allowed' + ) from e + else: + f_annotation, f_value = None, f_def + + if f_annotation: + annotations[f_name] = f_annotation + fields[f_name] = f_value + + namespace: 'DictStrAny' = {'__annotations__': annotations, '__module__': __module__} + if __validators__: + namespace.update(__validators__) + namespace.update(fields) + if __config__: + namespace['Config'] = inherit_config(__config__, BaseConfig) + resolved_bases = resolve_bases(__base__) + meta, ns, kwds = prepare_class(__model_name, resolved_bases, kwds=__cls_kwargs__) + if resolved_bases is not __base__: + ns['__orig_bases__'] = __base__ + namespace.update(ns) + return meta(__model_name, resolved_bases, namespace, **kwds) + + +_missing = object() + + +def validate_model( # noqa: C901 (ignore complexity) + model: Type[BaseModel], input_data: 'DictStrAny', cls: 'ModelOrDc' = None +) -> Tuple['DictStrAny', 'SetStr', Optional[ValidationError]]: + """ + validate data against a model. + """ + values = {} + errors = [] + # input_data names, possibly alias + names_used = set() + # field names, never aliases + fields_set = set() + config = model.__config__ + check_extra = config.extra is not Extra.ignore + cls_ = cls or model + + for validator in model.__pre_root_validators__: + try: + input_data = validator(cls_, input_data) + except (ValueError, TypeError, AssertionError) as exc: + return {}, set(), ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls_) + + for name, field in model.__fields__.items(): + value = input_data.get(field.alias, _missing) + using_name = False + if value is _missing and config.allow_population_by_field_name and field.alt_alias: + value = input_data.get(field.name, _missing) + using_name = True + + if value is _missing: + if field.required: + errors.append(ErrorWrapper(MissingError(), loc=field.alias)) + continue + + value = field.get_default() + + if not config.validate_all and not field.validate_always: + values[name] = value + continue + else: + fields_set.add(name) + if check_extra: + names_used.add(field.name if using_name else field.alias) + + v_, errors_ = field.validate(value, values, loc=field.alias, cls=cls_) + if isinstance(errors_, ErrorWrapper): + errors.append(errors_) + elif isinstance(errors_, list): + errors.extend(errors_) + else: + values[name] = v_ + + if check_extra: + if isinstance(input_data, GetterDict): + extra = input_data.extra_keys() - names_used + else: + extra = input_data.keys() - names_used + if extra: + fields_set |= extra + if config.extra is Extra.allow: + for f in extra: + values[f] = input_data[f] + else: + for f in sorted(extra): + errors.append(ErrorWrapper(ExtraError(), loc=f)) + + for skip_on_failure, validator in model.__post_root_validators__: + if skip_on_failure and errors: + continue + try: + values = validator(cls_, values) + except (ValueError, TypeError, AssertionError) as exc: + errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) + + if errors: + return values, fields_set, ValidationError(errors, cls_) + else: + return values, fields_set, None diff --git a/backend/venv/Lib/site-packages/pydantic/v1/mypy.py b/backend/venv/Lib/site-packages/pydantic/v1/mypy.py new file mode 100644 index 0000000..0a77569 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/mypy.py @@ -0,0 +1,949 @@ +import sys +from configparser import ConfigParser +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type as TypingType, Union + +from mypy.errorcodes import ErrorCode +from mypy.nodes import ( + ARG_NAMED, + ARG_NAMED_OPT, + ARG_OPT, + ARG_POS, + ARG_STAR2, + MDEF, + Argument, + AssignmentStmt, + Block, + CallExpr, + ClassDef, + Context, + Decorator, + EllipsisExpr, + FuncBase, + FuncDef, + JsonDict, + MemberExpr, + NameExpr, + PassStmt, + PlaceholderNode, + RefExpr, + StrExpr, + SymbolNode, + SymbolTableNode, + TempNode, + TypeInfo, + TypeVarExpr, + Var, +) +from mypy.options import Options +from mypy.plugin import ( + CheckerPluginInterface, + ClassDefContext, + FunctionContext, + MethodContext, + Plugin, + ReportConfigContext, + SemanticAnalyzerPluginInterface, +) +from mypy.plugins import dataclasses +from mypy.semanal import set_callable_name # type: ignore +from mypy.server.trigger import make_wildcard_trigger +from mypy.types import ( + AnyType, + CallableType, + Instance, + NoneType, + Overloaded, + ProperType, + Type, + TypeOfAny, + TypeType, + TypeVarId, + TypeVarType, + UnionType, + get_proper_type, +) +from mypy.typevars import fill_typevars +from mypy.util import get_unique_redefinition_name +from mypy.version import __version__ as mypy_version + +from pydantic.v1.utils import is_valid_field + +try: + from mypy.types import TypeVarDef # type: ignore[attr-defined] +except ImportError: # pragma: no cover + # Backward-compatible with TypeVarDef from Mypy 0.910. + from mypy.types import TypeVarType as TypeVarDef + +CONFIGFILE_KEY = 'pydantic-mypy' +METADATA_KEY = 'pydantic-mypy-metadata' +_NAMESPACE = __name__[:-5] # 'pydantic' in 1.10.X, 'pydantic.v1' in v2.X +BASEMODEL_FULLNAME = f'{_NAMESPACE}.main.BaseModel' +BASESETTINGS_FULLNAME = f'{_NAMESPACE}.env_settings.BaseSettings' +MODEL_METACLASS_FULLNAME = f'{_NAMESPACE}.main.ModelMetaclass' +FIELD_FULLNAME = f'{_NAMESPACE}.fields.Field' +DATACLASS_FULLNAME = f'{_NAMESPACE}.dataclasses.dataclass' + + +def parse_mypy_version(version: str) -> Tuple[int, ...]: + return tuple(map(int, version.partition('+')[0].split('.'))) + + +MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version) +BUILTINS_NAME = 'builtins' if MYPY_VERSION_TUPLE >= (0, 930) else '__builtins__' + +# Increment version if plugin changes and mypy caches should be invalidated +__version__ = 2 + + +def plugin(version: str) -> 'TypingType[Plugin]': + """ + `version` is the mypy version string + + We might want to use this to print a warning if the mypy version being used is + newer, or especially older, than we expect (or need). + """ + return PydanticPlugin + + +class PydanticPlugin(Plugin): + def __init__(self, options: Options) -> None: + self.plugin_config = PydanticPluginConfig(options) + self._plugin_data = self.plugin_config.to_data() + super().__init__(options) + + def get_base_class_hook(self, fullname: str) -> 'Optional[Callable[[ClassDefContext], None]]': + sym = self.lookup_fully_qualified(fullname) + if sym and isinstance(sym.node, TypeInfo): # pragma: no branch + # No branching may occur if the mypy cache has not been cleared + if any(get_fullname(base) == BASEMODEL_FULLNAME for base in sym.node.mro): + return self._pydantic_model_class_maker_callback + return None + + def get_metaclass_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]: + if fullname == MODEL_METACLASS_FULLNAME: + return self._pydantic_model_metaclass_marker_callback + return None + + def get_function_hook(self, fullname: str) -> 'Optional[Callable[[FunctionContext], Type]]': + sym = self.lookup_fully_qualified(fullname) + if sym and sym.fullname == FIELD_FULLNAME: + return self._pydantic_field_callback + return None + + def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], Type]]: + if fullname.endswith('.from_orm'): + return from_orm_callback + return None + + def get_class_decorator_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]: + """Mark pydantic.dataclasses as dataclass. + + Mypy version 1.1.1 added support for `@dataclass_transform` decorator. + """ + if fullname == DATACLASS_FULLNAME and MYPY_VERSION_TUPLE < (1, 1): + return dataclasses.dataclass_class_maker_callback # type: ignore[return-value] + return None + + def report_config_data(self, ctx: ReportConfigContext) -> Dict[str, Any]: + """Return all plugin config data. + + Used by mypy to determine if cache needs to be discarded. + """ + return self._plugin_data + + def _pydantic_model_class_maker_callback(self, ctx: ClassDefContext) -> None: + transformer = PydanticModelTransformer(ctx, self.plugin_config) + transformer.transform() + + def _pydantic_model_metaclass_marker_callback(self, ctx: ClassDefContext) -> None: + """Reset dataclass_transform_spec attribute of ModelMetaclass. + + Let the plugin handle it. This behavior can be disabled + if 'debug_dataclass_transform' is set to True', for testing purposes. + """ + if self.plugin_config.debug_dataclass_transform: + return + info_metaclass = ctx.cls.info.declared_metaclass + assert info_metaclass, "callback not passed from 'get_metaclass_hook'" + if getattr(info_metaclass.type, 'dataclass_transform_spec', None): + info_metaclass.type.dataclass_transform_spec = None # type: ignore[attr-defined] + + def _pydantic_field_callback(self, ctx: FunctionContext) -> 'Type': + """ + Extract the type of the `default` argument from the Field function, and use it as the return type. + + In particular: + * Check whether the default and default_factory argument is specified. + * Output an error if both are specified. + * Retrieve the type of the argument which is specified, and use it as return type for the function. + """ + default_any_type = ctx.default_return_type + + assert ctx.callee_arg_names[0] == 'default', '"default" is no longer first argument in Field()' + assert ctx.callee_arg_names[1] == 'default_factory', '"default_factory" is no longer second argument in Field()' + default_args = ctx.args[0] + default_factory_args = ctx.args[1] + + if default_args and default_factory_args: + error_default_and_default_factory_specified(ctx.api, ctx.context) + return default_any_type + + if default_args: + default_type = ctx.arg_types[0][0] + default_arg = default_args[0] + + # Fallback to default Any type if the field is required + if not isinstance(default_arg, EllipsisExpr): + return default_type + + elif default_factory_args: + default_factory_type = ctx.arg_types[1][0] + + # Functions which use `ParamSpec` can be overloaded, exposing the callable's types as a parameter + # Pydantic calls the default factory without any argument, so we retrieve the first item + if isinstance(default_factory_type, Overloaded): + if MYPY_VERSION_TUPLE > (0, 910): + default_factory_type = default_factory_type.items[0] + else: + # Mypy0.910 exposes the items of overloaded types in a function + default_factory_type = default_factory_type.items()[0] # type: ignore[operator] + + if isinstance(default_factory_type, CallableType): + ret_type = get_proper_type(default_factory_type.ret_type) + if ( + isinstance(ret_type, Instance) + and ret_type.args + and all(isinstance(arg, TypeVarType) for arg in ret_type.args) + ): + # Looks like the default factory is a type like `list` or `dict`, replace all args with `Any` + ret_type = ret_type.copy_modified(args=[default_any_type] * len(ret_type.args)) + return ret_type + + return default_any_type + + +class PydanticPluginConfig: + __slots__ = ( + 'init_forbid_extra', + 'init_typed', + 'warn_required_dynamic_aliases', + 'warn_untyped_fields', + 'debug_dataclass_transform', + ) + init_forbid_extra: bool + init_typed: bool + warn_required_dynamic_aliases: bool + warn_untyped_fields: bool + debug_dataclass_transform: bool # undocumented + + def __init__(self, options: Options) -> None: + if options.config_file is None: # pragma: no cover + return + + toml_config = parse_toml(options.config_file) + if toml_config is not None: + config = toml_config.get('tool', {}).get('pydantic-mypy', {}) + for key in self.__slots__: + setting = config.get(key, False) + if not isinstance(setting, bool): + raise ValueError(f'Configuration value must be a boolean for key: {key}') + setattr(self, key, setting) + else: + plugin_config = ConfigParser() + plugin_config.read(options.config_file) + for key in self.__slots__: + setting = plugin_config.getboolean(CONFIGFILE_KEY, key, fallback=False) + setattr(self, key, setting) + + def to_data(self) -> Dict[str, Any]: + return {key: getattr(self, key) for key in self.__slots__} + + +def from_orm_callback(ctx: MethodContext) -> Type: + """ + Raise an error if orm_mode is not enabled + """ + model_type: Instance + ctx_type = ctx.type + if isinstance(ctx_type, TypeType): + ctx_type = ctx_type.item + if isinstance(ctx_type, CallableType) and isinstance(ctx_type.ret_type, Instance): + model_type = ctx_type.ret_type # called on the class + elif isinstance(ctx_type, Instance): + model_type = ctx_type # called on an instance (unusual, but still valid) + else: # pragma: no cover + detail = f'ctx.type: {ctx_type} (of type {ctx_type.__class__.__name__})' + error_unexpected_behavior(detail, ctx.api, ctx.context) + return ctx.default_return_type + pydantic_metadata = model_type.type.metadata.get(METADATA_KEY) + if pydantic_metadata is None: + return ctx.default_return_type + orm_mode = pydantic_metadata.get('config', {}).get('orm_mode') + if orm_mode is not True: + error_from_orm(get_name(model_type.type), ctx.api, ctx.context) + return ctx.default_return_type + + +class PydanticModelTransformer: + tracked_config_fields: Set[str] = { + 'extra', + 'allow_mutation', + 'frozen', + 'orm_mode', + 'allow_population_by_field_name', + 'alias_generator', + } + + def __init__(self, ctx: ClassDefContext, plugin_config: PydanticPluginConfig) -> None: + self._ctx = ctx + self.plugin_config = plugin_config + + def transform(self) -> None: + """ + Configures the BaseModel subclass according to the plugin settings. + + In particular: + * determines the model config and fields, + * adds a fields-aware signature for the initializer and construct methods + * freezes the class if allow_mutation = False or frozen = True + * stores the fields, config, and if the class is settings in the mypy metadata for access by subclasses + """ + ctx = self._ctx + info = ctx.cls.info + + self.adjust_validator_signatures() + config = self.collect_config() + fields = self.collect_fields(config) + is_settings = any(get_fullname(base) == BASESETTINGS_FULLNAME for base in info.mro[:-1]) + self.add_initializer(fields, config, is_settings) + self.add_construct_method(fields) + self.set_frozen(fields, frozen=config.allow_mutation is False or config.frozen is True) + info.metadata[METADATA_KEY] = { + 'fields': {field.name: field.serialize() for field in fields}, + 'config': config.set_values_dict(), + } + + def adjust_validator_signatures(self) -> None: + """When we decorate a function `f` with `pydantic.validator(...), mypy sees + `f` as a regular method taking a `self` instance, even though pydantic + internally wraps `f` with `classmethod` if necessary. + + Teach mypy this by marking any function whose outermost decorator is a + `validator()` call as a classmethod. + """ + for name, sym in self._ctx.cls.info.names.items(): + if isinstance(sym.node, Decorator): + first_dec = sym.node.original_decorators[0] + if ( + isinstance(first_dec, CallExpr) + and isinstance(first_dec.callee, NameExpr) + and first_dec.callee.fullname == f'{_NAMESPACE}.class_validators.validator' + ): + sym.node.func.is_class = True + + def collect_config(self) -> 'ModelConfigData': + """ + Collects the values of the config attributes that are used by the plugin, accounting for parent classes. + """ + ctx = self._ctx + cls = ctx.cls + config = ModelConfigData() + for stmt in cls.defs.body: + if not isinstance(stmt, ClassDef): + continue + if stmt.name == 'Config': + for substmt in stmt.defs.body: + if not isinstance(substmt, AssignmentStmt): + continue + config.update(self.get_config_update(substmt)) + if ( + config.has_alias_generator + and not config.allow_population_by_field_name + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(ctx.api, stmt) + for info in cls.info.mro[1:]: # 0 is the current class + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of fields in its ancestors + ctx.api.add_plugin_dependency(make_wildcard_trigger(get_fullname(info))) + for name, value in info.metadata[METADATA_KEY]['config'].items(): + config.setdefault(name, value) + return config + + def collect_fields(self, model_config: 'ModelConfigData') -> List['PydanticModelField']: + """ + Collects the fields for the model, accounting for parent classes + """ + # First, collect fields belonging to the current class. + ctx = self._ctx + cls = self._ctx.cls + fields = [] # type: List[PydanticModelField] + known_fields = set() # type: Set[str] + for stmt in cls.defs.body: + if not isinstance(stmt, AssignmentStmt): # `and stmt.new_syntax` to require annotation + continue + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or not is_valid_field(lhs.name): + continue + + if not stmt.new_syntax and self.plugin_config.warn_untyped_fields: + error_untyped_fields(ctx.api, stmt) + + # if lhs.name == '__config__': # BaseConfig not well handled; I'm not sure why yet + # continue + + sym = cls.info.names.get(lhs.name) + if sym is None: # pragma: no cover + # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation) + # This is the same logic used in the dataclasses plugin + continue + + node = sym.node + if isinstance(node, PlaceholderNode): # pragma: no cover + # See the PlaceholderNode docstring for more detail about how this can occur + # Basically, it is an edge case when dealing with complex import logic + # This is the same logic used in the dataclasses plugin + continue + if not isinstance(node, Var): # pragma: no cover + # Don't know if this edge case still happens with the `is_valid_field` check above + # but better safe than sorry + continue + + # x: ClassVar[int] is ignored by dataclasses. + if node.is_classvar: + continue + + is_required = self.get_is_required(cls, stmt, lhs) + alias, has_dynamic_alias = self.get_alias_info(stmt) + if ( + has_dynamic_alias + and not model_config.allow_population_by_field_name + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(ctx.api, stmt) + fields.append( + PydanticModelField( + name=lhs.name, + is_required=is_required, + alias=alias, + has_dynamic_alias=has_dynamic_alias, + line=stmt.line, + column=stmt.column, + ) + ) + known_fields.add(lhs.name) + all_fields = fields.copy() + for info in cls.info.mro[1:]: # 0 is the current class, -2 is BaseModel, -1 is object + if METADATA_KEY not in info.metadata: + continue + + superclass_fields = [] + # Each class depends on the set of fields in its ancestors + ctx.api.add_plugin_dependency(make_wildcard_trigger(get_fullname(info))) + + for name, data in info.metadata[METADATA_KEY]['fields'].items(): + if name not in known_fields: + field = PydanticModelField.deserialize(info, data) + known_fields.add(name) + superclass_fields.append(field) + else: + (field,) = (a for a in all_fields if a.name == name) + all_fields.remove(field) + superclass_fields.append(field) + all_fields = superclass_fields + all_fields + return all_fields + + def add_initializer(self, fields: List['PydanticModelField'], config: 'ModelConfigData', is_settings: bool) -> None: + """ + Adds a fields-aware `__init__` method to the class. + + The added `__init__` will be annotated with types vs. all `Any` depending on the plugin settings. + """ + ctx = self._ctx + typed = self.plugin_config.init_typed + use_alias = config.allow_population_by_field_name is not True + force_all_optional = is_settings or bool( + config.has_alias_generator and not config.allow_population_by_field_name + ) + init_arguments = self.get_field_arguments( + fields, typed=typed, force_all_optional=force_all_optional, use_alias=use_alias + ) + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + init_arguments.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + if '__init__' not in ctx.cls.info.names: + add_method(ctx, '__init__', init_arguments, NoneType()) + + def add_construct_method(self, fields: List['PydanticModelField']) -> None: + """ + Adds a fully typed `construct` classmethod to the class. + + Similar to the fields-aware __init__ method, but always uses the field names (not aliases), + and does not treat settings fields as optional. + """ + ctx = self._ctx + set_str = ctx.api.named_type(f'{BUILTINS_NAME}.set', [ctx.api.named_type(f'{BUILTINS_NAME}.str')]) + optional_set_str = UnionType([set_str, NoneType()]) + fields_set_argument = Argument(Var('_fields_set', optional_set_str), optional_set_str, None, ARG_OPT) + construct_arguments = self.get_field_arguments(fields, typed=True, force_all_optional=False, use_alias=False) + construct_arguments = [fields_set_argument] + construct_arguments + + obj_type = ctx.api.named_type(f'{BUILTINS_NAME}.object') + self_tvar_name = '_PydanticBaseModel' # Make sure it does not conflict with other names in the class + tvar_fullname = ctx.cls.fullname + '.' + self_tvar_name + if MYPY_VERSION_TUPLE >= (1, 4): + tvd = TypeVarType( + self_tvar_name, + tvar_fullname, + ( + TypeVarId(-1, namespace=ctx.cls.fullname + '.construct') + if MYPY_VERSION_TUPLE >= (1, 11) + else TypeVarId(-1) + ), + [], + obj_type, + AnyType(TypeOfAny.from_omitted_generics), # type: ignore[arg-type] + ) + self_tvar_expr = TypeVarExpr( + self_tvar_name, + tvar_fullname, + [], + obj_type, + AnyType(TypeOfAny.from_omitted_generics), # type: ignore[arg-type] + ) + else: + tvd = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type) + self_tvar_expr = TypeVarExpr(self_tvar_name, tvar_fullname, [], obj_type) + ctx.cls.info.names[self_tvar_name] = SymbolTableNode(MDEF, self_tvar_expr) + + # Backward-compatible with TypeVarDef from Mypy 0.910. + if isinstance(tvd, TypeVarType): + self_type = tvd + else: + self_type = TypeVarType(tvd) + + add_method( + ctx, + 'construct', + construct_arguments, + return_type=self_type, + self_type=self_type, + tvar_def=tvd, + is_classmethod=True, + ) + + def set_frozen(self, fields: List['PydanticModelField'], frozen: bool) -> None: + """ + Marks all fields as properties so that attempts to set them trigger mypy errors. + + This is the same approach used by the attrs and dataclasses plugins. + """ + ctx = self._ctx + info = ctx.cls.info + for field in fields: + sym_node = info.names.get(field.name) + if sym_node is not None: + var = sym_node.node + if isinstance(var, Var): + var.is_property = frozen + elif isinstance(var, PlaceholderNode) and not ctx.api.final_iteration: + # See https://github.com/pydantic/pydantic/issues/5191 to hit this branch for test coverage + ctx.api.defer() + else: # pragma: no cover + # I don't know whether it's possible to hit this branch, but I've added it for safety + try: + var_str = str(var) + except TypeError: + # This happens for PlaceholderNode; perhaps it will happen for other types in the future.. + var_str = repr(var) + detail = f'sym_node.node: {var_str} (of type {var.__class__})' + error_unexpected_behavior(detail, ctx.api, ctx.cls) + else: + var = field.to_var(info, use_alias=False) + var.info = info + var.is_property = frozen + var._fullname = get_fullname(info) + '.' + get_name(var) + info.names[get_name(var)] = SymbolTableNode(MDEF, var) + + def get_config_update(self, substmt: AssignmentStmt) -> Optional['ModelConfigData']: + """ + Determines the config update due to a single statement in the Config class definition. + + Warns if a tracked config attribute is set to a value the plugin doesn't know how to interpret (e.g., an int) + """ + lhs = substmt.lvalues[0] + if not (isinstance(lhs, NameExpr) and lhs.name in self.tracked_config_fields): + return None + if lhs.name == 'extra': + if isinstance(substmt.rvalue, StrExpr): + forbid_extra = substmt.rvalue.value == 'forbid' + elif isinstance(substmt.rvalue, MemberExpr): + forbid_extra = substmt.rvalue.name == 'forbid' + else: + error_invalid_config_value(lhs.name, self._ctx.api, substmt) + return None + return ModelConfigData(forbid_extra=forbid_extra) + if lhs.name == 'alias_generator': + has_alias_generator = True + if isinstance(substmt.rvalue, NameExpr) and substmt.rvalue.fullname == 'builtins.None': + has_alias_generator = False + return ModelConfigData(has_alias_generator=has_alias_generator) + if isinstance(substmt.rvalue, NameExpr) and substmt.rvalue.fullname in ('builtins.True', 'builtins.False'): + return ModelConfigData(**{lhs.name: substmt.rvalue.fullname == 'builtins.True'}) + error_invalid_config_value(lhs.name, self._ctx.api, substmt) + return None + + @staticmethod + def get_is_required(cls: ClassDef, stmt: AssignmentStmt, lhs: NameExpr) -> bool: + """ + Returns a boolean indicating whether the field defined in `stmt` is a required field. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only, so only non-required if Optional + value_type = get_proper_type(cls.info[lhs.name].type) + return not PydanticModelTransformer.type_has_implicit_default(value_type) + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + # The "default value" is a call to `Field`; at this point, the field is + # only required if default is Ellipsis (i.e., `field_name: Annotation = Field(...)`) or if default_factory + # is specified. + for arg, name in zip(expr.args, expr.arg_names): + # If name is None, then this arg is the default because it is the only positional argument. + if name is None or name == 'default': + return arg.__class__ is EllipsisExpr + if name == 'default_factory': + return False + # In this case, default and default_factory are not specified, so we need to look at the annotation + value_type = get_proper_type(cls.info[lhs.name].type) + return not PydanticModelTransformer.type_has_implicit_default(value_type) + # Only required if the "default value" is Ellipsis (i.e., `field_name: Annotation = ...`) + return isinstance(expr, EllipsisExpr) + + @staticmethod + def type_has_implicit_default(type_: Optional[ProperType]) -> bool: + """ + Returns True if the passed type will be given an implicit default value. + + In pydantic v1, this is the case for Optional types and Any (with default value None). + """ + if isinstance(type_, AnyType): + # Annotated as Any + return True + if isinstance(type_, UnionType) and any( + isinstance(item, NoneType) or isinstance(item, AnyType) for item in type_.items + ): + # Annotated as Optional, or otherwise having NoneType or AnyType in the union + return True + return False + + @staticmethod + def get_alias_info(stmt: AssignmentStmt) -> Tuple[Optional[str], bool]: + """ + Returns a pair (alias, has_dynamic_alias), extracted from the declaration of the field defined in `stmt`. + + `has_dynamic_alias` is True if and only if an alias is provided, but not as a string literal. + If `has_dynamic_alias` is True, `alias` will be None. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return None, False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return None, False + + for i, arg_name in enumerate(expr.arg_names): + if arg_name != 'alias': + continue + arg = expr.args[i] + if isinstance(arg, StrExpr): + return arg.value, False + else: + return None, True + return None, False + + def get_field_arguments( + self, fields: List['PydanticModelField'], typed: bool, force_all_optional: bool, use_alias: bool + ) -> List[Argument]: + """ + Helper function used during the construction of the `__init__` and `construct` method signatures. + + Returns a list of mypy Argument instances for use in the generated signatures. + """ + info = self._ctx.cls.info + arguments = [ + field.to_argument(info, typed=typed, force_optional=force_all_optional, use_alias=use_alias) + for field in fields + if not (use_alias and field.has_dynamic_alias) + ] + return arguments + + def should_init_forbid_extra(self, fields: List['PydanticModelField'], config: 'ModelConfigData') -> bool: + """ + Indicates whether the generated `__init__` should get a `**kwargs` at the end of its signature + + We disallow arbitrary kwargs if the extra config setting is "forbid", or if the plugin config says to, + *unless* a required dynamic alias is present (since then we can't determine a valid signature). + """ + if not config.allow_population_by_field_name: + if self.is_dynamic_alias_present(fields, bool(config.has_alias_generator)): + return False + if config.forbid_extra: + return True + return self.plugin_config.init_forbid_extra + + @staticmethod + def is_dynamic_alias_present(fields: List['PydanticModelField'], has_alias_generator: bool) -> bool: + """ + Returns whether any fields on the model have a "dynamic alias", i.e., an alias that cannot be + determined during static analysis. + """ + for field in fields: + if field.has_dynamic_alias: + return True + if has_alias_generator: + for field in fields: + if field.alias is None: + return True + return False + + +class PydanticModelField: + def __init__( + self, name: str, is_required: bool, alias: Optional[str], has_dynamic_alias: bool, line: int, column: int + ): + self.name = name + self.is_required = is_required + self.alias = alias + self.has_dynamic_alias = has_dynamic_alias + self.line = line + self.column = column + + def to_var(self, info: TypeInfo, use_alias: bool) -> Var: + name = self.name + if use_alias and self.alias is not None: + name = self.alias + return Var(name, info[self.name].type) + + def to_argument(self, info: TypeInfo, typed: bool, force_optional: bool, use_alias: bool) -> Argument: + if typed and info[self.name].type is not None: + type_annotation = info[self.name].type + else: + type_annotation = AnyType(TypeOfAny.explicit) + return Argument( + variable=self.to_var(info, use_alias), + type_annotation=type_annotation, + initializer=None, + kind=ARG_NAMED_OPT if force_optional or not self.is_required else ARG_NAMED, + ) + + def serialize(self) -> JsonDict: + return self.__dict__ + + @classmethod + def deserialize(cls, info: TypeInfo, data: JsonDict) -> 'PydanticModelField': + return cls(**data) + + +class ModelConfigData: + def __init__( + self, + forbid_extra: Optional[bool] = None, + allow_mutation: Optional[bool] = None, + frozen: Optional[bool] = None, + orm_mode: Optional[bool] = None, + allow_population_by_field_name: Optional[bool] = None, + has_alias_generator: Optional[bool] = None, + ): + self.forbid_extra = forbid_extra + self.allow_mutation = allow_mutation + self.frozen = frozen + self.orm_mode = orm_mode + self.allow_population_by_field_name = allow_population_by_field_name + self.has_alias_generator = has_alias_generator + + def set_values_dict(self) -> Dict[str, Any]: + return {k: v for k, v in self.__dict__.items() if v is not None} + + def update(self, config: Optional['ModelConfigData']) -> None: + if config is None: + return + for k, v in config.set_values_dict().items(): + setattr(self, k, v) + + def setdefault(self, key: str, value: Any) -> None: + if getattr(self, key) is None: + setattr(self, key, value) + + +ERROR_ORM = ErrorCode('pydantic-orm', 'Invalid from_orm call', 'Pydantic') +ERROR_CONFIG = ErrorCode('pydantic-config', 'Invalid config value', 'Pydantic') +ERROR_ALIAS = ErrorCode('pydantic-alias', 'Dynamic alias disallowed', 'Pydantic') +ERROR_UNEXPECTED = ErrorCode('pydantic-unexpected', 'Unexpected behavior', 'Pydantic') +ERROR_UNTYPED = ErrorCode('pydantic-field', 'Untyped field disallowed', 'Pydantic') +ERROR_FIELD_DEFAULTS = ErrorCode('pydantic-field', 'Invalid Field defaults', 'Pydantic') + + +def error_from_orm(model_name: str, api: CheckerPluginInterface, context: Context) -> None: + api.fail(f'"{model_name}" does not have orm_mode=True', context, code=ERROR_ORM) + + +def error_invalid_config_value(name: str, api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail(f'Invalid value for "Config.{name}"', context, code=ERROR_CONFIG) + + +def error_required_dynamic_aliases(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail('Required dynamic aliases disallowed', context, code=ERROR_ALIAS) + + +def error_unexpected_behavior( + detail: str, api: Union[CheckerPluginInterface, SemanticAnalyzerPluginInterface], context: Context +) -> None: # pragma: no cover + # Can't think of a good way to test this, but I confirmed it renders as desired by adding to a non-error path + link = 'https://github.com/pydantic/pydantic/issues/new/choose' + full_message = f'The pydantic mypy plugin ran into unexpected behavior: {detail}\n' + full_message += f'Please consider reporting this bug at {link} so we can try to fix it!' + api.fail(full_message, context, code=ERROR_UNEXPECTED) + + +def error_untyped_fields(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail('Untyped fields disallowed', context, code=ERROR_UNTYPED) + + +def error_default_and_default_factory_specified(api: CheckerPluginInterface, context: Context) -> None: + api.fail('Field default and default_factory cannot be specified together', context, code=ERROR_FIELD_DEFAULTS) + + +def add_method( + ctx: ClassDefContext, + name: str, + args: List[Argument], + return_type: Type, + self_type: Optional[Type] = None, + tvar_def: Optional[TypeVarDef] = None, + is_classmethod: bool = False, + is_new: bool = False, + # is_staticmethod: bool = False, +) -> None: + """ + Adds a new method to a class. + + This can be dropped if/when https://github.com/python/mypy/issues/7301 is merged + """ + info = ctx.cls.info + + # First remove any previously generated methods with the same name + # to avoid clashes and problems in the semantic analyzer. + if name in info.names: + sym = info.names[name] + if sym.plugin_generated and isinstance(sym.node, FuncDef): + ctx.cls.defs.body.remove(sym.node) # pragma: no cover + + self_type = self_type or fill_typevars(info) + if is_classmethod or is_new: + first = [Argument(Var('_cls'), TypeType.make_normalized(self_type), None, ARG_POS)] + # elif is_staticmethod: + # first = [] + else: + self_type = self_type or fill_typevars(info) + first = [Argument(Var('__pydantic_self__'), self_type, None, ARG_POS)] + args = first + args + arg_types, arg_names, arg_kinds = [], [], [] + for arg in args: + assert arg.type_annotation, 'All arguments must be fully typed.' + arg_types.append(arg.type_annotation) + arg_names.append(get_name(arg.variable)) + arg_kinds.append(arg.kind) + + function_type = ctx.api.named_type(f'{BUILTINS_NAME}.function') + signature = CallableType( + arg_types, arg_kinds, arg_names, return_type, function_type, variables=[tvar_def] if tvar_def else None + ) + + func = FuncDef(name, args, Block([PassStmt()])) + func.info = info + func.type = set_callable_name(signature, func) + func.is_class = is_classmethod + # func.is_static = is_staticmethod + func._fullname = get_fullname(info) + '.' + name + func.line = info.line + + # NOTE: we would like the plugin generated node to dominate, but we still + # need to keep any existing definitions so they get semantically analyzed. + if name in info.names: + # Get a nice unique name instead. + r_name = get_unique_redefinition_name(name, info.names) + info.names[r_name] = info.names[name] + + if is_classmethod: # or is_staticmethod: + func.is_decorated = True + v = Var(name, func.type) + v.info = info + v._fullname = func._fullname + # if is_classmethod: + v.is_classmethod = True + dec = Decorator(func, [NameExpr('classmethod')], v) + # else: + # v.is_staticmethod = True + # dec = Decorator(func, [NameExpr('staticmethod')], v) + + dec.line = info.line + sym = SymbolTableNode(MDEF, dec) + else: + sym = SymbolTableNode(MDEF, func) + sym.plugin_generated = True + + info.names[name] = sym + info.defn.defs.body.append(func) + + +def get_fullname(x: Union[FuncBase, SymbolNode]) -> str: + """ + Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped. + """ + fn = x.fullname + if callable(fn): # pragma: no cover + return fn() + return fn + + +def get_name(x: Union[FuncBase, SymbolNode]) -> str: + """ + Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped. + """ + fn = x.name + if callable(fn): # pragma: no cover + return fn() + return fn + + +def parse_toml(config_file: str) -> Optional[Dict[str, Any]]: + if not config_file.endswith('.toml'): + return None + + read_mode = 'rb' + if sys.version_info >= (3, 11): + import tomllib as toml_ + else: + try: + import tomli as toml_ + except ImportError: + # older versions of mypy have toml as a dependency, not tomli + read_mode = 'r' + try: + import toml as toml_ # type: ignore[no-redef] + except ImportError: # pragma: no cover + import warnings + + warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.') + return None + + with open(config_file, read_mode) as rf: + return toml_.load(rf) # type: ignore[arg-type] diff --git a/backend/venv/Lib/site-packages/pydantic/v1/networks.py b/backend/venv/Lib/site-packages/pydantic/v1/networks.py new file mode 100644 index 0000000..ba07b74 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/networks.py @@ -0,0 +1,747 @@ +import re +from ipaddress import ( + IPv4Address, + IPv4Interface, + IPv4Network, + IPv6Address, + IPv6Interface, + IPv6Network, + _BaseAddress, + _BaseNetwork, +) +from typing import ( + TYPE_CHECKING, + Any, + Collection, + Dict, + Generator, + List, + Match, + Optional, + Pattern, + Set, + Tuple, + Type, + Union, + cast, + no_type_check, +) + +from pydantic.v1 import errors +from pydantic.v1.utils import Representation, update_not_none +from pydantic.v1.validators import constr_length_validator, str_validator + +if TYPE_CHECKING: + import email_validator + from typing_extensions import TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.typing import AnyCallable + + CallableGenerator = Generator[AnyCallable, None, None] + + class Parts(TypedDict, total=False): + scheme: str + user: Optional[str] + password: Optional[str] + ipv4: Optional[str] + ipv6: Optional[str] + domain: Optional[str] + port: Optional[str] + path: Optional[str] + query: Optional[str] + fragment: Optional[str] + + class HostParts(TypedDict, total=False): + host: str + tld: Optional[str] + host_type: Optional[str] + port: Optional[str] + rebuild: bool + +else: + email_validator = None + + class Parts(dict): + pass + + +NetworkType = Union[str, bytes, int, Tuple[Union[str, bytes, int], Union[str, int]]] + +__all__ = [ + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'stricturl', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'validate_email', +] + +_url_regex_cache = None +_multi_host_url_regex_cache = None +_ascii_domain_regex_cache = None +_int_domain_regex_cache = None +_host_regex_cache = None + +_host_regex = ( + r'(?:' + r'(?P(?:\d{1,3}\.){3}\d{1,3})(?=$|[/:#?])|' # ipv4 + r'(?P\[[A-F0-9]*:[A-F0-9:]+\])(?=$|[/:#?])|' # ipv6 + r'(?P[^\s/:?#]+)' # domain, validation occurs later + r')?' + r'(?::(?P\d+))?' # port +) +_scheme_regex = r'(?:(?P[a-z][a-z0-9+\-.]+)://)?' # scheme https://tools.ietf.org/html/rfc3986#appendix-A +_user_info_regex = r'(?:(?P[^\s:/]*)(?::(?P[^\s/]*))?@)?' +_path_regex = r'(?P/[^\s?#]*)?' +_query_regex = r'(?:\?(?P[^\s#]*))?' +_fragment_regex = r'(?:#(?P[^\s#]*))?' + + +def url_regex() -> Pattern[str]: + global _url_regex_cache + if _url_regex_cache is None: + _url_regex_cache = re.compile( + rf'{_scheme_regex}{_user_info_regex}{_host_regex}{_path_regex}{_query_regex}{_fragment_regex}', + re.IGNORECASE, + ) + return _url_regex_cache + + +def multi_host_url_regex() -> Pattern[str]: + """ + Compiled multi host url regex. + + Additionally to `url_regex` it allows to match multiple hosts. + E.g. host1.db.net,host2.db.net + """ + global _multi_host_url_regex_cache + if _multi_host_url_regex_cache is None: + _multi_host_url_regex_cache = re.compile( + rf'{_scheme_regex}{_user_info_regex}' + r'(?P([^/]*))' # validation occurs later + rf'{_path_regex}{_query_regex}{_fragment_regex}', + re.IGNORECASE, + ) + return _multi_host_url_regex_cache + + +def ascii_domain_regex() -> Pattern[str]: + global _ascii_domain_regex_cache + if _ascii_domain_regex_cache is None: + ascii_chunk = r'[_0-9a-z](?:[-_0-9a-z]{0,61}[_0-9a-z])?' + ascii_domain_ending = r'(?P\.[a-z]{2,63})?\.?' + _ascii_domain_regex_cache = re.compile( + fr'(?:{ascii_chunk}\.)*?{ascii_chunk}{ascii_domain_ending}', re.IGNORECASE + ) + return _ascii_domain_regex_cache + + +def int_domain_regex() -> Pattern[str]: + global _int_domain_regex_cache + if _int_domain_regex_cache is None: + int_chunk = r'[_0-9a-\U00040000](?:[-_0-9a-\U00040000]{0,61}[_0-9a-\U00040000])?' + int_domain_ending = r'(?P(\.[^\W\d_]{2,63})|(\.(?:xn--)[_0-9a-z-]{2,63}))?\.?' + _int_domain_regex_cache = re.compile(fr'(?:{int_chunk}\.)*?{int_chunk}{int_domain_ending}', re.IGNORECASE) + return _int_domain_regex_cache + + +def host_regex() -> Pattern[str]: + global _host_regex_cache + if _host_regex_cache is None: + _host_regex_cache = re.compile( + _host_regex, + re.IGNORECASE, + ) + return _host_regex_cache + + +class AnyUrl(str): + strip_whitespace = True + min_length = 1 + max_length = 2**16 + allowed_schemes: Optional[Collection[str]] = None + tld_required: bool = False + user_required: bool = False + host_required: bool = True + hidden_parts: Set[str] = set() + + __slots__ = ('scheme', 'user', 'password', 'host', 'tld', 'host_type', 'port', 'path', 'query', 'fragment') + + @no_type_check + def __new__(cls, url: Optional[str], **kwargs) -> object: + return str.__new__(cls, cls.build(**kwargs) if url is None else url) + + def __init__( + self, + url: str, + *, + scheme: str, + user: Optional[str] = None, + password: Optional[str] = None, + host: Optional[str] = None, + tld: Optional[str] = None, + host_type: str = 'domain', + port: Optional[str] = None, + path: Optional[str] = None, + query: Optional[str] = None, + fragment: Optional[str] = None, + ) -> None: + str.__init__(url) + self.scheme = scheme + self.user = user + self.password = password + self.host = host + self.tld = tld + self.host_type = host_type + self.port = port + self.path = path + self.query = query + self.fragment = fragment + + @classmethod + def build( + cls, + *, + scheme: str, + user: Optional[str] = None, + password: Optional[str] = None, + host: str, + port: Optional[str] = None, + path: Optional[str] = None, + query: Optional[str] = None, + fragment: Optional[str] = None, + **_kwargs: str, + ) -> str: + parts = Parts( + scheme=scheme, + user=user, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + **_kwargs, # type: ignore[misc] + ) + + url = scheme + '://' + if user: + url += user + if password: + url += ':' + password + if user or password: + url += '@' + url += host + if port and ('port' not in cls.hidden_parts or cls.get_default_parts(parts).get('port') != port): + url += ':' + port + if path: + url += path + if query: + url += '?' + query + if fragment: + url += '#' + fragment + return url + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minLength=cls.min_length, maxLength=cls.max_length, format='uri') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any, field: 'ModelField', config: 'BaseConfig') -> 'AnyUrl': + if value.__class__ == cls: + return value + value = str_validator(value) + if cls.strip_whitespace: + value = value.strip() + url: str = cast(str, constr_length_validator(value, field, config)) + + m = cls._match_url(url) + # the regex should always match, if it doesn't please report with details of the URL tried + assert m, 'URL regex failed unexpectedly' + + original_parts = cast('Parts', m.groupdict()) + parts = cls.apply_default_parts(original_parts) + parts = cls.validate_parts(parts) + + if m.end() != len(url): + raise errors.UrlExtraError(extra=url[m.end() :]) + + return cls._build_url(m, url, parts) + + @classmethod + def _build_url(cls, m: Match[str], url: str, parts: 'Parts') -> 'AnyUrl': + """ + Validate hosts and build the AnyUrl object. Split from `validate` so this method + can be altered in `MultiHostDsn`. + """ + host, tld, host_type, rebuild = cls.validate_host(parts) + + return cls( + None if rebuild else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + host=host, + tld=tld, + host_type=host_type, + port=parts['port'], + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + ) + + @staticmethod + def _match_url(url: str) -> Optional[Match[str]]: + return url_regex().match(url) + + @staticmethod + def _validate_port(port: Optional[str]) -> None: + if port is not None and int(port) > 65_535: + raise errors.UrlPortError() + + @classmethod + def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts': + """ + A method used to validate parts of a URL. + Could be overridden to set default values for parts if missing + """ + scheme = parts['scheme'] + if scheme is None: + raise errors.UrlSchemeError() + + if cls.allowed_schemes and scheme.lower() not in cls.allowed_schemes: + raise errors.UrlSchemePermittedError(set(cls.allowed_schemes)) + + if validate_port: + cls._validate_port(parts['port']) + + user = parts['user'] + if cls.user_required and user is None: + raise errors.UrlUserInfoError() + + return parts + + @classmethod + def validate_host(cls, parts: 'Parts') -> Tuple[str, Optional[str], str, bool]: + tld, host_type, rebuild = None, None, False + for f in ('domain', 'ipv4', 'ipv6'): + host = parts[f] # type: ignore[literal-required] + if host: + host_type = f + break + + if host is None: + if cls.host_required: + raise errors.UrlHostError() + elif host_type == 'domain': + is_international = False + d = ascii_domain_regex().fullmatch(host) + if d is None: + d = int_domain_regex().fullmatch(host) + if d is None: + raise errors.UrlHostError() + is_international = True + + tld = d.group('tld') + if tld is None and not is_international: + d = int_domain_regex().fullmatch(host) + assert d is not None + tld = d.group('tld') + is_international = True + + if tld is not None: + tld = tld[1:] + elif cls.tld_required: + raise errors.UrlHostTldError() + + if is_international: + host_type = 'int_domain' + rebuild = True + host = host.encode('idna').decode('ascii') + if tld is not None: + tld = tld.encode('idna').decode('ascii') + + return host, tld, host_type, rebuild # type: ignore + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return {} + + @classmethod + def apply_default_parts(cls, parts: 'Parts') -> 'Parts': + for key, value in cls.get_default_parts(parts).items(): + if not parts[key]: # type: ignore[literal-required] + parts[key] = value # type: ignore[literal-required] + return parts + + def __repr__(self) -> str: + extra = ', '.join(f'{n}={getattr(self, n)!r}' for n in self.__slots__ if getattr(self, n) is not None) + return f'{self.__class__.__name__}({super().__repr__()}, {extra})' + + +class AnyHttpUrl(AnyUrl): + allowed_schemes = {'http', 'https'} + + __slots__ = () + + +class HttpUrl(AnyHttpUrl): + tld_required = True + # https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + max_length = 2083 + hidden_parts = {'port'} + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return {'port': '80' if parts['scheme'] == 'http' else '443'} + + +class FileUrl(AnyUrl): + allowed_schemes = {'file'} + host_required = False + + __slots__ = () + + +class MultiHostDsn(AnyUrl): + __slots__ = AnyUrl.__slots__ + ('hosts',) + + def __init__(self, *args: Any, hosts: Optional[List['HostParts']] = None, **kwargs: Any): + super().__init__(*args, **kwargs) + self.hosts = hosts + + @staticmethod + def _match_url(url: str) -> Optional[Match[str]]: + return multi_host_url_regex().match(url) + + @classmethod + def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts': + return super().validate_parts(parts, validate_port=False) + + @classmethod + def _build_url(cls, m: Match[str], url: str, parts: 'Parts') -> 'MultiHostDsn': + hosts_parts: List['HostParts'] = [] + host_re = host_regex() + for host in m.groupdict()['hosts'].split(','): + d: Parts = host_re.match(host).groupdict() # type: ignore + host, tld, host_type, rebuild = cls.validate_host(d) + port = d.get('port') + cls._validate_port(port) + hosts_parts.append( + { + 'host': host, + 'host_type': host_type, + 'tld': tld, + 'rebuild': rebuild, + 'port': port, + } + ) + + if len(hosts_parts) > 1: + return cls( + None if any([hp['rebuild'] for hp in hosts_parts]) else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + host_type=None, + hosts=hosts_parts, + ) + else: + # backwards compatibility with single host + host_part = hosts_parts[0] + return cls( + None if host_part['rebuild'] else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + host=host_part['host'], + tld=host_part['tld'], + host_type=host_part['host_type'], + port=host_part.get('port'), + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + ) + + +class PostgresDsn(MultiHostDsn): + allowed_schemes = { + 'postgres', + 'postgresql', + 'postgresql+asyncpg', + 'postgresql+pg8000', + 'postgresql+psycopg', + 'postgresql+psycopg2', + 'postgresql+psycopg2cffi', + 'postgresql+py-postgresql', + 'postgresql+pygresql', + } + user_required = True + + __slots__ = () + + +class CockroachDsn(AnyUrl): + allowed_schemes = { + 'cockroachdb', + 'cockroachdb+psycopg2', + 'cockroachdb+asyncpg', + } + user_required = True + + +class AmqpDsn(AnyUrl): + allowed_schemes = {'amqp', 'amqps'} + host_required = False + + +class RedisDsn(AnyUrl): + __slots__ = () + allowed_schemes = {'redis', 'rediss'} + host_required = False + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'domain': 'localhost' if not (parts['ipv4'] or parts['ipv6']) else '', + 'port': '6379', + 'path': '/0', + } + + +class MongoDsn(AnyUrl): + allowed_schemes = {'mongodb'} + + # TODO: Needed to generic "Parts" for "Replica Set", "Sharded Cluster", and other mongodb deployment modes + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'port': '27017', + } + + +class KafkaDsn(AnyUrl): + allowed_schemes = {'kafka'} + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'domain': 'localhost', + 'port': '9092', + } + + +def stricturl( + *, + strip_whitespace: bool = True, + min_length: int = 1, + max_length: int = 2**16, + tld_required: bool = True, + host_required: bool = True, + allowed_schemes: Optional[Collection[str]] = None, +) -> Type[AnyUrl]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + min_length=min_length, + max_length=max_length, + tld_required=tld_required, + host_required=host_required, + allowed_schemes=allowed_schemes, + ) + return type('UrlValue', (AnyUrl,), namespace) + + +def import_email_validator() -> None: + global email_validator + try: + import email_validator + except ImportError as e: + raise ImportError('email-validator is not installed, run `pip install pydantic[email]`') from e + + +class EmailStr(str): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='email') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + # included here and below so the error happens straight away + import_email_validator() + + yield str_validator + yield cls.validate + + @classmethod + def validate(cls, value: Union[str]) -> str: + return validate_email(value)[1] + + +class NameEmail(Representation): + __slots__ = 'name', 'email' + + def __init__(self, name: str, email: str): + self.name = name + self.email = email + + def __eq__(self, other: Any) -> bool: + return isinstance(other, NameEmail) and (self.name, self.email) == (other.name, other.email) + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='name-email') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + import_email_validator() + + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> 'NameEmail': + if value.__class__ == cls: + return value + value = str_validator(value) + return cls(*validate_email(value)) + + def __str__(self) -> str: + return f'{self.name} <{self.email}>' + + +class IPvAnyAddress(_BaseAddress): + __slots__ = () + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanyaddress') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Union[str, bytes, int]) -> Union[IPv4Address, IPv6Address]: + try: + return IPv4Address(value) + except ValueError: + pass + + try: + return IPv6Address(value) + except ValueError: + raise errors.IPvAnyAddressError() + + +class IPvAnyInterface(_BaseAddress): + __slots__ = () + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanyinterface') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: NetworkType) -> Union[IPv4Interface, IPv6Interface]: + try: + return IPv4Interface(value) + except ValueError: + pass + + try: + return IPv6Interface(value) + except ValueError: + raise errors.IPvAnyInterfaceError() + + +class IPvAnyNetwork(_BaseNetwork): # type: ignore + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanynetwork') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: NetworkType) -> Union[IPv4Network, IPv6Network]: + # Assume IP Network is defined with a default value for ``strict`` argument. + # Define your own class if you want to specify network address check strictness. + try: + return IPv4Network(value) + except ValueError: + pass + + try: + return IPv6Network(value) + except ValueError: + raise errors.IPvAnyNetworkError() + + +pretty_email_regex = re.compile(r'([\w ]*?) *<(.*)> *') +MAX_EMAIL_LENGTH = 2048 +"""Maximum length for an email. +A somewhat arbitrary but very generous number compared to what is allowed by most implementations. +""" + + +def validate_email(value: Union[str]) -> Tuple[str, str]: + """ + Email address validation using https://pypi.org/project/email-validator/ + Notes: + * raw ip address (literal) domain parts are not allowed. + * "John Doe " style "pretty" email addresses are processed + * spaces are striped from the beginning and end of addresses but no error is raised + """ + if email_validator is None: + import_email_validator() + + if len(value) > MAX_EMAIL_LENGTH: + raise errors.EmailError() + + m = pretty_email_regex.fullmatch(value) + name: Union[str, None] = None + if m: + name, value = m.groups() + email = value.strip() + try: + parts = email_validator.validate_email(email, check_deliverability=False) + except email_validator.EmailNotValidError as e: + raise errors.EmailError from e + + if hasattr(parts, 'normalized'): + # email-validator >= 2 + email = parts.normalized + assert email is not None + name = name or parts.local_part + return name, email + else: + # email-validator >1, <2 + at_index = email.index('@') + local_part = email[:at_index] # RFC 5321, local part must be case-sensitive. + global_part = email[at_index:].lower() + + return name or local_part, local_part + global_part diff --git a/backend/venv/Lib/site-packages/pydantic/v1/parse.py b/backend/venv/Lib/site-packages/pydantic/v1/parse.py new file mode 100644 index 0000000..431d75a --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/parse.py @@ -0,0 +1,66 @@ +import json +import pickle +from enum import Enum +from pathlib import Path +from typing import Any, Callable, Union + +from pydantic.v1.types import StrBytes + + +class Protocol(str, Enum): + json = 'json' + pickle = 'pickle' + + +def load_str_bytes( + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + if proto is None and content_type: + if content_type.endswith(('json', 'javascript')): + pass + elif allow_pickle and content_type.endswith('pickle'): + proto = Protocol.pickle + else: + raise TypeError(f'Unknown content-type: {content_type}') + + proto = proto or Protocol.json + + if proto == Protocol.json: + if isinstance(b, bytes): + b = b.decode(encoding) + return json_loads(b) + elif proto == Protocol.pickle: + if not allow_pickle: + raise RuntimeError('Trying to decode with pickle with allow_pickle=False') + bb = b if isinstance(b, bytes) else b.encode() + return pickle.loads(bb) + else: + raise TypeError(f'Unknown protocol: {proto}') + + +def load_file( + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + path = Path(path) + b = path.read_bytes() + if content_type is None: + if path.suffix in ('.js', '.json'): + proto = Protocol.json + elif path.suffix == '.pkl': + proto = Protocol.pickle + + return load_str_bytes( + b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle, json_loads=json_loads + ) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/py.typed b/backend/venv/Lib/site-packages/pydantic/v1/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/backend/venv/Lib/site-packages/pydantic/v1/schema.py b/backend/venv/Lib/site-packages/pydantic/v1/schema.py new file mode 100644 index 0000000..a91fe2c --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/schema.py @@ -0,0 +1,1163 @@ +import re +import warnings +from collections import defaultdict +from dataclasses import is_dataclass +from datetime import date, datetime, time, timedelta +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + ForwardRef, + FrozenSet, + Generic, + Iterable, + List, + Optional, + Pattern, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) +from uuid import UUID + +from typing_extensions import Annotated, Literal + +from pydantic.v1.fields import ( + MAPPING_LIKE_SHAPES, + SHAPE_DEQUE, + SHAPE_FROZENSET, + SHAPE_GENERIC, + SHAPE_ITERABLE, + SHAPE_LIST, + SHAPE_SEQUENCE, + SHAPE_SET, + SHAPE_SINGLETON, + SHAPE_TUPLE, + SHAPE_TUPLE_ELLIPSIS, + FieldInfo, + ModelField, +) +from pydantic.v1.json import pydantic_encoder +from pydantic.v1.networks import AnyUrl, EmailStr +from pydantic.v1.types import ( + ConstrainedDecimal, + ConstrainedFloat, + ConstrainedFrozenSet, + ConstrainedInt, + ConstrainedList, + ConstrainedSet, + ConstrainedStr, + SecretBytes, + SecretStr, + StrictBytes, + StrictStr, + conbytes, + condecimal, + confloat, + confrozenset, + conint, + conlist, + conset, + constr, +) +from pydantic.v1.typing import ( + all_literal_values, + get_args, + get_origin, + get_sub_types, + is_callable_type, + is_literal_type, + is_namedtuple, + is_none_type, + is_union, +) +from pydantic.v1.utils import ROOT_KEY, get_model, lenient_issubclass + +if TYPE_CHECKING: + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.main import BaseModel + +default_prefix = '#/definitions/' +default_ref_template = '#/definitions/{model}' + +TypeModelOrEnum = Union[Type['BaseModel'], Type[Enum]] +TypeModelSet = Set[TypeModelOrEnum] + + +def _apply_modify_schema( + modify_schema: Callable[..., None], field: Optional[ModelField], field_schema: Dict[str, Any] +) -> None: + from inspect import signature + + sig = signature(modify_schema) + args = set(sig.parameters.keys()) + if 'field' in args or 'kwargs' in args: + modify_schema(field_schema, field=field) + else: + modify_schema(field_schema) + + +def schema( + models: Sequence[Union[Type['BaseModel'], Type['Dataclass']]], + *, + by_alias: bool = True, + title: Optional[str] = None, + description: Optional[str] = None, + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, +) -> Dict[str, Any]: + """ + Process a list of models and generate a single JSON Schema with all of them defined in the ``definitions`` + top-level JSON key, including their sub-models. + + :param models: a list of models to include in the generated JSON Schema + :param by_alias: generate the schemas using the aliases defined, if any + :param title: title for the generated schema that includes the definitions + :param description: description for the generated schema + :param ref_prefix: the JSON Pointer prefix for schema references with ``$ref``, if None, will be set to the + default of ``#/definitions/``. Update it if you want the schemas to reference the definitions somewhere + else, e.g. for OpenAPI use ``#/components/schemas/``. The resulting generated schemas will still be at the + top-level key ``definitions``, so you can extract them from there. But all the references will have the set + prefix. + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful + for references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For + a sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :return: dict with the JSON Schema with a ``definitions`` top-level key including the schema definitions for + the models and sub-models passed in ``models``. + """ + clean_models = [get_model(model) for model in models] + flat_models = get_flat_models_from_models(clean_models) + model_name_map = get_model_name_map(flat_models) + definitions = {} + output_schema: Dict[str, Any] = {} + if title: + output_schema['title'] = title + if description: + output_schema['description'] = description + for model in clean_models: + m_schema, m_definitions, m_nested_models = model_process_schema( + model, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + ) + definitions.update(m_definitions) + model_name = model_name_map[model] + definitions[model_name] = m_schema + if definitions: + output_schema['definitions'] = definitions + return output_schema + + +def model_schema( + model: Union[Type['BaseModel'], Type['Dataclass']], + by_alias: bool = True, + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, +) -> Dict[str, Any]: + """ + Generate a JSON Schema for one model. With all the sub-models defined in the ``definitions`` top-level + JSON key. + + :param model: a Pydantic model (a class that inherits from BaseModel) + :param by_alias: generate the schemas using the aliases defined, if any + :param ref_prefix: the JSON Pointer prefix for schema references with ``$ref``, if None, will be set to the + default of ``#/definitions/``. Update it if you want the schemas to reference the definitions somewhere + else, e.g. for OpenAPI use ``#/components/schemas/``. The resulting generated schemas will still be at the + top-level key ``definitions``, so you can extract them from there. But all the references will have the set + prefix. + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful for + references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For a + sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :return: dict with the JSON Schema for the passed ``model`` + """ + model = get_model(model) + flat_models = get_flat_models_from_model(model) + model_name_map = get_model_name_map(flat_models) + model_name = model_name_map[model] + m_schema, m_definitions, nested_models = model_process_schema( + model, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, ref_template=ref_template + ) + if model_name in nested_models: + # model_name is in Nested models, it has circular references + m_definitions[model_name] = m_schema + m_schema = get_schema_ref(model_name, ref_prefix, ref_template, False) + if m_definitions: + m_schema.update({'definitions': m_definitions}) + return m_schema + + +def get_field_info_schema(field: ModelField, schema_overrides: bool = False) -> Tuple[Dict[str, Any], bool]: + # If no title is explicitly set, we don't set title in the schema for enums. + # The behaviour is the same as `BaseModel` reference, where the default title + # is in the definitions part of the schema. + schema_: Dict[str, Any] = {} + if field.field_info.title or not lenient_issubclass(field.type_, Enum): + schema_['title'] = field.field_info.title or field.alias.title().replace('_', ' ') + + if field.field_info.title: + schema_overrides = True + + if field.field_info.description: + schema_['description'] = field.field_info.description + schema_overrides = True + + if not field.required and field.default is not None and not is_callable_type(field.outer_type_): + schema_['default'] = encode_default(field.default) + schema_overrides = True + + return schema_, schema_overrides + + +def field_schema( + field: ModelField, + *, + by_alias: bool = True, + model_name_map: Dict[TypeModelOrEnum, str], + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, + known_models: Optional[TypeModelSet] = None, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Process a Pydantic field and return a tuple with a JSON Schema for it as the first item. + Also return a dictionary of definitions with models as keys and their schemas as values. If the passed field + is a model and has sub-models, and those sub-models don't have overrides (as ``title``, ``default``, etc), they + will be included in the definitions and referenced in the schema instead of included recursively. + + :param field: a Pydantic ``ModelField`` + :param by_alias: use the defined alias (if any) in the returned schema + :param model_name_map: used to generate the JSON Schema references to other models included in the definitions + :param ref_prefix: the JSON Pointer prefix to use for references to other schemas, if None, the default of + #/definitions/ will be used + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful for + references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For a + sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :param known_models: used to solve circular references + :return: tuple of the schema for this field and additional definitions + """ + s, schema_overrides = get_field_info_schema(field) + + validation_schema = get_field_schema_validations(field) + if validation_schema: + s.update(validation_schema) + schema_overrides = True + + f_schema, f_definitions, f_nested_models = field_type_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models or set(), + ) + + # $ref will only be returned when there are no schema_overrides + if '$ref' in f_schema: + return f_schema, f_definitions, f_nested_models + else: + s.update(f_schema) + return s, f_definitions, f_nested_models + + +numeric_types = (int, float, Decimal) +_str_types_attrs: Tuple[Tuple[str, Union[type, Tuple[type, ...]], str], ...] = ( + ('max_length', numeric_types, 'maxLength'), + ('min_length', numeric_types, 'minLength'), + ('regex', str, 'pattern'), +) + +_numeric_types_attrs: Tuple[Tuple[str, Union[type, Tuple[type, ...]], str], ...] = ( + ('gt', numeric_types, 'exclusiveMinimum'), + ('lt', numeric_types, 'exclusiveMaximum'), + ('ge', numeric_types, 'minimum'), + ('le', numeric_types, 'maximum'), + ('multiple_of', numeric_types, 'multipleOf'), +) + + +def get_field_schema_validations(field: ModelField) -> Dict[str, Any]: + """ + Get the JSON Schema validation keywords for a ``field`` with an annotation of + a Pydantic ``FieldInfo`` with validation arguments. + """ + f_schema: Dict[str, Any] = {} + + if lenient_issubclass(field.type_, Enum): + # schema is already updated by `enum_process_schema`; just update with field extra + if field.field_info.extra: + f_schema.update(field.field_info.extra) + return f_schema + + if lenient_issubclass(field.type_, (str, bytes)): + for attr_name, t, keyword in _str_types_attrs: + attr = getattr(field.field_info, attr_name, None) + if isinstance(attr, t): + f_schema[keyword] = attr + if lenient_issubclass(field.type_, numeric_types) and not issubclass(field.type_, bool): + for attr_name, t, keyword in _numeric_types_attrs: + attr = getattr(field.field_info, attr_name, None) + if isinstance(attr, t): + f_schema[keyword] = attr + if field.field_info is not None and field.field_info.const: + f_schema['const'] = field.default + if field.field_info.extra: + f_schema.update(field.field_info.extra) + modify_schema = getattr(field.outer_type_, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + return f_schema + + +def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str]: + """ + Process a set of models and generate unique names for them to be used as keys in the JSON Schema + definitions. By default the names are the same as the class name. But if two models in different Python + modules have the same name (e.g. "users.Model" and "items.Model"), the generated names will be + based on the Python module path for those conflicting models to prevent name collisions. + + :param unique_models: a Python set of models + :return: dict mapping models to names + """ + name_model_map = {} + conflicting_names: Set[str] = set() + for model in unique_models: + model_name = normalize_name(model.__name__) + if model_name in conflicting_names: + model_name = get_long_model_name(model) + name_model_map[model_name] = model + elif model_name in name_model_map: + conflicting_names.add(model_name) + conflicting_model = name_model_map.pop(model_name) + name_model_map[get_long_model_name(conflicting_model)] = conflicting_model + name_model_map[get_long_model_name(model)] = model + else: + 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: Optional[TypeModelSet] = None) -> TypeModelSet: + """ + Take a single ``model`` and generate a set with itself and all the sub-models in the tree. I.e. if you pass + model ``Foo`` (subclass of Pydantic ``BaseModel``) as ``model``, and it has a field of type ``Bar`` (also + subclass of ``BaseModel``) and that model ``Bar`` has a field of type ``Baz`` (also subclass of ``BaseModel``), + the return value will be ``set([Foo, Bar, Baz])``. + + :param model: a Pydantic ``BaseModel`` subclass + :param known_models: used to solve circular references + :return: a set with the initial model and all its sub-models + """ + known_models = known_models or set() + flat_models: TypeModelSet = set() + flat_models.add(model) + known_models |= flat_models + fields = cast(Sequence[ModelField], model.__fields__.values()) + flat_models |= get_flat_models_from_fields(fields, known_models=known_models) + return flat_models + + +def get_flat_models_from_field(field: ModelField, known_models: TypeModelSet) -> TypeModelSet: + """ + Take a single Pydantic ``ModelField`` (from a model) that could have been declared as a subclass of BaseModel + (so, it could be a submodel), and generate a set with its model and all the sub-models in the tree. + I.e. if you pass a field that was declared to be of type ``Foo`` (subclass of BaseModel) as ``field``, and that + model ``Foo`` has a field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of + type ``Baz`` (also subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + + :param field: a Pydantic ``ModelField`` + :param known_models: used to solve circular references + :return: a set with the model used in the declaration for this field, if any, and all its sub-models + """ + from pydantic.v1.main import BaseModel + + flat_models: TypeModelSet = set() + + field_type = field.type_ + if lenient_issubclass(getattr(field_type, '__pydantic_model__', None), BaseModel): + field_type = field_type.__pydantic_model__ + + if field.sub_fields and not lenient_issubclass(field_type, BaseModel): + flat_models |= get_flat_models_from_fields(field.sub_fields, known_models=known_models) + elif lenient_issubclass(field_type, BaseModel) and field_type not in known_models: + flat_models |= get_flat_models_from_model(field_type, known_models=known_models) + elif lenient_issubclass(field_type, Enum): + flat_models.add(field_type) + return flat_models + + +def get_flat_models_from_fields(fields: Sequence[ModelField], known_models: TypeModelSet) -> TypeModelSet: + """ + Take a list of Pydantic ``ModelField``s (from a model) that could have been declared as subclasses of ``BaseModel`` + (so, any of them could be a submodel), and generate a set with their models and all the sub-models in the tree. + I.e. if you pass a the fields of a model ``Foo`` (subclass of ``BaseModel``) as ``fields``, and on of them has a + field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of type ``Baz`` (also + subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + + :param fields: a list of Pydantic ``ModelField``s + :param known_models: used to solve circular references + :return: a set with any model declared in the fields, and all their sub-models + """ + flat_models: TypeModelSet = set() + for field in fields: + flat_models |= get_flat_models_from_field(field, known_models=known_models) + return flat_models + + +def get_flat_models_from_models(models: Sequence[Type['BaseModel']]) -> TypeModelSet: + """ + Take a list of ``models`` and generate a set with them and all their sub-models in their trees. I.e. if you pass + a list of two models, ``Foo`` and ``Bar``, both subclasses of Pydantic ``BaseModel`` as models, and ``Bar`` has + a field of type ``Baz`` (also subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + """ + flat_models: TypeModelSet = set() + for model in models: + flat_models |= get_flat_models_from_model(model) + return flat_models + + +def get_long_model_name(model: TypeModelOrEnum) -> str: + return f'{model.__module__}__{model.__qualname__}'.replace('.', '__') + + +def field_type_schema( + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Used by ``field_schema()``, you probably should be using that function. + + Take a single ``field`` and generate the schema for its type only, not including additional + information as title, etc. Also return additional schema definitions, from sub-models. + """ + from pydantic.v1.main import BaseModel # noqa: F811 + + definitions = {} + nested_models: Set[str] = set() + f_schema: Dict[str, Any] + if field.shape in { + SHAPE_LIST, + SHAPE_TUPLE_ELLIPSIS, + SHAPE_SEQUENCE, + SHAPE_SET, + SHAPE_FROZENSET, + SHAPE_ITERABLE, + SHAPE_DEQUE, + }: + items_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + f_schema = {'type': 'array', 'items': items_schema} + if field.shape in {SHAPE_SET, SHAPE_FROZENSET}: + f_schema['uniqueItems'] = True + + elif field.shape in MAPPING_LIKE_SHAPES: + f_schema = {'type': 'object'} + key_field = cast(ModelField, field.key_field) + regex = getattr(key_field.type_, 'regex', None) + items_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + if regex: + # Dict keys have a regex pattern + # items_schema might be a schema or empty dict, add it either way + f_schema['patternProperties'] = {ConstrainedStr._get_pattern(regex): items_schema} + if items_schema: + # The dict values are not simply Any, so they need a schema + f_schema['additionalProperties'] = items_schema + elif field.shape == SHAPE_TUPLE or (field.shape == SHAPE_GENERIC and not issubclass(field.type_, BaseModel)): + sub_schema = [] + sub_fields = cast(List[ModelField], field.sub_fields) + for sf in sub_fields: + sf_schema, sf_definitions, sf_nested_models = field_type_schema( + sf, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(sf_definitions) + nested_models.update(sf_nested_models) + sub_schema.append(sf_schema) + + sub_fields_len = len(sub_fields) + if field.shape == SHAPE_GENERIC: + all_of_schemas = sub_schema[0] if sub_fields_len == 1 else {'type': 'array', 'items': sub_schema} + f_schema = {'allOf': [all_of_schemas]} + else: + f_schema = { + 'type': 'array', + 'minItems': sub_fields_len, + 'maxItems': sub_fields_len, + } + if sub_fields_len >= 1: + f_schema['items'] = sub_schema + else: + assert field.shape in {SHAPE_SINGLETON, SHAPE_GENERIC}, field.shape + f_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + + # check field type to avoid repeated calls to the same __modify_schema__ method + if field.type_ != field.outer_type_: + if field.shape == SHAPE_GENERIC: + field_type = field.type_ + else: + field_type = field.outer_type_ + modify_schema = getattr(field_type, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + return f_schema, definitions, nested_models + + +def model_process_schema( + model: TypeModelOrEnum, + *, + by_alias: bool = True, + model_name_map: Dict[TypeModelOrEnum, str], + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, + known_models: Optional[TypeModelSet] = None, + field: Optional[ModelField] = None, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Used by ``model_schema()``, you probably should be using that function. + + Take a single ``model`` and generate its schema. Also return additional schema definitions, from sub-models. The + sub-models of the returned schema will be referenced, but their definitions will not be included in the schema. All + the definitions are returned as the second value. + """ + from inspect import getdoc, signature + + known_models = known_models or set() + if lenient_issubclass(model, Enum): + model = cast(Type[Enum], model) + s = enum_process_schema(model, field=field) + return s, {}, set() + model = cast(Type['BaseModel'], model) + s = {'title': model.__config__.title or model.__name__} + doc = getdoc(model) + if doc: + s['description'] = doc + known_models.add(model) + m_schema, m_definitions, nested_models = model_type_schema( + model, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + s.update(m_schema) + schema_extra = model.__config__.schema_extra + if callable(schema_extra): + if len(signature(schema_extra).parameters) == 1: + schema_extra(s) + else: + schema_extra(s, model) + else: + s.update(schema_extra) + return s, m_definitions, nested_models + + +def model_type_schema( + model: Type['BaseModel'], + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + You probably should be using ``model_schema()``, this function is indirectly used by that function. + + Take a single ``model`` and generate the schema for its type only, not including additional + information as title, etc. Also return additional schema definitions, from sub-models. + """ + properties = {} + required = [] + definitions: Dict[str, Any] = {} + nested_models: Set[str] = set() + for k, f in model.__fields__.items(): + try: + f_schema, f_definitions, f_nested_models = field_schema( + f, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + except SkipField as skip: + warnings.warn(skip.message, UserWarning) + continue + definitions.update(f_definitions) + nested_models.update(f_nested_models) + if by_alias: + properties[f.alias] = f_schema + if f.required: + required.append(f.alias) + else: + properties[k] = f_schema + if f.required: + required.append(k) + if ROOT_KEY in properties: + out_schema = properties[ROOT_KEY] + out_schema['title'] = model.__config__.title or model.__name__ + else: + out_schema = {'type': 'object', 'properties': properties} + if required: + out_schema['required'] = required + if model.__config__.extra == 'forbid': + out_schema['additionalProperties'] = False + return out_schema, definitions, nested_models + + +def enum_process_schema(enum: Type[Enum], *, field: Optional[ModelField] = None) -> Dict[str, Any]: + """ + Take a single `enum` and generate its schema. + + This is similar to the `model_process_schema` function, but applies to ``Enum`` objects. + """ + import inspect + + schema_: Dict[str, Any] = { + 'title': enum.__name__, + # Python assigns all enums a default docstring value of 'An enumeration', so + # all enums will have a description field even if not explicitly provided. + 'description': inspect.cleandoc(enum.__doc__ or 'An enumeration.'), + # Add enum values and the enum field type to the schema. + 'enum': [item.value for item in cast(Iterable[Enum], enum)], + } + + add_field_type_to_schema(enum, schema_) + + modify_schema = getattr(enum, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, schema_) + + return schema_ + + +def field_singleton_sub_fields_schema( + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + This function is indirectly used by ``field_schema()``, you probably should be using that function. + + Take a list of Pydantic ``ModelField`` from the declaration of a type with parameters, and generate their + schema. I.e., fields used as "type parameters", like ``str`` and ``int`` in ``Tuple[str, int]``. + """ + sub_fields = cast(List[ModelField], field.sub_fields) + definitions = {} + nested_models: Set[str] = set() + if len(sub_fields) == 1: + return field_type_schema( + sub_fields[0], + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + else: + s: Dict[str, Any] = {} + # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminator-object + field_has_discriminator: bool = field.discriminator_key is not None + if field_has_discriminator: + assert field.sub_fields_mapping is not None + + discriminator_models_refs: Dict[str, Union[str, Dict[str, Any]]] = {} + + for discriminator_value, sub_field in field.sub_fields_mapping.items(): + if isinstance(discriminator_value, Enum): + discriminator_value = str(discriminator_value.value) + # sub_field is either a `BaseModel` or directly an `Annotated` `Union` of many + if is_union(get_origin(sub_field.type_)): + sub_models = get_sub_types(sub_field.type_) + discriminator_models_refs[discriminator_value] = { + model_name_map[sub_model]: get_schema_ref( + model_name_map[sub_model], ref_prefix, ref_template, False + ) + for sub_model in sub_models + } + else: + sub_field_type = sub_field.type_ + if hasattr(sub_field_type, '__pydantic_model__'): + sub_field_type = sub_field_type.__pydantic_model__ + + discriminator_model_name = model_name_map[sub_field_type] + discriminator_model_ref = get_schema_ref(discriminator_model_name, ref_prefix, ref_template, False) + discriminator_models_refs[discriminator_value] = discriminator_model_ref['$ref'] + + s['discriminator'] = { + 'propertyName': field.discriminator_alias if by_alias else field.discriminator_key, + 'mapping': discriminator_models_refs, + } + + sub_field_schemas = [] + for sf in sub_fields: + sub_schema, sub_definitions, sub_nested_models = field_type_schema( + sf, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(sub_definitions) + if schema_overrides and 'allOf' in sub_schema: + # if the sub_field is a referenced schema we only need the referenced + # object. Otherwise we will end up with several allOf inside anyOf/oneOf. + # See https://github.com/pydantic/pydantic/issues/1209 + sub_schema = sub_schema['allOf'][0] + + if sub_schema.keys() == {'discriminator', 'oneOf'}: + # we don't want discriminator information inside oneOf choices, this is dealt with elsewhere + sub_schema.pop('discriminator') + sub_field_schemas.append(sub_schema) + nested_models.update(sub_nested_models) + s['oneOf' if field_has_discriminator else 'anyOf'] = sub_field_schemas + return s, definitions, nested_models + + +# Order is important, e.g. subclasses of str must go before str +# this is used only for standard library types, custom types should use __modify_schema__ instead +field_class_to_schema: Tuple[Tuple[Any, Dict[str, Any]], ...] = ( + (Path, {'type': 'string', 'format': 'path'}), + (datetime, {'type': 'string', 'format': 'date-time'}), + (date, {'type': 'string', 'format': 'date'}), + (time, {'type': 'string', 'format': 'time'}), + (timedelta, {'type': 'number', 'format': 'time-delta'}), + (IPv4Network, {'type': 'string', 'format': 'ipv4network'}), + (IPv6Network, {'type': 'string', 'format': 'ipv6network'}), + (IPv4Interface, {'type': 'string', 'format': 'ipv4interface'}), + (IPv6Interface, {'type': 'string', 'format': 'ipv6interface'}), + (IPv4Address, {'type': 'string', 'format': 'ipv4'}), + (IPv6Address, {'type': 'string', 'format': 'ipv6'}), + (Pattern, {'type': 'string', 'format': 'regex'}), + (str, {'type': 'string'}), + (bytes, {'type': 'string', 'format': 'binary'}), + (bool, {'type': 'boolean'}), + (int, {'type': 'integer'}), + (float, {'type': 'number'}), + (Decimal, {'type': 'number'}), + (UUID, {'type': 'string', 'format': 'uuid'}), + (dict, {'type': 'object'}), + (list, {'type': 'array', 'items': {}}), + (tuple, {'type': 'array', 'items': {}}), + (set, {'type': 'array', 'items': {}, 'uniqueItems': True}), + (frozenset, {'type': 'array', 'items': {}, 'uniqueItems': True}), +) + +json_scheme = {'type': 'string', 'format': 'json-string'} + + +def add_field_type_to_schema(field_type: Any, schema_: Dict[str, Any]) -> None: + """ + Update the given `schema` with the type-specific metadata for the given `field_type`. + + This function looks through `field_class_to_schema` for a class that matches the given `field_type`, + and then modifies the given `schema` with the information from that type. + """ + for type_, t_schema in field_class_to_schema: + # Fallback for `typing.Pattern` and `re.Pattern` as they are not a valid class + if lenient_issubclass(field_type, type_) or field_type is type_ is Pattern: + schema_.update(t_schema) + break + + +def get_schema_ref(name: str, ref_prefix: Optional[str], ref_template: str, schema_overrides: bool) -> Dict[str, Any]: + if ref_prefix: + schema_ref = {'$ref': ref_prefix + name} + else: + schema_ref = {'$ref': ref_template.format(model=name)} + return {'allOf': [schema_ref]} if schema_overrides else schema_ref + + +def field_singleton_schema( # noqa: C901 (ignore complexity) + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + This function is indirectly used by ``field_schema()``, you should probably be using that function. + + Take a single Pydantic ``ModelField``, and return its schema and any additional definitions from sub-models. + """ + from pydantic.v1.main import BaseModel + + definitions: Dict[str, Any] = {} + nested_models: Set[str] = set() + field_type = field.type_ + + # Recurse into this field if it contains sub_fields and is NOT a + # BaseModel OR that BaseModel is a const + if field.sub_fields and ( + (field.field_info and field.field_info.const) or not lenient_issubclass(field_type, BaseModel) + ): + return field_singleton_sub_fields_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + if field_type is Any or field_type is object or field_type.__class__ == TypeVar or get_origin(field_type) is type: + return {}, definitions, nested_models # no restrictions + if is_none_type(field_type): + return {'type': 'null'}, definitions, nested_models + if is_callable_type(field_type): + raise SkipField(f'Callable {field.name} was excluded from schema since JSON schema has no equivalent type.') + f_schema: Dict[str, Any] = {} + if field.field_info is not None and field.field_info.const: + f_schema['const'] = field.default + + if is_literal_type(field_type): + values = tuple(x.value if isinstance(x, Enum) else x for x in all_literal_values(field_type)) + + if len({v.__class__ for v in values}) > 1: + return field_schema( + multitypes_literal_field_for_schema(values, field), + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + + # All values have the same type + field_type = values[0].__class__ + f_schema['enum'] = list(values) + add_field_type_to_schema(field_type, f_schema) + elif lenient_issubclass(field_type, Enum): + enum_name = model_name_map[field_type] + f_schema, schema_overrides = get_field_info_schema(field, schema_overrides) + f_schema.update(get_schema_ref(enum_name, ref_prefix, ref_template, schema_overrides)) + definitions[enum_name] = enum_process_schema(field_type, field=field) + elif is_namedtuple(field_type): + sub_schema, *_ = model_process_schema( + field_type.__pydantic_model__, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + field=field, + ) + items_schemas = list(sub_schema['properties'].values()) + f_schema.update( + { + 'type': 'array', + 'items': items_schemas, + 'minItems': len(items_schemas), + 'maxItems': len(items_schemas), + } + ) + elif not hasattr(field_type, '__pydantic_model__'): + add_field_type_to_schema(field_type, f_schema) + + modify_schema = getattr(field_type, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + + if f_schema: + return f_schema, definitions, nested_models + + # Handle dataclass-based models + if lenient_issubclass(getattr(field_type, '__pydantic_model__', None), BaseModel): + field_type = field_type.__pydantic_model__ + + if issubclass(field_type, BaseModel): + model_name = model_name_map[field_type] + if field_type not in known_models: + sub_schema, sub_definitions, sub_nested_models = model_process_schema( + field_type, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + field=field, + ) + definitions.update(sub_definitions) + definitions[model_name] = sub_schema + nested_models.update(sub_nested_models) + else: + nested_models.add(model_name) + schema_ref = get_schema_ref(model_name, ref_prefix, ref_template, schema_overrides) + return schema_ref, definitions, nested_models + + # For generics with no args + args = get_args(field_type) + if args is not None and not args and Generic in field_type.__bases__: + return f_schema, definitions, nested_models + + raise ValueError(f'Value not declarable with JSON Schema, field: {field}') + + +def multitypes_literal_field_for_schema(values: Tuple[Any, ...], field: ModelField) -> ModelField: + """ + To support `Literal` with values of different types, we split it into multiple `Literal` with same type + e.g. `Literal['qwe', 'asd', 1, 2]` becomes `Union[Literal['qwe', 'asd'], Literal[1, 2]]` + """ + literal_distinct_types = defaultdict(list) + for v in values: + literal_distinct_types[v.__class__].append(v) + distinct_literals = (Literal[tuple(same_type_values)] for same_type_values in literal_distinct_types.values()) + + return ModelField( + name=field.name, + type_=Union[tuple(distinct_literals)], # type: ignore + class_validators=field.class_validators, + model_config=field.model_config, + default=field.default, + required=field.required, + alias=field.alias, + field_info=field.field_info, + ) + + +def encode_default(dft: Any) -> Any: + from pydantic.v1.main import BaseModel + + if isinstance(dft, BaseModel) or is_dataclass(dft): + dft = cast('dict[str, Any]', pydantic_encoder(dft)) + + if isinstance(dft, dict): + return {encode_default(k): encode_default(v) for k, v in dft.items()} + elif isinstance(dft, Enum): + return dft.value + elif isinstance(dft, (int, float, str)): + return dft + elif isinstance(dft, (list, tuple)): + t = dft.__class__ + seq_args = (encode_default(v) for v in dft) + return t(*seq_args) if is_namedtuple(t) else t(seq_args) + elif dft is None: + return None + else: + return pydantic_encoder(dft) + + +_map_types_constraint: Dict[Any, Callable[..., type]] = {int: conint, float: confloat, Decimal: condecimal} + + +def get_annotation_from_field_info( + annotation: Any, field_info: FieldInfo, field_name: str, validate_assignment: bool = False +) -> Type[Any]: + """ + Get an annotation with validation implemented for numbers and strings based on the field_info. + :param annotation: an annotation from a field specification, as ``str``, ``ConstrainedStr`` + :param field_info: an instance of FieldInfo, possibly with declarations for validations and JSON Schema + :param field_name: name of the field for use in error messages + :param validate_assignment: default False, flag for BaseModel Config value of validate_assignment + :return: the same ``annotation`` if unmodified or a new annotation with validation in place + """ + constraints = field_info.get_constraints() + used_constraints: Set[str] = set() + if constraints: + annotation, used_constraints = get_annotation_with_constraints(annotation, field_info) + if validate_assignment: + used_constraints.add('allow_mutation') + + unused_constraints = constraints - used_constraints + if unused_constraints: + raise ValueError( + f'On field "{field_name}" the following field constraints are set but not enforced: ' + f'{", ".join(unused_constraints)}. ' + f'\nFor more details see https://docs.pydantic.dev/usage/schema/#unenforced-field-constraints' + ) + + return annotation + + +def get_annotation_with_constraints(annotation: Any, field_info: FieldInfo) -> Tuple[Type[Any], Set[str]]: # noqa: C901 + """ + Get an annotation with used constraints implemented for numbers and strings based on the field_info. + + :param annotation: an annotation from a field specification, as ``str``, ``ConstrainedStr`` + :param field_info: an instance of FieldInfo, possibly with declarations for validations and JSON Schema + :return: the same ``annotation`` if unmodified or a new annotation along with the used constraints. + """ + used_constraints: Set[str] = set() + + def go(type_: Any) -> Type[Any]: + if ( + is_literal_type(type_) + or isinstance(type_, ForwardRef) + or lenient_issubclass(type_, (ConstrainedList, ConstrainedSet, ConstrainedFrozenSet)) + ): + return type_ + origin = get_origin(type_) + if origin is not None: + args: Tuple[Any, ...] = get_args(type_) + if any(isinstance(a, ForwardRef) for a in args): + # forward refs cause infinite recursion below + return type_ + + if origin is Annotated: + return go(args[0]) + if is_union(origin): + return Union[tuple(go(a) for a in args)] # type: ignore + + if issubclass(origin, List) and ( + field_info.min_items is not None + or field_info.max_items is not None + or field_info.unique_items is not None + ): + used_constraints.update({'min_items', 'max_items', 'unique_items'}) + return conlist( + go(args[0]), + min_items=field_info.min_items, + max_items=field_info.max_items, + unique_items=field_info.unique_items, + ) + + if issubclass(origin, Set) and (field_info.min_items is not None or field_info.max_items is not None): + used_constraints.update({'min_items', 'max_items'}) + return conset(go(args[0]), min_items=field_info.min_items, max_items=field_info.max_items) + + if issubclass(origin, FrozenSet) and (field_info.min_items is not None or field_info.max_items is not None): + used_constraints.update({'min_items', 'max_items'}) + return confrozenset(go(args[0]), min_items=field_info.min_items, max_items=field_info.max_items) + + for t in (Tuple, List, Set, FrozenSet, Sequence): + if issubclass(origin, t): # type: ignore + return t[tuple(go(a) for a in args)] # type: ignore + + if issubclass(origin, Dict): + return Dict[args[0], go(args[1])] # type: ignore + + attrs: Optional[Tuple[str, ...]] = None + constraint_func: Optional[Callable[..., type]] = None + if isinstance(type_, type): + if issubclass(type_, (SecretStr, SecretBytes)): + attrs = ('max_length', 'min_length') + + def constraint_func(**kw: Any) -> Type[Any]: # noqa: F811 + return type(type_.__name__, (type_,), kw) + + elif issubclass(type_, str) and not issubclass(type_, (EmailStr, AnyUrl)): + attrs = ('max_length', 'min_length', 'regex') + if issubclass(type_, StrictStr): + + def constraint_func(**kw: Any) -> Type[Any]: + return type(type_.__name__, (type_,), kw) + + else: + constraint_func = constr + elif issubclass(type_, bytes): + attrs = ('max_length', 'min_length', 'regex') + if issubclass(type_, StrictBytes): + + def constraint_func(**kw: Any) -> Type[Any]: + return type(type_.__name__, (type_,), kw) + + else: + constraint_func = conbytes + elif issubclass(type_, numeric_types) and not issubclass( + type_, + ( + ConstrainedInt, + ConstrainedFloat, + ConstrainedDecimal, + ConstrainedList, + ConstrainedSet, + ConstrainedFrozenSet, + bool, + ), + ): + # Is numeric type + attrs = ('gt', 'lt', 'ge', 'le', 'multiple_of') + if issubclass(type_, float): + attrs += ('allow_inf_nan',) + if issubclass(type_, Decimal): + attrs += ('max_digits', 'decimal_places') + numeric_type = next(t for t in numeric_types if issubclass(type_, t)) # pragma: no branch + constraint_func = _map_types_constraint[numeric_type] + + if attrs: + used_constraints.update(set(attrs)) + kwargs = { + attr_name: attr + for attr_name, attr in ((attr_name, getattr(field_info, attr_name)) for attr_name in attrs) + if attr is not None + } + if kwargs: + constraint_func = cast(Callable[..., type], constraint_func) + return constraint_func(**kwargs) + return type_ + + return go(annotation), used_constraints + + +def normalize_name(name: str) -> str: + """ + Normalizes the given name. This can be applied to either a model *or* enum. + """ + return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name) + + +class SkipField(Exception): + """ + Utility exception used to exclude fields from schema. + """ + + def __init__(self, message: str) -> None: + self.message = message diff --git a/backend/venv/Lib/site-packages/pydantic/v1/tools.py b/backend/venv/Lib/site-packages/pydantic/v1/tools.py new file mode 100644 index 0000000..6838a23 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/tools.py @@ -0,0 +1,92 @@ +import json +from functools import lru_cache +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, Optional, Type, TypeVar, Union + +from pydantic.v1.parse import Protocol, load_file, load_str_bytes +from pydantic.v1.types import StrBytes +from pydantic.v1.typing import display_as_type + +__all__ = ('parse_file_as', 'parse_obj_as', 'parse_raw_as', 'schema_of', 'schema_json_of') + +NameFactory = Union[str, Callable[[Type[Any]], str]] + +if TYPE_CHECKING: + from pydantic.v1.typing import DictStrAny + + +def _generate_parsing_type_name(type_: Any) -> str: + return f'ParsingModel[{display_as_type(type_)}]' + + +@lru_cache(maxsize=2048) +def _get_parsing_type(type_: Any, *, type_name: Optional[NameFactory] = None) -> Any: + from pydantic.v1.main import create_model + + if type_name is None: + type_name = _generate_parsing_type_name + if not isinstance(type_name, str): + type_name = type_name(type_) + return create_model(type_name, __root__=(type_, ...)) + + +T = TypeVar('T') + + +def parse_obj_as(type_: Type[T], obj: Any, *, type_name: Optional[NameFactory] = None) -> T: + model_type = _get_parsing_type(type_, type_name=type_name) # type: ignore[arg-type] + return model_type(__root__=obj).__root__ + + +def parse_file_as( + type_: Type[T], + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, + type_name: Optional[NameFactory] = None, +) -> T: + obj = load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=json_loads, + ) + return parse_obj_as(type_, obj, type_name=type_name) + + +def parse_raw_as( + type_: Type[T], + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, + type_name: Optional[NameFactory] = None, +) -> T: + obj = load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=json_loads, + ) + return parse_obj_as(type_, obj, type_name=type_name) + + +def schema_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_kwargs: Any) -> 'DictStrAny': + """Generate a JSON schema (as dict) for the passed model or dynamically generated one""" + return _get_parsing_type(type_, type_name=title).schema(**schema_kwargs) + + +def schema_json_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_json_kwargs: Any) -> str: + """Generate a JSON schema (as JSON) for the passed model or dynamically generated one""" + return _get_parsing_type(type_, type_name=title).schema_json(**schema_json_kwargs) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/types.py b/backend/venv/Lib/site-packages/pydantic/v1/types.py new file mode 100644 index 0000000..e1840d9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/types.py @@ -0,0 +1,1205 @@ +import abc +import math +import re +import warnings +from datetime import date +from decimal import Decimal, InvalidOperation +from enum import Enum +from pathlib import Path +from types import new_class +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + FrozenSet, + List, + Optional, + Pattern, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) +from uuid import UUID +from weakref import WeakSet + +from pydantic.v1 import errors +from pydantic.v1.datetime_parse import parse_date +from pydantic.v1.utils import import_string, update_not_none +from pydantic.v1.validators import ( + bytes_validator, + constr_length_validator, + constr_lower, + constr_strip_whitespace, + constr_upper, + decimal_validator, + float_finite_validator, + float_validator, + frozenset_validator, + int_validator, + list_validator, + number_multiple_validator, + number_size_validator, + path_exists_validator, + path_validator, + set_validator, + str_validator, + strict_bytes_validator, + strict_float_validator, + strict_int_validator, + strict_str_validator, +) + +__all__ = [ + 'NoneStr', + 'NoneBytes', + 'StrBytes', + 'NoneStrBytes', + 'StrictStr', + 'ConstrainedBytes', + 'conbytes', + 'ConstrainedList', + 'conlist', + 'ConstrainedSet', + 'conset', + 'ConstrainedFrozenSet', + 'confrozenset', + 'ConstrainedStr', + 'constr', + 'PyObject', + 'ConstrainedInt', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'ConstrainedFloat', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'ConstrainedDecimal', + 'condecimal', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'FilePath', + 'DirectoryPath', + 'Json', + 'JsonWrapper', + 'SecretField', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'ConstrainedDate', + 'condate', +] + +NoneStr = Optional[str] +NoneBytes = Optional[bytes] +StrBytes = Union[str, bytes] +NoneStrBytes = Optional[StrBytes] +OptionalInt = Optional[int] +OptionalIntFloat = Union[OptionalInt, float] +OptionalIntFloatDecimal = Union[OptionalIntFloat, Decimal] +OptionalDate = Optional[date] +StrIntFloat = Union[str, int, float] + +if TYPE_CHECKING: + from typing_extensions import Annotated + + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import CallableGenerator + + ModelOrDc = Type[Union[BaseModel, Dataclass]] + +T = TypeVar('T') +_DEFINED_TYPES: 'WeakSet[type]' = WeakSet() + + +@overload +def _registered(typ: Type[T]) -> Type[T]: + pass + + +@overload +def _registered(typ: 'ConstrainedNumberMeta') -> 'ConstrainedNumberMeta': + pass + + +def _registered(typ: Union[Type[T], 'ConstrainedNumberMeta']) -> Union[Type[T], 'ConstrainedNumberMeta']: + # In order to generate valid examples of constrained types, Hypothesis needs + # to inspect the type object - so we keep a weakref to each contype object + # until it can be registered. When (or if) our Hypothesis plugin is loaded, + # it monkeypatches this function. + # If Hypothesis is never used, the total effect is to keep a weak reference + # which has minimal memory usage and doesn't even affect garbage collection. + _DEFINED_TYPES.add(typ) + return typ + + +class ConstrainedNumberMeta(type): + def __new__(cls, name: str, bases: Any, dct: Dict[str, Any]) -> 'ConstrainedInt': # type: ignore + new_cls = cast('ConstrainedInt', type.__new__(cls, name, bases, dct)) + + if new_cls.gt is not None and new_cls.ge is not None: + raise errors.ConfigError('bounds gt and ge cannot be specified at the same time') + if new_cls.lt is not None and new_cls.le is not None: + raise errors.ConfigError('bounds lt and le cannot be specified at the same time') + + return _registered(new_cls) # type: ignore + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + StrictBool = bool +else: + + class StrictBool(int): + """ + StrictBool to allow for bools which are not type-coerced. + """ + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='boolean') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> bool: + """ + Ensure that we only allow bools. + """ + if isinstance(value, bool): + return value + + raise errors.StrictBoolError() + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedInt(int, metaclass=ConstrainedNumberMeta): + strict: bool = False + gt: OptionalInt = None + ge: OptionalInt = None + lt: OptionalInt = None + le: OptionalInt = None + multiple_of: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_int_validator if cls.strict else int_validator + yield number_size_validator + yield number_multiple_validator + + +def conint( + *, + strict: bool = False, + gt: Optional[int] = None, + ge: Optional[int] = None, + lt: Optional[int] = None, + le: Optional[int] = None, + multiple_of: Optional[int] = None, +) -> Type[int]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of) + return type('ConstrainedIntValue', (ConstrainedInt,), namespace) + + +if TYPE_CHECKING: + PositiveInt = int + NegativeInt = int + NonPositiveInt = int + NonNegativeInt = int + StrictInt = int +else: + + class PositiveInt(ConstrainedInt): + gt = 0 + + class NegativeInt(ConstrainedInt): + lt = 0 + + class NonPositiveInt(ConstrainedInt): + le = 0 + + class NonNegativeInt(ConstrainedInt): + ge = 0 + + class StrictInt(ConstrainedInt): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedFloat(float, metaclass=ConstrainedNumberMeta): + strict: bool = False + gt: OptionalIntFloat = None + ge: OptionalIntFloat = None + lt: OptionalIntFloat = None + le: OptionalIntFloat = None + multiple_of: OptionalIntFloat = None + allow_inf_nan: Optional[bool] = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + # Modify constraints to account for differences between IEEE floats and JSON + if field_schema.get('exclusiveMinimum') == -math.inf: + del field_schema['exclusiveMinimum'] + if field_schema.get('minimum') == -math.inf: + del field_schema['minimum'] + if field_schema.get('exclusiveMaximum') == math.inf: + del field_schema['exclusiveMaximum'] + if field_schema.get('maximum') == math.inf: + del field_schema['maximum'] + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_float_validator if cls.strict else float_validator + yield number_size_validator + yield number_multiple_validator + yield float_finite_validator + + +def confloat( + *, + strict: bool = False, + gt: float = None, + ge: float = None, + lt: float = None, + le: float = None, + multiple_of: float = None, + allow_inf_nan: Optional[bool] = None, +) -> Type[float]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of, allow_inf_nan=allow_inf_nan) + return type('ConstrainedFloatValue', (ConstrainedFloat,), namespace) + + +if TYPE_CHECKING: + PositiveFloat = float + NegativeFloat = float + NonPositiveFloat = float + NonNegativeFloat = float + StrictFloat = float + FiniteFloat = float +else: + + class PositiveFloat(ConstrainedFloat): + gt = 0 + + class NegativeFloat(ConstrainedFloat): + lt = 0 + + class NonPositiveFloat(ConstrainedFloat): + le = 0 + + class NonNegativeFloat(ConstrainedFloat): + ge = 0 + + class StrictFloat(ConstrainedFloat): + strict = True + + class FiniteFloat(ConstrainedFloat): + allow_inf_nan = False + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedBytes(bytes): + strip_whitespace = False + to_upper = False + to_lower = False + min_length: OptionalInt = None + max_length: OptionalInt = None + strict: bool = False + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minLength=cls.min_length, maxLength=cls.max_length) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_bytes_validator if cls.strict else bytes_validator + yield constr_strip_whitespace + yield constr_upper + yield constr_lower + yield constr_length_validator + + +def conbytes( + *, + strip_whitespace: bool = False, + to_upper: bool = False, + to_lower: bool = False, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + strict: bool = False, +) -> Type[bytes]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + min_length=min_length, + max_length=max_length, + strict=strict, + ) + return _registered(type('ConstrainedBytesValue', (ConstrainedBytes,), namespace)) + + +if TYPE_CHECKING: + StrictBytes = bytes +else: + + class StrictBytes(ConstrainedBytes): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedStr(str): + strip_whitespace = False + to_upper = False + to_lower = False + min_length: OptionalInt = None + max_length: OptionalInt = None + curtail_length: OptionalInt = None + regex: Optional[Union[str, Pattern[str]]] = None + strict = False + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + minLength=cls.min_length, + maxLength=cls.max_length, + pattern=cls.regex and cls._get_pattern(cls.regex), + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_str_validator if cls.strict else str_validator + yield constr_strip_whitespace + yield constr_upper + yield constr_lower + yield constr_length_validator + yield cls.validate + + @classmethod + def validate(cls, value: Union[str]) -> Union[str]: + if cls.curtail_length and len(value) > cls.curtail_length: + value = value[: cls.curtail_length] + + if cls.regex: + if not re.match(cls.regex, value): + raise errors.StrRegexError(pattern=cls._get_pattern(cls.regex)) + + return value + + @staticmethod + def _get_pattern(regex: Union[str, Pattern[str]]) -> str: + return regex if isinstance(regex, str) else regex.pattern + + +def constr( + *, + strip_whitespace: bool = False, + to_upper: bool = False, + to_lower: bool = False, + strict: bool = False, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + curtail_length: Optional[int] = None, + regex: Optional[str] = None, +) -> Type[str]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + strict=strict, + min_length=min_length, + max_length=max_length, + curtail_length=curtail_length, + regex=regex and re.compile(regex), + ) + return _registered(type('ConstrainedStrValue', (ConstrainedStr,), namespace)) + + +if TYPE_CHECKING: + StrictStr = str +else: + + class StrictStr(ConstrainedStr): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# This types superclass should be Set[T], but cython chokes on that... +class ConstrainedSet(set): # type: ignore + # Needed for pydantic to detect that this is a set + __origin__ = set + __args__: Set[Type[T]] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.set_length_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) + + @classmethod + def set_length_validator(cls, v: 'Optional[Set[T]]') -> 'Optional[Set[T]]': + if v is None: + return None + + v = set_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.SetMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.SetMaxLengthError(limit_value=cls.max_items) + + return v + + +def conset(item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None) -> Type[Set[T]]: + # __args__ is needed to conform to typing generics api + namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedSetValue', (ConstrainedSet,), {}, lambda ns: ns.update(namespace)) + + +# This types superclass should be FrozenSet[T], but cython chokes on that... +class ConstrainedFrozenSet(frozenset): # type: ignore + # Needed for pydantic to detect that this is a set + __origin__ = frozenset + __args__: FrozenSet[Type[T]] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.frozenset_length_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) + + @classmethod + def frozenset_length_validator(cls, v: 'Optional[FrozenSet[T]]') -> 'Optional[FrozenSet[T]]': + if v is None: + return None + + v = frozenset_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.FrozenSetMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.FrozenSetMaxLengthError(limit_value=cls.max_items) + + return v + + +def confrozenset( + item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None +) -> Type[FrozenSet[T]]: + # __args__ is needed to conform to typing generics api + namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedFrozenSetValue', (ConstrainedFrozenSet,), {}, lambda ns: ns.update(namespace)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LIST TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# This types superclass should be List[T], but cython chokes on that... +class ConstrainedList(list): # type: ignore + # Needed for pydantic to detect that this is a list + __origin__ = list + __args__: Tuple[Type[T], ...] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + unique_items: Optional[bool] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.list_length_validator + if cls.unique_items: + yield cls.unique_items_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items, uniqueItems=cls.unique_items) + + @classmethod + def list_length_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': + if v is None: + return None + + v = list_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.ListMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.ListMaxLengthError(limit_value=cls.max_items) + + return v + + @classmethod + def unique_items_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': + if v is None: + return None + + for i, value in enumerate(v, start=1): + if value in v[i:]: + raise errors.ListUniqueItemsError() + + return v + + +def conlist( + item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None, unique_items: bool = None +) -> Type[List[T]]: + # __args__ is needed to conform to typing generics api + namespace = dict( + min_items=min_items, max_items=max_items, unique_items=unique_items, item_type=item_type, __args__=(item_type,) + ) + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedListValue', (ConstrainedList,), {}, lambda ns: ns.update(namespace)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PYOBJECT TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +if TYPE_CHECKING: + PyObject = Callable[..., Any] +else: + + class PyObject: + validate_always = True + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> Any: + if isinstance(value, Callable): + return value + + try: + value = str_validator(value) + except errors.StrError: + raise errors.PyObjectError(error_message='value is neither a valid import path not a valid callable') + + try: + return import_string(value) + except ImportError as e: + raise errors.PyObjectError(error_message=str(e)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedDecimal(Decimal, metaclass=ConstrainedNumberMeta): + gt: OptionalIntFloatDecimal = None + ge: OptionalIntFloatDecimal = None + lt: OptionalIntFloatDecimal = None + le: OptionalIntFloatDecimal = None + max_digits: OptionalInt = None + decimal_places: OptionalInt = None + multiple_of: OptionalIntFloatDecimal = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield decimal_validator + yield number_size_validator + yield number_multiple_validator + yield cls.validate + + @classmethod + def validate(cls, value: Decimal) -> Decimal: + try: + normalized_value = value.normalize() + except InvalidOperation: + normalized_value = value + digit_tuple, exponent = normalized_value.as_tuple()[1:] + if exponent in {'F', 'n', 'N'}: + raise errors.DecimalIsNotFiniteError() + + if exponent >= 0: + # A positive exponent adds that many trailing zeros. + digits = len(digit_tuple) + exponent + decimals = 0 + else: + # If the absolute value of the negative exponent is larger than the + # number of digits, then it's the same as the number of digits, + # because it'll consume all of the digits in digit_tuple and then + # add abs(exponent) - len(digit_tuple) leading zeros after the + # decimal point. + if abs(exponent) > len(digit_tuple): + digits = decimals = abs(exponent) + else: + digits = len(digit_tuple) + decimals = abs(exponent) + whole_digits = digits - decimals + + if cls.max_digits is not None and digits > cls.max_digits: + raise errors.DecimalMaxDigitsError(max_digits=cls.max_digits) + + if cls.decimal_places is not None and decimals > cls.decimal_places: + raise errors.DecimalMaxPlacesError(decimal_places=cls.decimal_places) + + if cls.max_digits is not None and cls.decimal_places is not None: + expected = cls.max_digits - cls.decimal_places + if whole_digits > expected: + raise errors.DecimalWholeDigitsError(whole_digits=expected) + + return value + + +def condecimal( + *, + gt: Decimal = None, + ge: Decimal = None, + lt: Decimal = None, + le: Decimal = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + multiple_of: Decimal = None, +) -> Type[Decimal]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + gt=gt, ge=ge, lt=lt, le=le, max_digits=max_digits, decimal_places=decimal_places, multiple_of=multiple_of + ) + return type('ConstrainedDecimalValue', (ConstrainedDecimal,), namespace) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + UUID1 = UUID + UUID3 = UUID + UUID4 = UUID + UUID5 = UUID +else: + + class UUID1(UUID): + _required_version = 1 + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format=f'uuid{cls._required_version}') + + class UUID3(UUID1): + _required_version = 3 + + class UUID4(UUID1): + _required_version = 4 + + class UUID5(UUID1): + _required_version = 5 + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + FilePath = Path + DirectoryPath = Path +else: + + class FilePath(Path): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(format='file-path') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield path_validator + yield path_exists_validator + yield cls.validate + + @classmethod + def validate(cls, value: Path) -> Path: + if not value.is_file(): + raise errors.PathNotAFileError(path=value) + + return value + + class DirectoryPath(Path): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(format='directory-path') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield path_validator + yield path_exists_validator + yield cls.validate + + @classmethod + def validate(cls, value: Path) -> Path: + if not value.is_dir(): + raise errors.PathNotADirectoryError(path=value) + + return value + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class JsonWrapper: + pass + + +class JsonMeta(type): + def __getitem__(self, t: Type[Any]) -> Type[JsonWrapper]: + if t is Any: + return Json # allow Json[Any] to replicate plain Json + return _registered(type('JsonWrapperValue', (JsonWrapper,), {'inner_type': t})) + + +if TYPE_CHECKING: + Json = Annotated[T, ...] # Json[list[str]] will be recognized by type checkers as list[str] + +else: + + class Json(metaclass=JsonMeta): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='json-string') + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class SecretField(abc.ABC): + """ + Note: this should be implemented as a generic like `SecretField(ABC, Generic[T])`, + the `__init__()` should be part of the abstract class and the + `get_secret_value()` method should use the generic `T` type. + + However Cython doesn't support very well generics at the moment and + the generated code fails to be imported (see + https://github.com/cython/cython/issues/2753). + """ + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() + + def __str__(self) -> str: + return '**********' if self.get_secret_value() else '' + + def __hash__(self) -> int: + return hash(self.get_secret_value()) + + @abc.abstractmethod + def get_secret_value(self) -> Any: # pragma: no cover + ... + + +class SecretStr(SecretField): + min_length: OptionalInt = None + max_length: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + type='string', + writeOnly=True, + format='password', + minLength=cls.min_length, + maxLength=cls.max_length, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + yield constr_length_validator + + @classmethod + def validate(cls, value: Any) -> 'SecretStr': + if isinstance(value, cls): + return value + value = str_validator(value) + return cls(value) + + def __init__(self, value: str): + self._secret_value = value + + def __repr__(self) -> str: + return f"SecretStr('{self}')" + + def __len__(self) -> int: + return len(self._secret_value) + + def display(self) -> str: + warnings.warn('`secret_str.display()` is deprecated, use `str(secret_str)` instead', DeprecationWarning) + return str(self) + + def get_secret_value(self) -> str: + return self._secret_value + + +class SecretBytes(SecretField): + min_length: OptionalInt = None + max_length: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + type='string', + writeOnly=True, + format='password', + minLength=cls.min_length, + maxLength=cls.max_length, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + yield constr_length_validator + + @classmethod + def validate(cls, value: Any) -> 'SecretBytes': + if isinstance(value, cls): + return value + value = bytes_validator(value) + return cls(value) + + def __init__(self, value: bytes): + self._secret_value = value + + def __repr__(self) -> str: + return f"SecretBytes(b'{self}')" + + def __len__(self) -> int: + return len(self._secret_value) + + def display(self) -> str: + warnings.warn('`secret_bytes.display()` is deprecated, use `str(secret_bytes)` instead', DeprecationWarning) + return str(self) + + def get_secret_value(self) -> bytes: + return self._secret_value + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class PaymentCardBrand(str, Enum): + # If you add another card type, please also add it to the + # Hypothesis strategy in `pydantic._hypothesis_plugin`. + amex = 'American Express' + mastercard = 'Mastercard' + visa = 'Visa' + other = 'other' + + def __str__(self) -> str: + return self.value + + +class PaymentCardNumber(str): + """ + Based on: https://en.wikipedia.org/wiki/Payment_card_number + """ + + strip_whitespace: ClassVar[bool] = True + min_length: ClassVar[int] = 12 + max_length: ClassVar[int] = 19 + bin: str + last4: str + brand: PaymentCardBrand + + def __init__(self, card_number: str): + self.bin = card_number[:6] + self.last4 = card_number[-4:] + self.brand = self._get_brand(card_number) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield str_validator + yield constr_strip_whitespace + yield constr_length_validator + yield cls.validate_digits + yield cls.validate_luhn_check_digit + yield cls + yield cls.validate_length_for_brand + + @property + def masked(self) -> str: + num_masked = len(self) - 10 # len(bin) + len(last4) == 10 + return f'{self.bin}{"*" * num_masked}{self.last4}' + + @classmethod + def validate_digits(cls, card_number: str) -> str: + if not card_number.isdigit(): + raise errors.NotDigitError + return card_number + + @classmethod + def validate_luhn_check_digit(cls, card_number: str) -> str: + """ + Based on: https://en.wikipedia.org/wiki/Luhn_algorithm + """ + sum_ = int(card_number[-1]) + length = len(card_number) + parity = length % 2 + for i in range(length - 1): + digit = int(card_number[i]) + if i % 2 == parity: + digit *= 2 + if digit > 9: + digit -= 9 + sum_ += digit + valid = sum_ % 10 == 0 + if not valid: + raise errors.LuhnValidationError + return card_number + + @classmethod + def validate_length_for_brand(cls, card_number: 'PaymentCardNumber') -> 'PaymentCardNumber': + """ + Validate length based on BIN for major brands: + https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN) + """ + required_length: Union[None, int, str] = None + if card_number.brand in PaymentCardBrand.mastercard: + required_length = 16 + valid = len(card_number) == required_length + elif card_number.brand == PaymentCardBrand.visa: + required_length = '13, 16 or 19' + valid = len(card_number) in {13, 16, 19} + elif card_number.brand == PaymentCardBrand.amex: + required_length = 15 + valid = len(card_number) == required_length + else: + valid = True + if not valid: + raise errors.InvalidLengthForBrand(brand=card_number.brand, required_length=required_length) + return card_number + + @staticmethod + def _get_brand(card_number: str) -> PaymentCardBrand: + if card_number[0] == '4': + brand = PaymentCardBrand.visa + elif 51 <= int(card_number[:2]) <= 55: + brand = PaymentCardBrand.mastercard + elif card_number[:2] in {'34', '37'}: + brand = PaymentCardBrand.amex + else: + brand = PaymentCardBrand.other + return brand + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +BYTE_SIZES = { + 'b': 1, + 'kb': 10**3, + 'mb': 10**6, + 'gb': 10**9, + 'tb': 10**12, + 'pb': 10**15, + 'eb': 10**18, + 'kib': 2**10, + 'mib': 2**20, + 'gib': 2**30, + 'tib': 2**40, + 'pib': 2**50, + 'eib': 2**60, +} +BYTE_SIZES.update({k.lower()[0]: v for k, v in BYTE_SIZES.items() if 'i' not in k}) +byte_string_re = re.compile(r'^\s*(\d*\.?\d+)\s*(\w+)?', re.IGNORECASE) + + +class ByteSize(int): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, v: StrIntFloat) -> 'ByteSize': + try: + return cls(int(v)) + except ValueError: + pass + + str_match = byte_string_re.match(str(v)) + if str_match is None: + raise errors.InvalidByteSize() + + scalar, unit = str_match.groups() + if unit is None: + unit = 'b' + + try: + unit_mult = BYTE_SIZES[unit.lower()] + except KeyError: + raise errors.InvalidByteSizeUnit(unit=unit) + + return cls(int(float(scalar) * unit_mult)) + + def human_readable(self, decimal: bool = False) -> str: + if decimal: + divisor = 1000 + units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] + final_unit = 'EB' + else: + divisor = 1024 + units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] + final_unit = 'EiB' + + num = float(self) + for unit in units: + if abs(num) < divisor: + return f'{num:0.1f}{unit}' + num /= divisor + + return f'{num:0.1f}{final_unit}' + + def to(self, unit: str) -> float: + try: + unit_div = BYTE_SIZES[unit.lower()] + except KeyError: + raise errors.InvalidByteSizeUnit(unit=unit) + + return self / unit_div + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + PastDate = date + FutureDate = date +else: + + class PastDate(date): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield cls.validate + + @classmethod + def validate(cls, value: date) -> date: + if value >= date.today(): + raise errors.DateNotInThePastError() + + return value + + class FutureDate(date): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield cls.validate + + @classmethod + def validate(cls, value: date) -> date: + if value <= date.today(): + raise errors.DateNotInTheFutureError() + + return value + + +class ConstrainedDate(date, metaclass=ConstrainedNumberMeta): + gt: OptionalDate = None + ge: OptionalDate = None + lt: OptionalDate = None + le: OptionalDate = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, exclusiveMinimum=cls.gt, exclusiveMaximum=cls.lt, minimum=cls.ge, maximum=cls.le) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield number_size_validator + + +def condate( + *, + gt: date = None, + ge: date = None, + lt: date = None, + le: date = None, +) -> Type[date]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(gt=gt, ge=ge, lt=lt, le=le) + return type('ConstrainedDateValue', (ConstrainedDate,), namespace) diff --git a/backend/venv/Lib/site-packages/pydantic/v1/typing.py b/backend/venv/Lib/site-packages/pydantic/v1/typing.py new file mode 100644 index 0000000..9741161 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/typing.py @@ -0,0 +1,614 @@ +import functools +import operator +import sys +import typing +from collections.abc import Callable +from os import PathLike +from typing import ( # type: ignore + TYPE_CHECKING, + AbstractSet, + Any, + Callable as TypingCallable, + ClassVar, + Dict, + ForwardRef, + Generator, + Iterable, + List, + Mapping, + NewType, + Optional, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + _eval_type, + cast, + get_type_hints, +) + +from typing_extensions import ( + Annotated, + Final, + Literal, + NotRequired as TypedDictNotRequired, + Required as TypedDictRequired, +) + +try: + from typing import _TypingBase as typing_base # type: ignore +except ImportError: + from typing import _Final as typing_base # type: ignore + +try: + from typing import GenericAlias as TypingGenericAlias # type: ignore +except ImportError: + # python < 3.9 does not have GenericAlias (list[int], tuple[str, ...] and so on) + TypingGenericAlias = () + +try: + from types import UnionType as TypesUnionType # type: ignore +except ImportError: + # python < 3.10 does not have UnionType (str | int, byte | bool and so on) + TypesUnionType = () + + +if sys.version_info < (3, 9): + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + return type_._evaluate(globalns, localns) + +elif sys.version_info < (3, 12, 4): + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + # Even though it is the right signature for python 3.9, mypy complains with + # `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast... + # Python 3.13/3.12.4+ made `recursive_guard` a kwarg, so name it explicitly to avoid: + # TypeError: ForwardRef._evaluate() missing 1 required keyword-only argument: 'recursive_guard' + return cast(Any, type_)._evaluate(globalns, localns, recursive_guard=set()) + +else: + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + # Pydantic 1.x will not support PEP 695 syntax, but provide `type_params` to avoid + # warnings: + return cast(Any, type_)._evaluate(globalns, localns, type_params=(), recursive_guard=set()) + + +if sys.version_info < (3, 9): + # Ensure we always get all the whole `Annotated` hint, not just the annotated type. + # For 3.7 to 3.8, `get_type_hints` doesn't recognize `typing_extensions.Annotated`, + # so it already returns the full annotation + get_all_type_hints = get_type_hints + +else: + + def get_all_type_hints(obj: Any, globalns: Any = None, localns: Any = None) -> Any: + return get_type_hints(obj, globalns, localns, include_extras=True) + + +_T = TypeVar('_T') + +AnyCallable = TypingCallable[..., Any] +NoArgAnyCallable = TypingCallable[[], Any] + +# workaround for https://github.com/python/mypy/issues/9496 +AnyArgTCallable = TypingCallable[..., _T] + + +# Annotated[...] is implemented by returning an instance of one of these classes, depending on +# python/typing_extensions version. +AnnotatedTypeNames = {'AnnotatedMeta', '_AnnotatedAlias'} + + +LITERAL_TYPES: Set[Any] = {Literal} +if hasattr(typing, 'Literal'): + LITERAL_TYPES.add(typing.Literal) + + +if sys.version_info < (3, 8): + + def get_origin(t: Type[Any]) -> Optional[Type[Any]]: + if type(t).__name__ in AnnotatedTypeNames: + # weirdly this is a runtime requirement, as well as for mypy + return cast(Type[Any], Annotated) + return getattr(t, '__origin__', None) + +else: + from typing import get_origin as _typing_get_origin + + def get_origin(tp: Type[Any]) -> Optional[Type[Any]]: + """ + We can't directly use `typing.get_origin` since we need a fallback to support + custom generic classes like `ConstrainedList` + It should be useless once https://github.com/cython/cython/issues/3537 is + solved and https://github.com/pydantic/pydantic/pull/1753 is merged. + """ + if type(tp).__name__ in AnnotatedTypeNames: + return cast(Type[Any], Annotated) # mypy complains about _SpecialForm + return _typing_get_origin(tp) or getattr(tp, '__origin__', None) + + +if sys.version_info < (3, 8): + from typing import _GenericAlias + + def get_args(t: Type[Any]) -> Tuple[Any, ...]: + """Compatibility version of get_args for python 3.7. + + Mostly compatible with the python 3.8 `typing` module version + and able to handle almost all use cases. + """ + if type(t).__name__ in AnnotatedTypeNames: + return t.__args__ + t.__metadata__ + if isinstance(t, _GenericAlias): + res = t.__args__ + if t.__origin__ is Callable and res and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return getattr(t, '__args__', ()) + +else: + from typing import get_args as _typing_get_args + + def _generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]: + """ + In python 3.9, `typing.Dict`, `typing.List`, ... + do have an empty `__args__` by default (instead of the generic ~T for example). + In order to still support `Dict` for example and consider it as `Dict[Any, Any]`, + we retrieve the `_nparams` value that tells us how many parameters it needs. + """ + if hasattr(tp, '_nparams'): + return (Any,) * tp._nparams + # Special case for `tuple[()]`, which used to return ((),) with `typing.Tuple` + # in python 3.10- but now returns () for `tuple` and `Tuple`. + # This will probably be clarified in pydantic v2 + try: + if tp == Tuple[()] or sys.version_info >= (3, 9) and tp == tuple[()]: # type: ignore[misc] + return ((),) + # there is a TypeError when compiled with cython + except TypeError: # pragma: no cover + pass + return () + + def get_args(tp: Type[Any]) -> Tuple[Any, ...]: + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if type(tp).__name__ in AnnotatedTypeNames: + return tp.__args__ + tp.__metadata__ + # the fallback is needed for the same reasons as `get_origin` (see above) + return _typing_get_args(tp) or getattr(tp, '__args__', ()) or _generic_get_args(tp) + + +if sys.version_info < (3, 9): + + def convert_generics(tp: Type[Any]) -> Type[Any]: + """Python 3.9 and older only supports generics from `typing` module. + They convert strings to ForwardRef automatically. + + Examples:: + typing.List['Hero'] == typing.List[ForwardRef('Hero')] + """ + return tp + +else: + + def convert_generics(tp: Type[Any]) -> Type[Any]: + """ + Recursively searches for `str` type hints and replaces them with ForwardRef. + + Examples:: + convert_generics(list['Hero']) == list[ForwardRef('Hero')] + convert_generics(dict['Hero', 'Team']) == dict[ForwardRef('Hero'), ForwardRef('Team')] + convert_generics(typing.Dict['Hero', 'Team']) == typing.Dict[ForwardRef('Hero'), ForwardRef('Team')] + convert_generics(list[str | 'Hero'] | int) == list[str | ForwardRef('Hero')] | int + """ + origin = get_origin(tp) + if not origin or not hasattr(tp, '__args__'): + return tp + + args = get_args(tp) + + # typing.Annotated needs special treatment + if origin is Annotated: + return Annotated[(convert_generics(args[0]), *args[1:])] # type: ignore + + # recursively replace `str` instances inside of `GenericAlias` with `ForwardRef(arg)` + converted = tuple( + ForwardRef(arg) if isinstance(arg, str) and isinstance(tp, TypingGenericAlias) else convert_generics(arg) + for arg in args + ) + + if converted == args: + return tp + elif isinstance(tp, TypingGenericAlias): + return TypingGenericAlias(origin, converted) + elif isinstance(tp, TypesUnionType): + # recreate types.UnionType (PEP604, Python >= 3.10) + return functools.reduce(operator.or_, converted) # type: ignore + else: + try: + setattr(tp, '__args__', converted) + except AttributeError: + pass + return tp + + +if sys.version_info < (3, 10): + + def is_union(tp: Optional[Type[Any]]) -> bool: + return tp is Union + + WithArgsTypes = (TypingGenericAlias,) + +else: + import types + import typing + + def is_union(tp: Optional[Type[Any]]) -> bool: + return tp is Union or tp is types.UnionType # noqa: E721 + + WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType) + + +StrPath = Union[str, PathLike] + + +if TYPE_CHECKING: + from pydantic.v1.fields import ModelField + + TupleGenerator = Generator[Tuple[str, Any], None, None] + DictStrAny = Dict[str, Any] + DictAny = Dict[Any, Any] + SetStr = Set[str] + ListStr = List[str] + IntStr = Union[int, str] + AbstractSetIntStr = AbstractSet[IntStr] + DictIntStrAny = Dict[IntStr, Any] + MappingIntStrAny = Mapping[IntStr, Any] + CallableGenerator = Generator[AnyCallable, None, None] + ReprArgs = Sequence[Tuple[Optional[str], Any]] + + MYPY = False + if MYPY: + AnyClassMethod = classmethod[Any] + else: + # classmethod[TargetType, CallableParamSpecType, CallableReturnType] + AnyClassMethod = classmethod[Any, Any, Any] + +__all__ = ( + 'AnyCallable', + 'NoArgAnyCallable', + 'NoneType', + 'is_none_type', + 'display_as_type', + 'resolve_annotations', + 'is_callable_type', + 'is_literal_type', + 'all_literal_values', + 'is_namedtuple', + 'is_typeddict', + 'is_typeddict_special', + 'is_new_type', + 'new_type_supertype', + 'is_classvar', + 'is_finalvar', + 'update_field_forward_refs', + 'update_model_forward_refs', + 'TupleGenerator', + 'DictStrAny', + 'DictAny', + 'SetStr', + 'ListStr', + 'IntStr', + 'AbstractSetIntStr', + 'DictIntStrAny', + 'CallableGenerator', + 'ReprArgs', + 'AnyClassMethod', + 'CallableGenerator', + 'WithArgsTypes', + 'get_args', + 'get_origin', + 'get_sub_types', + 'typing_base', + 'get_all_type_hints', + 'is_union', + 'StrPath', + 'MappingIntStrAny', +) + + +NoneType = None.__class__ + + +NONE_TYPES: Tuple[Any, Any, Any] = (None, NoneType, Literal[None]) + + +if sys.version_info < (3, 8): + # Even though this implementation is slower, we need it for python 3.7: + # In python 3.7 "Literal" is not a builtin type and uses a different + # mechanism. + # for this reason `Literal[None] is Literal[None]` evaluates to `False`, + # breaking the faster implementation used for the other python versions. + + def is_none_type(type_: Any) -> bool: + return type_ in NONE_TYPES + +elif sys.version_info[:2] == (3, 8): + + def is_none_type(type_: Any) -> bool: + for none_type in NONE_TYPES: + if type_ is none_type: + return True + # With python 3.8, specifically 3.8.10, Literal "is" check sare very flakey + # can change on very subtle changes like use of types in other modules, + # hopefully this check avoids that issue. + if is_literal_type(type_): # pragma: no cover + return all_literal_values(type_) == (None,) + return False + +else: + + def is_none_type(type_: Any) -> bool: + return type_ in NONE_TYPES + + +def display_as_type(v: Type[Any]) -> str: + if not isinstance(v, typing_base) and not isinstance(v, WithArgsTypes) and not isinstance(v, type): + v = v.__class__ + + if is_union(get_origin(v)): + return f'Union[{", ".join(map(display_as_type, get_args(v)))}]' + + if isinstance(v, WithArgsTypes): + # Generic alias are constructs like `list[int]` + return str(v).replace('typing.', '') + + try: + return v.__name__ + except AttributeError: + # happens with typing objects + return str(v).replace('typing.', '') + + +def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Optional[str]) -> Dict[str, Type[Any]]: + """ + Partially taken from typing.get_type_hints. + + Resolve string or ForwardRef annotations into type objects if possible. + """ + base_globals: Optional[Dict[str, Any]] = None + if module_name: + try: + module = sys.modules[module_name] + except KeyError: + # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363 + pass + else: + base_globals = module.__dict__ + + annotations = {} + for name, value in raw_annotations.items(): + if isinstance(value, str): + if (3, 10) > sys.version_info >= (3, 9, 8) or sys.version_info >= (3, 10, 1): + value = ForwardRef(value, is_argument=False, is_class=True) + else: + value = ForwardRef(value, is_argument=False) + try: + if sys.version_info >= (3, 13): + value = _eval_type(value, base_globals, None, type_params=()) + else: + value = _eval_type(value, base_globals, None) + except NameError: + # this is ok, it can be fixed with update_forward_refs + pass + annotations[name] = value + return annotations + + +def is_callable_type(type_: Type[Any]) -> bool: + return type_ is Callable or get_origin(type_) is Callable + + +def is_literal_type(type_: Type[Any]) -> bool: + return Literal is not None and get_origin(type_) in LITERAL_TYPES + + +def literal_values(type_: Type[Any]) -> Tuple[Any, ...]: + return get_args(type_) + + +def all_literal_values(type_: Type[Any]) -> Tuple[Any, ...]: + """ + This method is used to retrieve all Literal values as + Literal can be used recursively (see https://www.python.org/dev/peps/pep-0586) + e.g. `Literal[Literal[Literal[1, 2, 3], "foo"], 5, None]` + """ + if not is_literal_type(type_): + return (type_,) + + values = literal_values(type_) + return tuple(x for value in values for x in all_literal_values(value)) + + +def is_namedtuple(type_: Type[Any]) -> bool: + """ + Check if a given class is a named tuple. + It can be either a `typing.NamedTuple` or `collections.namedtuple` + """ + from pydantic.v1.utils import lenient_issubclass + + return lenient_issubclass(type_, tuple) and hasattr(type_, '_fields') + + +def is_typeddict(type_: Type[Any]) -> bool: + """ + Check if a given class is a typed dict (from `typing` or `typing_extensions`) + In 3.10, there will be a public method (https://docs.python.org/3.10/library/typing.html#typing.is_typeddict) + """ + from pydantic.v1.utils import lenient_issubclass + + return lenient_issubclass(type_, dict) and hasattr(type_, '__total__') + + +def _check_typeddict_special(type_: Any) -> bool: + return type_ is TypedDictRequired or type_ is TypedDictNotRequired + + +def is_typeddict_special(type_: Any) -> bool: + """ + Check if type is a TypedDict special form (Required or NotRequired). + """ + return _check_typeddict_special(type_) or _check_typeddict_special(get_origin(type_)) + + +test_type = NewType('test_type', str) + + +def is_new_type(type_: Type[Any]) -> bool: + """ + Check whether type_ was created using typing.NewType + """ + return isinstance(type_, test_type.__class__) and hasattr(type_, '__supertype__') # type: ignore + + +def new_type_supertype(type_: Type[Any]) -> Type[Any]: + while hasattr(type_, '__supertype__'): + type_ = type_.__supertype__ + return type_ + + +def _check_classvar(v: Optional[Type[Any]]) -> bool: + if v is None: + return False + + return v.__class__ == ClassVar.__class__ and getattr(v, '_name', None) == 'ClassVar' + + +def _check_finalvar(v: Optional[Type[Any]]) -> bool: + """ + Check if a given type is a `typing.Final` type. + """ + if v is None: + return False + + return v.__class__ == Final.__class__ and (sys.version_info < (3, 8) or getattr(v, '_name', None) == 'Final') + + +def is_classvar(ann_type: Type[Any]) -> bool: + if _check_classvar(ann_type) or _check_classvar(get_origin(ann_type)): + return True + + # this is an ugly workaround for class vars that contain forward references and are therefore themselves + # forward references, see #3679 + if ann_type.__class__ == ForwardRef and ann_type.__forward_arg__.startswith('ClassVar['): + return True + + return False + + +def is_finalvar(ann_type: Type[Any]) -> bool: + return _check_finalvar(ann_type) or _check_finalvar(get_origin(ann_type)) + + +def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None: + """ + Try to update ForwardRefs on fields based on this ModelField, globalns and localns. + """ + prepare = False + if field.type_.__class__ == ForwardRef: + prepare = True + field.type_ = evaluate_forwardref(field.type_, globalns, localns or None) + if field.outer_type_.__class__ == ForwardRef: + prepare = True + field.outer_type_ = evaluate_forwardref(field.outer_type_, globalns, localns or None) + if prepare: + field.prepare() + + if field.sub_fields: + for sub_f in field.sub_fields: + update_field_forward_refs(sub_f, globalns=globalns, localns=localns) + + if field.discriminator_key is not None: + field.prepare_discriminated_union_sub_fields() + + +def update_model_forward_refs( + model: Type[Any], + fields: Iterable['ModelField'], + json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable], + localns: 'DictStrAny', + exc_to_suppress: Tuple[Type[BaseException], ...] = (), +) -> None: + """ + Try to update model fields ForwardRefs based on model and localns. + """ + if model.__module__ in sys.modules: + globalns = sys.modules[model.__module__].__dict__.copy() + else: + globalns = {} + + globalns.setdefault(model.__name__, model) + + for f in fields: + try: + update_field_forward_refs(f, globalns=globalns, localns=localns) + except exc_to_suppress: + pass + + for key in set(json_encoders.keys()): + if isinstance(key, str): + fr: ForwardRef = ForwardRef(key) + elif isinstance(key, ForwardRef): + fr = key + else: + continue + + try: + new_key = evaluate_forwardref(fr, globalns, localns or None) + except exc_to_suppress: # pragma: no cover + continue + + json_encoders[new_key] = json_encoders.pop(key) + + +def get_class(type_: Type[Any]) -> Union[None, bool, Type[Any]]: + """ + Tries to get the class of a Type[T] annotation. Returns True if Type is used + without brackets. Otherwise returns None. + """ + if type_ is type: + return True + + if get_origin(type_) is None: + return None + + args = get_args(type_) + if not args or not isinstance(args[0], type): + return True + else: + return args[0] + + +def get_sub_types(tp: Any) -> List[Any]: + """ + Return all the types that are allowed by type `tp` + `tp` can be a `Union` of allowed types or an `Annotated` type + """ + origin = get_origin(tp) + if origin is Annotated: + return get_sub_types(get_args(tp)[0]) + elif is_union(origin): + return [x for t in get_args(tp) for x in get_sub_types(t)] + else: + return [tp] diff --git a/backend/venv/Lib/site-packages/pydantic/v1/utils.py b/backend/venv/Lib/site-packages/pydantic/v1/utils.py new file mode 100644 index 0000000..02543fd --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/utils.py @@ -0,0 +1,806 @@ +import keyword +import warnings +import weakref +from collections import OrderedDict, defaultdict, deque +from copy import deepcopy +from itertools import islice, zip_longest +from types import BuiltinFunctionType, CodeType, FunctionType, GeneratorType, LambdaType, ModuleType +from typing import ( + TYPE_CHECKING, + AbstractSet, + Any, + Callable, + Collection, + Dict, + Generator, + Iterable, + Iterator, + List, + Mapping, + NoReturn, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from typing_extensions import Annotated + +from pydantic.v1.errors import ConfigError +from pydantic.v1.typing import ( + NoneType, + WithArgsTypes, + all_literal_values, + display_as_type, + get_args, + get_origin, + is_literal_type, + is_union, +) +from pydantic.v1.version import version_info + +if TYPE_CHECKING: + from inspect import Signature + from pathlib import Path + + from pydantic.v1.config import BaseConfig + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.fields import ModelField + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import AbstractSetIntStr, DictIntStrAny, IntStr, MappingIntStrAny, ReprArgs + + RichReprResult = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]] + +__all__ = ( + 'import_string', + 'sequence_like', + 'validate_field_name', + 'lenient_isinstance', + 'lenient_issubclass', + 'in_ipython', + 'is_valid_identifier', + 'deep_update', + 'update_not_none', + 'almost_equal_floats', + 'get_model', + 'to_camel', + 'to_lower_camel', + 'is_valid_field', + 'smart_deepcopy', + 'PyObjectStr', + 'Representation', + 'GetterDict', + 'ValueItems', + 'version_info', # required here to match behaviour in v1.3 + 'ClassAttribute', + 'path_type', + 'ROOT_KEY', + 'get_unique_discriminator_alias', + 'get_discriminator_alias_and_values', + 'DUNDER_ATTRIBUTES', +) + +ROOT_KEY = '__root__' +# these are types that are returned unchanged by deepcopy +IMMUTABLE_NON_COLLECTIONS_TYPES: Set[Type[Any]] = { + int, + float, + complex, + str, + bool, + bytes, + type, + NoneType, + FunctionType, + BuiltinFunctionType, + LambdaType, + weakref.ref, + CodeType, + # note: including ModuleType will differ from behaviour of deepcopy by not producing error. + # It might be not a good idea in general, but considering that this function used only internally + # against default values of fields, this will allow to actually have a field with module as default value + ModuleType, + NotImplemented.__class__, + Ellipsis.__class__, +} + +# these are types that if empty, might be copied with simple copy() instead of deepcopy() +BUILTIN_COLLECTIONS: Set[Type[Any]] = { + list, + set, + tuple, + frozenset, + dict, + OrderedDict, + defaultdict, + deque, +} + + +def import_string(dotted_path: str) -> Any: + """ + Stolen approximately from django. Import a dotted module path and return the attribute/class designated by the + last name in the path. Raise ImportError if the import fails. + """ + from importlib import import_module + + try: + module_path, class_name = dotted_path.strip(' ').rsplit('.', 1) + except ValueError as e: + raise ImportError(f'"{dotted_path}" doesn\'t look like a module path') from e + + module = import_module(module_path) + try: + return getattr(module, class_name) + except AttributeError as e: + raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute') from e + + +def truncate(v: Union[str], *, max_len: int = 80) -> str: + """ + Truncate a value and add a unicode ellipsis (three dots) to the end if it was too long + """ + warnings.warn('`truncate` is no-longer used by pydantic and is deprecated', DeprecationWarning) + if isinstance(v, str) and len(v) > (max_len - 2): + # -3 so quote + string + … + quote has correct length + return (v[: (max_len - 3)] + '…').__repr__() + try: + v = v.__repr__() + except TypeError: + v = v.__class__.__repr__(v) # in case v is a type + if len(v) > max_len: + v = v[: max_len - 1] + '…' + return v + + +def sequence_like(v: Any) -> bool: + return isinstance(v, (list, tuple, set, frozenset, GeneratorType, deque)) + + +def validate_field_name(bases: Iterable[Type[Any]], field_name: str) -> None: + """ + Ensure that the field's name does not shadow an existing attribute of the model. + """ + for base in bases: + if getattr(base, field_name, None): + raise NameError( + f'Field name "{field_name}" shadows a BaseModel attribute; ' + f'use a different field name with "alias=\'{field_name}\'".' + ) + + +def lenient_isinstance(o: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]) -> bool: + try: + return isinstance(o, class_or_tuple) # type: ignore[arg-type] + except TypeError: + return False + + +def lenient_issubclass(cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]) -> bool: + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] + except TypeError: + if isinstance(cls, WithArgsTypes): + return False + raise # pragma: no cover + + +def in_ipython() -> bool: + """ + Check whether we're in an ipython environment, including jupyter notebooks. + """ + try: + eval('__IPYTHON__') + except NameError: + return False + else: # pragma: no cover + return True + + +def is_valid_identifier(identifier: str) -> bool: + """ + Checks that a string is a valid identifier and not a Python keyword. + :param identifier: The identifier to test. + :return: True if the identifier is valid. + """ + return identifier.isidentifier() and not keyword.iskeyword(identifier) + + +KeyType = TypeVar('KeyType') + + +def deep_update(mapping: Dict[KeyType, Any], *updating_mappings: Dict[KeyType, Any]) -> Dict[KeyType, Any]: + updated_mapping = mapping.copy() + for updating_mapping in updating_mappings: + for k, v in updating_mapping.items(): + if k in updated_mapping and isinstance(updated_mapping[k], dict) and isinstance(v, dict): + updated_mapping[k] = deep_update(updated_mapping[k], v) + else: + updated_mapping[k] = v + return updated_mapping + + +def update_not_none(mapping: Dict[Any, Any], **update: Any) -> None: + mapping.update({k: v for k, v in update.items() if v is not None}) + + +def almost_equal_floats(value_1: float, value_2: float, *, delta: float = 1e-8) -> bool: + """ + Return True if two floats are almost equal + """ + return abs(value_1 - value_2) <= delta + + +def generate_model_signature( + init: Callable[..., None], fields: Dict[str, 'ModelField'], config: Type['BaseConfig'] +) -> 'Signature': + """ + Generate signature for model based on its fields + """ + from inspect import Parameter, Signature, signature + + from pydantic.v1.config import Extra + + present_params = signature(init).parameters.values() + merged_params: Dict[str, Parameter] = {} + var_kw = None + use_var_kw = False + + for param in islice(present_params, 1, None): # skip self arg + if param.kind is param.VAR_KEYWORD: + var_kw = param + continue + merged_params[param.name] = param + + if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through + allow_names = config.allow_population_by_field_name + for field_name, field in fields.items(): + param_name = field.alias + if field_name in merged_params or param_name in merged_params: + continue + elif not is_valid_identifier(param_name): + if allow_names and is_valid_identifier(field_name): + param_name = field_name + else: + use_var_kw = True + continue + + # TODO: replace annotation with actual expected types once #1055 solved + kwargs = {'default': field.default} if not field.required else {} + merged_params[param_name] = Parameter( + param_name, Parameter.KEYWORD_ONLY, annotation=field.annotation, **kwargs + ) + + if config.extra is Extra.allow: + use_var_kw = True + + if var_kw and use_var_kw: + # Make sure the parameter for extra kwargs + # does not have the same name as a field + default_model_signature = [ + ('__pydantic_self__', Parameter.POSITIONAL_OR_KEYWORD), + ('data', Parameter.VAR_KEYWORD), + ] + if [(p.name, p.kind) for p in present_params] == default_model_signature: + # if this is the standard model signature, use extra_data as the extra args name + var_kw_name = 'extra_data' + else: + # else start from var_kw + var_kw_name = var_kw.name + + # generate a name that's definitely unique + while var_kw_name in fields: + var_kw_name += '_' + merged_params[var_kw_name] = var_kw.replace(name=var_kw_name) + + return Signature(parameters=list(merged_params.values()), return_annotation=None) + + +def get_model(obj: Union[Type['BaseModel'], Type['Dataclass']]) -> Type['BaseModel']: + from pydantic.v1.main import BaseModel + + try: + model_cls = obj.__pydantic_model__ # type: ignore + except AttributeError: + model_cls = obj + + if not issubclass(model_cls, BaseModel): + raise TypeError('Unsupported type, must be either BaseModel or dataclass') + return model_cls + + +def to_camel(string: str) -> str: + return ''.join(word.capitalize() for word in string.split('_')) + + +def to_lower_camel(string: str) -> str: + if len(string) >= 1: + pascal_string = to_camel(string) + return pascal_string[0].lower() + pascal_string[1:] + return string.lower() + + +T = TypeVar('T') + + +def unique_list( + input_list: Union[List[T], Tuple[T, ...]], + *, + name_factory: Callable[[T], str] = str, +) -> List[T]: + """ + Make a list unique while maintaining order. + We update the list if another one with the same name is set + (e.g. root validator overridden in subclass) + """ + result: List[T] = [] + result_names: List[str] = [] + for v in input_list: + v_name = name_factory(v) + if v_name not in result_names: + result_names.append(v_name) + result.append(v) + else: + result[result_names.index(v_name)] = v + + return result + + +class PyObjectStr(str): + """ + String class where repr doesn't include quotes. Useful with Representation when you want to return a string + representation of something that valid (or pseudo-valid) python. + """ + + def __repr__(self) -> str: + return str(self) + + +class Representation: + """ + Mixin to provide __str__, __repr__, and __pretty__ methods. See #884 for more details. + + __pretty__ is used by [devtools](https://python-devtools.helpmanual.io/) to provide human readable representations + of objects. + """ + + __slots__: Tuple[str, ...] = tuple() + + def __repr_args__(self) -> 'ReprArgs': + """ + Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden. + + Can either return: + * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]` + * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]` + """ + attrs = ((s, getattr(self, s)) for s in self.__slots__) + return [(a, v) for a, v in attrs if v is not None] + + def __repr_name__(self) -> str: + """ + Name of the instance's class, used in __repr__. + """ + return self.__class__.__name__ + + def __repr_str__(self, join_str: str) -> str: + return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) + + def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any, None, None]: + """ + Used by devtools (https://python-devtools.helpmanual.io/) to provide a human readable representations of objects + """ + yield self.__repr_name__() + '(' + yield 1 + for name, value in self.__repr_args__(): + if name is not None: + yield name + '=' + yield fmt(value) + yield ',' + yield 0 + yield -1 + yield ')' + + def __str__(self) -> str: + return self.__repr_str__(' ') + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + def __rich_repr__(self) -> 'RichReprResult': + """Get fields for Rich library""" + for name, field_repr in self.__repr_args__(): + if name is None: + yield field_repr + else: + yield name, field_repr + + +class GetterDict(Representation): + """ + Hack to make object's smell just enough like dicts for validate_model. + + We can't inherit from Mapping[str, Any] because it upsets cython so we have to implement all methods ourselves. + """ + + __slots__ = ('_obj',) + + def __init__(self, obj: Any): + self._obj = obj + + def __getitem__(self, key: str) -> Any: + try: + return getattr(self._obj, key) + except AttributeError as e: + raise KeyError(key) from e + + def get(self, key: Any, default: Any = None) -> Any: + return getattr(self._obj, key, default) + + def extra_keys(self) -> Set[Any]: + """ + We don't want to get any other attributes of obj if the model didn't explicitly ask for them + """ + return set() + + def keys(self) -> List[Any]: + """ + Keys of the pseudo dictionary, uses a list not set so order information can be maintained like python + dictionaries. + """ + return list(self) + + def values(self) -> List[Any]: + return [self[k] for k in self] + + def items(self) -> Iterator[Tuple[str, Any]]: + for k in self: + yield k, self.get(k) + + def __iter__(self) -> Iterator[str]: + for name in dir(self._obj): + if not name.startswith('_'): + yield name + + def __len__(self) -> int: + return sum(1 for _ in self) + + def __contains__(self, item: Any) -> bool: + return item in self.keys() + + def __eq__(self, other: Any) -> bool: + return dict(self) == dict(other.items()) + + def __repr_args__(self) -> 'ReprArgs': + return [(None, dict(self))] + + def __repr_name__(self) -> str: + return f'GetterDict[{display_as_type(self._obj)}]' + + +class ValueItems(Representation): + """ + Class for more convenient calculation of excluded or included fields on values. + """ + + __slots__ = ('_items', '_type') + + def __init__(self, value: Any, items: Union['AbstractSetIntStr', 'MappingIntStrAny']) -> None: + items = self._coerce_items(items) + + if isinstance(value, (list, tuple)): + items = self._normalize_indexes(items, len(value)) + + self._items: 'MappingIntStrAny' = items + + def is_excluded(self, item: Any) -> bool: + """ + Check if item is fully excluded. + + :param item: key or index of a value + """ + return self.is_true(self._items.get(item)) + + def is_included(self, item: Any) -> bool: + """ + Check if value is contained in self._items + + :param item: key or index of value + """ + return item in self._items + + def for_element(self, e: 'IntStr') -> Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']]: + """ + :param e: key or index of element on value + :return: raw values for element if self._items is dict and contain needed element + """ + + item = self._items.get(e) + return item if not self.is_true(item) else None + + def _normalize_indexes(self, items: 'MappingIntStrAny', v_length: int) -> 'DictIntStrAny': + """ + :param items: dict or set of indexes which will be normalized + :param v_length: length of sequence indexes of which will be + + >>> self._normalize_indexes({0: True, -2: True, -1: True}, 4) + {0: True, 2: True, 3: True} + >>> self._normalize_indexes({'__all__': True}, 4) + {0: True, 1: True, 2: True, 3: True} + """ + + normalized_items: 'DictIntStrAny' = {} + all_items = None + for i, v in items.items(): + if not (isinstance(v, Mapping) or isinstance(v, AbstractSet) or self.is_true(v)): + raise TypeError(f'Unexpected type of exclude value for index "{i}" {v.__class__}') + if i == '__all__': + all_items = self._coerce_value(v) + continue + if not isinstance(i, int): + raise TypeError( + 'Excluding fields from a sequence of sub-models or dicts must be performed index-wise: ' + 'expected integer keys or keyword "__all__"' + ) + normalized_i = v_length + i if i < 0 else i + normalized_items[normalized_i] = self.merge(v, normalized_items.get(normalized_i)) + + if not all_items: + return normalized_items + if self.is_true(all_items): + for i in range(v_length): + normalized_items.setdefault(i, ...) + return normalized_items + for i in range(v_length): + normalized_item = normalized_items.setdefault(i, {}) + if not self.is_true(normalized_item): + normalized_items[i] = self.merge(all_items, normalized_item) + return normalized_items + + @classmethod + def merge(cls, base: Any, override: Any, intersect: bool = False) -> Any: + """ + Merge a ``base`` item with an ``override`` item. + + Both ``base`` and ``override`` are converted to dictionaries if possible. + Sets are converted to dictionaries with the sets entries as keys and + Ellipsis as values. + + Each key-value pair existing in ``base`` is merged with ``override``, + while the rest of the key-value pairs are updated recursively with this function. + + Merging takes place based on the "union" of keys if ``intersect`` is + set to ``False`` (default) and on the intersection of keys if + ``intersect`` is set to ``True``. + """ + override = cls._coerce_value(override) + base = cls._coerce_value(base) + if override is None: + return base + if cls.is_true(base) or base is None: + return override + if cls.is_true(override): + return base if intersect else override + + # intersection or union of keys while preserving ordering: + if intersect: + merge_keys = [k for k in base if k in override] + [k for k in override if k in base] + else: + merge_keys = list(base) + [k for k in override if k not in base] + + merged: 'DictIntStrAny' = {} + for k in merge_keys: + merged_item = cls.merge(base.get(k), override.get(k), intersect=intersect) + if merged_item is not None: + merged[k] = merged_item + + return merged + + @staticmethod + def _coerce_items(items: Union['AbstractSetIntStr', 'MappingIntStrAny']) -> 'MappingIntStrAny': + if isinstance(items, Mapping): + pass + elif isinstance(items, AbstractSet): + items = dict.fromkeys(items, ...) + else: + class_name = getattr(items, '__class__', '???') + assert_never( + items, + f'Unexpected type of exclude value {class_name}', + ) + return items + + @classmethod + def _coerce_value(cls, value: Any) -> Any: + if value is None or cls.is_true(value): + return value + return cls._coerce_items(value) + + @staticmethod + def is_true(v: Any) -> bool: + return v is True or v is ... + + def __repr_args__(self) -> 'ReprArgs': + return [(None, self._items)] + + +class ClassAttribute: + """ + Hide class attribute from its instances + """ + + __slots__ = ( + 'name', + 'value', + ) + + def __init__(self, name: str, value: Any) -> None: + self.name = name + self.value = value + + def __get__(self, instance: Any, owner: Type[Any]) -> None: + if instance is None: + return self.value + raise AttributeError(f'{self.name!r} attribute of {owner.__name__!r} is class-only') + + +path_types = { + 'is_dir': 'directory', + 'is_file': 'file', + 'is_mount': 'mount point', + 'is_symlink': 'symlink', + 'is_block_device': 'block device', + 'is_char_device': 'char device', + 'is_fifo': 'FIFO', + 'is_socket': 'socket', +} + + +def path_type(p: 'Path') -> str: + """ + Find out what sort of thing a path is. + """ + assert p.exists(), 'path does not exist' + for method, name in path_types.items(): + if getattr(p, method)(): + return name + + return 'unknown' + + +Obj = TypeVar('Obj') + + +def smart_deepcopy(obj: Obj) -> Obj: + """ + Return type as is for immutable built-in types + Use obj.copy() for built-in empty collections + Use copy.deepcopy() for non-empty collections and unknown objects + """ + + obj_type = obj.__class__ + if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES: + return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway + try: + if not obj and obj_type in BUILTIN_COLLECTIONS: + # faster way for empty collections, no need to copy its members + return obj if obj_type is tuple else obj.copy() # type: ignore # tuple doesn't have copy method + except (TypeError, ValueError, RuntimeError): + # do we really dare to catch ALL errors? Seems a bit risky + pass + + return deepcopy(obj) # slowest way when we actually might need a deepcopy + + +def is_valid_field(name: str) -> bool: + if not name.startswith('_'): + return True + return ROOT_KEY == name + + +DUNDER_ATTRIBUTES = { + '__annotations__', + '__classcell__', + '__doc__', + '__module__', + '__orig_bases__', + '__orig_class__', + '__qualname__', + '__firstlineno__', + '__static_attributes__', +} + + +def is_valid_private_name(name: str) -> bool: + return not is_valid_field(name) and name not in DUNDER_ATTRIBUTES + + +_EMPTY = object() + + +def all_identical(left: Iterable[Any], right: Iterable[Any]) -> bool: + """ + Check that the items of `left` are the same objects as those in `right`. + + >>> a, b = object(), object() + >>> all_identical([a, b, a], [a, b, a]) + True + >>> all_identical([a, b, [a]], [a, b, [a]]) # new list object, while "equal" is not "identical" + False + """ + for left_item, right_item in zip_longest(left, right, fillvalue=_EMPTY): + if left_item is not right_item: + return False + return True + + +def assert_never(obj: NoReturn, msg: str) -> NoReturn: + """ + Helper to make sure that we have covered all possible types. + + This is mostly useful for ``mypy``, docs: + https://mypy.readthedocs.io/en/latest/literal_types.html#exhaustive-checks + """ + raise TypeError(msg) + + +def get_unique_discriminator_alias(all_aliases: Collection[str], discriminator_key: str) -> str: + """Validate that all aliases are the same and if that's the case return the alias""" + unique_aliases = set(all_aliases) + if len(unique_aliases) > 1: + raise ConfigError( + f'Aliases for discriminator {discriminator_key!r} must be the same (got {", ".join(sorted(all_aliases))})' + ) + return unique_aliases.pop() + + +def get_discriminator_alias_and_values(tp: Any, discriminator_key: str) -> Tuple[str, Tuple[str, ...]]: + """ + Get alias and all valid values in the `Literal` type of the discriminator field + `tp` can be a `BaseModel` class or directly an `Annotated` `Union` of many. + """ + is_root_model = getattr(tp, '__custom_root_type__', False) + + if get_origin(tp) is Annotated: + tp = get_args(tp)[0] + + if hasattr(tp, '__pydantic_model__'): + tp = tp.__pydantic_model__ + + if is_union(get_origin(tp)): + alias, all_values = _get_union_alias_and_all_values(tp, discriminator_key) + return alias, tuple(v for values in all_values for v in values) + elif is_root_model: + union_type = tp.__fields__[ROOT_KEY].type_ + alias, all_values = _get_union_alias_and_all_values(union_type, discriminator_key) + + if len(set(all_values)) > 1: + raise ConfigError( + f'Field {discriminator_key!r} is not the same for all submodels of {display_as_type(tp)!r}' + ) + + return alias, all_values[0] + + else: + try: + t_discriminator_type = tp.__fields__[discriminator_key].type_ + except AttributeError as e: + raise TypeError(f'Type {tp.__name__!r} is not a valid `BaseModel` or `dataclass`') from e + except KeyError as e: + raise ConfigError(f'Model {tp.__name__!r} needs a discriminator field for key {discriminator_key!r}') from e + + if not is_literal_type(t_discriminator_type): + raise ConfigError(f'Field {discriminator_key!r} of model {tp.__name__!r} needs to be a `Literal`') + + return tp.__fields__[discriminator_key].alias, all_literal_values(t_discriminator_type) + + +def _get_union_alias_and_all_values( + union_type: Type[Any], discriminator_key: str +) -> Tuple[str, Tuple[Tuple[str, ...], ...]]: + zipped_aliases_values = [get_discriminator_alias_and_values(t, discriminator_key) for t in get_args(union_type)] + # unzip: [('alias_a',('v1', 'v2)), ('alias_b', ('v3',))] => [('alias_a', 'alias_b'), (('v1', 'v2'), ('v3',))] + all_aliases, all_values = zip(*zipped_aliases_values) + return get_unique_discriminator_alias(all_aliases, discriminator_key), all_values diff --git a/backend/venv/Lib/site-packages/pydantic/v1/validators.py b/backend/venv/Lib/site-packages/pydantic/v1/validators.py new file mode 100644 index 0000000..c0940e8 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/validators.py @@ -0,0 +1,768 @@ +import math +import re +from collections import OrderedDict, deque +from collections.abc import Hashable as CollectionsHashable +from datetime import date, datetime, time, timedelta +from decimal import Decimal, DecimalException +from enum import Enum, IntEnum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Deque, + Dict, + ForwardRef, + FrozenSet, + Generator, + Hashable, + List, + NamedTuple, + Pattern, + Set, + Tuple, + Type, + TypeVar, + Union, +) +from uuid import UUID +from warnings import warn + +from pydantic.v1 import errors +from pydantic.v1.datetime_parse import parse_date, parse_datetime, parse_duration, parse_time +from pydantic.v1.typing import ( + AnyCallable, + all_literal_values, + display_as_type, + get_class, + is_callable_type, + is_literal_type, + is_namedtuple, + is_none_type, + is_typeddict, +) +from pydantic.v1.utils import almost_equal_floats, lenient_issubclass, sequence_like + +if TYPE_CHECKING: + from typing_extensions import Literal, TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.types import ConstrainedDecimal, ConstrainedFloat, ConstrainedInt + + ConstrainedNumber = Union[ConstrainedDecimal, ConstrainedFloat, ConstrainedInt] + AnyOrderedDict = OrderedDict[Any, Any] + Number = Union[int, float, Decimal] + StrBytes = Union[str, bytes] + + +def str_validator(v: Any) -> Union[str]: + if isinstance(v, str): + if isinstance(v, Enum): + return v.value + else: + return v + elif isinstance(v, (float, int, Decimal)): + # is there anything else we want to add here? If you think so, create an issue. + return str(v) + elif isinstance(v, (bytes, bytearray)): + return v.decode() + else: + raise errors.StrError() + + +def strict_str_validator(v: Any) -> Union[str]: + if isinstance(v, str) and not isinstance(v, Enum): + return v + raise errors.StrError() + + +def bytes_validator(v: Any) -> Union[bytes]: + if isinstance(v, bytes): + return v + elif isinstance(v, bytearray): + return bytes(v) + elif isinstance(v, str): + return v.encode() + elif isinstance(v, (float, int, Decimal)): + return str(v).encode() + else: + raise errors.BytesError() + + +def strict_bytes_validator(v: Any) -> Union[bytes]: + if isinstance(v, bytes): + return v + elif isinstance(v, bytearray): + return bytes(v) + else: + raise errors.BytesError() + + +BOOL_FALSE = {0, '0', 'off', 'f', 'false', 'n', 'no'} +BOOL_TRUE = {1, '1', 'on', 't', 'true', 'y', 'yes'} + + +def bool_validator(v: Any) -> bool: + if v is True or v is False: + return v + if isinstance(v, bytes): + v = v.decode() + if isinstance(v, str): + v = v.lower() + try: + if v in BOOL_TRUE: + return True + if v in BOOL_FALSE: + return False + except TypeError: + raise errors.BoolError() + raise errors.BoolError() + + +# matches the default limit cpython, see https://github.com/python/cpython/pull/96500 +max_str_int = 4_300 + + +def int_validator(v: Any) -> int: + if isinstance(v, int) and not (v is True or v is False): + return v + + # see https://github.com/pydantic/pydantic/issues/1477 and in turn, https://github.com/python/cpython/issues/95778 + # this check should be unnecessary once patch releases are out for 3.7, 3.8, 3.9 and 3.10 + # but better to check here until then. + # NOTICE: this does not fully protect user from the DOS risk since the standard library JSON implementation + # (and other std lib modules like xml) use `int()` and are likely called before this, the best workaround is to + # 1. update to the latest patch release of python once released, 2. use a different JSON library like ujson + if isinstance(v, (str, bytes, bytearray)) and len(v) > max_str_int: + raise errors.IntegerError() + + try: + return int(v) + except (TypeError, ValueError, OverflowError): + raise errors.IntegerError() + + +def strict_int_validator(v: Any) -> int: + if isinstance(v, int) and not (v is True or v is False): + return v + raise errors.IntegerError() + + +def float_validator(v: Any) -> float: + if isinstance(v, float): + return v + + try: + return float(v) + except (TypeError, ValueError): + raise errors.FloatError() + + +def strict_float_validator(v: Any) -> float: + if isinstance(v, float): + return v + raise errors.FloatError() + + +def float_finite_validator(v: 'Number', field: 'ModelField', config: 'BaseConfig') -> 'Number': + allow_inf_nan = getattr(field.type_, 'allow_inf_nan', None) + if allow_inf_nan is None: + allow_inf_nan = config.allow_inf_nan + + if allow_inf_nan is False and (math.isnan(v) or math.isinf(v)): + raise errors.NumberNotFiniteError() + return v + + +def number_multiple_validator(v: 'Number', field: 'ModelField') -> 'Number': + field_type: ConstrainedNumber = field.type_ + if field_type.multiple_of is not None: + mod = float(v) / float(field_type.multiple_of) % 1 + if not almost_equal_floats(mod, 0.0) and not almost_equal_floats(mod, 1.0): + raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) + return v + + +def number_size_validator(v: 'Number', field: 'ModelField') -> 'Number': + field_type: ConstrainedNumber = field.type_ + if field_type.gt is not None and not v > field_type.gt: + raise errors.NumberNotGtError(limit_value=field_type.gt) + elif field_type.ge is not None and not v >= field_type.ge: + raise errors.NumberNotGeError(limit_value=field_type.ge) + + if field_type.lt is not None and not v < field_type.lt: + raise errors.NumberNotLtError(limit_value=field_type.lt) + if field_type.le is not None and not v <= field_type.le: + raise errors.NumberNotLeError(limit_value=field_type.le) + + return v + + +def constant_validator(v: 'Any', field: 'ModelField') -> 'Any': + """Validate ``const`` fields. + + The value provided for a ``const`` field must be equal to the default value + of the field. This is to support the keyword of the same name in JSON + Schema. + """ + if v != field.default: + raise errors.WrongConstantError(given=v, permitted=[field.default]) + + return v + + +def anystr_length_validator(v: 'StrBytes', config: 'BaseConfig') -> 'StrBytes': + v_len = len(v) + + min_length = config.min_anystr_length + if v_len < min_length: + raise errors.AnyStrMinLengthError(limit_value=min_length) + + max_length = config.max_anystr_length + if max_length is not None and v_len > max_length: + raise errors.AnyStrMaxLengthError(limit_value=max_length) + + return v + + +def anystr_strip_whitespace(v: 'StrBytes') -> 'StrBytes': + return v.strip() + + +def anystr_upper(v: 'StrBytes') -> 'StrBytes': + return v.upper() + + +def anystr_lower(v: 'StrBytes') -> 'StrBytes': + return v.lower() + + +def ordered_dict_validator(v: Any) -> 'AnyOrderedDict': + if isinstance(v, OrderedDict): + return v + + try: + return OrderedDict(v) + except (TypeError, ValueError): + raise errors.DictError() + + +def dict_validator(v: Any) -> Dict[Any, Any]: + if isinstance(v, dict): + return v + + try: + return dict(v) + except (TypeError, ValueError): + raise errors.DictError() + + +def list_validator(v: Any) -> List[Any]: + if isinstance(v, list): + return v + elif sequence_like(v): + return list(v) + else: + raise errors.ListError() + + +def tuple_validator(v: Any) -> Tuple[Any, ...]: + if isinstance(v, tuple): + return v + elif sequence_like(v): + return tuple(v) + else: + raise errors.TupleError() + + +def set_validator(v: Any) -> Set[Any]: + if isinstance(v, set): + return v + elif sequence_like(v): + return set(v) + else: + raise errors.SetError() + + +def frozenset_validator(v: Any) -> FrozenSet[Any]: + if isinstance(v, frozenset): + return v + elif sequence_like(v): + return frozenset(v) + else: + raise errors.FrozenSetError() + + +def deque_validator(v: Any) -> Deque[Any]: + if isinstance(v, deque): + return v + elif sequence_like(v): + return deque(v) + else: + raise errors.DequeError() + + +def enum_member_validator(v: Any, field: 'ModelField', config: 'BaseConfig') -> Enum: + try: + enum_v = field.type_(v) + except ValueError: + # field.type_ should be an enum, so will be iterable + raise errors.EnumMemberError(enum_values=list(field.type_)) + return enum_v.value if config.use_enum_values else enum_v + + +def uuid_validator(v: Any, field: 'ModelField') -> UUID: + try: + if isinstance(v, str): + v = UUID(v) + elif isinstance(v, (bytes, bytearray)): + try: + v = UUID(v.decode()) + except ValueError: + # 16 bytes in big-endian order as the bytes argument fail + # the above check + v = UUID(bytes=v) + except ValueError: + raise errors.UUIDError() + + if not isinstance(v, UUID): + raise errors.UUIDError() + + required_version = getattr(field.type_, '_required_version', None) + if required_version and v.version != required_version: + raise errors.UUIDVersionError(required_version=required_version) + + return v + + +def decimal_validator(v: Any) -> Decimal: + if isinstance(v, Decimal): + return v + elif isinstance(v, (bytes, bytearray)): + v = v.decode() + + v = str(v).strip() + + try: + v = Decimal(v) + except DecimalException: + raise errors.DecimalError() + + if not v.is_finite(): + raise errors.DecimalIsNotFiniteError() + + return v + + +def hashable_validator(v: Any) -> Hashable: + if isinstance(v, Hashable): + return v + + raise errors.HashableError() + + +def ip_v4_address_validator(v: Any) -> IPv4Address: + if isinstance(v, IPv4Address): + return v + + try: + return IPv4Address(v) + except ValueError: + raise errors.IPv4AddressError() + + +def ip_v6_address_validator(v: Any) -> IPv6Address: + if isinstance(v, IPv6Address): + return v + + try: + return IPv6Address(v) + except ValueError: + raise errors.IPv6AddressError() + + +def ip_v4_network_validator(v: Any) -> IPv4Network: + """ + Assume IPv4Network initialised with a default ``strict`` argument + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network + """ + if isinstance(v, IPv4Network): + return v + + try: + return IPv4Network(v) + except ValueError: + raise errors.IPv4NetworkError() + + +def ip_v6_network_validator(v: Any) -> IPv6Network: + """ + Assume IPv6Network initialised with a default ``strict`` argument + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network + """ + if isinstance(v, IPv6Network): + return v + + try: + return IPv6Network(v) + except ValueError: + raise errors.IPv6NetworkError() + + +def ip_v4_interface_validator(v: Any) -> IPv4Interface: + if isinstance(v, IPv4Interface): + return v + + try: + return IPv4Interface(v) + except ValueError: + raise errors.IPv4InterfaceError() + + +def ip_v6_interface_validator(v: Any) -> IPv6Interface: + if isinstance(v, IPv6Interface): + return v + + try: + return IPv6Interface(v) + except ValueError: + raise errors.IPv6InterfaceError() + + +def path_validator(v: Any) -> Path: + if isinstance(v, Path): + return v + + try: + return Path(v) + except TypeError: + raise errors.PathError() + + +def path_exists_validator(v: Any) -> Path: + if not v.exists(): + raise errors.PathNotExistsError(path=v) + + return v + + +def callable_validator(v: Any) -> AnyCallable: + """ + Perform a simple check if the value is callable. + + Note: complete matching of argument type hints and return types is not performed + """ + if callable(v): + return v + + raise errors.CallableError(value=v) + + +def enum_validator(v: Any) -> Enum: + if isinstance(v, Enum): + return v + + raise errors.EnumError(value=v) + + +def int_enum_validator(v: Any) -> IntEnum: + if isinstance(v, IntEnum): + return v + + raise errors.IntEnumError(value=v) + + +def make_literal_validator(type_: Any) -> Callable[[Any], Any]: + permitted_choices = all_literal_values(type_) + + # To have a O(1) complexity and still return one of the values set inside the `Literal`, + # we create a dict with the set values (a set causes some problems with the way intersection works). + # In some cases the set value and checked value can indeed be different (see `test_literal_validator_str_enum`) + allowed_choices = {v: v for v in permitted_choices} + + def literal_validator(v: Any) -> Any: + try: + return allowed_choices[v] + except (KeyError, TypeError): + raise errors.WrongConstantError(given=v, permitted=permitted_choices) + + return literal_validator + + +def constr_length_validator(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + v_len = len(v) + + min_length = field.type_.min_length if field.type_.min_length is not None else config.min_anystr_length + if v_len < min_length: + raise errors.AnyStrMinLengthError(limit_value=min_length) + + max_length = field.type_.max_length if field.type_.max_length is not None else config.max_anystr_length + if max_length is not None and v_len > max_length: + raise errors.AnyStrMaxLengthError(limit_value=max_length) + + return v + + +def constr_strip_whitespace(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + strip_whitespace = field.type_.strip_whitespace or config.anystr_strip_whitespace + if strip_whitespace: + v = v.strip() + + return v + + +def constr_upper(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + upper = field.type_.to_upper or config.anystr_upper + if upper: + v = v.upper() + + return v + + +def constr_lower(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + lower = field.type_.to_lower or config.anystr_lower + if lower: + v = v.lower() + return v + + +def validate_json(v: Any, config: 'BaseConfig') -> Any: + if v is None: + # pass None through to other validators + return v + try: + return config.json_loads(v) # type: ignore + except ValueError: + raise errors.JsonError() + except TypeError: + raise errors.JsonTypeError() + + +T = TypeVar('T') + + +def make_arbitrary_type_validator(type_: Type[T]) -> Callable[[T], T]: + def arbitrary_type_validator(v: Any) -> T: + if isinstance(v, type_): + return v + raise errors.ArbitraryTypeError(expected_arbitrary_type=type_) + + return arbitrary_type_validator + + +def make_class_validator(type_: Type[T]) -> Callable[[Any], Type[T]]: + def class_validator(v: Any) -> Type[T]: + if lenient_issubclass(v, type_): + return v + raise errors.SubclassError(expected_class=type_) + + return class_validator + + +def any_class_validator(v: Any) -> Type[T]: + if isinstance(v, type): + return v + raise errors.ClassError() + + +def none_validator(v: Any) -> 'Literal[None]': + if v is None: + return v + raise errors.NotNoneError() + + +def pattern_validator(v: Any) -> Pattern[str]: + if isinstance(v, Pattern): + return v + + str_value = str_validator(v) + + try: + return re.compile(str_value) + except re.error: + raise errors.PatternError() + + +NamedTupleT = TypeVar('NamedTupleT', bound=NamedTuple) + + +def make_namedtuple_validator( + namedtuple_cls: Type[NamedTupleT], config: Type['BaseConfig'] +) -> Callable[[Tuple[Any, ...]], NamedTupleT]: + from pydantic.v1.annotated_types import create_model_from_namedtuple + + NamedTupleModel = create_model_from_namedtuple( + namedtuple_cls, + __config__=config, + __module__=namedtuple_cls.__module__, + ) + namedtuple_cls.__pydantic_model__ = NamedTupleModel # type: ignore[attr-defined] + + def namedtuple_validator(values: Tuple[Any, ...]) -> NamedTupleT: + annotations = NamedTupleModel.__annotations__ + + if len(values) > len(annotations): + raise errors.ListMaxLengthError(limit_value=len(annotations)) + + dict_values: Dict[str, Any] = dict(zip(annotations, values)) + validated_dict_values: Dict[str, Any] = dict(NamedTupleModel(**dict_values)) + return namedtuple_cls(**validated_dict_values) + + return namedtuple_validator + + +def make_typeddict_validator( + typeddict_cls: Type['TypedDict'], config: Type['BaseConfig'] # type: ignore[valid-type] +) -> Callable[[Any], Dict[str, Any]]: + from pydantic.v1.annotated_types import create_model_from_typeddict + + TypedDictModel = create_model_from_typeddict( + typeddict_cls, + __config__=config, + __module__=typeddict_cls.__module__, + ) + typeddict_cls.__pydantic_model__ = TypedDictModel # type: ignore[attr-defined] + + def typeddict_validator(values: 'TypedDict') -> Dict[str, Any]: # type: ignore[valid-type] + return TypedDictModel.parse_obj(values).dict(exclude_unset=True) + + return typeddict_validator + + +class IfConfig: + def __init__(self, validator: AnyCallable, *config_attr_names: str, ignored_value: Any = False) -> None: + self.validator = validator + self.config_attr_names = config_attr_names + self.ignored_value = ignored_value + + def check(self, config: Type['BaseConfig']) -> bool: + return any(getattr(config, name) not in {None, self.ignored_value} for name in self.config_attr_names) + + +# order is important here, for example: bool is a subclass of int so has to come first, datetime before date same, +# IPv4Interface before IPv4Address, etc +_VALIDATORS: List[Tuple[Type[Any], List[Any]]] = [ + (IntEnum, [int_validator, enum_member_validator]), + (Enum, [enum_member_validator]), + ( + str, + [ + str_validator, + IfConfig(anystr_strip_whitespace, 'anystr_strip_whitespace'), + IfConfig(anystr_upper, 'anystr_upper'), + IfConfig(anystr_lower, 'anystr_lower'), + IfConfig(anystr_length_validator, 'min_anystr_length', 'max_anystr_length'), + ], + ), + ( + bytes, + [ + bytes_validator, + IfConfig(anystr_strip_whitespace, 'anystr_strip_whitespace'), + IfConfig(anystr_upper, 'anystr_upper'), + IfConfig(anystr_lower, 'anystr_lower'), + IfConfig(anystr_length_validator, 'min_anystr_length', 'max_anystr_length'), + ], + ), + (bool, [bool_validator]), + (int, [int_validator]), + (float, [float_validator, IfConfig(float_finite_validator, 'allow_inf_nan', ignored_value=True)]), + (Path, [path_validator]), + (datetime, [parse_datetime]), + (date, [parse_date]), + (time, [parse_time]), + (timedelta, [parse_duration]), + (OrderedDict, [ordered_dict_validator]), + (dict, [dict_validator]), + (list, [list_validator]), + (tuple, [tuple_validator]), + (set, [set_validator]), + (frozenset, [frozenset_validator]), + (deque, [deque_validator]), + (UUID, [uuid_validator]), + (Decimal, [decimal_validator]), + (IPv4Interface, [ip_v4_interface_validator]), + (IPv6Interface, [ip_v6_interface_validator]), + (IPv4Address, [ip_v4_address_validator]), + (IPv6Address, [ip_v6_address_validator]), + (IPv4Network, [ip_v4_network_validator]), + (IPv6Network, [ip_v6_network_validator]), +] + + +def find_validators( # noqa: C901 (ignore complexity) + type_: Type[Any], config: Type['BaseConfig'] +) -> Generator[AnyCallable, None, None]: + from pydantic.v1.dataclasses import is_builtin_dataclass, make_dataclass_validator + + if type_ is Any or type_ is object: + return + type_type = type_.__class__ + if type_type == ForwardRef or type_type == TypeVar: + return + + if is_none_type(type_): + yield none_validator + return + if type_ is Pattern or type_ is re.Pattern: + yield pattern_validator + return + if type_ is Hashable or type_ is CollectionsHashable: + yield hashable_validator + return + if is_callable_type(type_): + yield callable_validator + return + if is_literal_type(type_): + yield make_literal_validator(type_) + return + if is_builtin_dataclass(type_): + yield from make_dataclass_validator(type_, config) + return + if type_ is Enum: + yield enum_validator + return + if type_ is IntEnum: + yield int_enum_validator + return + if is_namedtuple(type_): + yield tuple_validator + yield make_namedtuple_validator(type_, config) + return + if is_typeddict(type_): + yield make_typeddict_validator(type_, config) + return + + class_ = get_class(type_) + if class_ is not None: + if class_ is not Any and isinstance(class_, type): + yield make_class_validator(class_) + else: + yield any_class_validator + return + + for val_type, validators in _VALIDATORS: + try: + if issubclass(type_, val_type): + for v in validators: + if isinstance(v, IfConfig): + if v.check(config): + yield v.validator + else: + yield v + return + except TypeError: + raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') + + if config.arbitrary_types_allowed: + yield make_arbitrary_type_validator(type_) + else: + if hasattr(type_, '__pydantic_core_schema__'): + warn(f'Mixing V1 and V2 models is not supported. `{type_.__name__}` is a V2 model.', UserWarning) + raise RuntimeError(f'no validator found for {type_}, see `arbitrary_types_allowed` in Config') diff --git a/backend/venv/Lib/site-packages/pydantic/v1/version.py b/backend/venv/Lib/site-packages/pydantic/v1/version.py new file mode 100644 index 0000000..c77cde1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/v1/version.py @@ -0,0 +1,38 @@ +__all__ = 'compiled', 'VERSION', 'version_info' + +VERSION = '1.10.21' + +try: + import cython # type: ignore +except ImportError: + compiled: bool = False +else: # pragma: no cover + try: + compiled = cython.compiled + except AttributeError: + compiled = False + + +def version_info() -> str: + import platform + import sys + from importlib import import_module + from pathlib import Path + + optional_deps = [] + for p in ('devtools', 'dotenv', 'email-validator', 'typing-extensions'): + try: + import_module(p.replace('-', '_')) + except ImportError: + continue + optional_deps.append(p) + + info = { + 'pydantic version': VERSION, + 'pydantic compiled': compiled, + 'install path': Path(__file__).resolve().parent, + 'python version': sys.version, + 'platform': platform.platform(), + 'optional deps. installed': optional_deps, + } + return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items()) diff --git a/backend/venv/Lib/site-packages/pydantic/validate_call_decorator.py b/backend/venv/Lib/site-packages/pydantic/validate_call_decorator.py new file mode 100644 index 0000000..fe4d9c9 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/validate_call_decorator.py @@ -0,0 +1,116 @@ +"""Decorator for validating function calls.""" + +from __future__ import annotations as _annotations + +import inspect +from functools import partial +from types import BuiltinFunctionType +from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast, overload + +from ._internal import _generate_schema, _typing_extra, _validate_call +from .errors import PydanticUserError + +__all__ = ('validate_call',) + +if TYPE_CHECKING: + from .config import ConfigDict + + AnyCallableT = TypeVar('AnyCallableT', bound=Callable[..., Any]) + + +_INVALID_TYPE_ERROR_CODE = 'validate-call-type' + + +def _check_function_type(function: object) -> None: + """Check if the input function is a supported type for `validate_call`.""" + if isinstance(function, _generate_schema.VALIDATE_CALL_SUPPORTED_TYPES): + try: + inspect.signature(cast(_generate_schema.ValidateCallSupportedTypes, function)) + except ValueError: + raise PydanticUserError( + f"Input function `{function}` doesn't have a valid signature", code=_INVALID_TYPE_ERROR_CODE + ) + + if isinstance(function, partial): + try: + assert not isinstance(partial.func, partial), 'Partial of partial' + _check_function_type(function.func) + except PydanticUserError as e: + raise PydanticUserError( + f'Partial of `{function.func}` is invalid because the type of `{function.func}` is not supported by `validate_call`', + code=_INVALID_TYPE_ERROR_CODE, + ) from e + + return + + if isinstance(function, BuiltinFunctionType): + raise PydanticUserError(f'Input built-in function `{function}` is not supported', code=_INVALID_TYPE_ERROR_CODE) + if isinstance(function, (classmethod, staticmethod, property)): + name = type(function).__name__ + raise PydanticUserError( + f'The `@{name}` decorator should be applied after `@validate_call` (put `@{name}` on top)', + code=_INVALID_TYPE_ERROR_CODE, + ) + + if inspect.isclass(function): + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to functions, not classes (put `@validate_call` on top of `__init__` or `__new__` instead)', + code=_INVALID_TYPE_ERROR_CODE, + ) + if callable(function): + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to functions, not instances or other callables. Use `validate_call` explicitly on `__call__` instead.', + code=_INVALID_TYPE_ERROR_CODE, + ) + + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to one of the following: function, method, partial, or lambda', + code=_INVALID_TYPE_ERROR_CODE, + ) + + +@overload +def validate_call( + *, config: ConfigDict | None = None, validate_return: bool = False +) -> Callable[[AnyCallableT], AnyCallableT]: ... + + +@overload +def validate_call(func: AnyCallableT, /) -> AnyCallableT: ... + + +def validate_call( + func: AnyCallableT | None = None, + /, + *, + config: ConfigDict | None = None, + validate_return: bool = False, +) -> AnyCallableT | Callable[[AnyCallableT], AnyCallableT]: + """!!! abstract "Usage Documentation" + [Validation Decorator](../concepts/validation_decorator.md) + + Returns a decorated wrapper around the function that validates the arguments and, optionally, the return value. + + Usage may be either as a plain decorator `@validate_call` or with arguments `@validate_call(...)`. + + Args: + func: The function to be decorated. + config: The configuration dictionary. + validate_return: Whether to validate the return value. + + Returns: + The decorated function. + """ + parent_namespace = _typing_extra.parent_frame_namespace() + + def validate(function: AnyCallableT) -> AnyCallableT: + _check_function_type(function) + validate_call_wrapper = _validate_call.ValidateCallWrapper( + cast(_generate_schema.ValidateCallSupportedTypes, function), config, validate_return, parent_namespace + ) + return _validate_call.update_wrapper_attributes(function, validate_call_wrapper.__call__) # type: ignore + + if func is not None: + return validate(func) + else: + return validate diff --git a/backend/venv/Lib/site-packages/pydantic/validators.py b/backend/venv/Lib/site-packages/pydantic/validators.py new file mode 100644 index 0000000..7921b04 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/validators.py @@ -0,0 +1,5 @@ +"""The `validators` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/backend/venv/Lib/site-packages/pydantic/version.py b/backend/venv/Lib/site-packages/pydantic/version.py new file mode 100644 index 0000000..eaf2619 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/version.py @@ -0,0 +1,113 @@ +"""The `version` module holds the version information for Pydantic.""" + +from __future__ import annotations as _annotations + +import sys + +from pydantic_core import __version__ as __pydantic_core_version__ + +__all__ = 'VERSION', 'version_info' + +VERSION = '2.12.5' +"""The version of Pydantic. + +This version specifier is guaranteed to be compliant with the [specification], +introduced by [PEP 440]. + +[specification]: https://packaging.python.org/en/latest/specifications/version-specifiers/ +[PEP 440]: https://peps.python.org/pep-0440/ +""" + +# Keep this in sync with the version constraint in the `pyproject.toml` dependencies: +_COMPATIBLE_PYDANTIC_CORE_VERSION = '2.41.5' + + +def version_short() -> str: + """Return the `major.minor` part of Pydantic version. + + It returns '2.1' if Pydantic version is '2.1.1'. + """ + return '.'.join(VERSION.split('.')[:2]) + + +def version_info() -> str: + """Return complete version information for Pydantic and its dependencies.""" + import importlib.metadata + import platform + from pathlib import Path + + import pydantic_core._pydantic_core as pdc + + from ._internal import _git as git + + # get data about packages that are closely related to pydantic, use pydantic or often conflict with pydantic + package_names = { + 'email-validator', + 'fastapi', + 'mypy', + 'pydantic-extra-types', + 'pydantic-settings', + 'pyright', + 'typing_extensions', + } + related_packages = [] + + for dist in importlib.metadata.distributions(): + name = dist.metadata['Name'] + if name in package_names: + related_packages.append(f'{name}-{dist.version}') + + pydantic_dir = Path(__file__).parents[1].resolve() + most_recent_commit = ( + git.git_revision(pydantic_dir) if git.is_git_repo(pydantic_dir) and git.have_git() else 'unknown' + ) + + info = { + 'pydantic version': VERSION, + 'pydantic-core version': __pydantic_core_version__, + 'pydantic-core build': getattr(pdc, 'build_info', None) or pdc.build_profile, # pyright: ignore[reportPrivateImportUsage] + 'python version': sys.version, + 'platform': platform.platform(), + 'related packages': ' '.join(related_packages), + 'commit': most_recent_commit, + } + return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items()) + + +def check_pydantic_core_version() -> bool: + """Check that the installed `pydantic-core` dependency is compatible.""" + return __pydantic_core_version__ == _COMPATIBLE_PYDANTIC_CORE_VERSION + + +def _ensure_pydantic_core_version() -> None: # pragma: no cover + if not check_pydantic_core_version(): + raise_error = True + # Do not raise the error if pydantic is installed in editable mode (i.e. in development): + if sys.version_info >= (3, 13): # origin property added in 3.13 + from importlib.metadata import distribution + + dist = distribution('pydantic') + if getattr(getattr(dist.origin, 'dir_info', None), 'editable', False): + raise_error = False + + if raise_error: + raise SystemError( + f'The installed pydantic-core version ({__pydantic_core_version__}) is incompatible ' + f'with the current pydantic version, which requires {_COMPATIBLE_PYDANTIC_CORE_VERSION}. ' + "If you encounter this error, make sure that you haven't upgraded pydantic-core manually." + ) + + +def parse_mypy_version(version: str) -> tuple[int, int, int]: + """Parse `mypy` string version to a 3-tuple of ints. + + It parses normal version like `1.11.0` and extra info followed by a `+` sign + like `1.11.0+dev.d6d9d8cd4f27c52edac1f537e236ec48a01e54cb.dirty`. + + Args: + version: The mypy version string. + + Returns: + A triple of ints, e.g. `(1, 11, 0)`. + """ + return tuple(map(int, version.partition('+')[0].split('.'))) # pyright: ignore[reportReturnType] diff --git a/backend/venv/Lib/site-packages/pydantic/warnings.py b/backend/venv/Lib/site-packages/pydantic/warnings.py new file mode 100644 index 0000000..2e2dd83 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic/warnings.py @@ -0,0 +1,122 @@ +"""Pydantic-specific warnings.""" + +from __future__ import annotations as _annotations + +from .version import version_short + +__all__ = ( + 'PydanticDeprecatedSince20', + 'PydanticDeprecatedSince26', + 'PydanticDeprecatedSince29', + 'PydanticDeprecatedSince210', + 'PydanticDeprecatedSince211', + 'PydanticDeprecatedSince212', + 'PydanticDeprecationWarning', + 'PydanticExperimentalWarning', + 'ArbitraryTypeWarning', + 'UnsupportedFieldAttributeWarning', + 'TypedDictExtraConfigWarning', +) + + +class PydanticDeprecationWarning(DeprecationWarning): + """A Pydantic specific deprecation warning. + + This warning is raised when using deprecated functionality in Pydantic. It provides information on when the + deprecation was introduced and the expected version in which the corresponding functionality will be removed. + + Attributes: + message: Description of the warning. + since: Pydantic version in what the deprecation was introduced. + expected_removal: Pydantic version in what the corresponding functionality expected to be removed. + """ + + message: str + since: tuple[int, int] + expected_removal: tuple[int, int] + + def __init__( + self, message: str, *args: object, since: tuple[int, int], expected_removal: tuple[int, int] | None = None + ) -> None: + super().__init__(message, *args) + self.message = message.rstrip('.') + self.since = since + self.expected_removal = expected_removal if expected_removal is not None else (since[0] + 1, 0) + + def __str__(self) -> str: + message = ( + f'{self.message}. Deprecated in Pydantic V{self.since[0]}.{self.since[1]}' + f' to be removed in V{self.expected_removal[0]}.{self.expected_removal[1]}.' + ) + if self.since == (2, 0): + message += f' See Pydantic V2 Migration Guide at https://errors.pydantic.dev/{version_short()}/migration/' + return message + + +class PydanticDeprecatedSince20(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.0.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 0), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince26(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.6.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 6), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince29(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.9.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 9), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince210(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.10.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 10), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince211(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.11.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 11), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince212(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.12.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 12), expected_removal=(3, 0)) + + +class GenericBeforeBaseModelWarning(Warning): + pass + + +class PydanticExperimentalWarning(Warning): + """A Pydantic specific experimental functionality warning. + + It is raised to warn users that the functionality may change or be removed in future versions of Pydantic. + """ + + +class CoreSchemaGenerationWarning(UserWarning): + """A warning raised during core schema generation.""" + + +class ArbitraryTypeWarning(CoreSchemaGenerationWarning): + """A warning raised when Pydantic fails to generate a core schema for an arbitrary type.""" + + +class UnsupportedFieldAttributeWarning(CoreSchemaGenerationWarning): + """A warning raised when a `Field()` attribute isn't supported in the context it is used.""" + + +class TypedDictExtraConfigWarning(CoreSchemaGenerationWarning): + """A warning raised when the [`extra`][pydantic.ConfigDict.extra] configuration is incompatible with the `closed` or `extra_items` specification.""" diff --git a/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/INSTALLER b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/METADATA b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/METADATA new file mode 100644 index 0000000..468d2a5 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/METADATA @@ -0,0 +1,180 @@ +Metadata-Version: 2.4 +Name: pydantic_core +Version: 2.41.5 +Classifier: Development Status :: 3 - Alpha +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +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 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Implementation :: GraalPy +Classifier: Programming Language :: Rust +Classifier: Framework :: Pydantic +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS +Classifier: Typing :: Typed +Requires-Dist: typing-extensions>=4.14.1 +License-File: LICENSE +Summary: Core functionality for Pydantic validation and serialization +Home-Page: https://github.com/pydantic/pydantic-core +Author-email: Samuel Colvin , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, David Montague , David Hewitt , Sydney Runkle , Victorien Plot +License-Expression: MIT +Requires-Python: >=3.9 +Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM +Project-URL: Homepage, https://github.com/pydantic/pydantic-core +Project-URL: Funding, https://github.com/sponsors/samuelcolvin +Project-URL: Source, https://github.com/pydantic/pydantic-core + +# pydantic-core + +[![CI](https://github.com/pydantic/pydantic-core/workflows/ci/badge.svg?event=push)](https://github.com/pydantic/pydantic-core/actions?query=event%3Apush+branch%3Amain+workflow%3Aci) +[![Coverage](https://codecov.io/gh/pydantic/pydantic-core/branch/main/graph/badge.svg)](https://codecov.io/gh/pydantic/pydantic-core) +[![pypi](https://img.shields.io/pypi/v/pydantic-core.svg)](https://pypi.python.org/pypi/pydantic-core) +[![versions](https://img.shields.io/pypi/pyversions/pydantic-core.svg)](https://github.com/pydantic/pydantic-core) +[![license](https://img.shields.io/github/license/pydantic/pydantic-core.svg)](https://github.com/pydantic/pydantic-core/blob/main/LICENSE) + +This package provides the core functionality for [pydantic](https://docs.pydantic.dev) validation and serialization. + +Pydantic-core is currently around 17x faster than pydantic V1. +See [`tests/benchmarks/`](./tests/benchmarks/) for details. + +## Example of direct usage + +_NOTE: You should not need to use pydantic-core directly; instead, use pydantic, which in turn uses pydantic-core._ + +```py +from pydantic_core import SchemaValidator, ValidationError + + +v = SchemaValidator( + { + 'type': 'typed-dict', + 'fields': { + 'name': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'str', + }, + }, + 'age': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'int', + 'ge': 18, + }, + }, + 'is_developer': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'default', + 'schema': {'type': 'bool'}, + 'default': True, + }, + }, + }, + } +) + +r1 = v.validate_python({'name': 'Samuel', 'age': 35}) +assert r1 == {'name': 'Samuel', 'age': 35, 'is_developer': True} + +# pydantic-core can also validate JSON directly +r2 = v.validate_json('{"name": "Samuel", "age": 35}') +assert r1 == r2 + +try: + v.validate_python({'name': 'Samuel', 'age': 11}) +except ValidationError as e: + print(e) + """ + 1 validation error for model + age + Input should be greater than or equal to 18 + [type=greater_than_equal, context={ge: 18}, input_value=11, input_type=int] + """ +``` + +## Getting Started + +### Prerequisites + +You'll need: +1. **[Rust](https://rustup.rs/)** - Rust stable (or nightly for coverage) +2. **[uv](https://docs.astral.sh/uv/getting-started/installation/)** - Fast Python package manager (will install Python 3.9+ automatically) +3. **[git](https://git-scm.com/)** - For version control +4. **[make](https://www.gnu.org/software/make/)** - For running development commands (or use `nmake` on Windows) + +### Quick Start + +```bash +# Clone the repository (or from your fork) +git clone git@github.com:pydantic/pydantic-core.git +cd pydantic-core + +# Install all dependencies using uv, setup pre-commit hooks, and build the development version +make install +``` + +Verify your installation by running: + +```bash +make +``` + +This runs a full development cycle: formatting, building, linting, and testing + +### Development Commands + +Run `make help` to see all available commands, or use these common ones: + +```bash +make build-dev # to build the package during development +make build-prod # to perform an optimised build for benchmarking +make test # to run the tests +make testcov # to run the tests and generate a coverage report +make lint # to run the linter +make format # to format python and rust code +make all # to run to run build-dev + format + lint + test +``` + +### Useful Resources + +* [`python/pydantic_core/_pydantic_core.pyi`](./python/pydantic_core/_pydantic_core.pyi) - Python API types +* [`python/pydantic_core/core_schema.py`](./python/pydantic_core/core_schema.py) - Core schema definitions +* [`tests/`](./tests) - Comprehensive usage examples + +## Profiling + +It's possible to profile the code using the [`flamegraph` utility from `flamegraph-rs`](https://github.com/flamegraph-rs/flamegraph). (Tested on Linux.) You can install this with `cargo install flamegraph`. + +Run `make build-profiling` to install a release build with debugging symbols included (needed for profiling). + +Once that is built, you can profile pytest benchmarks with (e.g.): + +```bash +flamegraph -- pytest tests/benchmarks/test_micro_benchmarks.py -k test_list_of_ints_core_py --benchmark-enable +``` +The `flamegraph` command will produce an interactive SVG at `flamegraph.svg`. + +## Releasing + +1. Bump package version locally. Do not just edit `Cargo.toml` on Github, you need both `Cargo.toml` and `Cargo.lock` to be updated. +2. Make a PR for the version bump and merge it. +3. Go to https://github.com/pydantic/pydantic-core/releases and click "Draft a new release" +4. In the "Choose a tag" dropdown enter the new tag `v` and select "Create new tag on publish" when the option appears. +5. Enter the release title in the form "v " +6. Click Generate release notes button +7. Click Publish release +8. Go to https://github.com/pydantic/pydantic-core/actions and ensure that all build for release are done successfully. +9. Go to https://pypi.org/project/pydantic-core/ and ensure that the latest release is published. +10. Done 🎉 + diff --git a/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/RECORD b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/RECORD new file mode 100644 index 0000000..a90617a --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/RECORD @@ -0,0 +1,12 @@ +pydantic_core-2.41.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pydantic_core-2.41.5.dist-info/METADATA,sha256=Ex83HNMObeb0Be1hbVnx5CewzvIq2S18OeUn7UwBhKk,7420 +pydantic_core-2.41.5.dist-info/RECORD,, +pydantic_core-2.41.5.dist-info/WHEEL,sha256=n8ZdhGDUio-M1d1jdBhS3kD6MKEN1SRxo8BOjWwZdsg,96 +pydantic_core-2.41.5.dist-info/licenses/LICENSE,sha256=--f2FfGNE1wHAA5ahjJdsn9Cx3KWme8WasH3o_RYa_Q,1101 +pydantic_core/__init__.py,sha256=5kQVCp6sQ3LE_4Jsj2FN8oilYeOSUOlsWORH8XgGxr8,5286 +pydantic_core/__pycache__/__init__.cpython-312.pyc,, +pydantic_core/__pycache__/core_schema.cpython-312.pyc,, +pydantic_core/_pydantic_core.cp312-win_amd64.pyd,sha256=8RVtUmeKamoYJxhbwNSE-4sjYG8FOnIc7zbGLJm522s,5436928 +pydantic_core/_pydantic_core.pyi,sha256=9MaxWCkerllI7ar2Spz_0LSGSZJcmcGqC02rU-9Mdl4,45973 +pydantic_core/core_schema.py,sha256=k4n4J4QNy8uFumsUTXwzR5KbPh7EyLzWGX0x7pRdzxk,159165 +pydantic_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/WHEEL b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/WHEEL new file mode 100644 index 0000000..956a98b --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: maturin (1.9.6) +Root-Is-Purelib: false +Tag: cp312-cp312-win_amd64 diff --git a/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/licenses/LICENSE b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/licenses/LICENSE new file mode 100644 index 0000000..0716871 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core-2.41.5.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Samuel Colvin + +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/backend/venv/Lib/site-packages/pydantic_core/__init__.py b/backend/venv/Lib/site-packages/pydantic_core/__init__.py new file mode 100644 index 0000000..d5facd1 --- /dev/null +++ b/backend/venv/Lib/site-packages/pydantic_core/__init__.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +import sys as _sys +from typing import Any as _Any + +from typing_extensions import Sentinel + +from ._pydantic_core import ( + ArgsKwargs, + MultiHostUrl, + PydanticCustomError, + PydanticKnownError, + PydanticOmit, + PydanticSerializationError, + PydanticSerializationUnexpectedValue, + PydanticUndefined, + PydanticUndefinedType, + PydanticUseDefault, + SchemaError, + SchemaSerializer, + SchemaValidator, + Some, + TzInfo, + Url, + ValidationError, + __version__, + from_json, + to_json, + to_jsonable_python, +) +from .core_schema import CoreConfig, CoreSchema, CoreSchemaType, ErrorType + +if _sys.version_info < (3, 11): + from typing_extensions import NotRequired as _NotRequired +else: + from typing import NotRequired as _NotRequired + +if _sys.version_info < (3, 12): + from typing_extensions import TypedDict as _TypedDict +else: + from typing import TypedDict as _TypedDict + +__all__ = [ + '__version__', + 'UNSET', + 'CoreConfig', + 'CoreSchema', + 'CoreSchemaType', + 'SchemaValidator', + 'SchemaSerializer', + 'Some', + 'Url', + 'MultiHostUrl', + 'ArgsKwargs', + 'PydanticUndefined', + 'PydanticUndefinedType', + 'SchemaError', + 'ErrorDetails', + 'InitErrorDetails', + 'ValidationError', + 'PydanticCustomError', + 'PydanticKnownError', + 'PydanticOmit', + 'PydanticUseDefault', + 'PydanticSerializationError', + 'PydanticSerializationUnexpectedValue', + 'TzInfo', + 'to_json', + 'from_json', + 'to_jsonable_python', +] + + +class ErrorDetails(_TypedDict): + type: str + """ + The type of error that occurred, this is an identifier designed for + programmatic use that will change rarely or never. + + `type` is unique for each error message, and can hence be used as an identifier to build custom error messages. + """ + loc: tuple[int | str, ...] + """Tuple of strings and ints identifying where in the schema the error occurred.""" + msg: str + """A human readable error message.""" + input: _Any + """The input data at this `loc` that caused the error.""" + ctx: _NotRequired[dict[str, _Any]] + """ + Values which are required to render the error message, and could hence be useful in rendering custom error messages. + Also useful for passing custom error data forward. + """ + url: _NotRequired[str] + """ + The documentation URL giving information about the error. No URL is available if + a [`PydanticCustomError`][pydantic_core.PydanticCustomError] is used. + """ + + +class InitErrorDetails(_TypedDict): + type: str | PydanticCustomError + """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" + loc: _NotRequired[tuple[int | str, ...]] + """Tuple of strings and ints identifying where in the schema the error occurred.""" + input: _Any + """The input data at this `loc` that caused the error.""" + ctx: _NotRequired[dict[str, _Any]] + """ + Values which are required to render the error message, and could hence be useful in rendering custom error messages. + Also useful for passing custom error data forward. + """ + + +class ErrorTypeInfo(_TypedDict): + """ + Gives information about errors. + """ + + type: ErrorType + """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" + message_template_python: str + """String template to render a human readable error message from using context, when the input is Python.""" + example_message_python: str + """Example of a human readable error message, when the input is Python.""" + message_template_json: _NotRequired[str] + """String template to render a human readable error message from using context, when the input is JSON data.""" + example_message_json: _NotRequired[str] + """Example of a human readable error message, when the input is JSON data.""" + example_context: dict[str, _Any] | None + """Example of context values.""" + + +class MultiHostHost(_TypedDict): + """ + A host part of a multi-host URL. + """ + + username: str | None + """The username part of this host, or `None`.""" + password: str | None + """The password part of this host, or `None`.""" + host: str | None + """The host part of this host, or `None`.""" + port: int | None + """The port part of this host, or `None`.""" + + +MISSING = Sentinel('MISSING') +"""A singleton indicating a field value was not provided during validation. + +This singleton can be used a default value, as an alternative to `None` when it has +an explicit meaning. During serialization, any field with `MISSING` as a value is excluded +from the output. + +Example: + ```python + from pydantic import BaseModel + + from pydantic_core import MISSING + + + class Configuration(BaseModel): + timeout: int | None | MISSING = MISSING + + + # configuration defaults, stored somewhere else: + defaults = {'timeout': 200} + + conf = Configuration.model_validate({...}) + timeout = conf.timeout if timeout.timeout is not MISSING else defaults['timeout'] +""" diff --git a/backend/venv/Lib/site-packages/pydantic_core/__pycache__/__init__.cpython-312.pyc b/backend/venv/Lib/site-packages/pydantic_core/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88bfb623f75ef5c6019f5735db3eebab505f29c5 GIT binary patch literal 3151 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

        + FastAPI +