From 06e3458397720e0f7e66dd1abd1192a7ccd26cf1 Mon Sep 17 00:00:00 2001 From: newton-cn Date: Tue, 23 Apr 2024 16:34:28 +0900 Subject: [PATCH] first commit --- .venv/bin/Activate.ps1 | 247 + .venv/bin/activate | 69 + .venv/bin/activate.csh | 26 + .venv/bin/activate.fish | 69 + .venv/bin/pip | 8 + .venv/bin/pip3 | 8 + .venv/bin/pip3.10 | 8 + .venv/bin/python | 1 + .venv/bin/python3 | 1 + .venv/bin/python3.10 | 1 + .venv/bin/uvicorn | 8 + .../Jinja2-3.1.3.dist-info/INSTALLER | 1 + .../Jinja2-3.1.3.dist-info/LICENSE.rst | 28 + .../Jinja2-3.1.3.dist-info/METADATA | 105 + .../Jinja2-3.1.3.dist-info/RECORD | 59 + .../Jinja2-3.1.3.dist-info/REQUESTED | 0 .../Jinja2-3.1.3.dist-info/WHEEL | 5 + .../Jinja2-3.1.3.dist-info/entry_points.txt | 2 + .../Jinja2-3.1.3.dist-info/top_level.txt | 1 + .../MarkupSafe-2.1.5.dist-info/INSTALLER | 1 + .../MarkupSafe-2.1.5.dist-info/LICENSE.rst | 28 + .../MarkupSafe-2.1.5.dist-info/METADATA | 93 + .../MarkupSafe-2.1.5.dist-info/RECORD | 14 + .../MarkupSafe-2.1.5.dist-info/WHEEL | 6 + .../MarkupSafe-2.1.5.dist-info/top_level.txt | 1 + .../typing_extensions.cpython-310.pyc | Bin 0 -> 93603 bytes .../site-packages/_distutils_hack/__init__.py | 222 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 7590 bytes .../__pycache__/override.cpython-310.pyc | Bin 0 -> 243 bytes .../site-packages/_distutils_hack/override.py | 1 + .../annotated_types-0.6.0.dist-info/INSTALLER | 1 + .../annotated_types-0.6.0.dist-info/METADATA | 242 + .../annotated_types-0.6.0.dist-info/RECORD | 10 + .../annotated_types-0.6.0.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../site-packages/annotated_types/__init__.py | 396 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 13106 bytes .../__pycache__/test_cases.cpython-310.pyc | Bin 0 -> 5574 bytes .../site-packages/annotated_types/py.typed | 0 .../annotated_types/test_cases.py | 147 + .../anyio-4.3.0.dist-info/INSTALLER | 1 + .../anyio-4.3.0.dist-info/LICENSE | 20 + .../anyio-4.3.0.dist-info/METADATA | 104 + .../anyio-4.3.0.dist-info/RECORD | 82 + .../site-packages/anyio-4.3.0.dist-info/WHEEL | 5 + .../anyio-4.3.0.dist-info/entry_points.txt | 2 + .../anyio-4.3.0.dist-info/top_level.txt | 1 + .../site-packages/anyio/__init__.py | 76 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3038 bytes .../__pycache__/from_thread.cpython-310.pyc | Bin 0 -> 15277 bytes .../__pycache__/lowlevel.cpython-310.pyc | Bin 0 -> 5178 bytes .../__pycache__/pytest_plugin.cpython-310.pyc | Bin 0 -> 5132 bytes .../__pycache__/to_process.cpython-310.pyc | Bin 0 -> 6587 bytes .../__pycache__/to_thread.cpython-310.pyc | Bin 0 -> 2621 bytes .../site-packages/anyio/_backends/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 193 bytes .../__pycache__/_asyncio.cpython-310.pyc | Bin 0 -> 69991 bytes .../__pycache__/_trio.cpython-310.pyc | Bin 0 -> 39080 bytes .../site-packages/anyio/_backends/_asyncio.py | 2478 +++++ .../site-packages/anyio/_backends/_trio.py | 1169 +++ .../site-packages/anyio/_core/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 189 bytes .../__pycache__/_eventloop.cpython-310.pyc | Bin 0 -> 4746 bytes .../__pycache__/_exceptions.cpython-310.pyc | Bin 0 -> 3363 bytes .../_core/__pycache__/_fileio.cpython-310.pyc | Bin 0 -> 23576 bytes .../__pycache__/_resources.cpython-310.pyc | Bin 0 -> 768 bytes .../__pycache__/_signals.cpython-310.pyc | Bin 0 -> 1184 bytes .../__pycache__/_sockets.cpython-310.pyc | Bin 0 -> 19703 bytes .../__pycache__/_streams.cpython-310.pyc | Bin 0 -> 2009 bytes .../__pycache__/_subprocesses.cpython-310.pyc | Bin 0 -> 4991 bytes .../_synchronization.cpython-310.pyc | Bin 0 -> 21165 bytes .../_core/__pycache__/_tasks.cpython-310.pyc | Bin 0 -> 5855 bytes .../__pycache__/_testing.cpython-310.pyc | Bin 0 -> 2745 bytes .../__pycache__/_typedattr.cpython-310.pyc | Bin 0 -> 3302 bytes .../site-packages/anyio/_core/_eventloop.py | 163 + .../site-packages/anyio/_core/_exceptions.py | 73 + .../site-packages/anyio/_core/_fileio.py | 645 ++ .../site-packages/anyio/_core/_resources.py | 18 + .../site-packages/anyio/_core/_signals.py | 25 + .../site-packages/anyio/_core/_sockets.py | 716 ++ .../site-packages/anyio/_core/_streams.py | 52 + .../anyio/_core/_subprocesses.py | 140 + .../anyio/_core/_synchronization.py | 649 ++ .../site-packages/anyio/_core/_tasks.py | 158 + .../site-packages/anyio/_core/_testing.py | 74 + .../site-packages/anyio/_core/_typedattr.py | 81 + .../site-packages/anyio/abc/__init__.py | 57 + .../abc/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2138 bytes .../__pycache__/_eventloop.cpython-310.pyc | Bin 0 -> 12311 bytes .../__pycache__/_resources.cpython-310.pyc | Bin 0 -> 1440 bytes .../abc/__pycache__/_sockets.cpython-310.pyc | Bin 0 -> 7784 bytes .../abc/__pycache__/_streams.cpython-310.pyc | Bin 0 -> 7501 bytes .../__pycache__/_subprocesses.cpython-310.pyc | Bin 0 -> 2995 bytes .../abc/__pycache__/_tasks.cpython-310.pyc | Bin 0 -> 3769 bytes .../abc/__pycache__/_testing.cpython-310.pyc | Bin 0 -> 2619 bytes .../site-packages/anyio/abc/_eventloop.py | 392 + .../site-packages/anyio/abc/_resources.py | 31 + .../site-packages/anyio/abc/_sockets.py | 194 + .../site-packages/anyio/abc/_streams.py | 203 + .../site-packages/anyio/abc/_subprocesses.py | 79 + .../site-packages/anyio/abc/_tasks.py | 97 + .../site-packages/anyio/abc/_testing.py | 66 + .../site-packages/anyio/from_thread.py | 476 + .../site-packages/anyio/lowlevel.py | 163 + .../python3.10/site-packages/anyio/py.typed | 0 .../site-packages/anyio/pytest_plugin.py | 149 + .../site-packages/anyio/streams/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 191 bytes .../__pycache__/buffered.cpython-310.pyc | Bin 0 -> 4100 bytes .../streams/__pycache__/file.cpython-310.pyc | Bin 0 -> 5546 bytes .../__pycache__/memory.cpython-310.pyc | Bin 0 -> 8889 bytes .../__pycache__/stapled.cpython-310.pyc | Bin 0 -> 5390 bytes .../streams/__pycache__/text.cpython-310.pyc | Bin 0 -> 6327 bytes .../streams/__pycache__/tls.cpython-310.pyc | Bin 0 -> 10943 bytes .../site-packages/anyio/streams/buffered.py | 119 + .../site-packages/anyio/streams/file.py | 148 + .../site-packages/anyio/streams/memory.py | 283 + .../site-packages/anyio/streams/stapled.py | 141 + .../site-packages/anyio/streams/text.py | 147 + .../site-packages/anyio/streams/tls.py | 338 + .../site-packages/anyio/to_process.py | 259 + .../site-packages/anyio/to_thread.py | 69 + .../click-8.1.7.dist-info/INSTALLER | 1 + .../click-8.1.7.dist-info/LICENSE.rst | 28 + .../click-8.1.7.dist-info/METADATA | 103 + .../click-8.1.7.dist-info/RECORD | 39 + .../site-packages/click-8.1.7.dist-info/WHEEL | 5 + .../click-8.1.7.dist-info/top_level.txt | 1 + .../site-packages/click/__init__.py | 73 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2627 bytes .../click/__pycache__/_compat.cpython-310.pyc | Bin 0 -> 15685 bytes .../__pycache__/_termui_impl.cpython-310.pyc | Bin 0 -> 16325 bytes .../__pycache__/_textwrap.cpython-310.pyc | Bin 0 -> 1561 bytes .../__pycache__/_winconsole.cpython-310.pyc | Bin 0 -> 7677 bytes .../click/__pycache__/core.cpython-310.pyc | Bin 0 -> 91155 bytes .../__pycache__/decorators.cpython-310.pyc | Bin 0 -> 17225 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 10269 bytes .../__pycache__/formatting.cpython-310.pyc | Bin 0 -> 9474 bytes .../click/__pycache__/globals.cpython-310.pyc | Bin 0 -> 2446 bytes .../click/__pycache__/parser.cpython-310.pyc | Bin 0 -> 13687 bytes .../shell_completion.cpython-310.pyc | Bin 0 -> 16862 bytes .../click/__pycache__/termui.cpython-310.pyc | Bin 0 -> 26147 bytes .../click/__pycache__/testing.cpython-310.pyc | Bin 0 -> 15220 bytes .../click/__pycache__/types.cpython-310.pyc | Bin 0 -> 33704 bytes .../click/__pycache__/utils.cpython-310.pyc | Bin 0 -> 18860 bytes .../python3.10/site-packages/click/_compat.py | 623 ++ .../site-packages/click/_termui_impl.py | 739 ++ .../site-packages/click/_textwrap.py | 49 + .../site-packages/click/_winconsole.py | 279 + .../python3.10/site-packages/click/core.py | 3042 ++++++ .../site-packages/click/decorators.py | 561 ++ .../site-packages/click/exceptions.py | 288 + .../site-packages/click/formatting.py | 301 + .../python3.10/site-packages/click/globals.py | 68 + .../python3.10/site-packages/click/parser.py | 529 + .../python3.10/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 596 ++ .../python3.10/site-packages/click/termui.py | 784 ++ .../python3.10/site-packages/click/testing.py | 479 + .../python3.10/site-packages/click/types.py | 1089 +++ .../python3.10/site-packages/click/utils.py | 624 ++ .../site-packages/distutils-precedence.pth | 1 + .../exceptiongroup-1.2.0.dist-info/INSTALLER | 1 + .../exceptiongroup-1.2.0.dist-info/LICENSE | 73 + .../exceptiongroup-1.2.0.dist-info/METADATA | 155 + .../exceptiongroup-1.2.0.dist-info/RECORD | 18 + .../exceptiongroup-1.2.0.dist-info/WHEEL | 4 + .../site-packages/exceptiongroup/__init__.py | 46 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 888 bytes .../__pycache__/_catch.cpython-310.pyc | Bin 0 -> 3274 bytes .../__pycache__/_exceptions.cpython-310.pyc | Bin 0 -> 9610 bytes .../__pycache__/_formatting.cpython-310.pyc | Bin 0 -> 12225 bytes .../__pycache__/_suppress.cpython-310.pyc | Bin 0 -> 1132 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 515 bytes .../site-packages/exceptiongroup/_catch.py | 138 + .../exceptiongroup/_exceptions.py | 327 + .../exceptiongroup/_formatting.py | 603 ++ .../site-packages/exceptiongroup/_suppress.py | 40 + .../site-packages/exceptiongroup/_version.py | 16 + .../site-packages/exceptiongroup/py.typed | 0 .../fastapi-0.110.1.dist-info/INSTALLER | 1 + .../fastapi-0.110.1.dist-info/METADATA | 532 + .../fastapi-0.110.1.dist-info/RECORD | 91 + .../fastapi-0.110.1.dist-info/REQUESTED | 0 .../fastapi-0.110.1.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../site-packages/fastapi/__init__.py | 25 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1074 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 17633 bytes .../__pycache__/applications.cpython-310.pyc | Bin 0 -> 68387 bytes .../__pycache__/background.cpython-310.pyc | Bin 0 -> 2165 bytes .../__pycache__/concurrency.cpython-310.pyc | Bin 0 -> 1027 bytes .../datastructures.cpython-310.pyc | Bin 0 -> 6526 bytes .../__pycache__/encoders.cpython-310.pyc | Bin 0 -> 7743 bytes .../exception_handlers.cpython-310.pyc | Bin 0 -> 1560 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 6249 bytes .../__pycache__/logger.cpython-310.pyc | Bin 0 -> 242 bytes .../param_functions.cpython-310.pyc | Bin 0 -> 23478 bytes .../__pycache__/params.cpython-310.pyc | Bin 0 -> 15641 bytes .../__pycache__/requests.cpython-310.pyc | Bin 0 -> 272 bytes .../__pycache__/responses.cpython-310.pyc | Bin 0 -> 1949 bytes .../__pycache__/routing.cpython-310.pyc | Bin 0 -> 56501 bytes .../__pycache__/staticfiles.cpython-310.pyc | Bin 0 -> 245 bytes .../__pycache__/templating.cpython-310.pyc | Bin 0 -> 247 bytes .../__pycache__/testclient.cpython-310.pyc | Bin 0 -> 242 bytes .../fastapi/__pycache__/types.cpython-310.pyc | Bin 0 -> 603 bytes .../fastapi/__pycache__/utils.cpython-310.pyc | Bin 0 -> 5896 bytes .../__pycache__/websockets.cpython-310.pyc | Bin 0 -> 320 bytes .../site-packages/fastapi/_compat.py | 634 ++ .../site-packages/fastapi/applications.py | 4585 +++++++++ .../site-packages/fastapi/background.py | 59 + .../site-packages/fastapi/concurrency.py | 39 + .../site-packages/fastapi/datastructures.py | 204 + .../fastapi/dependencies/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 198 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 2277 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 18569 bytes .../fastapi/dependencies/models.py | 58 + .../fastapi/dependencies/utils.py | 818 ++ .../site-packages/fastapi/encoders.py | 341 + .../fastapi/exception_handlers.py | 34 + .../site-packages/fastapi/exceptions.py | 176 + .../site-packages/fastapi/logger.py | 3 + .../fastapi/middleware/__init__.py | 1 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 251 bytes .../__pycache__/cors.cpython-310.pyc | Bin 0 -> 256 bytes .../__pycache__/gzip.cpython-310.pyc | Bin 0 -> 256 bytes .../__pycache__/httpsredirect.cpython-310.pyc | Bin 0 -> 283 bytes .../__pycache__/trustedhost.cpython-310.pyc | Bin 0 -> 277 bytes .../__pycache__/wsgi.cpython-310.pyc | Bin 0 -> 256 bytes .../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-310.pyc | Bin 0 -> 193 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 351 bytes .../openapi/__pycache__/docs.cpython-310.pyc | Bin 0 -> 9593 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 19921 bytes .../openapi/__pycache__/utils.cpython-310.pyc | Bin 0 -> 11633 bytes .../fastapi/openapi/constants.py | 3 + .../site-packages/fastapi/openapi/docs.py | 344 + .../site-packages/fastapi/openapi/models.py | 611 ++ .../site-packages/fastapi/openapi/utils.py | 530 + .../site-packages/fastapi/param_functions.py | 2360 +++++ .../site-packages/fastapi/params.py | 777 ++ .../python3.10/site-packages/fastapi/py.typed | 0 .../site-packages/fastapi/requests.py | 2 + .../site-packages/fastapi/responses.py | 48 + .../site-packages/fastapi/routing.py | 4385 +++++++++ .../fastapi/security/__init__.py | 15 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 833 bytes .../__pycache__/api_key.cpython-310.pyc | Bin 0 -> 7583 bytes .../security/__pycache__/base.cpython-310.pyc | Bin 0 -> 482 bytes .../security/__pycache__/http.cpython-310.pyc | Bin 0 -> 10866 bytes .../__pycache__/oauth2.cpython-310.pyc | Bin 0 -> 15510 bytes .../open_id_connect_url.cpython-310.pyc | Bin 0 -> 2764 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 516 bytes .../site-packages/fastapi/security/api_key.py | 301 + .../site-packages/fastapi/security/base.py | 6 + .../site-packages/fastapi/security/http.py | 420 + .../site-packages/fastapi/security/oauth2.py | 638 ++ .../fastapi/security/open_id_connect_url.py | 84 + .../site-packages/fastapi/security/utils.py | 10 + .../site-packages/fastapi/staticfiles.py | 1 + .../site-packages/fastapi/templating.py | 1 + .../site-packages/fastapi/testclient.py | 1 + .../python3.10/site-packages/fastapi/types.py | 10 + .../python3.10/site-packages/fastapi/utils.py | 229 + .../site-packages/fastapi/websockets.py | 3 + .../h11-0.14.0.dist-info/INSTALLER | 1 + .../h11-0.14.0.dist-info/LICENSE.txt | 22 + .../h11-0.14.0.dist-info/METADATA | 193 + .../site-packages/h11-0.14.0.dist-info/RECORD | 52 + .../site-packages/h11-0.14.0.dist-info/WHEEL | 5 + .../h11-0.14.0.dist-info/top_level.txt | 1 + .../python3.10/site-packages/h11/__init__.py | 62 + .../h11/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1010 bytes .../h11/__pycache__/_abnf.cpython-310.pyc | Bin 0 -> 1254 bytes .../__pycache__/_connection.cpython-310.pyc | Bin 0 -> 15845 bytes .../h11/__pycache__/_events.cpython-310.pyc | Bin 0 -> 10154 bytes .../h11/__pycache__/_headers.cpython-310.pyc | Bin 0 -> 5572 bytes .../h11/__pycache__/_readers.cpython-310.pyc | Bin 0 -> 6242 bytes .../_receivebuffer.cpython-310.pyc | Bin 0 -> 3197 bytes .../h11/__pycache__/_state.cpython-310.pyc | Bin 0 -> 5591 bytes .../h11/__pycache__/_util.cpython-310.pyc | Bin 0 -> 3860 bytes .../h11/__pycache__/_version.cpython-310.pyc | Bin 0 -> 203 bytes .../h11/__pycache__/_writers.cpython-310.pyc | Bin 0 -> 4519 bytes .../lib/python3.10/site-packages/h11/_abnf.py | 132 + .../site-packages/h11/_connection.py | 633 ++ .../python3.10/site-packages/h11/_events.py | 369 + .../python3.10/site-packages/h11/_headers.py | 278 + .../python3.10/site-packages/h11/_readers.py | 247 + .../site-packages/h11/_receivebuffer.py | 153 + .../python3.10/site-packages/h11/_state.py | 367 + .../lib/python3.10/site-packages/h11/_util.py | 135 + .../python3.10/site-packages/h11/_version.py | 16 + .../python3.10/site-packages/h11/_writers.py | 145 + .../lib/python3.10/site-packages/h11/py.typed | 1 + .../site-packages/h11/tests/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 187 bytes .../tests/__pycache__/helpers.cpython-310.pyc | Bin 0 -> 2804 bytes .../test_against_stdlib_http.cpython-310.pyc | Bin 0 -> 3839 bytes .../test_connection.cpython-310.pyc | Bin 0 -> 33072 bytes .../__pycache__/test_events.cpython-310.pyc | Bin 0 -> 2935 bytes .../__pycache__/test_headers.cpython-310.pyc | Bin 0 -> 3687 bytes .../__pycache__/test_helpers.cpython-310.pyc | Bin 0 -> 852 bytes .../tests/__pycache__/test_io.cpython-310.pyc | Bin 0 -> 12308 bytes .../test_receivebuffer.cpython-310.pyc | Bin 0 -> 2302 bytes .../__pycache__/test_state.cpython-310.pyc | Bin 0 -> 5371 bytes .../__pycache__/test_util.cpython-310.pyc | Bin 0 -> 3542 bytes .../site-packages/h11/tests/data/test-file | 1 + .../site-packages/h11/tests/helpers.py | 101 + .../h11/tests/test_against_stdlib_http.py | 115 + .../h11/tests/test_connection.py | 1122 +++ .../site-packages/h11/tests/test_events.py | 150 + .../site-packages/h11/tests/test_headers.py | 157 + .../site-packages/h11/tests/test_helpers.py | 32 + .../site-packages/h11/tests/test_io.py | 572 ++ .../h11/tests/test_receivebuffer.py | 135 + .../site-packages/h11/tests/test_state.py | 271 + .../site-packages/h11/tests/test_util.py | 112 + .../idna-3.7.dist-info/INSTALLER | 1 + .../idna-3.7.dist-info/LICENSE.md | 31 + .../site-packages/idna-3.7.dist-info/METADATA | 243 + .../site-packages/idna-3.7.dist-info/RECORD | 22 + .../site-packages/idna-3.7.dist-info/WHEEL | 4 + .../python3.10/site-packages/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 841 bytes .../idna/__pycache__/codec.cpython-310.pyc | Bin 0 -> 3267 bytes .../idna/__pycache__/compat.cpython-310.pyc | Bin 0 -> 741 bytes .../idna/__pycache__/core.cpython-310.pyc | Bin 0 -> 9472 bytes .../idna/__pycache__/idnadata.cpython-310.pyc | Bin 0 -> 194442 bytes .../__pycache__/intranges.cpython-310.pyc | Bin 0 -> 1978 bytes .../__pycache__/package_data.cpython-310.pyc | Bin 0 -> 205 bytes .../__pycache__/uts46data.cpython-310.pyc | Bin 0 -> 152370 bytes .../python3.10/site-packages/idna/codec.py | 118 + .../python3.10/site-packages/idna/compat.py | 13 + .../lib/python3.10/site-packages/idna/core.py | 395 + .../python3.10/site-packages/idna/idnadata.py | 4245 ++++++++ .../site-packages/idna/intranges.py | 54 + .../site-packages/idna/package_data.py | 2 + .../python3.10/site-packages/idna/py.typed | 0 .../site-packages/idna/uts46data.py | 8598 ++++++++++++++++ .../site-packages/jinja2/__init__.py | 37 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1612 bytes .../__pycache__/_identifier.cpython-310.pyc | Bin 0 -> 2087 bytes .../__pycache__/async_utils.cpython-310.pyc | Bin 0 -> 2701 bytes .../__pycache__/bccache.cpython-310.pyc | Bin 0 -> 13958 bytes .../__pycache__/compiler.cpython-310.pyc | Bin 0 -> 54561 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 1548 bytes .../jinja2/__pycache__/debug.cpython-310.pyc | Bin 0 -> 4004 bytes .../__pycache__/defaults.cpython-310.pyc | Bin 0 -> 1348 bytes .../__pycache__/environment.cpython-310.pyc | Bin 0 -> 53398 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5547 bytes .../jinja2/__pycache__/ext.cpython-310.pyc | Bin 0 -> 25853 bytes .../__pycache__/filters.cpython-310.pyc | Bin 0 -> 51382 bytes .../__pycache__/idtracking.cpython-310.pyc | Bin 0 -> 11099 bytes .../jinja2/__pycache__/lexer.cpython-310.pyc | Bin 0 -> 20449 bytes .../__pycache__/loaders.cpython-310.pyc | Bin 0 -> 20505 bytes .../jinja2/__pycache__/meta.cpython-310.pyc | Bin 0 -> 3828 bytes .../__pycache__/nativetypes.cpython-310.pyc | Bin 0 -> 5023 bytes .../jinja2/__pycache__/nodes.cpython-310.pyc | Bin 0 -> 40314 bytes .../__pycache__/optimizer.cpython-310.pyc | Bin 0 -> 1968 bytes .../jinja2/__pycache__/parser.cpython-310.pyc | Bin 0 -> 27742 bytes .../__pycache__/runtime.cpython-310.pyc | Bin 0 -> 32157 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 11980 bytes .../jinja2/__pycache__/tests.cpython-310.pyc | Bin 0 -> 6702 bytes .../jinja2/__pycache__/utils.cpython-310.pyc | Bin 0 -> 24521 bytes .../__pycache__/visitor.cpython-310.pyc | Bin 0 -> 3987 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 84 + .../site-packages/jinja2/bccache.py | 406 + .../site-packages/jinja2/compiler.py | 1956 ++++ .../site-packages/jinja2/constants.py | 20 + .../python3.10/site-packages/jinja2/debug.py | 191 + .../site-packages/jinja2/defaults.py | 48 + .../site-packages/jinja2/environment.py | 1667 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.10/site-packages/jinja2/ext.py | 869 ++ .../site-packages/jinja2/filters.py | 1854 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.10/site-packages/jinja2/lexer.py | 866 ++ .../site-packages/jinja2/loaders.py | 661 ++ .../python3.10/site-packages/jinja2/meta.py | 111 + .../site-packages/jinja2/nativetypes.py | 130 + .../python3.10/site-packages/jinja2/nodes.py | 1204 +++ .../site-packages/jinja2/optimizer.py | 47 + .../python3.10/site-packages/jinja2/parser.py | 1034 ++ .../python3.10/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1051 ++ .../site-packages/jinja2/sandbox.py | 428 + .../python3.10/site-packages/jinja2/tests.py | 255 + .../python3.10/site-packages/jinja2/utils.py | 755 ++ .../site-packages/jinja2/visitor.py | 92 + .../site-packages/markupsafe/__init__.py | 332 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 11357 bytes .../__pycache__/_native.cpython-310.pyc | Bin 0 -> 2012 bytes .../site-packages/markupsafe/_native.py | 63 + .../site-packages/markupsafe/_speedups.c | 320 + .../_speedups.cpython-310-x86_64-linux-gnu.so | Bin 0 -> 44240 bytes .../site-packages/markupsafe/_speedups.pyi | 9 + .../site-packages/markupsafe/py.typed | 0 .../site-packages/multipart/__init__.py | 16 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 525 bytes .../__pycache__/decoders.cpython-310.pyc | Bin 0 -> 5710 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 1557 bytes .../__pycache__/multipart.cpython-310.pyc | Bin 0 -> 46889 bytes .../site-packages/multipart/decoders.py | 171 + .../site-packages/multipart/exceptions.py | 34 + .../site-packages/multipart/multipart.py | 1911 ++++ .../pip-24.0.dist-info/AUTHORS.txt | 760 ++ .../pip-24.0.dist-info/INSTALLER | 1 + .../pip-24.0.dist-info/LICENSE.txt | 20 + .../site-packages/pip-24.0.dist-info/METADATA | 88 + .../site-packages/pip-24.0.dist-info/RECORD | 1024 ++ .../pip-24.0.dist-info/REQUESTED | 0 .../site-packages/pip-24.0.dist-info/WHEEL | 5 + .../pip-24.0.dist-info/entry_points.txt | 4 + .../pip-24.0.dist-info/top_level.txt | 1 + .../python3.10/site-packages/pip/__init__.py | 13 + .../python3.10/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 635 bytes .../pip/__pycache__/__main__.cpython-310.pyc | Bin 0 -> 471 bytes .../__pip-runner__.cpython-310.pyc | Bin 0 -> 1635 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 699 bytes .../__pycache__/build_env.cpython-310.pyc | Bin 0 -> 9716 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 9050 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 11653 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 25471 bytes .../__pycache__/main.cpython-310.pyc | Bin 0 -> 623 bytes .../__pycache__/pyproject.cpython-310.pyc | Bin 0 -> 3645 bytes .../self_outdated_check.cpython-310.pyc | Bin 0 -> 6949 bytes .../__pycache__/wheel_builder.cpython-310.pyc | Bin 0 -> 8650 bytes .../site-packages/pip/_internal/build_env.py | 311 + .../site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 278 bytes .../autocompletion.cpython-310.pyc | Bin 0 -> 5412 bytes .../__pycache__/base_command.cpython-310.pyc | Bin 0 -> 6495 bytes .../__pycache__/cmdoptions.cpython-310.pyc | Bin 0 -> 23515 bytes .../command_context.cpython-310.pyc | Bin 0 -> 1318 bytes .../cli/__pycache__/main.cpython-310.pyc | Bin 0 -> 1512 bytes .../__pycache__/main_parser.cpython-310.pyc | Bin 0 -> 3001 bytes .../cli/__pycache__/parser.cpython-310.pyc | Bin 0 -> 9927 bytes .../__pycache__/progress_bars.cpython-310.pyc | Bin 0 -> 1902 bytes .../__pycache__/req_command.cpython-310.pyc | Bin 0 -> 13173 bytes .../cli/__pycache__/spinners.cpython-310.pyc | Bin 0 -> 4968 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 357 bytes .../pip/_internal/cli/autocompletion.py | 172 + .../pip/_internal/cli/base_command.py | 236 + .../pip/_internal/cli/cmdoptions.py | 1074 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 505 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3257 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 6428 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 1636 bytes .../__pycache__/completion.cpython-310.pyc | Bin 0 -> 4324 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 8941 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 6891 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 4251 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 2977 bytes .../commands/__pycache__/hash.cpython-310.pyc | Bin 0 -> 2154 bytes .../commands/__pycache__/help.cpython-310.pyc | Bin 0 -> 1315 bytes .../__pycache__/index.cpython-310.pyc | Bin 0 -> 4592 bytes .../__pycache__/inspect.cpython-310.pyc | Bin 0 -> 2975 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 17725 bytes .../commands/__pycache__/list.cpython-310.pyc | Bin 0 -> 10373 bytes .../__pycache__/search.cpython-310.pyc | Bin 0 -> 5368 bytes .../commands/__pycache__/show.cpython-310.pyc | Bin 0 -> 6529 bytes .../__pycache__/uninstall.cpython-310.pyc | Bin 0 -> 3336 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4982 bytes .../pip/_internal/commands/cache.py | 225 + .../pip/_internal/commands/check.py | 54 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 147 + .../pip/_internal/commands/freeze.py | 108 + .../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 | 774 ++ .../pip/_internal/commands/list.py | 368 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 189 + .../pip/_internal/commands/uninstall.py | 113 + .../pip/_internal/commands/wheel.py | 183 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 805 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 2487 bytes .../__pycache__/installed.cpython-310.pyc | Bin 0 -> 1489 bytes .../__pycache__/sdist.cpython-310.pyc | Bin 0 -> 5292 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1854 bytes .../pip/_internal/distributions/base.py | 51 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 156 + .../pip/_internal/distributions/wheel.py | 40 + .../site-packages/pip/_internal/exceptions.py | 728 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 232 bytes .../__pycache__/collector.cpython-310.pyc | Bin 0 -> 15317 bytes .../package_finder.cpython-310.pyc | Bin 0 -> 29460 bytes .../index/__pycache__/sources.cpython-310.pyc | Bin 0 -> 8922 bytes .../pip/_internal/index/collector.py | 507 + .../pip/_internal/index/package_finder.py | 1027 ++ .../pip/_internal/index/sources.py | 285 + .../pip/_internal/locations/__init__.py | 467 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 11034 bytes .../__pycache__/_distutils.cpython-310.pyc | Bin 0 -> 4599 bytes .../__pycache__/_sysconfig.cpython-310.pyc | Bin 0 -> 5998 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 2402 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 213 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 128 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 4809 bytes .../__pycache__/_json.cpython-310.pyc | Bin 0 -> 2192 bytes .../metadata/__pycache__/base.cpython-310.pyc | Bin 0 -> 27337 bytes .../__pycache__/pkg_resources.cpython-310.pyc | Bin 0 -> 10619 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 702 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 353 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 2755 bytes .../__pycache__/_dists.cpython-310.pyc | Bin 0 -> 9061 bytes .../__pycache__/_envs.cpython-310.pyc | Bin 0 -> 7753 bytes .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 227 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 278 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 266 bytes .../__pycache__/candidate.cpython-310.pyc | Bin 0 -> 1444 bytes .../__pycache__/direct_url.cpython-310.pyc | Bin 0 -> 7711 bytes .../format_control.cpython-310.pyc | Bin 0 -> 2737 bytes .../models/__pycache__/index.cpython-310.pyc | Bin 0 -> 1235 bytes .../installation_report.cpython-310.pyc | Bin 0 -> 1756 bytes .../models/__pycache__/link.cpython-310.pyc | Bin 0 -> 18090 bytes .../models/__pycache__/scheme.cpython-310.pyc | Bin 0 -> 1034 bytes .../__pycache__/search_scope.cpython-310.pyc | Bin 0 -> 3553 bytes .../selection_prefs.cpython-310.pyc | Bin 0 -> 1696 bytes .../__pycache__/target_python.cpython-310.pyc | Bin 0 -> 3813 bytes .../models/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4466 bytes .../pip/_internal/models/candidate.py | 30 + .../pip/_internal/models/direct_url.py | 235 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 579 ++ .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 132 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 122 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 254 bytes .../network/__pycache__/auth.cpython-310.pyc | Bin 0 -> 14425 bytes .../network/__pycache__/cache.cpython-310.pyc | Bin 0 -> 4592 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 5530 bytes .../__pycache__/lazy_wheel.cpython-310.pyc | Bin 0 -> 8422 bytes .../__pycache__/session.cpython-310.pyc | Bin 0 -> 12523 bytes .../network/__pycache__/utils.cpython-310.pyc | Bin 0 -> 1457 bytes .../__pycache__/xmlrpc.cpython-310.pyc | Bin 0 -> 2110 bytes .../pip/_internal/network/auth.py | 561 ++ .../pip/_internal/network/cache.py | 106 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 520 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 202 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 5206 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 6223 bytes .../__pycache__/prepare.cpython-310.pyc | Bin 0 -> 15660 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 208 bytes .../__pycache__/build_tracker.cpython-310.pyc | Bin 0 -> 5058 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 1441 bytes .../metadata_editable.cpython-310.pyc | Bin 0 -> 1475 bytes .../metadata_legacy.cpython-310.pyc | Bin 0 -> 2380 bytes .../build/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1231 bytes .../wheel_editable.cpython-310.pyc | Bin 0 -> 1455 bytes .../__pycache__/wheel_legacy.cpython-310.pyc | Bin 0 -> 2765 bytes .../operations/build/build_tracker.py | 139 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 187 + .../pip/_internal/operations/freeze.py | 255 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 266 bytes .../editable_legacy.cpython-310.pyc | Bin 0 -> 1495 bytes .../install/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 21314 bytes .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 734 ++ .../pip/_internal/operations/prepare.py | 730 ++ .../site-packages/pip/_internal/pyproject.py | 179 + .../pip/_internal/req/__init__.py | 92 + .../req/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2571 bytes .../__pycache__/constructors.cpython-310.pyc | Bin 0 -> 14155 bytes .../req/__pycache__/req_file.cpython-310.pyc | Bin 0 -> 13999 bytes .../__pycache__/req_install.cpython-310.pyc | Bin 0 -> 24522 bytes .../req/__pycache__/req_set.cpython-310.pyc | Bin 0 -> 5224 bytes .../__pycache__/req_uninstall.cpython-310.pyc | Bin 0 -> 19236 bytes .../pip/_internal/req/constructors.py | 576 ++ .../pip/_internal/req/req_file.py | 554 ++ .../pip/_internal/req/req_install.py | 923 ++ .../pip/_internal/req/req_set.py | 119 + .../pip/_internal/req/req_uninstall.py | 649 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 202 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1054 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 209 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 14911 bytes .../_internal/resolution/legacy/resolver.py | 598 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 213 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 6266 bytes .../__pycache__/candidates.cpython-310.pyc | Bin 0 -> 20467 bytes .../__pycache__/factory.cpython-310.pyc | Bin 0 -> 21371 bytes .../found_candidates.cpython-310.pyc | Bin 0 -> 4873 bytes .../__pycache__/provider.cpython-310.pyc | Bin 0 -> 7941 bytes .../__pycache__/reporter.cpython-310.pyc | Bin 0 -> 3710 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 8225 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 8758 bytes .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 597 ++ .../resolution/resolvelib/factory.py | 812 ++ .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 255 + .../resolution/resolvelib/reporter.py | 80 + .../resolution/resolvelib/requirements.py | 166 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 248 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 197 bytes .../__pycache__/_jaraco_text.cpython-310.pyc | Bin 0 -> 3853 bytes .../utils/__pycache__/_log.cpython-310.pyc | Bin 0 -> 1525 bytes .../utils/__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 1623 bytes .../utils/__pycache__/compat.cpython-310.pyc | Bin 0 -> 1513 bytes .../compatibility_tags.cpython-310.pyc | Bin 0 -> 4082 bytes .../__pycache__/datetime.cpython-310.pyc | Bin 0 -> 520 bytes .../__pycache__/deprecation.cpython-310.pyc | Bin 0 -> 3318 bytes .../direct_url_helpers.cpython-310.pyc | Bin 0 -> 2088 bytes .../__pycache__/egg_link.cpython-310.pyc | Bin 0 -> 2418 bytes .../__pycache__/encoding.cpython-310.pyc | Bin 0 -> 1310 bytes .../__pycache__/entrypoints.cpython-310.pyc | Bin 0 -> 2703 bytes .../__pycache__/filesystem.cpython-310.pyc | Bin 0 -> 4486 bytes .../__pycache__/filetypes.cpython-310.pyc | Bin 0 -> 947 bytes .../utils/__pycache__/glibc.cpython-310.pyc | Bin 0 -> 1718 bytes .../utils/__pycache__/hashes.cpython-310.pyc | Bin 0 -> 5486 bytes .../utils/__pycache__/logging.cpython-310.pyc | Bin 0 -> 9680 bytes .../utils/__pycache__/misc.cpython-310.pyc | Bin 0 -> 23283 bytes .../utils/__pycache__/models.cpython-310.pyc | Bin 0 -> 1993 bytes .../__pycache__/packaging.cpython-310.pyc | Bin 0 -> 2085 bytes .../setuptools_build.cpython-310.pyc | Bin 0 -> 3821 bytes .../__pycache__/subprocess.cpython-310.pyc | Bin 0 -> 5775 bytes .../__pycache__/temp_dir.cpython-310.pyc | Bin 0 -> 8328 bytes .../__pycache__/unpacking.cpython-310.pyc | Bin 0 -> 6657 bytes .../utils/__pycache__/urls.cpython-310.pyc | Bin 0 -> 1590 bytes .../__pycache__/virtualenv.cpython-310.pyc | Bin 0 -> 3293 bytes .../utils/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4405 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 | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 120 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 151 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 783 ++ .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 520 bytes .../vcs/__pycache__/bazaar.cpython-310.pyc | Bin 0 -> 3486 bytes .../vcs/__pycache__/git.cpython-310.pyc | Bin 0 -> 12409 bytes .../vcs/__pycache__/mercurial.cpython-310.pyc | Bin 0 -> 5080 bytes .../__pycache__/subversion.cpython-310.pyc | Bin 0 -> 8458 bytes .../versioncontrol.cpython-310.pyc | Bin 0 -> 21130 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 ++ .../pip/_internal/wheel_builder.py | 354 + .../site-packages/pip/_vendor/__init__.py | 121 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3155 bytes .../_vendor/__pycache__/six.cpython-310.pyc | Bin 0 -> 27587 bytes .../typing_extensions.cpython-310.pyc | Bin 0 -> 89123 bytes .../pip/_vendor/cachecontrol/__init__.py | 28 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 768 bytes .../__pycache__/_cmd.cpython-310.pyc | Bin 0 -> 1837 bytes .../__pycache__/adapter.cpython-310.pyc | Bin 0 -> 4420 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 3281 bytes .../__pycache__/controller.cpython-310.pyc | Bin 0 -> 10131 bytes .../__pycache__/filewrapper.cpython-310.pyc | Bin 0 -> 3221 bytes .../__pycache__/heuristics.cpython-310.pyc | Bin 0 -> 5396 bytes .../__pycache__/serialize.cpython-310.pyc | Bin 0 -> 4110 bytes .../__pycache__/wrapper.cpython-310.pyc | Bin 0 -> 1472 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 161 + .../pip/_vendor/cachecontrol/cache.py | 74 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 431 bytes .../__pycache__/file_cache.cpython-310.pyc | Bin 0 -> 5587 bytes .../__pycache__/redis_cache.cpython-310.pyc | Bin 0 -> 2046 bytes .../_vendor/cachecontrol/caches/file_cache.py | 181 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 494 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 154 + .../pip/_vendor/cachecontrol/py.typed | 0 .../pip/_vendor/cachecontrol/serialize.py | 206 + .../pip/_vendor/cachecontrol/wrapper.py | 43 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 310 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 460 bytes .../certifi/__pycache__/core.cpython-310.pyc | Bin 0 -> 1930 bytes .../pip/_vendor/certifi/cacert.pem | 4635 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 108 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/chardet/__init__.py | 115 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3178 bytes .../__pycache__/big5freq.cpython-310.pyc | Bin 0 -> 27184 bytes .../__pycache__/big5prober.cpython-310.pyc | Bin 0 -> 1162 bytes .../chardistribution.cpython-310.pyc | Bin 0 -> 6579 bytes .../charsetgroupprober.cpython-310.pyc | Bin 0 -> 2429 bytes .../__pycache__/charsetprober.cpython-310.pyc | Bin 0 -> 3835 bytes .../codingstatemachine.cpython-310.pyc | Bin 0 -> 3072 bytes .../codingstatemachinedict.cpython-310.pyc | Bin 0 -> 701 bytes .../__pycache__/cp949prober.cpython-310.pyc | Bin 0 -> 1169 bytes .../chardet/__pycache__/enums.cpython-310.pyc | Bin 0 -> 2662 bytes .../__pycache__/escprober.cpython-310.pyc | Bin 0 -> 2820 bytes .../chardet/__pycache__/escsm.cpython-310.pyc | Bin 0 -> 8523 bytes .../__pycache__/eucjpprober.cpython-310.pyc | Bin 0 -> 2606 bytes .../__pycache__/euckrfreq.cpython-310.pyc | Bin 0 -> 12068 bytes .../__pycache__/euckrprober.cpython-310.pyc | Bin 0 -> 1170 bytes .../__pycache__/euctwfreq.cpython-310.pyc | Bin 0 -> 27188 bytes .../__pycache__/euctwprober.cpython-310.pyc | Bin 0 -> 1170 bytes .../__pycache__/gb2312freq.cpython-310.pyc | Bin 0 -> 19112 bytes .../__pycache__/gb2312prober.cpython-310.pyc | Bin 0 -> 1178 bytes .../__pycache__/hebrewprober.cpython-310.pyc | Bin 0 -> 3419 bytes .../__pycache__/jisfreq.cpython-310.pyc | Bin 0 -> 22140 bytes .../__pycache__/johabfreq.cpython-310.pyc | Bin 0 -> 138764 bytes .../__pycache__/johabprober.cpython-310.pyc | Bin 0 -> 1169 bytes .../__pycache__/jpcntx.cpython-310.pyc | Bin 0 -> 37990 bytes .../langbulgarianmodel.cpython-310.pyc | Bin 0 -> 47932 bytes .../langgreekmodel.cpython-310.pyc | Bin 0 -> 46122 bytes .../langhebrewmodel.cpython-310.pyc | Bin 0 -> 44569 bytes .../langhungarianmodel.cpython-310.pyc | Bin 0 -> 47892 bytes .../langrussianmodel.cpython-310.pyc | Bin 0 -> 61033 bytes .../__pycache__/langthaimodel.cpython-310.pyc | Bin 0 -> 44745 bytes .../langturkishmodel.cpython-310.pyc | Bin 0 -> 44586 bytes .../__pycache__/latin1prober.cpython-310.pyc | Bin 0 -> 4568 bytes .../macromanprober.cpython-310.pyc | Bin 0 -> 4709 bytes .../mbcharsetprober.cpython-310.pyc | Bin 0 -> 2318 bytes .../mbcsgroupprober.cpython-310.pyc | Bin 0 -> 1266 bytes .../__pycache__/mbcssm.cpython-310.pyc | Bin 0 -> 20941 bytes .../__pycache__/resultdict.cpython-310.pyc | Bin 0 -> 581 bytes .../sbcharsetprober.cpython-310.pyc | Bin 0 -> 3687 bytes .../sbcsgroupprober.cpython-310.pyc | Bin 0 -> 1745 bytes .../__pycache__/sjisprober.cpython-310.pyc | Bin 0 -> 2644 bytes .../universaldetector.cpython-310.pyc | Bin 0 -> 7132 bytes .../__pycache__/utf1632prober.cpython-310.pyc | Bin 0 -> 6104 bytes .../__pycache__/utf8prober.cpython-310.pyc | Bin 0 -> 2114 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 446 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 261 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 147 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../cli/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 201 bytes .../__pycache__/chardetect.cpython-310.pyc | Bin 0 -> 3043 bytes .../pip/_vendor/chardet/cli/chardetect.py | 112 + .../pip/_vendor/chardet/codingstatemachine.py | 90 + .../_vendor/chardet/codingstatemachinedict.py | 19 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 85 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 261 + .../pip/_vendor/chardet/eucjpprober.py | 102 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 316 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 238 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 147 + .../pip/_vendor/chardet/macromanprober.py | 162 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 57 + .../pip/_vendor/chardet/mbcssm.py | 661 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 206 bytes .../__pycache__/languages.cpython-310.pyc | Bin 0 -> 8189 bytes .../pip/_vendor/chardet/metadata/languages.py | 352 + .../pip/_vendor/chardet/py.typed | 0 .../pip/_vendor/chardet/resultdict.py | 16 + .../pip/_vendor/chardet/sbcharsetprober.py | 162 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 105 + .../pip/_vendor/chardet/universaldetector.py | 362 + .../pip/_vendor/chardet/utf1632prober.py | 225 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 7 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 484 bytes .../colorama/__pycache__/ansi.cpython-310.pyc | Bin 0 -> 3010 bytes .../__pycache__/ansitowin32.cpython-310.pyc | Bin 0 -> 8522 bytes .../__pycache__/initialise.cpython-310.pyc | Bin 0 -> 2267 bytes .../__pycache__/win32.cpython-310.pyc | Bin 0 -> 4477 bytes .../__pycache__/winterm.cpython-310.pyc | Bin 0 -> 5173 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 277 + .../pip/_vendor/colorama/initialise.py | 121 + .../pip/_vendor/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 204 bytes .../__pycache__/ansi_test.cpython-310.pyc | Bin 0 -> 2296 bytes .../ansitowin32_test.cpython-310.pyc | Bin 0 -> 11607 bytes .../initialise_test.cpython-310.pyc | Bin 0 -> 6904 bytes .../__pycache__/isatty_test.cpython-310.pyc | Bin 0 -> 2695 bytes .../tests/__pycache__/utils.cpython-310.pyc | Bin 0 -> 1604 bytes .../__pycache__/winterm_test.cpython-310.pyc | Bin 0 -> 3197 bytes .../pip/_vendor/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../_vendor/colorama/tests/initialise_test.py | 189 + .../pip/_vendor/colorama/tests/isatty_test.py | 57 + .../pip/_vendor/colorama/tests/utils.py | 49 + .../_vendor/colorama/tests/winterm_test.py | 131 + .../pip/_vendor/colorama/win32.py | 180 + .../pip/_vendor/colorama/winterm.py | 195 + .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1068 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 31445 bytes .../__pycache__/database.cpython-310.pyc | Bin 0 -> 43182 bytes .../distlib/__pycache__/index.cpython-310.pyc | Bin 0 -> 17305 bytes .../__pycache__/locators.cpython-310.pyc | Bin 0 -> 38332 bytes .../__pycache__/manifest.cpython-310.pyc | Bin 0 -> 10233 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 5321 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 27036 bytes .../__pycache__/resources.cpython-310.pyc | Bin 0 -> 11042 bytes .../__pycache__/scripts.cpython-310.pyc | Bin 0 -> 11528 bytes .../distlib/__pycache__/util.cpython-310.pyc | Bin 0 -> 52146 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 20289 bytes .../distlib/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 27684 bytes .../pip/_vendor/distlib/compat.py | 1138 +++ .../pip/_vendor/distlib/database.py | 1359 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1303 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 167 + .../pip/_vendor/distlib/metadata.py | 1068 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 452 + .../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 | 2025 ++++ .../pip/_vendor/distlib/version.py | 751 ++ .../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 | 1099 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 921 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 275 bytes .../distro/__pycache__/distro.cpython-310.pyc | Bin 0 -> 42069 bytes .../pip/_vendor/distro/distro.py | 1399 +++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 853 bytes .../idna/__pycache__/codec.cpython-310.pyc | Bin 0 -> 2824 bytes .../idna/__pycache__/compat.cpython-310.pyc | Bin 0 -> 753 bytes .../idna/__pycache__/core.cpython-310.pyc | Bin 0 -> 9682 bytes .../idna/__pycache__/idnadata.cpython-310.pyc | Bin 0 -> 38389 bytes .../__pycache__/intranges.cpython-310.pyc | Bin 0 -> 1990 bytes .../__pycache__/package_data.cpython-310.pyc | Bin 0 -> 217 bytes .../__pycache__/uts46data.cpython-310.pyc | Bin 0 -> 152404 bytes .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2151 +++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../site-packages/pip/_vendor/idna/py.typed | 0 .../pip/_vendor/idna/uts46data.py | 8600 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1451 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 1814 bytes .../msgpack/__pycache__/ext.cpython-310.pyc | Bin 0 -> 6321 bytes .../__pycache__/fallback.cpython-310.pyc | Bin 0 -> 25484 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 596 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 452 bytes .../__pycache__/_manylinux.cpython-310.pyc | Bin 0 -> 7306 bytes .../__pycache__/_musllinux.cpython-310.pyc | Bin 0 -> 4618 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2711 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9293 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 3981 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 21533 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 12196 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 3581 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 12931 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 ++ .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pkg_resources/__init__.py | 3361 +++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 101067 bytes .../pip/_vendor/platformdirs/__init__.py | 566 ++ .../pip/_vendor/platformdirs/__main__.py | 53 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 14375 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 1387 bytes .../__pycache__/android.cpython-310.pyc | Bin 0 -> 6625 bytes .../__pycache__/api.cpython-310.pyc | Bin 0 -> 7623 bytes .../__pycache__/macos.cpython-310.pyc | Bin 0 -> 4264 bytes .../__pycache__/unix.cpython-310.pyc | Bin 0 -> 8855 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 296 bytes .../__pycache__/windows.cpython-310.pyc | Bin 0 -> 8629 bytes .../pip/_vendor/platformdirs/android.py | 210 + .../pip/_vendor/platformdirs/api.py | 223 + .../pip/_vendor/platformdirs/macos.py | 91 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 223 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 255 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2941 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 594 bytes .../__pycache__/cmdline.cpython-310.pyc | Bin 0 -> 15609 bytes .../__pycache__/console.cpython-310.pyc | Bin 0 -> 1889 bytes .../__pycache__/filter.cpython-310.pyc | Bin 0 -> 2660 bytes .../__pycache__/formatter.cpython-310.pyc | Bin 0 -> 3962 bytes .../__pycache__/lexer.cpython-310.pyc | Bin 0 -> 26237 bytes .../__pycache__/modeline.cpython-310.pyc | Bin 0 -> 1198 bytes .../__pycache__/plugin.cpython-310.pyc | Bin 0 -> 2526 bytes .../__pycache__/regexopt.cpython-310.pyc | Bin 0 -> 2962 bytes .../__pycache__/scanner.cpython-310.pyc | Bin 0 -> 3564 bytes .../__pycache__/sphinxext.cpython-310.pyc | Bin 0 -> 7127 bytes .../__pycache__/style.cpython-310.pyc | Bin 0 -> 4585 bytes .../__pycache__/token.cpython-310.pyc | Bin 0 -> 4677 bytes .../__pycache__/unistring.cpython-310.pyc | Bin 0 -> 31238 bytes .../pygments/__pycache__/util.cpython-310.pyc | Bin 0 -> 10210 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 29614 bytes .../pip/_vendor/pygments/formatter.py | 124 + .../_vendor/pygments/formatters/__init__.py | 158 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 5014 bytes .../__pycache__/_mapping.cpython-310.pyc | Bin 0 -> 4006 bytes .../__pycache__/bbcode.cpython-310.pyc | Bin 0 -> 3091 bytes .../__pycache__/groff.cpython-310.pyc | Bin 0 -> 4416 bytes .../__pycache__/html.cpython-310.pyc | Bin 0 -> 29169 bytes .../__pycache__/img.cpython-310.pyc | Bin 0 -> 17568 bytes .../__pycache__/irc.cpython-310.pyc | Bin 0 -> 4104 bytes .../__pycache__/latex.cpython-310.pyc | Bin 0 -> 13804 bytes .../__pycache__/other.cpython-310.pyc | Bin 0 -> 4810 bytes .../__pycache__/pangomarkup.cpython-310.pyc | Bin 0 -> 2110 bytes .../__pycache__/rtf.cpython-310.pyc | Bin 0 -> 4140 bytes .../__pycache__/svg.cpython-310.pyc | Bin 0 -> 6338 bytes .../__pycache__/terminal.cpython-310.pyc | Bin 0 -> 4005 bytes .../__pycache__/terminal256.cpython-310.pyc | Bin 0 -> 9255 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 943 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 10008 bytes .../__pycache__/_mapping.cpython-310.pyc | Bin 0 -> 60953 bytes .../lexers/__pycache__/python.cpython-310.pyc | Bin 0 -> 30010 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 559 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 217 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 103 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3599 bytes .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 330 + .../pip/_vendor/pyparsing/__init__.py | 322 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 7111 bytes .../__pycache__/actions.cpython-310.pyc | Bin 0 -> 7657 bytes .../__pycache__/common.cpython-310.pyc | Bin 0 -> 10185 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 188248 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 9617 bytes .../__pycache__/helpers.cpython-310.pyc | Bin 0 -> 35675 bytes .../__pycache__/results.cpython-310.pyc | Bin 0 -> 25651 bytes .../__pycache__/testing.cpython-310.pyc | Bin 0 -> 12151 bytes .../__pycache__/unicode.cpython-310.pyc | Bin 0 -> 10264 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 10058 bytes .../pip/_vendor/pyparsing/actions.py | 217 + .../pip/_vendor/pyparsing/common.py | 432 + .../pip/_vendor/pyparsing/core.py | 6115 ++++++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 656 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 16904 bytes .../pip/_vendor/pyparsing/exceptions.py | 299 + .../pip/_vendor/pyparsing/helpers.py | 1100 +++ .../pip/_vendor/pyparsing/py.typed | 0 .../pip/_vendor/pyparsing/results.py | 796 ++ .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 361 + .../pip/_vendor/pyparsing/util.py | 284 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 592 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 343 bytes .../__pycache__/_impl.cpython-310.pyc | Bin 0 -> 11395 bytes .../pip/_vendor/pyproject_hooks/_compat.py | 8 + .../pip/_vendor/pyproject_hooks/_impl.py | 330 + .../pyproject_hooks/_in_process/__init__.py | 18 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 830 bytes .../__pycache__/_in_process.cpython-310.pyc | Bin 0 -> 9712 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 182 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 4013 bytes .../__pycache__/__version__.cpython-310.pyc | Bin 0 -> 556 bytes .../_internal_utils.cpython-310.pyc | Bin 0 -> 1632 bytes .../__pycache__/adapters.cpython-310.pyc | Bin 0 -> 16218 bytes .../requests/__pycache__/api.cpython-310.pyc | Bin 0 -> 6732 bytes .../requests/__pycache__/auth.cpython-310.pyc | Bin 0 -> 8128 bytes .../__pycache__/certs.cpython-310.pyc | Bin 0 -> 815 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 1377 bytes .../__pycache__/cookies.cpython-310.pyc | Bin 0 -> 18697 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5747 bytes .../requests/__pycache__/help.cpython-310.pyc | Bin 0 -> 2873 bytes .../__pycache__/hooks.cpython-310.pyc | Bin 0 -> 1000 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 24272 bytes .../__pycache__/packages.cpython-310.pyc | Bin 0 -> 514 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 19600 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 4679 bytes .../__pycache__/structures.cpython-310.pyc | Bin 0 -> 4444 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 24453 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 538 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 833 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1094 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 612 bytes .../__pycache__/providers.cpython-310.pyc | Bin 0 -> 6662 bytes .../__pycache__/reporters.cpython-310.pyc | Bin 0 -> 2615 bytes .../__pycache__/resolvers.cpython-310.pyc | Bin 0 -> 17443 bytes .../__pycache__/structs.cpython-310.pyc | Bin 0 -> 7271 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 207 bytes .../collections_abc.cpython-310.pyc | Bin 0 -> 383 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 | 274 + .../rich/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 6119 bytes .../rich/__pycache__/__main__.cpython-310.pyc | Bin 0 -> 7189 bytes .../__pycache__/_cell_widths.cpython-310.pyc | Bin 0 -> 7820 bytes .../__pycache__/_emoji_codes.cpython-310.pyc | Bin 0 -> 360060 bytes .../_emoji_replace.cpython-310.pyc | Bin 0 -> 1200 bytes .../_export_format.cpython-310.pyc | Bin 0 -> 2303 bytes .../__pycache__/_extension.cpython-310.pyc | Bin 0 -> 501 bytes .../rich/__pycache__/_fileno.cpython-310.pyc | Bin 0 -> 794 bytes .../rich/__pycache__/_inspect.cpython-310.pyc | Bin 0 -> 8678 bytes .../__pycache__/_log_render.cpython-310.pyc | Bin 0 -> 2646 bytes .../rich/__pycache__/_loop.cpython-310.pyc | Bin 0 -> 1298 bytes .../__pycache__/_null_file.cpython-310.pyc | Bin 0 -> 3245 bytes .../__pycache__/_palettes.cpython-310.pyc | Bin 0 -> 5103 bytes .../rich/__pycache__/_pick.cpython-310.pyc | Bin 0 -> 646 bytes .../rich/__pycache__/_ratio.cpython-310.pyc | Bin 0 -> 5163 bytes .../__pycache__/_spinners.cpython-310.pyc | Bin 0 -> 12277 bytes .../rich/__pycache__/_stack.cpython-310.pyc | Bin 0 -> 844 bytes .../rich/__pycache__/_timer.cpython-310.pyc | Bin 0 -> 693 bytes .../_win32_console.cpython-310.pyc | Bin 0 -> 19013 bytes .../rich/__pycache__/_windows.cpython-310.pyc | Bin 0 -> 1795 bytes .../_windows_renderer.cpython-310.pyc | Bin 0 -> 2049 bytes .../rich/__pycache__/_wrap.cpython-310.pyc | Bin 0 -> 1557 bytes .../rich/__pycache__/abc.cpython-310.pyc | Bin 0 -> 1320 bytes .../rich/__pycache__/align.cpython-310.pyc | Bin 0 -> 7948 bytes .../rich/__pycache__/ansi.cpython-310.pyc | Bin 0 -> 5986 bytes .../rich/__pycache__/bar.cpython-310.pyc | Bin 0 -> 2989 bytes .../rich/__pycache__/box.cpython-310.pyc | Bin 0 -> 8409 bytes .../rich/__pycache__/cells.cpython-310.pyc | Bin 0 -> 4159 bytes .../rich/__pycache__/color.cpython-310.pyc | Bin 0 -> 17726 bytes .../__pycache__/color_triplet.cpython-310.pyc | Bin 0 -> 1443 bytes .../rich/__pycache__/columns.cpython-310.pyc | Bin 0 -> 6203 bytes .../rich/__pycache__/console.cpython-310.pyc | Bin 0 -> 82804 bytes .../__pycache__/constrain.cpython-310.pyc | Bin 0 -> 1760 bytes .../__pycache__/containers.cpython-310.pyc | Bin 0 -> 6492 bytes .../rich/__pycache__/control.cpython-310.pyc | Bin 0 -> 8165 bytes .../default_styles.cpython-310.pyc | Bin 0 -> 6249 bytes .../rich/__pycache__/diagnose.cpython-310.pyc | Bin 0 -> 1227 bytes .../rich/__pycache__/emoji.cpython-310.pyc | Bin 0 -> 3273 bytes .../rich/__pycache__/errors.cpython-310.pyc | Bin 0 -> 1533 bytes .../__pycache__/file_proxy.cpython-310.pyc | Bin 0 -> 2406 bytes .../rich/__pycache__/filesize.cpython-310.pyc | Bin 0 -> 2623 bytes .../__pycache__/highlighter.cpython-310.pyc | Bin 0 -> 8065 bytes .../rich/__pycache__/json.cpython-310.pyc | Bin 0 -> 4737 bytes .../rich/__pycache__/jupyter.cpython-310.pyc | Bin 0 -> 4005 bytes .../rich/__pycache__/layout.cpython-310.pyc | Bin 0 -> 14653 bytes .../rich/__pycache__/live.cpython-310.pyc | Bin 0 -> 11683 bytes .../__pycache__/live_render.cpython-310.pyc | Bin 0 -> 3408 bytes .../rich/__pycache__/logging.cpython-310.pyc | Bin 0 -> 9914 bytes .../rich/__pycache__/markup.cpython-310.pyc | Bin 0 -> 5947 bytes .../rich/__pycache__/measure.cpython-310.pyc | Bin 0 -> 5082 bytes .../rich/__pycache__/padding.cpython-310.pyc | Bin 0 -> 4488 bytes .../rich/__pycache__/pager.cpython-310.pyc | Bin 0 -> 1482 bytes .../rich/__pycache__/palette.cpython-310.pyc | Bin 0 -> 3714 bytes .../rich/__pycache__/panel.cpython-310.pyc | Bin 0 -> 7434 bytes .../rich/__pycache__/pretty.cpython-310.pyc | Bin 0 -> 27523 bytes .../rich/__pycache__/progress.cpython-310.pyc | Bin 0 -> 54012 bytes .../__pycache__/progress_bar.cpython-310.pyc | Bin 0 -> 6917 bytes .../rich/__pycache__/prompt.cpython-310.pyc | Bin 0 -> 11305 bytes .../rich/__pycache__/protocol.cpython-310.pyc | Bin 0 -> 1358 bytes .../rich/__pycache__/region.cpython-310.pyc | Bin 0 -> 533 bytes .../rich/__pycache__/repr.cpython-310.pyc | Bin 0 -> 4102 bytes .../rich/__pycache__/rule.cpython-310.pyc | Bin 0 -> 3949 bytes .../rich/__pycache__/scope.cpython-310.pyc | Bin 0 -> 2995 bytes .../rich/__pycache__/screen.cpython-310.pyc | Bin 0 -> 1885 bytes .../rich/__pycache__/segment.cpython-310.pyc | Bin 0 -> 20789 bytes .../rich/__pycache__/spinner.cpython-310.pyc | Bin 0 -> 4406 bytes .../rich/__pycache__/status.cpython-310.pyc | Bin 0 -> 4599 bytes .../rich/__pycache__/style.cpython-310.pyc | Bin 0 -> 21336 bytes .../rich/__pycache__/styled.cpython-310.pyc | Bin 0 -> 1769 bytes .../rich/__pycache__/syntax.cpython-310.pyc | Bin 0 -> 25756 bytes .../rich/__pycache__/table.cpython-310.pyc | Bin 0 -> 29948 bytes .../terminal_theme.cpython-310.pyc | Bin 0 -> 3022 bytes .../rich/__pycache__/text.cpython-310.pyc | Bin 0 -> 40110 bytes .../rich/__pycache__/theme.cpython-310.pyc | Bin 0 -> 4844 bytes .../rich/__pycache__/themes.cpython-310.pyc | Bin 0 -> 299 bytes .../__pycache__/traceback.cpython-310.pyc | Bin 0 -> 21715 bytes .../rich/__pycache__/tree.cpython-310.pyc | Bin 0 -> 7340 bytes .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 270 + .../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 | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 94 + .../site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 622 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2633 +++++ .../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 | 190 + .../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 | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 443 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 308 + .../site-packages/pip/_vendor/rich/pretty.py | 994 ++ .../pip/_vendor/rich/progress.py | 1702 ++++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/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 | 739 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 948 ++ .../site-packages/pip/_vendor/rich/table.py | 1002 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1307 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 756 ++ .../site-packages/pip/_vendor/rich/tree.py | 251 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 608 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 17264 bytes .../__pycache__/_asyncio.cpython-310.pyc | Bin 0 -> 2878 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 1511 bytes .../__pycache__/after.cpython-310.pyc | Bin 0 -> 1285 bytes .../__pycache__/before.cpython-310.pyc | Bin 0 -> 1163 bytes .../__pycache__/before_sleep.cpython-310.pyc | Bin 0 -> 1593 bytes .../tenacity/__pycache__/nap.cpython-310.pyc | Bin 0 -> 1205 bytes .../__pycache__/retry.cpython-310.pyc | Bin 0 -> 9777 bytes .../tenacity/__pycache__/stop.cpython-310.pyc | Bin 0 -> 4331 bytes .../__pycache__/tornadoweb.cpython-310.pyc | Bin 0 -> 1770 bytes .../tenacity/__pycache__/wait.cpython-310.pyc | Bin 0 -> 9292 bytes .../pip/_vendor/tenacity/_asyncio.py | 94 + .../pip/_vendor/tenacity/_utils.py | 76 + .../pip/_vendor/tenacity/after.py | 51 + .../pip/_vendor/tenacity/before.py | 46 + .../pip/_vendor/tenacity/before_sleep.py | 71 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/py.typed | 0 .../pip/_vendor/tenacity/retry.py | 272 + .../pip/_vendor/tenacity/stop.py | 103 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 228 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 361 bytes .../tomli/__pycache__/_parser.cpython-310.pyc | Bin 0 -> 17075 bytes .../tomli/__pycache__/_re.cpython-310.pyc | Bin 0 -> 2907 bytes .../tomli/__pycache__/_types.cpython-310.pyc | Bin 0 -> 331 bytes .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../site-packages/pip/_vendor/tomli/py.typed | 1 + .../pip/_vendor/truststore/__init__.py | 13 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 558 bytes .../__pycache__/_api.cpython-310.pyc | Bin 0 -> 9747 bytes .../__pycache__/_macos.cpython-310.pyc | Bin 0 -> 8655 bytes .../__pycache__/_openssl.cpython-310.pyc | Bin 0 -> 1488 bytes .../_ssl_constants.cpython-310.pyc | Bin 0 -> 802 bytes .../__pycache__/_windows.cpython-310.pyc | Bin 0 -> 10427 bytes .../pip/_vendor/truststore/_api.py | 302 + .../pip/_vendor/truststore/_macos.py | 501 + .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 554 ++ .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/typing_extensions.py | 3072 ++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2515 bytes .../__pycache__/_collections.cpython-310.pyc | Bin 0 -> 10869 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 220 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 13707 bytes .../connectionpool.cpython-310.pyc | Bin 0 -> 25789 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 11000 bytes .../__pycache__/fields.cpython-310.pyc | Bin 0 -> 8189 bytes .../__pycache__/filepost.cpython-310.pyc | Bin 0 -> 2756 bytes .../__pycache__/poolmanager.cpython-310.pyc | Bin 0 -> 15070 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 6388 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 22506 bytes .../pip/_vendor/urllib3/_collections.py | 337 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1132 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 205 bytes .../_appengine_environ.cpython-310.pyc | Bin 0 -> 1385 bytes .../__pycache__/appengine.cpython-310.pyc | Bin 0 -> 8202 bytes .../__pycache__/ntlmpool.cpython-310.pyc | Bin 0 -> 3629 bytes .../__pycache__/pyopenssl.cpython-310.pyc | Bin 0 -> 15815 bytes .../securetransport.cpython-310.pyc | Bin 0 -> 21947 bytes .../contrib/__pycache__/socks.cpython-310.pyc | Bin 0 -> 5607 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 222 bytes .../__pycache__/bindings.cpython-310.pyc | Bin 0 -> 10718 bytes .../__pycache__/low_level.cpython-310.pyc | Bin 0 -> 9105 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 | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 206 bytes .../packages/__pycache__/six.cpython-310.pyc | Bin 0 -> 27660 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 216 bytes .../__pycache__/makefile.cpython-310.pyc | Bin 0 -> 1316 bytes .../weakref_finalize.cpython-310.pyc | Bin 0 -> 4914 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 | 537 + .../pip/_vendor/urllib3/request.py | 191 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1115 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 3443 bytes .../util/__pycache__/proxy.cpython-310.pyc | Bin 0 -> 1348 bytes .../util/__pycache__/queue.cpython-310.pyc | Bin 0 -> 1070 bytes .../util/__pycache__/request.cpython-310.pyc | Bin 0 -> 3377 bytes .../util/__pycache__/response.cpython-310.pyc | Bin 0 -> 2363 bytes .../util/__pycache__/retry.cpython-310.pyc | Bin 0 -> 16163 bytes .../util/__pycache__/ssl_.cpython-310.pyc | Bin 0 -> 11315 bytes .../ssl_match_hostname.cpython-310.pyc | Bin 0 -> 3267 bytes .../__pycache__/ssltransport.cpython-310.pyc | Bin 0 -> 7405 bytes .../util/__pycache__/timeout.cpython-310.pyc | Bin 0 -> 9142 bytes .../util/__pycache__/url.cpython-310.pyc | Bin 0 -> 10719 bytes .../util/__pycache__/wait.cpython-310.pyc | Bin 0 -> 3099 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 620 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 9752 bytes .../__pycache__/labels.cpython-310.pyc | Bin 0 -> 5242 bytes .../__pycache__/mklabels.cpython-310.pyc | Bin 0 -> 1947 bytes .../__pycache__/tests.cpython-310.pyc | Bin 0 -> 5049 bytes .../x_user_defined.cpython-310.pyc | Bin 0 -> 2598 bytes .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../lib/python3.10/site-packages/pip/py.typed | 4 + .../site-packages/pkg_resources/__init__.py | 3296 +++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 100566 bytes .../pkg_resources/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 198 bytes .../__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 20259 bytes .../_vendor/__pycache__/zipp.cpython-310.pyc | Bin 0 -> 10241 bytes .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/importlib_resources/__init__.py | 36 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 653 bytes .../__pycache__/_adapters.cpython-310.pyc | Bin 0 -> 7361 bytes .../__pycache__/_common.cpython-310.pyc | Bin 0 -> 2651 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 3511 bytes .../__pycache__/_itertools.cpython-310.pyc | Bin 0 -> 898 bytes .../__pycache__/_legacy.cpython-310.pyc | Bin 0 -> 4234 bytes .../__pycache__/abc.cpython-310.pyc | Bin 0 -> 5387 bytes .../__pycache__/readers.cpython-310.pyc | Bin 0 -> 5471 bytes .../__pycache__/simple.cpython-310.pyc | Bin 0 -> 4735 bytes .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 104 + .../_vendor/importlib_resources/_compat.py | 98 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 121 + .../_vendor/importlib_resources/abc.py | 137 + .../_vendor/importlib_resources/readers.py | 122 + .../_vendor/importlib_resources/simple.py | 116 + .../pkg_resources/_vendor/jaraco/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 205 bytes .../__pycache__/context.cpython-310.pyc | Bin 0 -> 6337 bytes .../__pycache__/functools.cpython-310.pyc | Bin 0 -> 15629 bytes .../pkg_resources/_vendor/jaraco/context.py | 213 + .../pkg_resources/_vendor/jaraco/functools.py | 525 + .../_vendor/jaraco/text/__init__.py | 599 ++ .../text/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 19674 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 280 bytes .../__pycache__/more.cpython-310.pyc | Bin 0 -> 123053 bytes .../__pycache__/recipes.cpython-310.pyc | Bin 0 -> 20341 bytes .../_vendor/more_itertools/more.py | 4316 +++++++++ .../_vendor/more_itertools/recipes.py | 698 ++ .../_vendor/packaging/__about__.py | 26 + .../_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 605 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 461 bytes .../__pycache__/_manylinux.cpython-310.pyc | Bin 0 -> 7315 bytes .../__pycache__/_musllinux.cpython-310.pyc | Bin 0 -> 4627 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2720 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9311 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 3999 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 21542 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 12205 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 3590 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 12940 bytes .../_vendor/packaging/_manylinux.py | 301 + .../_vendor/packaging/_musllinux.py | 136 + .../_vendor/packaging/_structures.py | 61 + .../_vendor/packaging/markers.py | 304 + .../_vendor/packaging/requirements.py | 146 + .../_vendor/packaging/specifiers.py | 802 ++ .../pkg_resources/_vendor/packaging/tags.py | 487 + .../pkg_resources/_vendor/packaging/utils.py | 136 + .../_vendor/packaging/version.py | 504 + .../_vendor/pyparsing/__init__.py | 331 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 7132 bytes .../__pycache__/actions.cpython-310.pyc | Bin 0 -> 7194 bytes .../__pycache__/common.cpython-310.pyc | Bin 0 -> 10120 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 176437 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 9078 bytes .../__pycache__/helpers.cpython-310.pyc | Bin 0 -> 35355 bytes .../__pycache__/results.cpython-310.pyc | Bin 0 -> 24796 bytes .../__pycache__/testing.cpython-310.pyc | Bin 0 -> 12112 bytes .../__pycache__/unicode.cpython-310.pyc | Bin 0 -> 10073 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 8620 bytes .../_vendor/pyparsing/actions.py | 207 + .../pkg_resources/_vendor/pyparsing/common.py | 424 + .../pkg_resources/_vendor/pyparsing/core.py | 5814 +++++++++++ .../_vendor/pyparsing/diagram/__init__.py | 642 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 16572 bytes .../_vendor/pyparsing/exceptions.py | 267 + .../_vendor/pyparsing/helpers.py | 1088 +++ .../_vendor/pyparsing/results.py | 760 ++ .../_vendor/pyparsing/testing.py | 331 + .../_vendor/pyparsing/unicode.py | 352 + .../pkg_resources/_vendor/pyparsing/util.py | 235 + .../pkg_resources/_vendor/zipp.py | 329 + .../pkg_resources/extern/__init__.py | 76 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2951 bytes .../pydantic-2.6.4.dist-info/INSTALLER | 1 + .../pydantic-2.6.4.dist-info/METADATA | 890 ++ .../pydantic-2.6.4.dist-info/RECORD | 201 + .../pydantic-2.6.4.dist-info/WHEEL | 4 + .../pydantic-2.6.4.dist-info/licenses/LICENSE | 21 + .../site-packages/pydantic/__init__.py | 388 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 6876 bytes .../__pycache__/_migration.cpython-310.pyc | Bin 0 -> 10165 bytes .../alias_generators.cpython-310.pyc | Bin 0 -> 2068 bytes .../__pycache__/aliases.cpython-310.pyc | Bin 0 -> 4684 bytes .../annotated_handlers.cpython-310.pyc | Bin 0 -> 5288 bytes .../class_validators.cpython-310.pyc | Bin 0 -> 351 bytes .../__pycache__/color.cpython-310.pyc | Bin 0 -> 22268 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 2949 bytes .../__pycache__/dataclasses.cpython-310.pyc | Bin 0 -> 9796 bytes .../datetime_parse.cpython-310.pyc | Bin 0 -> 351 bytes .../__pycache__/decorator.cpython-310.pyc | Bin 0 -> 341 bytes .../__pycache__/env_settings.cpython-310.pyc | Bin 0 -> 347 bytes .../error_wrappers.cpython-310.pyc | Bin 0 -> 351 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 5348 bytes .../__pycache__/fields.cpython-310.pyc | Bin 0 -> 38449 bytes .../functional_serializers.cpython-310.pyc | Bin 0 -> 13570 bytes .../functional_validators.cpython-310.pyc | Bin 0 -> 22398 bytes .../__pycache__/generics.cpython-310.pyc | Bin 0 -> 339 bytes .../pydantic/__pycache__/json.cpython-310.pyc | Bin 0 -> 331 bytes .../__pycache__/json_schema.cpython-310.pyc | Bin 0 -> 77817 bytes .../pydantic/__pycache__/main.cpython-310.pyc | Bin 0 -> 45299 bytes .../pydantic/__pycache__/mypy.cpython-310.pyc | Bin 0 -> 39220 bytes .../__pycache__/networks.cpython-310.pyc | Bin 0 -> 13643 bytes .../__pycache__/parse.cpython-310.pyc | Bin 0 -> 333 bytes .../__pycache__/root_model.cpython-310.pyc | Bin 0 -> 5699 bytes .../__pycache__/schema.cpython-310.pyc | Bin 0 -> 335 bytes .../__pycache__/tools.cpython-310.pyc | Bin 0 -> 333 bytes .../__pycache__/type_adapter.cpython-310.pyc | Bin 0 -> 16930 bytes .../__pycache__/types.cpython-310.pyc | Bin 0 -> 67178 bytes .../__pycache__/typing.cpython-310.pyc | Bin 0 -> 331 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 333 bytes .../validate_call_decorator.cpython-310.pyc | Bin 0 -> 2479 bytes .../__pycache__/validators.cpython-310.pyc | Bin 0 -> 343 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 2771 bytes .../__pycache__/warnings.cpython-310.pyc | Bin 0 -> 3153 bytes .../pydantic/_internal/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 196 bytes .../__pycache__/_config.cpython-310.pyc | Bin 0 -> 11153 bytes .../_core_metadata.cpython-310.pyc | Bin 0 -> 3302 bytes .../__pycache__/_core_utils.cpython-310.pyc | Bin 0 -> 18658 bytes .../__pycache__/_dataclasses.cpython-310.pyc | Bin 0 -> 7835 bytes .../__pycache__/_decorators.cpython-310.pyc | Bin 0 -> 26472 bytes .../_decorators_v1.cpython-310.pyc | Bin 0 -> 7354 bytes .../_discriminated_union.cpython-310.pyc | Bin 0 -> 15822 bytes .../__pycache__/_fields.cpython-310.pyc | Bin 0 -> 8957 bytes .../__pycache__/_forward_ref.cpython-310.pyc | Bin 0 -> 1191 bytes .../_generate_schema.cpython-310.pyc | Bin 0 -> 66394 bytes .../__pycache__/_generics.cpython-310.pyc | Bin 0 -> 17743 bytes .../__pycache__/_git.cpython-310.pyc | Bin 0 -> 1202 bytes .../_internal_dataclass.cpython-310.pyc | Bin 0 -> 409 bytes .../_known_annotated_metadata.cpython-310.pyc | Bin 0 -> 10497 bytes .../__pycache__/_mock_val_ser.cpython-310.pyc | Bin 0 -> 4600 bytes .../_model_construction.cpython-310.pyc | Bin 0 -> 20188 bytes .../__pycache__/_repr.cpython-310.pyc | Bin 0 -> 4963 bytes .../_schema_generation_shared.cpython-310.pyc | Bin 0 -> 5224 bytes .../__pycache__/_signature.cpython-310.pyc | Bin 0 -> 4718 bytes .../_std_types_schema.cpython-310.pyc | Bin 0 -> 19986 bytes .../__pycache__/_typing_extra.cpython-310.pyc | Bin 0 -> 14612 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 12373 bytes .../_validate_call.cpython-310.pyc | Bin 0 -> 2591 bytes .../__pycache__/_validators.cpython-310.pyc | Bin 0 -> 8456 bytes .../pydantic/_internal/_config.py | 322 + .../pydantic/_internal/_core_metadata.py | 92 + .../pydantic/_internal/_core_utils.py | 570 ++ .../pydantic/_internal/_dataclasses.py | 225 + .../pydantic/_internal/_decorators.py | 791 ++ .../pydantic/_internal/_decorators_v1.py | 181 + .../_internal/_discriminated_union.py | 506 + .../pydantic/_internal/_fields.py | 319 + .../pydantic/_internal/_forward_ref.py | 23 + .../pydantic/_internal/_generate_schema.py | 2231 +++++ .../pydantic/_internal/_generics.py | 517 + .../site-packages/pydantic/_internal/_git.py | 26 + .../pydantic/_internal/_internal_dataclass.py | 10 + .../_internal/_known_annotated_metadata.py | 410 + .../pydantic/_internal/_mock_val_ser.py | 140 + .../pydantic/_internal/_model_construction.py | 637 ++ .../site-packages/pydantic/_internal/_repr.py | 117 + .../_internal/_schema_generation_shared.py | 124 + .../pydantic/_internal/_signature.py | 164 + .../pydantic/_internal/_std_types_schema.py | 714 ++ .../pydantic/_internal/_typing_extra.py | 469 + .../pydantic/_internal/_utils.py | 362 + .../pydantic/_internal/_validate_call.py | 84 + .../pydantic/_internal/_validators.py | 278 + .../site-packages/pydantic/_migration.py | 308 + .../pydantic/alias_generators.py | 50 + .../site-packages/pydantic/aliases.py | 112 + .../pydantic/annotated_handlers.py | 120 + .../pydantic/class_validators.py | 4 + .../site-packages/pydantic/color.py | 603 ++ .../site-packages/pydantic/config.py | 912 ++ .../site-packages/pydantic/dataclasses.py | 327 + .../site-packages/pydantic/datetime_parse.py | 4 + .../site-packages/pydantic/decorator.py | 4 + .../pydantic/deprecated/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 197 bytes .../class_validators.cpython-310.pyc | Bin 0 -> 9797 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 3129 bytes .../copy_internals.cpython-310.pyc | Bin 0 -> 5183 bytes .../__pycache__/decorator.cpython-310.pyc | Bin 0 -> 8736 bytes .../__pycache__/json.cpython-310.pyc | Bin 0 -> 4249 bytes .../__pycache__/parse.cpython-310.pyc | Bin 0 -> 2262 bytes .../__pycache__/tools.cpython-310.pyc | Bin 0 -> 2717 bytes .../pydantic/deprecated/class_validators.py | 253 + .../pydantic/deprecated/config.py | 72 + .../pydantic/deprecated/copy_internals.py | 224 + .../pydantic/deprecated/decorator.py | 279 + .../site-packages/pydantic/deprecated/json.py | 140 + .../pydantic/deprecated/parse.py | 80 + .../pydantic/deprecated/tools.py | 103 + .../site-packages/pydantic/env_settings.py | 4 + .../site-packages/pydantic/error_wrappers.py | 4 + .../site-packages/pydantic/errors.py | 152 + .../site-packages/pydantic/fields.py | 1154 +++ .../pydantic/functional_serializers.py | 395 + .../pydantic/functional_validators.py | 706 ++ .../site-packages/pydantic/generics.py | 4 + .../python3.10/site-packages/pydantic/json.py | 4 + .../site-packages/pydantic/json_schema.py | 2425 +++++ .../python3.10/site-packages/pydantic/main.py | 1500 +++ .../python3.10/site-packages/pydantic/mypy.py | 1287 +++ .../site-packages/pydantic/networks.py | 708 ++ .../site-packages/pydantic/parse.py | 4 + .../site-packages/pydantic/plugin/__init__.py | 170 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 7320 bytes .../__pycache__/_loader.cpython-310.pyc | Bin 0 -> 1446 bytes .../_schema_validator.cpython-310.pyc | Bin 0 -> 4910 bytes .../site-packages/pydantic/plugin/_loader.py | 50 + .../pydantic/plugin/_schema_validator.py | 138 + .../site-packages/pydantic/py.typed | 0 .../site-packages/pydantic/root_model.py | 149 + .../site-packages/pydantic/schema.py | 4 + .../site-packages/pydantic/tools.py | 4 + .../site-packages/pydantic/type_adapter.py | 460 + .../site-packages/pydantic/types.py | 2879 ++++++ .../site-packages/pydantic/typing.py | 4 + .../site-packages/pydantic/utils.py | 4 + .../site-packages/pydantic/v1/__init__.py | 131 + .../v1/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1999 bytes .../_hypothesis_plugin.cpython-310.pyc | Bin 0 -> 10261 bytes .../annotated_types.cpython-310.pyc | Bin 0 -> 3153 bytes .../class_validators.cpython-310.pyc | Bin 0 -> 13605 bytes .../v1/__pycache__/color.cpython-310.pyc | Bin 0 -> 18077 bytes .../v1/__pycache__/config.cpython-310.pyc | Bin 0 -> 6049 bytes .../__pycache__/dataclasses.cpython-310.pyc | Bin 0 -> 15108 bytes .../datetime_parse.cpython-310.pyc | Bin 0 -> 6636 bytes .../v1/__pycache__/decorator.cpython-310.pyc | Bin 0 -> 8730 bytes .../__pycache__/env_settings.cpython-310.pyc | Bin 0 -> 11857 bytes .../error_wrappers.cpython-310.pyc | Bin 0 -> 5932 bytes .../v1/__pycache__/errors.cpython-310.pyc | Bin 0 -> 22700 bytes .../v1/__pycache__/fields.cpython-310.pyc | Bin 0 -> 34748 bytes .../v1/__pycache__/generics.cpython-310.pyc | Bin 0 -> 11407 bytes .../v1/__pycache__/json.cpython-310.pyc | Bin 0 -> 3612 bytes .../v1/__pycache__/main.cpython-310.pyc | Bin 0 -> 29577 bytes .../v1/__pycache__/mypy.cpython-310.pyc | Bin 0 -> 29194 bytes .../v1/__pycache__/networks.cpython-310.pyc | Bin 0 -> 20179 bytes .../v1/__pycache__/parse.cpython-310.pyc | Bin 0 -> 1784 bytes .../v1/__pycache__/schema.cpython-310.pyc | Bin 0 -> 32606 bytes .../v1/__pycache__/tools.cpython-310.pyc | Bin 0 -> 2774 bytes .../v1/__pycache__/types.cpython-310.pyc | Bin 0 -> 32729 bytes .../v1/__pycache__/typing.cpython-310.pyc | Bin 0 -> 14682 bytes .../v1/__pycache__/utils.cpython-310.pyc | Bin 0 -> 25581 bytes .../v1/__pycache__/validators.cpython-310.pyc | Bin 0 -> 18413 bytes .../v1/__pycache__/version.cpython-310.pyc | Bin 0 -> 1308 bytes .../pydantic/v1/_hypothesis_plugin.py | 391 + .../pydantic/v1/annotated_types.py | 72 + .../pydantic/v1/class_validators.py | 361 + .../site-packages/pydantic/v1/color.py | 494 + .../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 + .../site-packages/pydantic/v1/errors.py | 646 ++ .../site-packages/pydantic/v1/fields.py | 1253 +++ .../site-packages/pydantic/v1/generics.py | 400 + .../site-packages/pydantic/v1/json.py | 112 + .../site-packages/pydantic/v1/main.py | 1107 +++ .../site-packages/pydantic/v1/mypy.py | 944 ++ .../site-packages/pydantic/v1/networks.py | 747 ++ .../site-packages/pydantic/v1/parse.py | 66 + .../site-packages/pydantic/v1/py.typed | 0 .../site-packages/pydantic/v1/schema.py | 1163 +++ .../site-packages/pydantic/v1/tools.py | 92 + .../site-packages/pydantic/v1/types.py | 1205 +++ .../site-packages/pydantic/v1/typing.py | 603 ++ .../site-packages/pydantic/v1/utils.py | 803 ++ .../site-packages/pydantic/v1/validators.py | 765 ++ .../site-packages/pydantic/v1/version.py | 38 + .../pydantic/validate_call_decorator.py | 67 + .../site-packages/pydantic/validators.py | 4 + .../site-packages/pydantic/version.py | 80 + .../site-packages/pydantic/warnings.py | 58 + .../pydantic_core-2.16.3.dist-info/INSTALLER | 1 + .../pydantic_core-2.16.3.dist-info/METADATA | 159 + .../pydantic_core-2.16.3.dist-info/RECORD | 12 + .../pydantic_core-2.16.3.dist-info/WHEEL | 4 + .../license_files/LICENSE | 21 + .../site-packages/pydantic_core/__init__.py | 139 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2740 bytes .../__pycache__/core_schema.cpython-310.pyc | Bin 0 -> 118405 bytes ...antic_core.cpython-310-x86_64-linux-gnu.so | Bin 0 -> 5454120 bytes .../pydantic_core/_pydantic_core.pyi | 882 ++ .../pydantic_core/core_schema.py | 3980 ++++++++ .../site-packages/pydantic_core/py.typed | 0 .../INSTALLER | 1 + .../python_multipart-0.0.9.dist-info/METADATA | 70 + .../python_multipart-0.0.9.dist-info/RECORD | 14 + .../REQUESTED | 0 .../python_multipart-0.0.9.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 14 + .../setuptools-65.5.0.dist-info/INSTALLER | 1 + .../setuptools-65.5.0.dist-info/LICENSE | 19 + .../setuptools-65.5.0.dist-info/METADATA | 144 + .../setuptools-65.5.0.dist-info/RECORD | 466 + .../setuptools-65.5.0.dist-info/REQUESTED | 0 .../setuptools-65.5.0.dist-info/WHEEL | 5 + .../entry_points.txt | 57 + .../setuptools-65.5.0.dist-info/top_level.txt | 3 + .../site-packages/setuptools/__init__.py | 247 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 9509 bytes .../_deprecation_warning.cpython-310.pyc | Bin 0 -> 559 bytes .../__pycache__/_entry_points.cpython-310.pyc | Bin 0 -> 3022 bytes .../__pycache__/_imp.cpython-310.pyc | Bin 0 -> 2085 bytes .../__pycache__/_importlib.cpython-310.pyc | Bin 0 -> 1355 bytes .../__pycache__/_itertools.cpython-310.pyc | Bin 0 -> 923 bytes .../__pycache__/_path.cpython-310.pyc | Bin 0 -> 1098 bytes .../__pycache__/_reqs.cpython-310.pyc | Bin 0 -> 838 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 6189 bytes .../__pycache__/build_meta.cpython-310.pyc | Bin 0 -> 18097 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 866 bytes .../__pycache__/depends.cpython-310.pyc | Bin 0 -> 5305 bytes .../__pycache__/discovery.cpython-310.pyc | Bin 0 -> 20596 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 38385 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 2493 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 5906 bytes .../__pycache__/glob.cpython-310.pyc | Bin 0 -> 3744 bytes .../__pycache__/installer.cpython-310.pyc | Bin 0 -> 2990 bytes .../__pycache__/launch.cpython-310.pyc | Bin 0 -> 916 bytes .../__pycache__/logging.cpython-310.pyc | Bin 0 -> 1253 bytes .../__pycache__/monkey.cpython-310.pyc | Bin 0 -> 4449 bytes .../__pycache__/msvc.cpython-310.pyc | Bin 0 -> 40632 bytes .../__pycache__/namespaces.cpython-310.pyc | Bin 0 -> 3627 bytes .../__pycache__/package_index.cpython-310.pyc | Bin 0 -> 32694 bytes .../__pycache__/py34compat.cpython-310.pyc | Bin 0 -> 491 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 15767 bytes .../__pycache__/unicode_utils.cpython-310.pyc | Bin 0 -> 1121 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 333 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 7601 bytes .../windows_support.cpython-310.pyc | Bin 0 -> 1039 bytes .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 24 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 567 bytes .../__pycache__/_collections.cpython-310.pyc | Bin 0 -> 2068 bytes .../__pycache__/_functools.cpython-310.pyc | Bin 0 -> 698 bytes .../__pycache__/_macos_compat.cpython-310.pyc | Bin 0 -> 462 bytes .../__pycache__/_msvccompiler.cpython-310.pyc | Bin 0 -> 13662 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 6566 bytes .../__pycache__/bcppcompiler.cpython-310.pyc | Bin 0 -> 6822 bytes .../__pycache__/ccompiler.cpython-310.pyc | Bin 0 -> 34188 bytes .../__pycache__/cmd.cpython-310.pyc | Bin 0 -> 13997 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 3587 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 7216 bytes .../cygwinccompiler.cpython-310.pyc | Bin 0 -> 8389 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 261 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 2778 bytes .../__pycache__/dir_util.cpython-310.pyc | Bin 0 -> 6120 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 34586 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 5003 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 7031 bytes .../__pycache__/fancy_getopt.cpython-310.pyc | Bin 0 -> 10700 bytes .../__pycache__/file_util.cpython-310.pyc | Bin 0 -> 5994 bytes .../__pycache__/filelist.cpython-310.pyc | Bin 0 -> 10822 bytes .../__pycache__/log.cpython-310.pyc | Bin 0 -> 2318 bytes .../__pycache__/msvc9compiler.cpython-310.pyc | Bin 0 -> 17792 bytes .../__pycache__/msvccompiler.cpython-310.pyc | Bin 0 -> 15024 bytes .../__pycache__/py38compat.cpython-310.pyc | Bin 0 -> 442 bytes .../__pycache__/py39compat.cpython-310.pyc | Bin 0 -> 743 bytes .../__pycache__/spawn.cpython-310.pyc | Bin 0 -> 2883 bytes .../__pycache__/sysconfig.cpython-310.pyc | Bin 0 -> 13177 bytes .../__pycache__/text_file.cpython-310.pyc | Bin 0 -> 8240 bytes .../__pycache__/unixccompiler.cpython-310.pyc | Bin 0 -> 10962 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 13512 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 7844 bytes .../versionpredicate.cpython-310.pyc | Bin 0 -> 5336 bytes .../setuptools/_distutils/_collections.py | 56 + .../setuptools/_distutils/_functools.py | 20 + .../setuptools/_distutils/_macos_compat.py | 12 + .../setuptools/_distutils/_msvccompiler.py | 572 ++ .../setuptools/_distutils/archive_util.py | 280 + .../setuptools/_distutils/bcppcompiler.py | 408 + .../setuptools/_distutils/ccompiler.py | 1220 +++ .../setuptools/_distutils/cmd.py | 436 + .../setuptools/_distutils/command/__init__.py | 25 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 525 bytes .../_framework_compat.cpython-310.pyc | Bin 0 -> 1932 bytes .../command/__pycache__/bdist.cpython-310.pyc | Bin 0 -> 3990 bytes .../__pycache__/bdist_dumb.cpython-310.pyc | Bin 0 -> 3662 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 12352 bytes .../command/__pycache__/build.cpython-310.pyc | Bin 0 -> 3916 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 4882 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 16320 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 9818 bytes .../__pycache__/build_scripts.cpython-310.pyc | Bin 0 -> 4609 bytes .../command/__pycache__/check.cpython-310.pyc | Bin 0 -> 4669 bytes .../command/__pycache__/clean.cpython-310.pyc | Bin 0 -> 2141 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 10373 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 17217 bytes .../__pycache__/install_data.cpython-310.pyc | Bin 0 -> 2362 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 3327 bytes .../install_headers.cpython-310.pyc | Bin 0 -> 1777 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 5205 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2210 bytes .../__pycache__/py37compat.cpython-310.pyc | Bin 0 -> 1049 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 8564 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 14519 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 5372 bytes .../_distutils/command/_framework_compat.py | 55 + .../setuptools/_distutils/command/bdist.py | 157 + .../_distutils/command/bdist_dumb.py | 144 + .../_distutils/command/bdist_rpm.py | 615 ++ .../setuptools/_distutils/command/build.py | 153 + .../_distutils/command/build_clib.py | 208 + .../_distutils/command/build_ext.py | 787 ++ .../setuptools/_distutils/command/build_py.py | 407 + .../_distutils/command/build_scripts.py | 173 + .../setuptools/_distutils/command/check.py | 151 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 377 + .../setuptools/_distutils/command/install.py | 814 ++ .../_distutils/command/install_data.py | 84 + .../_distutils/command/install_egg_info.py | 91 + .../_distutils/command/install_headers.py | 45 + .../_distutils/command/install_lib.py | 238 + .../_distutils/command/install_scripts.py | 61 + .../_distutils/command/py37compat.py | 31 + .../setuptools/_distutils/command/register.py | 319 + .../setuptools/_distutils/command/sdist.py | 531 + .../setuptools/_distutils/command/upload.py | 205 + .../setuptools/_distutils/config.py | 139 + .../setuptools/_distutils/core.py | 291 + .../setuptools/_distutils/cygwinccompiler.py | 364 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 96 + .../setuptools/_distutils/dir_util.py | 243 + .../setuptools/_distutils/dist.py | 1286 +++ .../setuptools/_distutils/errors.py | 127 + .../setuptools/_distutils/extension.py | 248 + .../setuptools/_distutils/fancy_getopt.py | 470 + .../setuptools/_distutils/file_util.py | 249 + .../setuptools/_distutils/filelist.py | 371 + .../setuptools/_distutils/log.py | 80 + .../setuptools/_distutils/msvc9compiler.py | 832 ++ .../setuptools/_distutils/msvccompiler.py | 695 ++ .../setuptools/_distutils/py38compat.py | 8 + .../setuptools/_distutils/py39compat.py | 22 + .../setuptools/_distutils/spawn.py | 109 + .../setuptools/_distutils/sysconfig.py | 558 ++ .../setuptools/_distutils/text_file.py | 287 + .../setuptools/_distutils/unixccompiler.py | 401 + .../setuptools/_distutils/util.py | 513 + .../setuptools/_distutils/version.py | 358 + .../setuptools/_distutils/versionpredicate.py | 175 + .../site-packages/setuptools/_entry_points.py | 86 + .../site-packages/setuptools/_imp.py | 82 + .../site-packages/setuptools/_importlib.py | 47 + .../site-packages/setuptools/_itertools.py | 23 + .../site-packages/setuptools/_path.py | 29 + .../site-packages/setuptools/_reqs.py | 19 + .../setuptools/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 195 bytes .../__pycache__/ordered_set.cpython-310.pyc | Bin 0 -> 16331 bytes .../typing_extensions.cpython-310.pyc | Bin 0 -> 66589 bytes .../_vendor/__pycache__/zipp.cpython-310.pyc | Bin 0 -> 10238 bytes .../_vendor/importlib_metadata/__init__.py | 1047 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 37428 bytes .../__pycache__/_adapters.cpython-310.pyc | Bin 0 -> 2415 bytes .../__pycache__/_collections.cpython-310.pyc | Bin 0 -> 1590 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 2079 bytes .../__pycache__/_functools.cpython-310.pyc | Bin 0 -> 3180 bytes .../__pycache__/_itertools.cpython-310.pyc | Bin 0 -> 2061 bytes .../__pycache__/_meta.cpython-310.pyc | Bin 0 -> 2369 bytes .../__pycache__/_text.cpython-310.pyc | Bin 0 -> 3113 bytes .../_vendor/importlib_metadata/_adapters.py | 68 + .../importlib_metadata/_collections.py | 30 + .../_vendor/importlib_metadata/_compat.py | 71 + .../_vendor/importlib_metadata/_functools.py | 104 + .../_vendor/importlib_metadata/_itertools.py | 73 + .../_vendor/importlib_metadata/_meta.py | 48 + .../_vendor/importlib_metadata/_text.py | 99 + .../_vendor/importlib_resources/__init__.py | 36 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 650 bytes .../__pycache__/_adapters.cpython-310.pyc | Bin 0 -> 7358 bytes .../__pycache__/_common.cpython-310.pyc | Bin 0 -> 2648 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 3508 bytes .../__pycache__/_itertools.cpython-310.pyc | Bin 0 -> 895 bytes .../__pycache__/_legacy.cpython-310.pyc | Bin 0 -> 4231 bytes .../__pycache__/abc.cpython-310.pyc | Bin 0 -> 5384 bytes .../__pycache__/readers.cpython-310.pyc | Bin 0 -> 5468 bytes .../__pycache__/simple.cpython-310.pyc | Bin 0 -> 4732 bytes .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 104 + .../_vendor/importlib_resources/_compat.py | 98 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 121 + .../_vendor/importlib_resources/abc.py | 137 + .../_vendor/importlib_resources/readers.py | 122 + .../_vendor/importlib_resources/simple.py | 116 + .../setuptools/_vendor/jaraco/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 202 bytes .../__pycache__/context.cpython-310.pyc | Bin 0 -> 6334 bytes .../__pycache__/functools.cpython-310.pyc | Bin 0 -> 15620 bytes .../setuptools/_vendor/jaraco/context.py | 213 + .../setuptools/_vendor/jaraco/functools.py | 525 + .../_vendor/jaraco/text/__init__.py | 599 ++ .../text/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 19662 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 276 bytes .../__pycache__/more.cpython-310.pyc | Bin 0 -> 109997 bytes .../__pycache__/recipes.cpython-310.pyc | Bin 0 -> 17976 bytes .../setuptools/_vendor/more_itertools/more.py | 3824 ++++++++ .../_vendor/more_itertools/recipes.py | 620 ++ .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 26 + .../setuptools/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 602 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 458 bytes .../__pycache__/_manylinux.cpython-310.pyc | Bin 0 -> 7312 bytes .../__pycache__/_musllinux.cpython-310.pyc | Bin 0 -> 4624 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2717 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9305 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 3993 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 21539 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 12202 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 3587 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 12937 bytes .../_vendor/packaging/_manylinux.py | 301 + .../_vendor/packaging/_musllinux.py | 136 + .../_vendor/packaging/_structures.py | 61 + .../setuptools/_vendor/packaging/markers.py | 304 + .../_vendor/packaging/requirements.py | 146 + .../_vendor/packaging/specifiers.py | 802 ++ .../setuptools/_vendor/packaging/tags.py | 487 + .../setuptools/_vendor/packaging/utils.py | 136 + .../setuptools/_vendor/packaging/version.py | 504 + .../setuptools/_vendor/pyparsing/__init__.py | 331 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 7129 bytes .../__pycache__/actions.cpython-310.pyc | Bin 0 -> 7191 bytes .../__pycache__/common.cpython-310.pyc | Bin 0 -> 10117 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 176434 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 9075 bytes .../__pycache__/helpers.cpython-310.pyc | Bin 0 -> 35352 bytes .../__pycache__/results.cpython-310.pyc | Bin 0 -> 24793 bytes .../__pycache__/testing.cpython-310.pyc | Bin 0 -> 12109 bytes .../__pycache__/unicode.cpython-310.pyc | Bin 0 -> 10070 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 8617 bytes .../setuptools/_vendor/pyparsing/actions.py | 207 + .../setuptools/_vendor/pyparsing/common.py | 424 + .../setuptools/_vendor/pyparsing/core.py | 5814 +++++++++++ .../_vendor/pyparsing/diagram/__init__.py | 642 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 16569 bytes .../_vendor/pyparsing/exceptions.py | 267 + .../setuptools/_vendor/pyparsing/helpers.py | 1088 +++ .../setuptools/_vendor/pyparsing/results.py | 760 ++ .../setuptools/_vendor/pyparsing/testing.py | 331 + .../setuptools/_vendor/pyparsing/unicode.py | 352 + .../setuptools/_vendor/pyparsing/util.py | 235 + .../setuptools/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 367 bytes .../tomli/__pycache__/_parser.cpython-310.pyc | Bin 0 -> 17081 bytes .../tomli/__pycache__/_re.cpython-310.pyc | Bin 0 -> 2913 bytes .../tomli/__pycache__/_types.cpython-310.pyc | Bin 0 -> 337 bytes .../setuptools/_vendor/tomli/_parser.py | 691 ++ .../setuptools/_vendor/tomli/_re.py | 107 + .../setuptools/_vendor/tomli/_types.py | 10 + .../setuptools/_vendor/typing_extensions.py | 2296 +++++ .../site-packages/setuptools/_vendor/zipp.py | 329 + .../site-packages/setuptools/archive_util.py | 213 + .../site-packages/setuptools/build_meta.py | 511 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli-arm64.exe | Bin 0 -> 137216 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 12 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 453 bytes .../command/__pycache__/alias.cpython-310.pyc | Bin 0 -> 2386 bytes .../__pycache__/bdist_egg.cpython-310.pyc | Bin 0 -> 13136 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 1599 bytes .../command/__pycache__/build.cpython-310.pyc | Bin 0 -> 6096 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 2473 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 12083 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 13953 bytes .../__pycache__/develop.cpython-310.pyc | Bin 0 -> 6162 bytes .../__pycache__/dist_info.cpython-310.pyc | Bin 0 -> 4748 bytes .../__pycache__/easy_install.cpython-310.pyc | Bin 0 -> 64431 bytes .../editable_wheel.cpython-310.pyc | Bin 0 -> 31926 bytes .../__pycache__/egg_info.cpython-310.pyc | Bin 0 -> 23293 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 4295 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 2469 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 4181 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2463 bytes .../__pycache__/py36compat.cpython-310.pyc | Bin 0 -> 4546 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 850 bytes .../__pycache__/rotate.cpython-310.pyc | Bin 0 -> 2517 bytes .../__pycache__/saveopts.cpython-310.pyc | Bin 0 -> 936 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 7862 bytes .../__pycache__/setopt.cpython-310.pyc | Bin 0 -> 4698 bytes .../command/__pycache__/test.cpython-310.pyc | Bin 0 -> 8199 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 823 bytes .../__pycache__/upload_docs.cpython-310.pyc | Bin 0 -> 6410 bytes .../site-packages/setuptools/command/alias.py | 78 + .../setuptools/command/bdist_egg.py | 457 + .../setuptools/command/bdist_rpm.py | 40 + .../site-packages/setuptools/command/build.py | 146 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 383 + .../setuptools/command/build_py.py | 368 + .../setuptools/command/develop.py | 193 + .../setuptools/command/dist_info.py | 142 + .../setuptools/command/easy_install.py | 2312 +++++ .../setuptools/command/editable_wheel.py | 844 ++ .../setuptools/command/egg_info.py | 763 ++ .../setuptools/command/install.py | 139 + .../setuptools/command/install_egg_info.py | 63 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 70 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 134 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 64 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 210 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 251 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 213 + .../setuptools/config/__init__.py | 35 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1452 bytes .../_apply_pyprojecttoml.cpython-310.pyc | Bin 0 -> 13535 bytes .../config/__pycache__/expand.cpython-310.pyc | Bin 0 -> 17594 bytes .../__pycache__/pyprojecttoml.cpython-310.pyc | Bin 0 -> 16332 bytes .../__pycache__/setupcfg.cpython-310.pyc | Bin 0 -> 22064 bytes .../setuptools/config/_apply_pyprojecttoml.py | 377 + .../config/_validate_pyproject/__init__.py | 34 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1527 bytes .../error_reporting.cpython-310.pyc | Bin 0 -> 11582 bytes .../extra_validations.cpython-310.pyc | Bin 0 -> 1422 bytes .../fastjsonschema_exceptions.cpython-310.pyc | Bin 0 -> 2459 bytes ...fastjsonschema_validations.cpython-310.pyc | Bin 0 -> 68726 bytes .../__pycache__/formats.cpython-310.pyc | Bin 0 -> 8593 bytes .../_validate_pyproject/error_reporting.py | 318 + .../_validate_pyproject/extra_validations.py | 36 + .../fastjsonschema_exceptions.py | 51 + .../fastjsonschema_validations.py | 1035 ++ .../config/_validate_pyproject/formats.py | 259 + .../site-packages/setuptools/config/expand.py | 462 + .../setuptools/config/pyprojecttoml.py | 493 + .../setuptools/config/setupcfg.py | 762 ++ .../site-packages/setuptools/dep_util.py | 25 + .../site-packages/setuptools/depends.py | 176 + .../site-packages/setuptools/discovery.py | 600 ++ .../site-packages/setuptools/dist.py | 1222 +++ .../site-packages/setuptools/errors.py | 58 + .../site-packages/setuptools/extension.py | 148 + .../setuptools/extern/__init__.py | 76 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3026 bytes .../site-packages/setuptools/glob.py | 167 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui-arm64.exe | Bin 0 -> 137728 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 104 + .../site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/logging.py | 36 + .../site-packages/setuptools/monkey.py | 165 + .../site-packages/setuptools/msvc.py | 1703 ++++ .../site-packages/setuptools/namespaces.py | 107 + .../site-packages/setuptools/package_index.py | 1126 +++ .../site-packages/setuptools/py34compat.py | 13 + .../site-packages/setuptools/sandbox.py | 530 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/unicode_utils.py | 42 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 222 + .../setuptools/windows_support.py | 29 + .../sniffio-1.3.1.dist-info/INSTALLER | 1 + .../sniffio-1.3.1.dist-info/LICENSE | 3 + .../sniffio-1.3.1.dist-info/LICENSE.APACHE2 | 202 + .../sniffio-1.3.1.dist-info/LICENSE.MIT | 20 + .../sniffio-1.3.1.dist-info/METADATA | 104 + .../sniffio-1.3.1.dist-info/RECORD | 19 + .../sniffio-1.3.1.dist-info/WHEEL | 5 + .../sniffio-1.3.1.dist-info/top_level.txt | 1 + .../site-packages/sniffio/__init__.py | 17 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 442 bytes .../sniffio/__pycache__/_impl.cpython-310.pyc | Bin 0 -> 2685 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 206 bytes .../python3.10/site-packages/sniffio/_impl.py | 95 + .../site-packages/sniffio/_tests/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 192 bytes .../__pycache__/test_sniffio.cpython-310.pyc | Bin 0 -> 2136 bytes .../sniffio/_tests/test_sniffio.py | 84 + .../site-packages/sniffio/_version.py | 3 + .../python3.10/site-packages/sniffio/py.typed | 0 .../starlette-0.37.2.dist-info/INSTALLER | 1 + .../starlette-0.37.2.dist-info/METADATA | 175 + .../starlette-0.37.2.dist-info/RECORD | 76 + .../starlette-0.37.2.dist-info/WHEEL | 4 + .../licenses/LICENSE.md | 27 + .../site-packages/starlette/__init__.py | 1 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 209 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 646 bytes .../_exception_handler.cpython-310.pyc | Bin 0 -> 2674 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 3739 bytes .../__pycache__/applications.cpython-310.pyc | Bin 0 -> 10430 bytes .../authentication.cpython-310.pyc | Bin 0 -> 5829 bytes .../__pycache__/background.cpython-310.pyc | Bin 0 -> 2031 bytes .../__pycache__/concurrency.cpython-310.pyc | Bin 0 -> 2271 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 5132 bytes .../__pycache__/convertors.cpython-310.pyc | Bin 0 -> 3798 bytes .../datastructures.cpython-310.pyc | Bin 0 -> 28010 bytes .../__pycache__/endpoints.cpython-310.pyc | Bin 0 -> 5175 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 2604 bytes .../__pycache__/formparsers.cpython-310.pyc | Bin 0 -> 8141 bytes .../__pycache__/requests.cpython-310.pyc | Bin 0 -> 10541 bytes .../__pycache__/responses.cpython-310.pyc | Bin 0 -> 11198 bytes .../__pycache__/routing.cpython-310.pyc | Bin 0 -> 28058 bytes .../__pycache__/schemas.cpython-310.pyc | Bin 0 -> 5020 bytes .../__pycache__/staticfiles.cpython-310.pyc | Bin 0 -> 7263 bytes .../__pycache__/status.cpython-310.pyc | Bin 0 -> 4476 bytes .../__pycache__/templating.cpython-310.pyc | Bin 0 -> 6621 bytes .../__pycache__/testclient.cpython-310.pyc | Bin 0 -> 21632 bytes .../__pycache__/types.cpython-310.pyc | Bin 0 -> 982 bytes .../__pycache__/websockets.cpython-310.pyc | Bin 0 -> 7567 bytes .../site-packages/starlette/_compat.py | 28 + .../starlette/_exception_handler.py | 87 + .../site-packages/starlette/_utils.py | 99 + .../site-packages/starlette/applications.py | 266 + .../site-packages/starlette/authentication.py | 155 + .../site-packages/starlette/background.py | 45 + .../site-packages/starlette/concurrency.py | 67 + .../site-packages/starlette/config.py | 153 + .../site-packages/starlette/convertors.py | 89 + .../site-packages/starlette/datastructures.py | 705 ++ .../site-packages/starlette/endpoints.py | 132 + .../site-packages/starlette/exceptions.py | 62 + .../site-packages/starlette/formparsers.py | 278 + .../starlette/middleware/__init__.py | 44 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2402 bytes .../authentication.cpython-310.pyc | Bin 0 -> 2152 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 7416 bytes .../__pycache__/cors.cpython-310.pyc | Bin 0 -> 5095 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 7562 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 2967 bytes .../__pycache__/gzip.cpython-310.pyc | Bin 0 -> 3412 bytes .../__pycache__/httpsredirect.cpython-310.pyc | Bin 0 -> 1313 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 3065 bytes .../__pycache__/trustedhost.cpython-310.pyc | Bin 0 -> 2129 bytes .../__pycache__/wsgi.cpython-310.pyc | Bin 0 -> 5370 bytes .../starlette/middleware/authentication.py | 53 + .../starlette/middleware/base.py | 217 + .../starlette/middleware/cors.py | 178 + .../starlette/middleware/errors.py | 261 + .../starlette/middleware/exceptions.py | 77 + .../starlette/middleware/gzip.py | 113 + .../starlette/middleware/httpsredirect.py | 19 + .../starlette/middleware/sessions.py | 85 + .../starlette/middleware/trustedhost.py | 62 + .../starlette/middleware/wsgi.py | 156 + .../site-packages/starlette/py.typed | 0 .../site-packages/starlette/requests.py | 320 + .../site-packages/starlette/responses.py | 360 + .../site-packages/starlette/routing.py | 922 ++ .../site-packages/starlette/schemas.py | 150 + .../site-packages/starlette/staticfiles.py | 239 + .../site-packages/starlette/status.py | 200 + .../site-packages/starlette/templating.py | 237 + .../site-packages/starlette/testclient.py | 839 ++ .../site-packages/starlette/types.py | 30 + .../site-packages/starlette/websockets.py | 224 + .../INSTALLER | 1 + .../LICENSE | 279 + .../METADATA | 66 + .../typing_extensions-4.11.0.dist-info/RECORD | 7 + .../typing_extensions-4.11.0.dist-info/WHEEL | 4 + .../site-packages/typing_extensions.py | 3332 +++++++ .../uvicorn-0.29.0.dist-info/INSTALLER | 1 + .../uvicorn-0.29.0.dist-info/METADATA | 181 + .../uvicorn-0.29.0.dist-info/RECORD | 87 + .../uvicorn-0.29.0.dist-info/REQUESTED | 0 .../uvicorn-0.29.0.dist-info/WHEEL | 4 + .../uvicorn-0.29.0.dist-info/entry_points.txt | 2 + .../licenses/LICENSE.md | 27 + .../site-packages/uvicorn/__init__.py | 5 + .../site-packages/uvicorn/__main__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 370 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 256 bytes .../__pycache__/_subprocess.cpython-310.pyc | Bin 0 -> 2365 bytes .../__pycache__/_types.cpython-310.pyc | Bin 0 -> 9095 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 14359 bytes .../__pycache__/importer.cpython-310.pyc | Bin 0 -> 1211 bytes .../__pycache__/logging.cpython-310.pyc | Bin 0 -> 5138 bytes .../uvicorn/__pycache__/main.cpython-310.pyc | Bin 0 -> 13126 bytes .../__pycache__/server.cpython-310.pyc | Bin 0 -> 8886 bytes .../__pycache__/workers.cpython-310.pyc | Bin 0 -> 3745 bytes .../site-packages/uvicorn/_subprocess.py | 78 + .../site-packages/uvicorn/_types.py | 293 + .../site-packages/uvicorn/config.py | 528 + .../site-packages/uvicorn/importer.py | 34 + .../uvicorn/lifespan/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 194 bytes .../lifespan/__pycache__/off.cpython-310.pyc | Bin 0 -> 932 bytes .../lifespan/__pycache__/on.cpython-310.pyc | Bin 0 -> 4124 bytes .../site-packages/uvicorn/lifespan/off.py | 17 + .../site-packages/uvicorn/lifespan/on.py | 137 + .../site-packages/uvicorn/logging.py | 117 + .../site-packages/uvicorn/loops/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 191 bytes .../loops/__pycache__/asyncio.cpython-310.pyc | Bin 0 -> 564 bytes .../loops/__pycache__/auto.cpython-310.pyc | Bin 0 -> 572 bytes .../loops/__pycache__/uvloop.cpython-310.pyc | Bin 0 -> 442 bytes .../site-packages/uvicorn/loops/asyncio.py | 10 + .../site-packages/uvicorn/loops/auto.py | 11 + .../site-packages/uvicorn/loops/uvloop.py | 7 + .../python3.10/site-packages/uvicorn/main.py | 584 ++ .../uvicorn/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 196 bytes .../__pycache__/asgi2.cpython-310.pyc | Bin 0 -> 917 bytes .../message_logger.cpython-310.pyc | Bin 0 -> 3022 bytes .../__pycache__/proxy_headers.cpython-310.pyc | Bin 0 -> 2870 bytes .../__pycache__/wsgi.cpython-310.pyc | Bin 0 -> 6020 bytes .../site-packages/uvicorn/middleware/asgi2.py | 15 + .../uvicorn/middleware/message_logger.py | 87 + .../uvicorn/middleware/proxy_headers.py | 69 + .../site-packages/uvicorn/middleware/wsgi.py | 200 + .../uvicorn/protocols/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 195 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 1985 bytes .../uvicorn/protocols/http/__init__.py | 0 .../http/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 200 bytes .../http/__pycache__/auto.cpython-310.pyc | Bin 0 -> 561 bytes .../__pycache__/flow_control.cpython-310.pyc | Bin 0 -> 2200 bytes .../http/__pycache__/h11_impl.cpython-310.pyc | Bin 0 -> 14416 bytes .../httptools_impl.cpython-310.pyc | Bin 0 -> 16215 bytes .../uvicorn/protocols/http/auto.py | 15 + .../uvicorn/protocols/http/flow_control.py | 64 + .../uvicorn/protocols/http/h11_impl.py | 547 ++ .../uvicorn/protocols/http/httptools_impl.py | 575 ++ .../site-packages/uvicorn/protocols/utils.py | 57 + .../uvicorn/protocols/websockets/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 206 bytes .../__pycache__/auto.cpython-310.pyc | Bin 0 -> 690 bytes .../websockets_impl.cpython-310.pyc | Bin 0 -> 12073 bytes .../__pycache__/wsproto_impl.cpython-310.pyc | Bin 0 -> 11192 bytes .../uvicorn/protocols/websockets/auto.py | 21 + .../protocols/websockets/websockets_impl.py | 388 + .../protocols/websockets/wsproto_impl.py | 377 + .../python3.10/site-packages/uvicorn/py.typed | 1 + .../site-packages/uvicorn/server.py | 335 + .../uvicorn/supervisors/__init__.py | 23 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 809 bytes .../__pycache__/basereload.cpython-310.pyc | Bin 0 -> 4261 bytes .../__pycache__/multiprocess.cpython-310.pyc | Bin 0 -> 2678 bytes .../__pycache__/statreload.cpython-310.pyc | Bin 0 -> 2055 bytes .../watchfilesreload.cpython-310.pyc | Bin 0 -> 3253 bytes .../watchgodreload.cpython-310.pyc | Bin 0 -> 4481 bytes .../uvicorn/supervisors/basereload.py | 121 + .../uvicorn/supervisors/multiprocess.py | 70 + .../uvicorn/supervisors/statreload.py | 52 + .../uvicorn/supervisors/watchfilesreload.py | 88 + .../uvicorn/supervisors/watchgodreload.py | 152 + .../site-packages/uvicorn/workers.py | 107 + .venv/lib64 | 1 + .venv/pyvenv.cfg | 3 + active | 1 + app/__pycache__/main.cpython-310.pyc | Bin 0 -> 889 bytes app/main.py | 30 + .../__pycache__/example.cpython-310.pyc | Bin 0 -> 1319 bytes app/routers/__pycache__/main.cpython-310.pyc | Bin 0 -> 491 bytes app/routers/example.py | 33 + deactive | 1 + nohup.out | 1227 +++ readme.md | 1 + runserver | 2 + static/js/example.js | 0 templates/main/index.html | 10 + 2314 files changed, 418620 insertions(+) create mode 100644 .venv/bin/Activate.ps1 create mode 100644 .venv/bin/activate create mode 100644 .venv/bin/activate.csh create mode 100644 .venv/bin/activate.fish create mode 100644 .venv/bin/pip create mode 100644 .venv/bin/pip3 create mode 100644 .venv/bin/pip3.10 create mode 120000 .venv/bin/python create mode 120000 .venv/bin/python3 create mode 120000 .venv/bin/python3.10 create mode 100644 .venv/bin/uvicorn create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/LICENSE.rst create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/entry_points.txt create mode 100644 .venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/_distutils_hack/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/_distutils_hack/override.py create mode 100644 .venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/licenses/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/annotated_types/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/annotated_types/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/annotated_types/__pycache__/test_cases.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/annotated_types/py.typed create mode 100644 .venv/lib/python3.10/site-packages/annotated_types/test_cases.py create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/entry_points.txt create mode 100644 .venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/anyio/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/from_thread.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/pytest_plugin.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_trio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/_asyncio.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_backends/_trio.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_eventloop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_fileio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_signals.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_streams.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_fileio.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_resources.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_signals.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_sockets.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_streams.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_tasks.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_testing.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_sockets.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_tasks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_resources.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_sockets.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_streams.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_tasks.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/abc/_testing.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/from_thread.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/lowlevel.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/py.typed create mode 100644 .venv/lib/python3.10/site-packages/anyio/pytest_plugin.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/file.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/__pycache__/tls.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/buffered.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/file.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/memory.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/stapled.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/text.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/streams/tls.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/to_process.py create mode 100644 .venv/lib/python3.10/site-packages/anyio/to_thread.py create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/LICENSE.rst create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/click-8.1.7.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/click/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/_winconsole.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/formatting.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/shell_completion.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/click/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/click/_termui_impl.py create mode 100644 .venv/lib/python3.10/site-packages/click/_textwrap.py create mode 100644 .venv/lib/python3.10/site-packages/click/_winconsole.py create mode 100644 .venv/lib/python3.10/site-packages/click/core.py create mode 100644 .venv/lib/python3.10/site-packages/click/decorators.py create mode 100644 .venv/lib/python3.10/site-packages/click/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/click/formatting.py create mode 100644 .venv/lib/python3.10/site-packages/click/globals.py create mode 100644 .venv/lib/python3.10/site-packages/click/parser.py create mode 100644 .venv/lib/python3.10/site-packages/click/py.typed create mode 100644 .venv/lib/python3.10/site-packages/click/shell_completion.py create mode 100644 .venv/lib/python3.10/site-packages/click/termui.py create mode 100644 .venv/lib/python3.10/site-packages/click/testing.py create mode 100644 .venv/lib/python3.10/site-packages/click/types.py create mode 100644 .venv/lib/python3.10/site-packages/click/utils.py create mode 100644 .venv/lib/python3.10/site-packages/distutils-precedence.pth create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/_catch.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/_version.py create mode 100644 .venv/lib/python3.10/site-packages/exceptiongroup/py.typed create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/licenses/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/applications.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/background.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/concurrency.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/datastructures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/encoders.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/exception_handlers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/logger.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/param_functions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/params.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/requests.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/responses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/routing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/staticfiles.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/templating.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/testclient.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/__pycache__/websockets.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/applications.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/background.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/concurrency.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/datastructures.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/models.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/models.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/dependencies/utils.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/encoders.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/exception_handlers.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/logger.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/cors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/gzip.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/wsgi.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/cors.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/gzip.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/httpsredirect.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/trustedhost.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/middleware/wsgi.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/constants.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/docs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/models.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/constants.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/docs.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/models.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/openapi/utils.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/param_functions.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/params.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/py.typed create mode 100644 .venv/lib/python3.10/site-packages/fastapi/requests.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/responses.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/routing.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/api_key.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/http.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/oauth2.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/open_id_connect_url.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/api_key.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/base.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/http.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/oauth2.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/open_id_connect_url.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/security/utils.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/staticfiles.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/templating.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/testclient.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/types.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/utils.py create mode 100644 .venv/lib/python3.10/site-packages/fastapi/websockets.py create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/LICENSE.txt create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/h11/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_connection.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_readers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/_abnf.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_connection.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_events.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_headers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_readers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_receivebuffer.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_state.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_util.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_version.py create mode 100644 .venv/lib/python3.10/site-packages/h11/_writers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/py.typed create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_against_stdlib_http.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_connection.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_events.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_headers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_io.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_receivebuffer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_state.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/data/test-file create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/helpers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_against_stdlib_http.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_connection.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_events.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_headers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_helpers.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_io.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_receivebuffer.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_state.py create mode 100644 .venv/lib/python3.10/site-packages/h11/tests/test_util.py create mode 100644 .venv/lib/python3.10/site-packages/idna-3.7.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/idna-3.7.dist-info/LICENSE.md create mode 100644 .venv/lib/python3.10/site-packages/idna-3.7.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/idna-3.7.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/idna-3.7.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/idna/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/codec.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/idnadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/intranges.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/package_data.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/__pycache__/uts46data.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/idna/codec.py create mode 100644 .venv/lib/python3.10/site-packages/idna/compat.py create mode 100644 .venv/lib/python3.10/site-packages/idna/core.py create mode 100644 .venv/lib/python3.10/site-packages/idna/idnadata.py create mode 100644 .venv/lib/python3.10/site-packages/idna/intranges.py create mode 100644 .venv/lib/python3.10/site-packages/idna/package_data.py create mode 100644 .venv/lib/python3.10/site-packages/idna/py.typed create mode 100644 .venv/lib/python3.10/site-packages/idna/uts46data.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/constants.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/debug.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/environment.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/ext.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/filters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/meta.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/tests.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/jinja2/_identifier.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/async_utils.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/bccache.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/compiler.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/constants.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/debug.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/defaults.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/environment.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/ext.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/filters.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/idtracking.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/lexer.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/loaders.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/meta.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/nativetypes.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/nodes.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/optimizer.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/parser.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/py.typed create mode 100644 .venv/lib/python3.10/site-packages/jinja2/runtime.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/sandbox.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/tests.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/utils.py create mode 100644 .venv/lib/python3.10/site-packages/jinja2/visitor.py create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/_native.py create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/_speedups.c create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/_speedups.pyi create mode 100644 .venv/lib/python3.10/site-packages/markupsafe/py.typed create mode 100644 .venv/lib/python3.10/site-packages/multipart/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/multipart/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/multipart/__pycache__/decoders.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/multipart/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/multipart/__pycache__/multipart.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/multipart/decoders.py create mode 100644 .venv/lib/python3.10/site-packages/multipart/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/multipart/multipart.py create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/AUTHORS.txt create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/LICENSE.txt create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/entry_points.txt create mode 100644 .venv/lib/python3.10/site-packages/pip-24.0.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/pip/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/__pip-runner__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/__pycache__/__pip-runner__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/build_env.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/configuration.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/main.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/pyproject.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/build_env.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/main.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/base_command.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/command_context.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/main.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/main_parser.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/parser.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/req_command.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/spinners.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/cli/status_codes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/check.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/completion.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/debug.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/download.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/hash.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/help.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/index.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/install.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/list.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/search.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/show.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/check.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/completion.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/configuration.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/debug.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/download.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/freeze.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/hash.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/help.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/index.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/inspect.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/install.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/list.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/search.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/show.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/uninstall.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/commands/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/configuration.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/base.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/installed.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/sdist.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/distributions/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/collector.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/__pycache__/sources.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/collector.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/package_finder.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/index/sources.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/_distutils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/locations/base.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/main.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/_json.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/base.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/candidate.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/format_control.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/index.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/link.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/scheme.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/target_python.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/candidate.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/direct_url.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/format_control.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/index.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/installation_report.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/link.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/scheme.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/search_scope.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/target_python.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/models/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/auth.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/download.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/session.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/auth.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/download.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/session.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/check.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/check.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/freeze.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/operations/prepare.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/pyproject.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/constructors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_file.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_install.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_set.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/constructors.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/req_file.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/req_install.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/req_set.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/base.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/self_outdated_check.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/_log.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/logging.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/misc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/models.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/urls.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/_log.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/appdirs.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/datetime.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/deprecation.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/egg_link.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/encoding.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/filesystem.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/filetypes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/glibc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/hashes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/logging.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/misc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/models.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/packaging.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/subprocess.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/unpacking.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/urls.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/utils/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/git.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/git.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/subversion.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_internal/wheel_builder.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/__pycache__/six.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/core.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/certifi/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachinedict.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/enums.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/macromanprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/resultdict.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/chardet/version.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansi_test.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/initialise_test.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/isatty_test.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/winterm_test.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/win32.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/database.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/index.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/locators.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/markers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/resources.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/util.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/version.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/distro.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/distro/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/codec.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/core.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/intranges.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/package_data.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/markers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/tags.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/packaging/version.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/console.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/filter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/style.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/token.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pygments/util.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/api.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/help.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/models.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/__version__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/adapters.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/api.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/auth.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/certs.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/compat.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/cookies.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/help.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/hooks.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/models.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/packages.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/sessions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/structures.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/requests/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/align.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/box.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/color.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/console.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/control.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/json.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/live.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/region.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/status.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/style.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/table.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/text.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_extension.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_loop.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_pick.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_stack.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_timer.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/abc.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/align.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/ansi.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/bar.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/box.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/cells.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/color.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/columns.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/console.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/constrain.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/containers.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/control.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/emoji.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/errors.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/filesize.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/json.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/layout.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/live.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/live_render.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/logging.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/markup.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/measure.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/padding.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/pager.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/palette.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/panel.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/pretty.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/progress.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/prompt.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/protocol.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/region.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/repr.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/rule.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/scope.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/screen.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/segment.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/spinner.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/status.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/style.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/styled.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/syntax.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/table.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/text.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/theme.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/themes.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/traceback.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/rich/tree.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/six.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/after.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/_re.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/_types.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/tomli/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/_api.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/_macos.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/_openssl.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/_ssl_constants.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/_windows.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/truststore/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/typing_extensions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/request.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/response.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/vendor.txt create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 .venv/lib/python3.10/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 .venv/lib/python3.10/site-packages/pip/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/__pycache__/zipp.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_adapters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_common.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_itertools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/_legacy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/abc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/readers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__pycache__/simple.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_common.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/abc.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/readers.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/simple.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__pycache__/context.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__pycache__/functools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/context.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/functools.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/text/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/more.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__pycache__/recipes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/more.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/recipes.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_manylinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_musllinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_manylinux.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_musllinux.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/actions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/common.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/results.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/unicode.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/actions.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/common.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/core.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/helpers.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/results.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/testing.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/unicode.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing/util.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/_vendor/zipp.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/extern/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic-2.6.4.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/pydantic-2.6.4.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/pydantic-2.6.4.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/pydantic-2.6.4.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/pydantic-2.6.4.dist-info/licenses/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/_migration.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/alias_generators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/aliases.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/annotated_handlers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/class_validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/color.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/dataclasses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/datetime_parse.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/decorator.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/env_settings.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/error_wrappers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/fields.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/functional_serializers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/functional_validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/generics.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/json.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/json_schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/main.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/mypy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/networks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/parse.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/root_model.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/tools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/type_adapter.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/typing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/validate_call_decorator.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/__pycache__/warnings.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_core_metadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_core_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_dataclasses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_decorators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_decorators_v1.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_discriminated_union.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_fields.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_forward_ref.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_generate_schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_generics.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_git.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_internal_dataclass.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_known_annotated_metadata.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_mock_val_ser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_model_construction.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_repr.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_schema_generation_shared.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_signature.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_std_types_schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_typing_extra.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_validate_call.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/__pycache__/_validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_config.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_core_metadata.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_core_utils.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_dataclasses.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_decorators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_decorators_v1.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_discriminated_union.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_fields.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_forward_ref.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_generics.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_git.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_internal_dataclass.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_known_annotated_metadata.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_mock_val_ser.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_model_construction.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_repr.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_schema_generation_shared.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_signature.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_std_types_schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_typing_extra.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_utils.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_internal/_validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/_migration.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/alias_generators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/aliases.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/annotated_handlers.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/class_validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/color.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/config.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/dataclasses.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/datetime_parse.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/decorator.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/class_validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/copy_internals.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/decorator.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/json.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/parse.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/__pycache__/tools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/class_validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/config.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/copy_internals.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/decorator.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/json.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/parse.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/deprecated/tools.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/env_settings.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/error_wrappers.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/errors.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/fields.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/functional_serializers.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/functional_validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/generics.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/json.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/json_schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/main.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/mypy.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/networks.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/parse.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/__pycache__/_loader.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/__pycache__/_schema_validator.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/_loader.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/plugin/_schema_validator.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pydantic/root_model.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/tools.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/type_adapter.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/types.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/typing.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/_hypothesis_plugin.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/annotated_types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/class_validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/color.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/dataclasses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/datetime_parse.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/decorator.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/env_settings.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/error_wrappers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/fields.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/generics.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/json.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/main.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/mypy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/networks.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/parse.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/tools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/typing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/validators.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/_hypothesis_plugin.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/annotated_types.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/class_validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/color.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/config.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/dataclasses.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/datetime_parse.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/decorator.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/env_settings.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/error_wrappers.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/errors.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/fields.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/generics.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/json.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/main.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/mypy.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/networks.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/parse.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/py.typed create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/tools.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/types.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/typing.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/utils.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/v1/version.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/validate_call_decorator.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/validators.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/version.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic/warnings.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core-2.16.3.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core-2.16.3.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core-2.16.3.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core-2.16.3.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core-2.16.3.dist-info/license_files/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/__pycache__/core_schema.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/_pydantic_core.cpython-310-x86_64-linux-gnu.so create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/_pydantic_core.pyi create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/core_schema.py create mode 100644 .venv/lib/python3.10/site-packages/pydantic_core/py.typed create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/python_multipart-0.0.9.dist-info/licenses/LICENSE.txt create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/entry_points.txt create mode 100644 .venv/lib/python3.10/site-packages/setuptools-65.5.0.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_entry_points.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_imp.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_importlib.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_itertools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_path.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/_reqs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/archive_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/build_meta.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/dep_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/depends.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/discovery.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/dist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/extension.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/glob.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/installer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/launch.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/logging.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/monkey.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/msvc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/namespaces.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/package_index.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/py34compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/sandbox.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/unicode_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/__pycache__/windows_support.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_deprecation_warning.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/_collections.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/_functools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/_macos_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/debug.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/dist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/extension.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/log.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/py39compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/_collections.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/_functools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/_macos_compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/archive_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/cmd.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/_framework_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/_framework_compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/build.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/check.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/clean.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/config.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/py37compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/register.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/command/upload.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/config.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/core.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/debug.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/dep_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/dir_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/dist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/errors.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/extension.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/file_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/filelist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/log.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/py38compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/py39compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/spawn.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/text_file.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/version.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_entry_points.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_imp.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_importlib.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_itertools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_path.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_reqs.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/typing_extensions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/__pycache__/zipp.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_adapters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_collections.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_functools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_itertools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_meta.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__pycache__/_text.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_collections.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_functools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_meta.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_text.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_adapters.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_common.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_itertools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/_legacy.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/abc.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/readers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__pycache__/simple.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_adapters.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_common.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_itertools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_legacy.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/abc.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/readers.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/simple.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__pycache__/context.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__pycache__/functools.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/context.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/functools.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/text/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_manylinux.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_musllinux.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/actions.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/common.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/core.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/helpers.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/results.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/testing.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/unicode.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/pyparsing/util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_parser.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_re.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_types.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/typing_extensions.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/_vendor/zipp.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/archive_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/build_meta.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/cli-32.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/cli-64.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/cli-arm64.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/cli.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/alias.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/build.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/build_py.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/develop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/dist_info.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/easy_install.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/egg_info.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/install.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/py36compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/register.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/rotate.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/saveopts.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/sdist.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/setopt.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/test.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/upload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/__pycache__/upload_docs.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/alias.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/bdist_egg.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/bdist_rpm.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/build.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/build_clib.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/build_ext.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/build_py.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/develop.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/dist_info.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/easy_install.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/editable_wheel.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/egg_info.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/install.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/install_egg_info.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/install_lib.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/install_scripts.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/launcher manifest.xml create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/py36compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/register.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/rotate.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/saveopts.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/sdist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/setopt.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/test.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/upload.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/command/upload_docs.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__pycache__/expand.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/__pycache__/setupcfg.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_apply_pyprojecttoml.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/error_reporting.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/extra_validations.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/formats.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/expand.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/pyprojecttoml.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/dep_util.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/depends.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/discovery.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/dist.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/errors.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/extension.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/extern/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/setuptools/glob.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/gui-32.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/gui-64.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/gui-arm64.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/gui.exe create mode 100644 .venv/lib/python3.10/site-packages/setuptools/installer.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/launch.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/logging.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/monkey.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/msvc.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/namespaces.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/package_index.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/py34compat.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/sandbox.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/script (dev).tmpl create mode 100644 .venv/lib/python3.10/site-packages/setuptools/script.tmpl create mode 100644 .venv/lib/python3.10/site-packages/setuptools/unicode_utils.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/version.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/wheel.py create mode 100644 .venv/lib/python3.10/site-packages/setuptools/windows_support.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/LICENSE.APACHE2 create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/LICENSE.MIT create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/sniffio-1.3.1.dist-info/top_level.txt create mode 100644 .venv/lib/python3.10/site-packages/sniffio/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/sniffio/__pycache__/_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/sniffio/__pycache__/_version.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_impl.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_tests/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_tests/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_tests/__pycache__/test_sniffio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_tests/test_sniffio.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio/_version.py create mode 100644 .venv/lib/python3.10/site-packages/sniffio/py.typed create mode 100644 .venv/lib/python3.10/site-packages/starlette-0.37.2.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/starlette-0.37.2.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/starlette-0.37.2.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/starlette-0.37.2.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/starlette-0.37.2.dist-info/licenses/LICENSE.md create mode 100644 .venv/lib/python3.10/site-packages/starlette/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/_compat.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/_exception_handler.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/_utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/applications.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/authentication.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/background.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/concurrency.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/convertors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/datastructures.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/endpoints.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/formparsers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/requests.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/responses.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/routing.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/schemas.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/staticfiles.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/status.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/templating.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/testclient.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/__pycache__/websockets.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/_compat.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/_exception_handler.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/_utils.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/applications.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/authentication.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/background.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/concurrency.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/config.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/convertors.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/datastructures.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/endpoints.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/formparsers.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/authentication.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/base.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/cors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/errors.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/exceptions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/gzip.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/httpsredirect.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/sessions.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/trustedhost.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/__pycache__/wsgi.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/authentication.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/base.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/cors.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/errors.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/gzip.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/httpsredirect.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/sessions.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/trustedhost.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/middleware/wsgi.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/py.typed create mode 100644 .venv/lib/python3.10/site-packages/starlette/requests.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/responses.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/routing.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/schemas.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/staticfiles.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/status.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/templating.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/testclient.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/types.py create mode 100644 .venv/lib/python3.10/site-packages/starlette/websockets.py create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions-4.11.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions-4.11.0.dist-info/LICENSE create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions-4.11.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions-4.11.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions-4.11.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/typing_extensions.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/INSTALLER create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/METADATA create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/RECORD create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/REQUESTED create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/WHEEL create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/entry_points.txt create mode 100644 .venv/lib/python3.10/site-packages/uvicorn-0.29.0.dist-info/licenses/LICENSE.md create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__main__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/__main__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/_subprocess.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/_types.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/config.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/importer.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/logging.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/main.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/server.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/__pycache__/workers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/_subprocess.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/_types.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/config.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/importer.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/__pycache__/off.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/__pycache__/on.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/off.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/lifespan/on.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/logging.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/__pycache__/asyncio.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/__pycache__/auto.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/__pycache__/uvloop.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/asyncio.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/auto.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/loops/uvloop.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/main.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__pycache__/asgi2.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__pycache__/message_logger.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__pycache__/proxy_headers.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/__pycache__/wsgi.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/asgi2.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/middleware/wsgi.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/__pycache__/utils.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__pycache__/auto.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__pycache__/flow_control.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__pycache__/h11_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/__pycache__/httptools_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/auto.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/flow_control.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/utils.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/__pycache__/auto.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/__pycache__/websockets_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/__pycache__/wsproto_impl.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/auto.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/websockets_impl.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/wsproto_impl.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/py.typed create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/server.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__init__.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/__init__.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/basereload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/multiprocess.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/statreload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/watchfilesreload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/__pycache__/watchgodreload.cpython-310.pyc create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/basereload.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/multiprocess.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/statreload.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/watchfilesreload.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/supervisors/watchgodreload.py create mode 100644 .venv/lib/python3.10/site-packages/uvicorn/workers.py create mode 120000 .venv/lib64 create mode 100644 .venv/pyvenv.cfg create mode 100644 active create mode 100644 app/__pycache__/main.cpython-310.pyc create mode 100644 app/main.py create mode 100644 app/routers/__pycache__/example.cpython-310.pyc create mode 100644 app/routers/__pycache__/main.cpython-310.pyc create mode 100644 app/routers/example.py create mode 100644 deactive create mode 100644 nohup.out create mode 100644 readme.md create mode 100644 runserver create mode 100644 static/js/example.js create mode 100644 templates/main/index.html diff --git a/.venv/bin/Activate.ps1 b/.venv/bin/Activate.ps1 new file mode 100644 index 0000000..eeea358 --- /dev/null +++ b/.venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/.venv/bin/activate b/.venv/bin/activate new file mode 100644 index 0000000..402ad3b --- /dev/null +++ b/.venv/bin/activate @@ -0,0 +1,69 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/dhkq92/.publish/finance.zois.kr/.venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(venv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv) " + export VIRTUAL_ENV_PROMPT +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/.venv/bin/activate.csh b/.venv/bin/activate.csh new file mode 100644 index 0000000..f5ba9d5 --- /dev/null +++ b/.venv/bin/activate.csh @@ -0,0 +1,26 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/dhkq92/.publish/finance.zois.kr/.venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(venv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/.venv/bin/activate.fish b/.venv/bin/activate.fish new file mode 100644 index 0000000..5d16c50 --- /dev/null +++ b/.venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/); you cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/dhkq92/.publish/finance.zois.kr/.venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(venv) " +end diff --git a/.venv/bin/pip b/.venv/bin/pip new file mode 100644 index 0000000..450f89f --- /dev/null +++ b/.venv/bin/pip @@ -0,0 +1,8 @@ +#!/home/dhkq92/.publish/finance.zois.kr/.venv/bin/python3.10 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/.venv/bin/pip3 b/.venv/bin/pip3 new file mode 100644 index 0000000..450f89f --- /dev/null +++ b/.venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/dhkq92/.publish/finance.zois.kr/.venv/bin/python3.10 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/.venv/bin/pip3.10 b/.venv/bin/pip3.10 new file mode 100644 index 0000000..450f89f --- /dev/null +++ b/.venv/bin/pip3.10 @@ -0,0 +1,8 @@ +#!/home/dhkq92/.publish/finance.zois.kr/.venv/bin/python3.10 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/.venv/bin/python b/.venv/bin/python new file mode 120000 index 0000000..c3cc991 --- /dev/null +++ b/.venv/bin/python @@ -0,0 +1 @@ +python3.10 \ No newline at end of file diff --git a/.venv/bin/python3 b/.venv/bin/python3 new file mode 120000 index 0000000..c3cc991 --- /dev/null +++ b/.venv/bin/python3 @@ -0,0 +1 @@ +python3.10 \ No newline at end of file diff --git a/.venv/bin/python3.10 b/.venv/bin/python3.10 new file mode 120000 index 0000000..bac1087 --- /dev/null +++ b/.venv/bin/python3.10 @@ -0,0 +1 @@ +/usr/local/bin/python3.10 \ No newline at end of file diff --git a/.venv/bin/uvicorn b/.venv/bin/uvicorn new file mode 100644 index 0000000..e5ab4f4 --- /dev/null +++ b/.venv/bin/uvicorn @@ -0,0 +1,8 @@ +#!/home/dhkq92/.publish/finance.zois.kr/.venv/bin/python3.10 +# -*- coding: utf-8 -*- +import re +import sys +from uvicorn.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/LICENSE.rst b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/METADATA b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/METADATA new file mode 100644 index 0000000..56e9429 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/METADATA @@ -0,0 +1,105 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.3 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/jinja/ +Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe >=2.0 +Provides-Extra: i18n +Requires-Dist: Babel >=2.7 ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + + {% endblock %} + + +Donate +------ + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://jinja.palletsprojects.com/ +- Changes: https://jinja.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Jinja2/ +- Source Code: https://github.com/pallets/jinja/ +- Issue Tracker: https://github.com/pallets/jinja/issues/ +- Chat: https://discord.gg/pallets diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/RECORD b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/RECORD new file mode 100644 index 0000000..b12361a --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/RECORD @@ -0,0 +1,59 @@ +Jinja2-3.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.1.3.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.1.3.dist-info/METADATA,sha256=0cLNbRCI91jytc7Bzv3XAQfZzFDF2gxkJuH46eF5vew,3301 +Jinja2-3.1.3.dist-info/RECORD,, +Jinja2-3.1.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Jinja2-3.1.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 +Jinja2-3.1.3.dist-info/entry_points.txt,sha256=zRd62fbqIyfUpsRtU7EVIFyiu1tPwfgO7EvPErnxgTE,59 +Jinja2-3.1.3.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=NTBwMwsECrdHmxeXF7seusHLzrh6Ldn1A9qhS5cDuf0,1927 +jinja2/__pycache__/__init__.cpython-310.pyc,, +jinja2/__pycache__/_identifier.cpython-310.pyc,, +jinja2/__pycache__/async_utils.cpython-310.pyc,, +jinja2/__pycache__/bccache.cpython-310.pyc,, +jinja2/__pycache__/compiler.cpython-310.pyc,, +jinja2/__pycache__/constants.cpython-310.pyc,, +jinja2/__pycache__/debug.cpython-310.pyc,, +jinja2/__pycache__/defaults.cpython-310.pyc,, +jinja2/__pycache__/environment.cpython-310.pyc,, +jinja2/__pycache__/exceptions.cpython-310.pyc,, +jinja2/__pycache__/ext.cpython-310.pyc,, +jinja2/__pycache__/filters.cpython-310.pyc,, +jinja2/__pycache__/idtracking.cpython-310.pyc,, +jinja2/__pycache__/lexer.cpython-310.pyc,, +jinja2/__pycache__/loaders.cpython-310.pyc,, +jinja2/__pycache__/meta.cpython-310.pyc,, +jinja2/__pycache__/nativetypes.cpython-310.pyc,, +jinja2/__pycache__/nodes.cpython-310.pyc,, +jinja2/__pycache__/optimizer.cpython-310.pyc,, +jinja2/__pycache__/parser.cpython-310.pyc,, +jinja2/__pycache__/runtime.cpython-310.pyc,, +jinja2/__pycache__/sandbox.cpython-310.pyc,, +jinja2/__pycache__/tests.cpython-310.pyc,, +jinja2/__pycache__/utils.cpython-310.pyc,, +jinja2/__pycache__/visitor.cpython-310.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=dFcmh6lMNfbh7eLKrBio8JqAKLHdZbpCuurFN4OERtY,2447 +jinja2/bccache.py,sha256=mhz5xtLxCcHRAa56azOhphIAe19u1we0ojifNMClDio,14061 +jinja2/compiler.py,sha256=PJzYdRLStlEOqmnQs1YxlizPrJoj3jTZuUleREn6AIQ,72199 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=0qldX3VQKZcm6lgn7zHz94oRFow7YPYERiqkquomNjU,61253 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=5fnMpllaXkfm2P_93RIvi-OnK7Tk8mCW8Du-GcD12Hc,31844 +jinja2/filters.py,sha256=vYjKb2zaPShvYtn_LpSmqfS8SScbrA_KOanNibsMDIE,53862 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=DW2nX9zk-6MWp65YR2bqqj0xqCvLtD-u9NWT8AnFRxQ,29726 +jinja2/loaders.py,sha256=ayAwxfrA1SAffQta0nwSDm3TDT4KYiIGN_D9Z45B310,23085 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=7GIGALVJgdyL80oZJdQUaUfwSt5q2lSSZbXt0dNf_M4,4210 +jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=Y199wPL-G67gJoi5G_5sHuu9uEP1PJkjjLEW_xTH8-k,39736 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=_6LkKIWFJjQdqlrgA3K39zBFQ-7Orm3wGDm96RwxQoE,33406 +jinja2/sandbox.py,sha256=Y0xZeXQnH6EX5VjaV2YixESxoepnRbW_3UeQosaBU3M,14584 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=IMwRIcN1SsTw2-jdQtlH2KzNABsXZBW_-tnFXafQBvY,23933 +jinja2/visitor.py,sha256=MH14C6yq24G_KVtWzjwaI7Wg14PCJIYlWW1kpkxYak0,3568 diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/REQUESTED b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/WHEEL new file mode 100644 index 0000000..98c0d20 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/entry_points.txt b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/entry_points.txt new file mode 100644 index 0000000..7b9666c --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract[i18n] diff --git a/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/top_level.txt b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/.venv/lib/python3.10/site-packages/Jinja2-3.1.3.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/METADATA b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/METADATA new file mode 100644 index 0000000..dfe37d5 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/METADATA @@ -0,0 +1,93 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.1.5 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("Hello") + Markup('hello') + + >>> escape(Markup("Hello")) + Markup('hello') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello {name}") + >>> template.format(name='"World"') + Markup('Hello "World"') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Chat: https://discord.gg/pallets diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/RECORD b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/RECORD new file mode 100644 index 0000000..acb4ef0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.1.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.1.5.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-2.1.5.dist-info/METADATA,sha256=2dRDPam6OZLfpX0wg1JN5P3u9arqACxVSfdGmsJU7o8,3003 +MarkupSafe-2.1.5.dist-info/RECORD,, +MarkupSafe-2.1.5.dist-info/WHEEL,sha256=1FEjxEYgybphwh9S0FO9IcZ0B-NIeM2ko8OzhFZeOeQ,152 +MarkupSafe-2.1.5.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=r7VOTjUq7EMQ4v3p4R1LoVOGJg6ysfYRncLr34laRBs,10958 +markupsafe/__pycache__/__init__.cpython-310.pyc,, +markupsafe/__pycache__/_native.cpython-310.pyc,, +markupsafe/_native.py,sha256=GR86Qvo_GcgKmKreA1WmYN9ud17OFwkww8E-fiW-57s,1713 +markupsafe/_speedups.c,sha256=X2XvQVtIdcK4Usz70BvkzoOfjTCmQlDkkjYSn-swE0g,7083 +markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so,sha256=kPt-fhZ_RG7PUbDvwmyC26ZvRJ9DvUlF3hszBIB6_xs,44240 +markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL new file mode 100644 index 0000000..1d81251 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: false +Tag: cp310-cp310-manylinux_2_17_x86_64 +Tag: cp310-cp310-manylinux2014_x86_64 + diff --git a/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/.venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc b/.venv/lib/python3.10/site-packages/__pycache__/typing_extensions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87c532874d0836cb35eae7d83ff397b43eb7060a GIT binary patch literal 93603 zcmeFa37lM4b?0AOS644;t(I3zSq9WCr1pZ%qS!{VWEo+*?O1I)l+ct){a#Dm>aLPr zRZH$p%Lrt!As7e{RvRRf1e_4UuqGs72}=ms*GX!U4B2Le$t0P?lT5}5_W%1k_ia_( zEju%r|9s~EpO)&?tNZS|%em*Cd$xOSW7Vqu41d4y_6sLJ`-j=gpXx{YZ!JG|@M&H? zl*xD*FFTW|xbJKwYrk{hcfOLh--SxSzI!S?_Fb$L?Yp;9vhTi1pMCdN`VVKk+~e8G zfS0cf`l~8Kw`RP8*YjY;>p7FFtoB!*$yC<(#p$(P@n}!5+w1j84`wRs>O+>+N7|Uz zAEp(&0e9#3O|P%4_xsLn@CMIiD;L<^D(*Jg-4J&dl4par+RJ-u9?4ZMvR`ZYwT@pG zTiNR=`vF?HVWw~PlFB97OnohFyTIE>+cx^E&g3hX^7}&XB7R@wU+P`_NWO9jOt!egWmb$lFZ$o5}IQu>2R1I_!;*I^tg*rfv2&dt1C0Ka#C% zBIj^r*dOuxysc+)!C&!vOJxh!7gt`)b!%m7eWRZ}yUov^9rd%*+x)A}<$%-G-ZpQP zI=6UNd0Y8@v3Iq14c}XN=bFkjT(7NM%k?FdmvFtVavj&}E7x;-$N^`^>ATwhsv<>8EX?c-VRCEj(1bKdobv))S| z%~y6D$#^gONVc*w8uxc(gWLR_XK(gielDBMSn4Z|_KUH;B9yyJb3cLQzS z{f?~Hl+{N{KE8olY?#kU<_f__B9j}aYy{B>y*Ly4X)?e+9QQuwO_fp^Y z`g_jgX~A8VcDJ{Ww0&XP_gdPxcMoazglTtM+P&U=q}>;$?X$G+^Ik*RYr?c~ORISM zN!#!5@h`eKWA)r)>96$;kbWSQey{hhyej>=&pTN8KL7jPkqfS%wXdnXhHIr#;kv)F zzrMq(`GvEu<=268+3A0EB2%e)hr9{iJ4lZ_&!<%1=2yjEb++bLyh-oyROVcva>&2W zJK{|V+Wwl!EI5A9n|?Is9rY$3RR3RN*zKRmQL}2R_?5|AWul(vJ6oCXX1rNy*>Ab( zmg^|Fyo$$&G`u>`JbQM`p3U>julV(T@3q$oaK85`3_eOb3IZy zQeQ_OPIxEj!%0%2xp{=t`@K0*d565BXIbyYH|8$Rh_2DzPm_D9GR1YeGF`uJL3DB+ z%5$`GG@H3EQ(slc_%rXw&3`kS(La@4Ir^GRJ$o`^c^Ak#Td8;C{i9Ugy36Z*zqd$V zro2<$1AI?gKVE13_#4V>R2uaQJ6Z>YeMdgXK~YY7uQNPv)QkLjo%ed^O0LrI-r${~ zq+{NL-W&NoPEX(DJw#6*qNf4B9`@eMuQ%I>Hu?P)?+5t(1Afye<_2rQTWLW)5Y=c^ zT3qKUbM*_!`-t~8^1h9dPVnpP-dp+gR{sPuuf^|oct6PRAGF_dR?a)EoY(T~UEVu+ z_Rg@Dll4B*-W{gh?+0fJm6P_y59y7j+Vvjqy}a>W|9(o>*e`hR^WJYg{{AFq@DNWH zD~nv`EAw?ntD}*0uzDZR`GEIB_U2-J4JCijdz6wNCEcwAr~Fgi4|$In{1&b34_UiE zMX3)|9$2>2uk!YXy$@Nb4_K*Zy>pa$E-v+T{_DICd5>GE4_K)mu~Pq#QcqV-FI(zg z@%9gUAF)zTTd6$f|B1_d8_wx-WQoUkJR@r)1Tj?)nD?yOqpMf%X}MY zU-5pPw4bMhh{n9#f1CGJ?`zhUw|ZX>%X~h0zp*qgslVWTlM=oem--I>9p2acAF!6b z)%!*FzQN&Jz@aDT<(*&hzQsG=3TM?1)=Q-Qa+nq{Z+_77|BB_mn6|yM^3Hmn_pAN| z-mm!=OcuOf_kQKULgk&7>o+Wy_=tB^-bJq8^xsIXHKv5Kji%`pMS&W_xSui`QF3ly?n%*Tyn7}<@>z0?kAzP`gm=- z{#&I{BhUQ{4rghfo)39{;Qir)#mc*_jelfqe1JUfue=}rNIc`e(;G>N-nXHGAE5Og zpsWwj`akymh}OTK_xrs+vG+gZ_fLPY^1=F`ai4z*SM?}x`!nxPfF(I9AGEp*%FWN) z%J%2pzh{+sjCJWhaF?k(=0E25RUfl_|Iy0)RaT>t_Z{y)lJ7(Qhj{v-daw7NyuTp# zhy4%p`@;r5aX3AJ+I+Thw!V$G`n><_{UvXmBkl3ZNBmuIR)6)8EbHeF)2hGr{tK=8 zFGj6@#Ma**@%|=Ue}B~bTklEA|EPbT|Iu&_{;%HOJg9fi(zfh$#=D-@6@!a(KmD=F z$LbeR=HGeOQ|9%4X8H+mI z-rrO2C#*;C<<#&hTK|)kpR5Zj|H1q3l>gs>piu0LN9 z9r$YHt6aZU5f}OO%GbGmqw)=|zfk!FuHUSDlj|>5ev#|9D&OMzOO;>Z`pcDH=K3p@ zU*Y^VgyYkyyf2Z<0Tz|Ln zyIyu*X1G6_$$Uq`b05ns@tbp zeo&j)*9xZUhueL3)q>jWzGMDGdsTe9GdSFAua1A-cCw~~!ajdyvRxRTKjyc4byXFE z;m!Emu^GQzyr+JwHgUAwxASCes#QBg(yE=!`TE3O)!AwU>7RPqx2q8}=2}yAzdd9b zZ}sb8&h_@29<==XTX)pzwZneUF5WyhImvfv*OA&({f^qP_E1-j-d&A3UJ2SgyZz&H zetTfIKUtfbY3-hxXtn#tYO}uQ+B$G&;Q4{?*@HfH!`%+-n>%)_5ww~+4>jAXq8~TU zw|rm{{oK`wq8sKUxsMVX3jbOIj@A=09UnA|c^Sc`ipwVhfG-j%^{_G(?Xtsxxs%BM> zOx0V>c9CuwnoTw1%lY()(6!pd31ydercZF582LfO~GpzHy z0V6pz>$lg2H`R$F{=`v3tHL-~(Y9gRIWtvbq*S`yS~d3M*11~XwTnvFs~oSn>z3-S zSKYGfw!LGwwtL15+@-O`-F|B>sJBaZ`!(;*`V2GZZct|m+-MJsHCo9JFan@YwD$R} zc9E&Z9BP+t2DZWc-aEm`+RThKu76i!X2zdrO*QJm@OleeWn>Eu2lq4rCX{!#KiTfv z6Eqh5y2|TIFu&JsrzYB^SJj$Fti&AU_c4iPoA*xnC)*{PPntmPPBW`?n?LWK7H*$v z0(xf0F-`G-@W$Tkxue#aIMN=vW6q{$lxKDLd!Ob^eZp_|#|f==>CR*73dE!Lu3C$^ zRd4s-E#Nh$tO@Z;d3B^`-_!z-D{6pfb&s2EJ@?cFjsAOUGjo2}%!wM!Tvcy4oU*ZP zU)b@p>iH85BOK!sqH*cJ96xsOd2$06KO==$C5MogW9i9z`F)v@Lc6cJ&j*F-{>%hq zGXB%OKD+od3tU7=M{;8e{Wmnj{5L(3c_P~`G$DDxF>=`DsRLIXY0Uapc}I>Of5o*| zjUJmjG&9vaa+RhRKpS0XOf^T323L)q@are8nwdIu)v@{3kw*O`qt{%0RTH|qP1F%W z*1QS?XKbp#$geknOmp-Ycvr0k%;akI?bP_BI#|dqtc&|F8a*C+qM*EWh*`DT?ypv7 z8{XWE?gy*Y<8!qc_ataV4NtldG?mui@-{wCs`I7HVAfKe$bBcz@9#)CxddK4BpSRn za?{EzW?I?lTq{3a;L|h7YP%1Bjg1uB{Zq}Udb1^fw2Q8r?N!wfrQKXD+K4yXgB_`T zh9a7*Kt9{*YIFPf)#j1L+>BR+Bx!P0Cxgap^_Z3~ADnEymv%LaTyohp*}^lyL)<=* z3l{nMP9K*gJyPGTN9(vr_h>Sw-UJVjJkk@qj<4XfF0a?+4Z57s<&C<;xZwb+N+0E8 zgSRfbq)x%t>J-vOb)LyJ`W7?O`N2$7YoV)FM!U%pJyn}ovDOb$U{ffw0pN|dbGPxi zcbw%Kc#UM+eG`onwP32oLR3;x9YRL(Dt8w?8VSKQKrtiPK&4Ia>G)F*^w%8b5>2~@ zGH8c1^-7hz-RHdm_l1Wtg-oS~xz$4tAeeXfEM6)$`qRBi)TenF7w{@GmkCNO$~%*N zL$;MWlR2AT%$^Hp=u4MQ9Lg%4@6D2wjZ=RjVLPKug;B#-V92v9DTn>uuEywoM=*+o#oLAzUe2$_{21E{S@` zJnbrS2_8iKZfZ7#eJ+X$wX*a#cMePtJ-T4o-j1Lj;W(XJ#Nh394I7R>`}`{3$-J5(vqL zo? zdzN9eza0K;D+?{An&k;NHQr#Ma#*2tYkt|x@KkefhvinIe57{5FSDALAuUH5UbCZI zl26zwR!+SE=0#)PEH@@qd-4)YgkNqQskN-k))C4+1RGR_O0uN0;xx;(fE>Y`Ulvs( zuU|gafXPx(Cs^_Mj=QF}rY0Of3}qpHqvf5ga>ylZwXQp2SzbCTLfRY`XGNrX*nz8> zm!gxa`82n1S#Ew#=NB`Fvy0isvv+5vGK;w%&b}?2t(SDpO$VXYlo-`;Mg~7bp@zxr zURE^!B=axd&QHuBZy2juJZjQMH+Db9Yu`|#q6v6Oc40t34+~j>*DBs?On}FFH4u?r z7Na$@el9MU1$aZrW}9dz*x-2YCFrfUcJK-6TwpvlR&R+{_7H<%`(`^}D-J~O?c&qa zn(Jj*1u_>h_n%IXLAlL;A5_+O_OTYH%7&tJX`2^SHZAa@D~3GMh{ z9{idfF6g3Pbibz>G#afXUC`R9Eh{eY8djAfOJ7={@N)UevMqOI$UQyVZPXeL!P zA)!HoCB8M~Lmzn~8vI5Om(%p2y<{#QJXo#TuvM!E50;T~f~iAuqS_4}jYF78ZPYDm zf^9GeFrsl`w;GM!fM!(>I|YDDmEvaGz-9~DKHmuC77_G>>%HPShEh`X(ERKT@d z)Cplgv$utO)ylUDtam-w^|N4yer3a7`NiB~{%9xNjdTJ?`ttLp_L&7A&hfl(WR%U`&3 zITT_=RsN3A)ZB=t!a9DmY%P?Srw$9r-83w;3rEoMwEJNEPz7~#XSrowc&ZnwRXk)e z!CNSL;dv{x%HzsOs`S9D2`C0YG7lC0PfQ;%@d>qeLKjz5j=4nECIToUx~ z^OHGGEWNyv%(n=yq#{Vti+&=Ug5rkSc^I+|lo7tgD6^3tj+^Rr46``ymZ`1Rn^x+@0$tXL+Y0CQTC zDfldx$`C}vk&k1wsi0X|70xGUoPG|8b5Bvpf|9!jV4zw>gADnZtyVW_48$?^XN%cV zZZMZagdWTma=EA1^c0wCB_>>dHg|fEyZ+q5MO~v57lg{G3%j8StswZCn*NKrEQjJh z&x7YBC=N|71WK#D1r#i={I}Dwq9)5dSAI3-50)v`3KIW;nltd5#~KK@tX)R2kwRI^ z!uxPZnVBz3HO+I#-+2p$X{J~>pc81=y<{~!A5*(b1JMj^k5<sjxI^UZ=AP76zsrqoiXw-en!b%Vv03frcoiy z*$)eOASD~5IepsQ%}}1NHP$;DDL^+>$JDonmbgUoSN~smXFQU zCcuJ|j8IUXZ2(t$h=?Nkt3s@F;b#-BGcG5p1HO*}gT~3NWxqCYBx2iXh3WNnM9ms4 zuOOhsIpU%v9?i8TUp{OowB01HL}kGSzYbL$02RSSI6{0i5P( zXJR?j7;Qmiv?VSIy;dUc{C^ev5y|Mpk}fIx%5HcaZum_klfX|1qM#aKr$h2uJaZ!b zMgYS)g%;97%8Vt&Icz2(A<1Nrtu-!ccqA?+5hKOWXv$QpBc*mP`6acs*TrvPOFFE@ zem+s|>XnIxCri=LL<0#F$~=SiwB87Q93s+QoxJSL&Cbq`YB`o)$Go8-va*`9N_ri$HJc&Rhunu65`4e*V@XXIv!IjV)A=!1F54gLHp zWU&O1((xw>zKf4ZhLX+CA==3TKxbaCOICmDOVS63q9|rGsH0=>x@v5@$9x1*ZAmzJ z*=XKEgG?njm<#k9p73_Q0;zO^`*is}U9{&Q7}sS|moZ)L&_yi|F5uGM7}>vN(ne~I zoH8zr(wFhrus28Y3#&t`ov8n4?a)NKUzR5d!Aja*yF}G_(|XnVxN5zy+G(rC+F1*Z zV!0WrRvWl5MAjJuU0e?$Pl3pJ0hC7ag`^qbL%KKhZ~U&gJ1`s8lPfgthwB@O=xCZV zjh0jbm!np0)TnHDbLsxe(jJ@cJGy-d%=iG^B-F8NgE z+}NahgdeTU8B^9w%LOYdM`=Wn&CI>rG{PLh$hzbGEoPyYpTa5qRQ@pPoaw^j*~Prn z{^VVQ_)<9A;}y_b`_41`-J}T+?9*ktE`P`c z6*H&-ISVA4NMk=6GysT6ufMEZf3Ea?*h&0zv>MULTfT4C?f2}yWp{Pw`1sxX+WDI2 zA@Ir^+U_yHw+k9&{Av<3z_!4Uq^67r8b~0b8-d%6+Lt2&S7Z_+k07ILaCfJ3PZ#pR zf8)jPs4E>*j+Zi#Uc7lVKNbce_1kprY+k0)bGiGVafpQ|z0i<7QB z&Pl_O%WgyzE@pGj1PoPdHebafL#QR4>!MzZkYO)-f~G^g{(Pt7K0-s2aqCW7>`YBY zjYD%boS_E=fJ>AEL&^%Jl@wgCmyIuMG-jGnHnR;hCxWS294}fv+_feq>~>^=W4%P+ zh?$rvEPGC=&x25ld-6yFli(e9-|5(G%*KJ!vTrS)JTe8>Ia{Mx=er{@%3PsR4ZJB2 za2Nvd#cCUfcW7b^hFt&*o)P2{!PC&|vMP;ioMc&^I7(le;pBBd`8^GVpgPzS6uIw! zxT?~#JNejZt3~q+i(}B&!sSIefKV;6P`)c_YD&=Qu)F1hpQf1LKj~DXb~ArXt<3@wVLo+yX1H#77d=dc9;o?TwC`i7)6{az`v97 zOewQkoP;SqNyF0^=SFyI-1KGx9D}cJ)Hk=v=(SO6%j8RwEGI<^J(PttsWF2Yf*Q;u z-D;$|CF7JFHyU%zvM-kgg#6YKI(VdUQdaJyLP|P`=ZB0LXc*@Z$V^z>qB^&P@6M_( zhs~yfAV3#nc4HE1V#F;!X;O0F&-f=OZ)+LXEK*dOBsRB-BcE)u**%Go+O;bzI|1jy zrVaoxc;#!#vvZ6Q@h7L!M`RJd?tXsvdINq5ednOJ3VmmvHw1pK z#&sf^hj++kEM;T#rwOFbZG4(i-!4KrkLCha2&n?S9Lm6f`Zifkr?W>;j4O2q?6xTf zuaI((H6u6O6XqzK$TVNJ*fU*h^-5Vd-FG;1j`h0vvR3~h%5}ck>bcnS!Q5k%^M>s4 zjjh4yRntRK6-v!MS-@mp2u=2dF}E211I=2vKI#H^$@n(#jATMG-pm2>QgHg0XwHFn zhjGCfSsi?Xw_Q1>b!TgN(b>w}g0J-)mg%m$?;O9gy7Tti@4WB!z5B+4?<%+Wp5QuN zG~_`K60l_DD-tI9DuH7f|RTJ+z-;uEYs&_l-n7#a6p@WPo z8(7NMLB=-ZHrTqC%Ok%?c6lau`jP@l;i&Vf7s_Cs2}_8w#?^@O%eiS~rct>pb%n@c z>X35A%bm#wm&oXGMw)Ck>h8-J*=DU5HQs|9qV5K(bulK;cpkAB!Jq2#Aziw9rF^Sc z9L$th!1-TVlBJNjF)&w(E2%t{kCeOIe+Cez$yoyn^+ z%`2R}jt&+*G|+FLThqP4F0Q4seIAhrkK`fEGS=``&0pkTJi5tB7$F5|TK9?T7>dBM9k zjWicf-8v!7RP`oS zX?nzL@Q?B1{211}u!WW~8T%Bby`WVD_g>KIb$FJ}7i^OOQaFbYvguTAq15U-i>QH3 zIcK()0hsK8`CB3e8z~#SK8fwblc(X`5W&p!Ai~Ps?#c11ok25=cY$ny<0Gq*k#ufy zHb3JrFviUdpr&iP7xqQQe{-Cdz)^LsTgIpd8e{C0Ca9DmMkn}ty_iSo&^=`D<-t}B z*(f)qyo@D7x&FKxwo+jzkFEhD${NxO*+OsbAJ#$93WeP1!qZC!EvhcW!Hz+rjzmKv zg@Nc=G$>vckPS#p!BFPsGL7|^bPLnmiS-{FNAgO*VOB=N{nHeKY#L)|cjuJzc6Ck* z<2pPV)@2tqbYq%qtTIr^S-*o4Gd3~X8T59Z8mfMAf!f6vF%L#0fqx3s3zQ@W&7UN>OR zI)*`%SK~~^y+bOf0PiGL6S;eiuXXS5%N!r{ z3Ji5mG&>}=kE2qGiB<43q`2kkuXSfrM0{L(Af*CwSh8OkwAP0LyHPKj0)Z{yf2ZeN zW3~|hR)i`q;^9zESdWe^hXoJ3AIxJ&e5RC>BwNVi+mHkQvw_~3AbZE3mOuTOd>%1< zJ`U~E3ZjuEfJP4HE?+5`L$l1-rAnVUH1`95q9X-r-1wdjY*e`-e5+OVG#6=BrZLAv zu8|mWGl>?Ud1D!6(|ru-OIj?a z)xL;}FixTv4ogRaG@;cf;b8M3E^;h6(Cgev<}&6|lGE#M+GMR~PvqLU(W~3pLtXH1 z_uX)qEn4><3vPOVf^7pq?)1jY!nSB#fLStTBU%^`qi&dKAfPvI8jatzrFUe|IexMz zcD<3H6C6KV+R(%qpNB5U!+72((0&ZA$?tTD8Dh= zpGTd8ezx??!X+!W8?+XunyAl%)B0((J+8ZN>tYQOa}ubcl^sj0$HDoVvzb%*Y-XX45{rx359YjHabt`5H{`sY zQ~3w-Cy9Hom}}l91U$P+{`jc$u8@=GNU1hWx9&hGTdu{-Rmhu}wmoFQ;%6xtcHbPD z7GrK84kl)FaBtljolf2>7E71WB;dj|BiUX)dB)Num1y%^B8r+5swrm7Fkm*ZZRnL` zG{<-{hy4~;u23>Zs-7=5Q9H>Hm$Fym$BFm$)WlJ|w(GbX%7U4qc2anko9Zg?*el;K z_|Oy-B*{l^rd@ufOZnHh*Jb`32fS;h(NvMc5iWO`u9Q=@tqJml?x)UZ*-;i?!C4Xz zN8G_M-jns=%~v(G=SimB&Db2Hx<(SK*L}61j&5W-dH{47C#O)w8Drr@Mkx{4oyf+j z3De`~cM$Hci~Q>oRfYW3$uR|ZQTG7r!)W->STwJQ+v4 zNm6}bFg~`hbx)0s8J>9BM#RXYEIESPKYES$Jtqj17uEwE@To&Q7#Y%*r-<4)60wgt z>sCG!VvRaz4YXz61Y%?VY?*AABCA5X@0R-~(AQ!k3I3McA$MpCVr2kJK%6nV#8vY~ z^1oHoMI8M_>oLB;u@`gwg;I|=_ziIIIq9#TLD2nf=`_n@aS-pCLN3so6MQ=UM1gkj zc~T5uv^Z+J28&|BN7>-z{a&;lS{9M~h%#mVUBQ)PUl`t5FC(!#aY|DoGOa{_6TQdk zG3to4{BSzRAHU&I9Qm^aCSIJ}3(Gja%T{1z{wgpqYgZw+us+(YySLu5Rf#&sM*6ym z`r}mPNV!UhksFZ_H$Fh#S@y2O2GiJB2(L4$r%m0hbG`t_{9DU)eo>$3w#8+_P`{VxX|Y;kd!-;M!vX#}8f z>o*{Zb3I2O^@cA5*RKR7_4(h%VA8K=1=I7%^jvVrTvh(%fFzDgZZOrVtY2L?bhDlS zpfJaC1W%7;4_>wsaMaU3i-DtGD*~ta0-mPHmJe6&<@_QfOT4y7R&VIHyosz1XU|KB zp5w$4;{Y!H%~GK3)e|E_mSYSnXBT(*ZMDS2XU!=`cwVs*G}P?Bq!!cr8Q~GxQR<3N ziOA07WLl`k>*=#kF(_iSDlNab0~nidyQsLFDfUk|k=z#Sgs=J+0x5LeYX7GgpfOe7 zc}O^BPoEox1#cICx32_If#vT6(U_Fyjg%{W2}~uL@8DzVm^7xv3uK>H@WC;R1F+Oy z?}O;#F%OhrnEL~v=R)nDF#-h1zMSSAvwK_|8%b`yZCe=dE`y~ zJ)I!a!Y7d|Y*cTa7dsab3vt2VggMMC%1iXT3*{eIrQg=23-4{HZs@ExS#GCC!wrg>heJV(>Uzf7g=6!_=7WbR8}}+XWFdW^ z*}`2z-VXTn;vU9)vk3&mo+4v=sMA-^***plM-)2%&S$dG9(2mZkZUp3mjSx~5Zgm@ z#|RwaS5F4o+Y$t?BoURde45}tXPVBP=}r8^X<#7L4mXW$#CxVNc?PQlc0qDuwuqjk z`1DW#H5}ZBkAw``g>DQ@LP|M)uZtcyH02RkC5ZLIzc*Mg<+uK=3Lu z?`apE%fOPs(}+*-X}*EW>rp>DTe)dFq`bTkw=xDzjxE6jxU--kJC&)wSS%*0Oca^H z3tD;UL|netW_fy7U%wv?-~G@+^JD67W~SZGc&T?D(UM%nm*#W+Y_KV_ALFNdvh`-Y;ms z2P7|3Df&egS`ocIyr0I^tlfA#$#yWl2OU#S3(u^XcF`nLFSe6v5I6AY<)bQ_pCiTW zpKDJQ8PFmdC$e+dVEtkdOK4tqC@#zq;&`sbO3&sK%P(yjvz0t-)99_!#8bU^;uHxl z(1Qn4@8fL1_(A-a7W3x{Z-yW|oUN7~&Q4>z!XkTv{YKyRFkwpBwzPXO$Mb=y%&8Jv zF$TR}f@J1SLDS!yX{`zlJd}Be9a?46xB0!^jDu?_MLp@W9)u7& zaO-Pxr`9i9(lhk(!o~HLu&Y(RK~x0N$b+Z{xiac%eWh`yXSE?Xm^)$x61CGZ@966KxEnGzQqFh z%Zoi+uUH)7y6IspFc;MJGLv>`yP{vljBI=o81#|c6)GCUbg@XF zra&`MHq}wlH z&|zi6yCv-urqUK(g`rnkq7GMtL--<;YbnT>_DIz^?O#%l^vDkG9ZQEOj#d~gLblt{ zl;rHagxWxBqnA@ykm(rG>*fCFb2aHIQ_Qeb993T+VgJMhxSmx*{7egUN+1-lzLyBwxeN zdb*K=G;&N9{YaZxJxT;FI60CUVZ^Ld5(EH`ubKHM376qn7lbQHfdj-LI;d5(MUH|N zuHP31KcV1q*F&5V&@*cyg!8l<#VK2O`9JHmu~dXJn0i}~aW}ov`CZ*EAQ))&2|lLI z+^n?6_}MOK1RPI4uiw3xOwF^_@b$Y&T2&q2dD|`fs(0ME`<~lxY4=#)oC;Jn!*KN_zs*aJa z@H92bmBI7~SJtFQS5v0aCu(GqqH=-VcIOCQP2(#4is|LJxXMt9Cj>1Vg5IkxXhzwv z>=l;EY*Z?3gs;n;mZ__dyQENr-{S+@UdWl70DNCDS9-d?2Uh;+BG2`Y-IwH8ms^Jw zUjM`!qE9|O2$PSei2ZgxBBes;D^lps$?<@Foc3J&q?u*yTXkp~g#K|K)`7V_retCV zBRbe&1Q%7-XBVF*MW|Z%QHhtp*I?ng`2D4GAzEZ?#YwvfF|Q4WFB8PNXtj*_p9OZN zKQ84K%1c@pEw-WG#4wU;~918w$yq z;dk$2xy9mz8LxC<2L4-Ka=op*IORw3@UnSt0KW4Te2f3&d$HiHx*_8Y;LcDum968R z5ZnwGIb>X9A-Ja{1H|g1J;5EMt}$LyE7aPgOm7`lb1-Epd#WTu=&8QNKH8iOCKvk_ zOWyh$GA#_F-iAe_bn3m}ksdhl{>kiOe|2C{_Wg~u<8*zejD2XAL!K>mGE9eCl1ngr zRI)AC*&Nvf30oxkm}2bW!Exa$AmFux)d}OWn4QpcZ8c{DGi1XWWrj5@?|2l6C5ySX z2-n$P8%3@v;|HmrlWcUd5K>y0?1=l;Z%H%Z*&c@T{UqrfI$nAYcQ-=E85?d0>M40<#aRjE=9b$cK2`$rDe>R z_iu;sOLjVnBh=sg^2vnb^k=rqj+jJXEvyl-2&OEX&Tw2toB7e7YLsY_Aan?!S@d z%-={`tSL8cww-#LN6I(eX!tU`Qii0|am=h%o0LP5VYD_Omvu(@#1zOyj<7=MQIp*< z=oy8#7BDI9b!YC5MUedBw3D(r)}=PPH<+w(U8C6X zHSLcznid5$ffKu)(aR~Wt+R)-yTG}_yItbacTBbBySuZ(3}Cl{Ubt}&?la4UeLDYi zh#M6Olf(;lTKrlxSV@NrMO@rF0_QRDHQ)w_#_SaFb%=(w(-0~yG@?sD!3^$>B7j_w zp@=7~MZ5gLe|jLPRKb+w2ch!ahW=D+J0)6=35a)?XnYuM-3wHrXUQ;uaI>|eqM+LO zBZgTIEfOFjMc$;Ha`-48YIyV7T@YbziX@FwaKtN2Oh+2&KxNvF z7+0pKWkg(nUvt2tqlbKL9Es``2t*{K-_H>dRwRWYPJ+y)`!}gZhqkpD#Cp{ndS0~3 z!*K^YAvqGaJR(()(p3NVGjR^Yb_t5hI~F`%n?wb<17lmtKFpZSu0c|F~5c z>0{qj+y;@0R3(YNVC<=DMJNR@u;`cuE?SEi0P85U(4X;|o0E_hPYvHiM!j!vkA!=_qmsSjMgzQ+3>BF@4Jf^}QbC zgtj`>PKr2$dL3IzuV%Bp+KW%R^@^dgJ!6i@IfV)#6RfB8vOjyQ1u=s9n)YL!2neHx zN6WzmF=+n)3x;}L+aI-q?1VqFXWXQhg&lE+$}O7|KA!Bb434`H%7Gdu8v$!_IIUm@ zh!|j)DBVerqk@GObQeRAjU_KGd{pzrMP=M3p#?vwSS^%5*3HH++(Rd5nV$&^S?D4# zyVx^bFlJd5wrDq=rVXPJMigObww+r?rUH++$^md|#jC4AVmdMLet_n9VDYyjgLsOB z`-e*emXzNTktTK5Ubj1pq7LZqbB~;?APY>eQzKxEeO7k~i!M=jWT0JA5w(H^k!}DzM9|ubW+(A_14aB-7!bP4!ck!{9P6}Fu zz=hW#UWKsOF#Ut_o|hLPyFsK3%GYGM+ok<+Wp?n1KE|Acrqq&Yk&uf$;AP_W7SSJl zyVY>d)XeO8nL%O+5tz}~yY$<-pJxNT;|V(mTsk=Yu*x41ZM*R%TVz(wX_2Y-D|FIU z)pj6y%NDixH5-{d_%aKqPHAF7oIJnS?xgVZyLa#1HEwtNkk9T>zC~Nnhkvt#w8wz2pQ7tQGOdd8@oobVy~Q;rOz^_ zq31e~;PB2^#-T?*()mI-X2qEHnBqdWCfFx=7zLJ+9^#1wBXr)x%<6vGI2DkN8I9m>GyQULFpK^ME5EsLvk z!ens3YG;p^-49?Vbgu79OSo4hv{s#Et0Lh)+-@|LBJbwYVJWNao>M4SEM?wGS#x%6 zYuz-PRb-C0dD6FV<35ZP$C^Y-2K^-aZe5W<6RxCG{+q?*!C zrhV>ZPB@e8G9|F6uVQZyt#JzAChBOXK(BR=w(JSFG1|ckxj{pferq`s!kP26EO>}Q zoU`D=x>Kl-?Fm0A-^ zxkY+(@EIRLHL*Cp3$7LuWtQ|y?Zv<7Qm0TX$s|fk3IsXJdFbl)A&MR&T}jY$~y>mPNjI@oCEJA1|(} zO(ONFB(*w@1HFi+HYODY6$fz(XR+1sFgJfDm=z{kdcO)9vrr6P8Xh86TGT{woTnrHyRDXh7gr}n;E^b=f=O#QRdpZ!S5Vfe#?Q%liBdV6d zOfb2^_$;Y@Y%A}zo=e7yF^9I(4hex;g#aB!G(k_L&eo(!YG_Zh%8Y9-M}>!*@efUx zhXDv#0J69!^*O}E&CMh;c|rslNqYhFFOkUk5p1{duPrxp!%;;1mCe zb%3P9|FBkE!o^J3eTfNMTjx{e>p;sl=6J_69JN)gdl{4c`avyY;s^0V*rZ@bS}ojZ zUMc25&@r1l8&GWhJ}+tO7+rfRp}aT`pXvB^_ewn z@YNPySEL-`Ciryx2>|-Dg);Fo>pU(bi7o7W&ENw2EFwq0H^6tvVsd0sn>L4nx6;zu zZCvhlM~g9rA*nG-hRBI#U&M`c%R+Gbl4A(g>X%bX4YQpfiD)voqO(_+QHyY@qQuYG zN~~F9i}U7Ivd$RAv9%?t6cs=it=_$Al#aD^X6mR`79#b{YHhURqg?69EKb~ewDvM* zRA;odcRth;Q>4r|wKRCZN-ynY{ct>mm}*R8HQETO5rwG8L_(Q}21^5`d&b*&?P>JI z@LJe+HVwkjwxNbWzcpYw)e29jnvTAM**3oL zJrr%5Kf(Hd`*zVW;{@jmb9SE?@-=e3SEwjst8CFl*f@^KxTuTygaKM1Scdwxi;wLt zaE!eCf}5pRX9#^kd=JGcB=D+)Dmy|-QM`VV7fe2&q2JKGdKA2uOW1OY+}s}} zd2x5QB5DacRPuM=}@>Qcsp-cXiga@oa?V)uZDlQwn?aT zl1jDu(Wr?EK94(;j+aUcN#JReb&1bJjHz3!k!}XMu=`G!p3Wc52dg~Iz#Sx~rr zyeg!=l1%2%)b{enEk-KURCBxZyVO=+& z7u7*dHK_^u0sS;|*Q9>Cy07N58;6kjgm>sEvHfyQufcMH2OWRv@eV$AG(vib(+(0h zD=R%5z{?&INqn}+5?5*#wmz?qvFbN`s-2_OogT4pTsY0p)=22Bhz^Q`JMKNjX5A7V zYLh5GWaxpVam%9fR!~bE<)X3gG~=s}aT{#s((Nn>ASh>2U4 zyu<=*)x?j+S^T<`b95_4)Y$ZErl%?RVl{kNRYazWsd`+P7Q{pqd1p1^bgbWNv=I2ywmkfPKB> zfSeXq$P(u0;Lt6=lU$SyZr#k7@F(RNKzEn$H8Cu^_?wkGu*)_3!0`3vVX=$vbd%!7 zM{X36V1z=@ISe`sF@~+X7O6aDbs}oH3ku<68I3Xwj~s|wE}e9g?l}`|2N2V9wWEOL zOVD|+9n~uV#Ya5fJIaU@;vJ2!H>kF2G~?v+7iBcFV<{E&6T@&PpI{d1DUZGvjccNH zfLrPZR4U0JBP|AXQRNTm&8}5Q-gmzrQGbqWSsRzdYUx6_snY0AEET!kdS2%yW>yDS z)zQ1S&=1 zhlFPo<&5nhJvg2bj?Zjoglmyacj2D6neK>!FcQ0LozlvfkN^=SC^X~PF@2#*A?`t( znA^2jp)@jTT<5|IlCq)i5>4AKKz@Z(Rd*<~<__f3=+`bXm`5Xi01 zW;9+7!CpiU{z9!4>g2@aJk#02u0S?p=iBlqY;`PbUlrf@i5ea?f#BgH$s~ZXJL5AX zEPqb*4{;+tqfjQSCGNe0LonKFt2bkhztzzs)1;4N?X21kK+%OnEVzjuVz*30bLTSY zm(KMy8&In>DXYx|01~Fdo+zf@^T>glq!>sJ^Lr_i>Q+>=TJu=h=MHIO$T6)Y;SNQU zs|`_8i^yMx-MvO^~= zn`&JtPtS|14P{@y{iGmu(_G*ZPYzrlkViyO z@;ai^(upe2BBlTn{aZa9+=inx>v9i6fVZ7DL?1d zkSz>Fw=i&DycqG(ZA-TE%X@3zpi4Hfv@XUxTeu)#bJtYE31ZG2suG40?$D?1F`SoD z3H45`iCkbF&1@!somaA3VsKKlF*ml`q8{;{>7-qFVwD;31*!QGCFxuEuMr;Jjrwpu z_MZr!z>DGNXQ#Va{EAH&}A=Dm<&t@d*27g3l6K+9sZ>BxCk(R-5^#l)KgDCPtw zy~A}mb%tln#3%))gK4jExNeNHNk+t80-sZib;_YEir5{$AG)IAUK}S0@e}8wI9Zr_ z7kU$uX1ANWnk|&D$MI;wBr#bC>V6<8&ZMlVI(8xCLEBjAgn;^d=v8l#n^>TLea#+{1&YcB~bUq9WP(WWcYBXQ$&DAESzKmuSVL+vpQo_L3d0$7AgfF3Zyq_!q z8)U-eTJiwFEc(S!x${QYtmoR?g~;ggQ`O(2)`{`g;hIDlCUmDx*;tqB&jp{M%q38h zFk(w{nHw?qUhWajUDR+eKrE<$9QcKSwFzgwNIrKO!|!tktg>pk`1_GuWkBscQ43^S zu?AN$+;=y4z#8l<`iCND_9Lhuq&yRRPOYT0jz7{eJNQ_%&2H76-$Q6o7z9oUUsVkU z_KvChr|JvOw=Xjmjngo=+S_IH2?2>it7yU)al=*&q9T|%6=p&{?9P~>&+~LD>VXLl z^deB|k{)Q1SPw4eCh38XBVdV=wzKp5q34qIlwSvPgUfE4uv4Cdv9A;H}afv{LB(%ushU$KIMckn!T zr!JqS5wbkvro&Od!ITCeriwI|7%5I5l$%xa1ee$|=>qdY${x-tQU*~n*ekbKSfq)M z7T(6ry85NdJtq`MUQZW`!M4SGbA;V{+fbpn0P)4eQdP%1b5g+>tbV9cN@tjoiwY4! zP~jca{zM`8IgMk|gD>*)iF{Y;!Zl0~>x|TLp`Ix59yO&&XQxM*I-)2}#1H_3r@82; zrp}BIIGahD+{6ns)cS<7ceP894b(WrHU_=%qN%rf zC2owpV8>d*8wm!^HVp@2`VS*8m#cSOlSz!;+vq~@!`v)foHVmb??FKdG_{iY<20=| z3=Y1aN^CVTZHUTG)oHccEY@h96ztY;BidEW>4-T5x~GTMxuUenEtzbZw>$VOi3pdr zvN#J1Q;(xCIZLmPvE*cm4UMx+eegR3*t6{sIr)r!ka`(AFRA7|#bvUvc1; zi9o90KIxOCBkvCeug^3CweO`w8F?g+IycDjT{X_k634vMAM#dnduLBvSC;Z!Tgy&s zA)cKn6D?sZunLtKv2Np+QkET8Gh-cj z89U8M%-)*%%qBREoAq_Rj}%;?SwYfg&=5J4luzS5+91Ir-q5C3Ogc-B-DMHPkmqEs zM5L0)q`!F0VDvJ=HhqL`Pij1k^~%JNTG`zoc@{b#%yT;6E?V+69(+Rh_Azc2HpVb8 zfW}T36cYdGKCV=PC`uNm;6)T=^f4jyn3joZRl8%9mYHB?-2Kt*#xr0yeOEi=TCGMcMpLjI-u&t^$fL3UdOVLViqR&7 z;j_-9;MX+J%$?p*2bkd3Rm)1#=9{YOH^{NDOjXY^ZGzua$y)nxEqtAj%yhWVJ~@6# zmHw70O=fD`KbsiAZ>#8JUL}aHDt=n;|BiB4g_2yCApUdW%Z)QXA78GbL&zwecbCF^ojY*FQERAJ-Oj&8h_z^SZYaG)ZGUEihBX~t`eK4JBn+SRrdlq}E zd3N^n5-?B9HouM87Mp`?yn|AMFRAt~b3x`wm}3*|zoJJ8BV1aU5stf1={u%HRO?P^ zER2IQ+blf`xnH&`YD;3a^xaaAzKK7RmsAb+yEaDQ=f?jAUsdz*wfh?13tL9x*Po5u z4Zf}(uEgj5XW@+TxtGQz(x5I*H~5AsUp}zuX#v9FB1!C^8|NL&OQm8hHp?=p=5eFl>&wiP{#;O1qe!KBaOboaA;Ktcbr+=8SV-OBEn=03M`N7t*7BAuZWULGyR&wUFKLRJ6IM4W zh!0P0{{Bf(Tu{AQJykx5ydW(0y-qOcJ^i_@JmpE(fTZFMn5HsXYZD^ClN~8=ru!E` z8dsNLBAnRS0>r}!@2oqPwxmmfEo=+O~?9?X0 zZ__cw;m~b!7*jd!iCi*+np3&8+*34F7Q#SoJgL;S{^TE9l>VYKA&nT!yJ19N#X5q2BZkNLZ_bXUh-JC_ zb37P{%U+X|?a0a4p5S*WW(l_{b!488aU(kPOj`{Ov!wv_uIw^8%9g$6+!eS(9n4)1 zcLc`gu1Gv?jyhA=bdL=or1aG>zUjNwuaXvv=fuMf5X`N25zYpC&&%O#Gu6S^-jg3& zxZq}6T9dPcwP241X8c)Y$BjArh-o-~mTq8#Nu!X0cXnY*@D%~=G(9uFH#>|>m7pb- z?IdMUDmi7xa;oB(Lk>Qxcg%A<5m6+oA|MC{92Ol%BjQeVigMG@*VPi0^HRCe1_ z*#{8QtoOgCM*qGp0$ij|EV6fMa_atWPG8*UE7cn@u`b?Y81<3O)17@-VUvZ>NOK}N z%@K{xDpmg#r7kxi^x)M(TGJ+V0LnT1$M{M{15yMin|Ru4twStRirJMEHFv0%AE7Y| zsi{G9R@5^~CLX!m!|B>T$X&bSd^B3~!C5^xr;Dlb6K&L2 zlx8X^^~%M>TyYbHgr6rR{9MkB2|rimz?dBFjm123;hEAp>8x-NEd(Mq6MQ=U1PA>! zU(F?whjgT)JJ8W29Z5tbV$z#5q;soGdrS~_+dJ6r6Q*6e2a%HoP0Crtlo)JZRNa-Z z)gixXej|G(qDobpXlM0& z8G%o1UILSd6OQT;Hc0y7%sk8lDm>eI{eL^2! zz|W&XSh>9{Tz8(1I)bu{TSM>|uZCO3T=53&533@9JVjLgqtZ-gAxd^cV3syUQEe~M zX0h`D`q>EDM^v^g!0GKwT@6S&{uSz-RmV*aalVQ}B1iG@pN2rc|2bsgxGFQUaK6eM zmFO6ARip}c@i7N8=beEw4QS=uX+W5+(^iBiOnB!A^8#)RQC1~U*IRk>%)uGID`ZNf zKRnG#jwA_}BP?1ju##}-gvL^)M0vxk(P?i%U~51enu@=aRC2} zr!CdWCxffD@MrULtZ!tfn+l&+U9Zp0fz4xr?$MsLT%NtzdcI`I6xG!rH!EClx?%TgP-39n_6WF$7JgLCHH%qJ+rTs; zw;a4(^Q2u$F7p8JdN?g3XH-R`m#q>GIkX>Gi?D5sD2>_VUwF|jXW3U!yK=3ZqQTPW zV9YXg%&7TNF6=}kB3`QWK#97h(eYBUu_A5lGYJhl_~^n_sT%epR!18qEM_jhyBx4a zJ7z$H%trNO;x}ZrBLw8trHJ!gNNoOFa5hHyKF=G0>?~b$?@bI+a2M&|4V-DD+lh8T zEQgdm&Wdjec0*6i4I9zm6LAGrm8cwk*2|Q;7~_VyI%%^s%Gn%e=VpWdv>a|kli%!1 z@{|k5GW*9bBKtj(c+n40(=>swOtoX;^TC5LPkWHajVQd*>L>}OBB?q)6t9I?TubZC z;+QJ9SKwS390H(1O@~?l}1THBtk`=>F|>BM9|EICQ$?I;mze8NOy&q z_ouN1F&AsGbNfyCjV>=p8!TcSS0Ws;@(H%7QA(Bq&AoSMP=sgwgA-gk{*=6fPf+KA zbJ?0Sm7z1UOJ;L4V!>aiPAy8oU#?X9FY@%PFwxlS%eu>k#X!xXUCy#m7P{${-ganh z{Yg6YSJd}m6}zAu`W5_VU3T)bqrGaYR*GGGo-A{*o$PQ_&JUT5Ryk7OtrqdoSCFrf z+#mO`YD*@bN&+Sb=Fa0C#4_4~niRP|3c2HK---g!p~;N#PV}aHcusMTV&z;JjFn39 zRwaYOra*AsHE2HZx33?@$Hv}-gt(x#ae+Hy%_zrrgcCzCUxK635QPV{gznOj#;s<~ z$(Zj`>X^0eO>H%JizU)L3^a66`2I*$HSNBN? zJ@N>cV?@tSwDPtDSmVZN=1yK1W`0UpO+;nWSl1w23hAYsBSupU{S|_kEx4NZar4x! zZR{zOEeEPc1o_ZP2MLGr5s;t>9TZM!hC%KO>qQlDOq1JrTvF1xg9mMgo%1j}K>K(% zOk<#wU=3{@Y0MoyV#sP+^eqG#-HuCS>6tqe4TW%8{qfnB#gv^8R;wCHqjlQYB41jf zt&1kAD;#7`V0+@C5mz}Cp#5Y(EHx}_)^Y2$)nIr^IdsaOG;@L~lrbNW?`ct3%e#TvivW#wVG%V68?(CRoY?6bwVNu)lT16-cE z3@eB{Ug7*Wg$eqRT9`-iEy&nD4!KSCdO>t)}ibK z-yMJ59GN=+(OO2|I{C3YZ^r!1CVoWx&2+AV!y)i;#Nj-F%g&|e=@e|(X$o?E`l#;I zvEaXExpehK{Mo;!FQy8WGO6&)P>zT*0%hFZ4jwP~>&{{lmhSI)@aHj0r(eO}=yEf4 ztjN*@|Aj2DYzw^jzk+3ps6f0{f?p0D_coaV{~K90tN;JW~HQ- zFRe$*D+D5TuXeIFWjiVy)8|%j=Y0VoWpH;!8HkxPf8fAUE-GYPQReCxJ;&N@=5QXp zSFNUfqO`8bPhv97V44ylsf3>goL35WODi)r(v>aUhYDJTEmcM7KWqF=#3 za#_N&h!5GprztH`WJ2?@6*m5@wC!T~pqt*1w;ET$es7JpmhS;?owuIvL2rY10pF|q zq3PA$M(;v1wXN|kLSu6=dr`v0UjV}hW?akTw1jigL;X?*3z6fIKD+ps?cD7`zzyHo z+HlA3wzfU3uAA*OE*uT4@p@F@`rOt80*s(8Qo%?fP+dZ|(ZKrR~ygTmT{>QLR1@wNE?9IJfYk zuJ*+lm%vV=E!c&-`V}wdgSlu||5)&&s<_UDR#{7yIZ)7!l7EmEIG^y#y6R3HCBKY$ zJRUpQWGq?_`aEsr2!4cw;74^?&O|PA$3v>~XK37#@mRqIM^@`>@F(h)sXJG!;2c@r zq6+>@6E8HCXKi(9?adUVbc1?*Um2EHWYS9Js>isLWC@N^B7D*!2v^G;G zXKOn~t0oznr7a{Dd2 z#>-pEd+xsT4vznVliM_+Q;j;#xN(^$yK;a3RQ=doYk1_8dqdNQx8gctw6;lFf5eB9<|8>DDt_EALgR&?al-F|B>s5kYn8~S3lF&{SlVbxBoZ=z9e$2dVy zR2#76-VyJ-oC-B|o>oywD-vi1eVQg+L_uKtnHY?#gWb;ojJ1zbkW_la$!|4gjs4Y@ z1e1_V4Igd`UFLuYS)ZgA#cE*`6_FeuaKs|-M~ZsJ1yz2u4I0HH5&07ZomMHGXkeQD z&R6P|*U39eLa%XPs5N!@Nj0Wd6Q~Ku8XPN;D0(=s&HBR#cpPM?oHjc09PS>`GUM57 zE-eU&M2jHv-<87e@}kJWc}iMRxlKWXa%eycPmWS+(|>Gpkj(FN_)&ma64j-twJ}Nt z;aTQ@aQ@fhIdGAk6W>8f!~sQ$RFkaGD$1t5Gv4^@h_wuH^lnbZg@zei!D=0#NxPUH z$*HSmKCzQ(;{n2w79HQ|PGpJH0!cRv+;;Hj9gP!HesYW*){&&_WyT>q(=I-;hBkJ_ zg;mKboNhPE<`!37+*IY(pA~!KW>JDWYOF^0b1n{RghrqPKXn9*pr8SA=e{l}N|oPu z%`0B%%x5u)#?*{Z5KsQIx(F1o>-Wkhr7`Ymwr$Dn)^w{D?EXzc>`jECE<=W{6&*9%YKmq!qyoG5Z!*ef znKvcWZ_~2GFKOF(DcB_Jj9G*u|M%xid-i}quZ+=n&2!Ko3WFV7pB;mPRYIi|37^n+ zyaRocf}bP$4pG6r7=87t_ULm&%4BW*zbN^?93@l7QPmV&TOcR&@i7IRiB3R-253IC zmU$E&BHiNg#E~idmXwJ=I^xQkcr}T4;!y88%)Xv%?QfbRQnP%}&NEOvR`Wf=o)NV;k42yWV5*DK4WhvxVNc>^Kf9K5*} zn5RV461ladl?HCRX~fhbkgERSaU4C&-|XOc(;TqiEbYVxF`3K1o*W==MZ~Z>h)=8Y zZ`H6IbltWl86?FO35*GxydAeaf3*nj2s}*eOR2z|7PBJwlO=!@Z4AN{Tdd4x*&_^d*O(AKU_x zgokp5iWLpimhJ(i=H*(wh4zNcHFS=OGQl;f(xlhgOamC1Rxrd!;~UMrCh`RBKN#(v z2C_6c5pxx}wuWv1uR*PtkxtNB>|oi&=Z6brd`z*mzk_ebF-sD5EEeN*$jE_k>|S2F zuXkH{i^|#(p;+0xwltL}`O5MZ6`gv>=$m_$7TC!~V>s%UT+u`Z_FHpf(7_`@3fxI8 zA@6QJ5jOjlu<#Py)bt40qioD=^-I>CC*62_e2Bsm)@*5(OY6K83C;%x#y$2nbrdKR zLZrzNe3$k6DLa3kmm2-B`&V2$+CRYp6#wa-RVmSa$`Socwv~pKHCyHB)0D|5+&g9)Xm!Zc3cJQI1>G}t*UnwHRd?UHD|nn2gJ;y>59lt@qJE8^ zk43D<;Q!Ozxd+E}-S>U>?qac6EFJ{Ghp5+@b_IYY8R}tKe#xXLN}_GSvWQp`Wpx2! z7bGAMpzbb2bG2}2(TS)ww#VbT)5%z==y4mXY0{)l(lkw*q~jzLC+Vckq@CGLJ8A4D zO(yNMQS2nNW%l#^o%`HfP)gk7k1l2p?%sRP`*+Uyy??S7yRo-HkuVEGDU*>|AOy*! z9BX$=Ym#lW{_|n!#mr>Z*PWj6()1kW`|1QqI9{QF-U)b!NC4d^9Z}r8*;jh}a9$*1 zY=W5Jki|XSLCsfa%c~;rin!DAbtg5}8sm^j@M?u0eYLFuT`TiKD%7f1p-Kh!6%`A* zz8H?jBqqGR?(~4F+HsU`WHTXmVzH>k3^=TgF;$cXQ-jD?sKZq9w;XDJyRuFy*_kdR zJz_tml6LV%Pf6U%9OfGmRlu9Ajq4+%yH%MXq&MiQpFCX%=}&5q_+nirt+TR+uq`hB z4WgwtQNvHD{YF*k*Onvg?@?<^_;;hOwi?)XBXTF;u!4i^M{+3|fvT2^fLOI1<=d!`I8eQk zC9;g%v0`wARlHf&V`qj+(wg_ib8ah;B}q ztid4;$Go^`I%;9~Q7akJj0r%`@&vKm)zE?~6j}9f;T!|s$>u!GNEejLc<8H|3|U-X zy(NjRg}YT)wjB3f#}Si_#T#|Rq?dm|gAjVlD|n+`xv&^^HvF$nALiSbBk2W%Kx<;K zPJns4VBSNW;CnA8K z=ZrQaAQ@*g0i_)I3$TR2ISzmwEg5d_v}mK^ngZ*H9GDjxB81-^@}YKb#bI~*#AWO$ zFnG3AiAF=jc)XOzqgVTkPg;UOtLH;ZczzzK0jL|kl@tdfrs0oD^I7`eLbR9GrL`@b zCL~Q#(!UTTJ>vTd7a~+TiIi%L^%1Rwa+9=8ZH%I^a0G#IOjEI5=L2GDj&N#occAti zvs+!r0ZO}_(wxcM+#R}v>zXPYHR`!2a&%~>6V@DaCgEpWwzPHJ{Jix_^LL&=(i<37 z?%S}Pf1eFas-}RhF}yyS4-FvTf`6+J!Dk2<9J!g&ctl9GklLs^6)vHZe5R(_2y2># zoIwNMVwha0NEscTDp?&0o}PtZ;2d?3G&TU_MZo$NO-s7vE>iyB+nLQM}b8T`2$694yBw*eb_$G=l`6y>njyczRKBQrJAq+hc zEmi=+(b+T+iYta_qceig(-dN236tcZ%MY-#J{uC@q4H=k6YTeS30=7#k|$Abqe+w4 zoCr@c9FP;~fQC|mT|T#h8q>4m)=0c|-70aCywG1kAZcxA+=sb3VwD-&F|Me;cq>rSOjMUH+G?ZL>4)k#PHRrzbsPXY2h3Wu54tUbZ-YQin-|q%t}jVxxmAPQ;q45nvn6hJiD7cnm~pvwO?`3^l89a z*9^%|LDPZ)T{~080WVgt*bln2rVXY23_mBs3TM;vTUYTGP0A7 zTnQ7{3?J2Q=c&u+o)Dw)1fV-$-5|3ygwWsnq?ro(mUqj)A(cALW*Re$(WU0}8nU!WP@>?b(_%g!>MzI+aj*`8*R{w$Q4}QMgs`W2(gv>)+j~f?wj5QC09IE_!l;`j8qr3{sonGQHeAwowtZLsqpLj=Ml1G#M#uL@J|&MNMw2@iD1cKcbT{9h`{@|K+Otm2)d6uc69Jw_SoA~yKb_!k0zw$ zk8Z5F7{Ps;J}r-VLPO48ICo)weg<15TEs3L;GUv3|GCK za^oqLs^FN|dun5O6=S{z-XEKLrxGK1Bw>`Uj)pjZ(=-uFJZA4%X~qzY)qcW(F$5t{ z@j)hu1Y(f@#HZyBFKTvcoc_zOI%=09#xE_e))mXdR9pOi3CuVMzsgmo&}f35`+aG5 zf#I!MBLcWRPG~W(W(@n=&)Ix zGY=bUh*jyA9Eil-I@V8D&|x=>_Fr1P=>JzOp}-o%l!c^hl~@+XO%F$~8cqPJXEgyI z@|buPr%F(C$q2HdX(1F}ay=u9uvpoN*-8UEliECkrvxFmEHfF6g4MdHZ%(5vk+pT} zG2`2_unZ!A9O=u&Kmj<9I;f(MV|ZZj{UM++vCW!}q`>rU0j{93I0^8VIIqCc7ceUB zjF^Yu=;zqe=d0q+M>j^1&9&-l(eH7K9PR?~a_Kkx+qC;nDVbI>qhue+LG# zR}|%#4BUpyFkiE(cp>vb_66^S+za^^2A1$9DBkvFpsj}OQ?+EIba>q#r(aAn17P1xu4H3p+ntC265 zboOe}FEA0JPClcy5d?&D6oL*VXXF6wOq54ER|8C5ev0a zkCKCAA%(1x)GKdba9qo*Mfain=tPmJLi)6QI(om4g35Q%jR;y(4fxCT;$a|uTJsso zDK&)Qr>nQqQHAfZ9x3nE*;3Q@|7r-1ahMrvf$HxgV5#-WrkgTC_nFs422y!mOVtzgzUNpO-HxnKz;M+Nu=qdd1Rj2Mzl_&7HK_3b;QSWwMrLd-nfhx zbKu-bDT1GIrjDaVJw=1u3VSl-X(oGe*A|`N(GaJy@cpGVq}f)E&@P9787g*#COFJ2qPIIk z(J20qaKdq3A>JKfQruthYQEUIt@IT&M`vumMbVZAd^X;udo%w$$YnYQHFpZ99{I)Q2Hg_S|R#rn_l)pbOEz)4L8n~O60NQ~JVSQ2Z&Y01?;+H0Q#u@HnBEH&S-ForuhB%SyUVi5 z?J!4Tq%mAuy_-=_nOIcyEmOPRQa^LAK4peO9Sw@=Pt^q6hPXv~KDv6MT2Cu-3mHtJ z#{W>IH0%^b_pLC>i$O~|Z`3ZobO<<&IJmMCVv`G2 zUsQ}utW9e?L&21?HAo9FLX-qKlz<%aTzw538v!yay78{4Ea^hn{MEsqcsSxBa&ag4MlUd;Idr}hXjt704&i9fPQ{nr<8>77*mD4=6-L-;(|0l`{08s^vJXI z)qTJ$yzjFxE{)ufmOugn>n+s$C^~XteqK5T(`pwpBVH7uO#KRSMU784$=)|jtItIA`@+_u?*}=)?67$uPmHOq&;$mcSVS26Ru= zz<8je+BH+Dk&B4H#FjH>gW>ifO(#x4ZG+I7a;LC$KO|CBeFI&FfLQKAeWN|C>wux$ zL@8trG2R5UB+q@ID%dLB{PZ4cQB0I2fWZof)DAN-$x#kFdsKOheFx37bA*s6M!c3bi zms_TPCeD8(ZjvlFiqksQB(@B?a`;|Z$%l?kOwv1GVHpZ0)g26Exve`Q&MtfdH~a?1 z;z_eR*)UB7EyA2qAU0EUVJ*K(weD1oWfu}J#0?MSzv;W(T;Z=!&NZFiQkX3jh5bwH zm%moXTg->;@p=li;i^v95sn7=B8F~`>&78QO)~ZuJ$dGT5i#6~_u|0iY%Q~q@h2dF zP&B@b7_OPWOvK1bp5K7sn^`SvGIlj@b?|I)GnXYy#LCc%`L_3R>2m%`Hee8oJv?Aq zj|6q!%r}P><%jZyc)R=}kti=qPto%qyPR7Yc@f=3a_7kHn9Bno3Q~|$-ht+*;sTMk zytb{+dxPP7?E$@W*~`1NBGN*Bu@`dc9nPpr%elhzg!ap%5dEUsA|4=*Im?k#TA?X^d6mSNa za}IixQ=y_1$y2Mv{~o5iwPSiFu-@Ugh&C_CzYAI{EhQsLEZVxD%R#A$kAIk-D1J*; z=HT=(t~zBGe;PR{DxYr6MRckab1N#6hF=!FNwh_GW+%OIxgmN>3O03MCPOHM8l==2 zeFU@N7{0ofA2xPC!DX~AqOk*R8L6xrsaFu4N4>`fMbu5MU#0{j&{5pB4a54gGwM$& zl4p0%BnrQip1rEAWYQx>^ugEZPpUXnF~}Evl0Eb9;+Ow6C3h=%yOMj9#N(>k-%aiQ zJGsAQNsYZ!5W!b+jDVncjJoP#=Sfd-SJyj(=Y1hM{_(H@uQQdw>#Zje$YSC&F*0&( zeeHk{8PEZTqQ#*UlEkaSfrU%~E)uB*+v+wyy-%JTRn+>B96%??ROM~2%?oG;#0GBo zcW6`v>YV{KvfpzJ>Hayn}@9y-KsbGdkdX%PV+Sy}{C7?A*4f{V@C>Av9s)QT{hH z`faZ+MaB5{5Q$ag>WLCzk}T_*SIPDmO_NA_KzpDz_;lWXSozxnyE9J@_z#ObwepCn*DQb+ z5WECpwsV-DWRnCFj9Hv)z2P1Q^#f#KB}zx_>ZoH;T@5P z0BS^na-&_LR$(^c&swT3xXd?(3=U9IxGUJGe6EYnv$l+?h{?hu92V}Zc?qFVR~eoP zO!**2wXg1q5b8v=;Jy}dCUqzRONNS_;Qy-%1a+E8d8+8*`&`O4i0kti?-^OV2+lBn zkd>AHhXTel;B`vx7IT{by65g)V=29=l6PmW?yZ`r2VZy?qb@JT?9cf1z6}yEn`ql& zv;+;3@l98R7Ocf=XEED>KJD_~LR;6hwslN+7irR)wrr9bNpOUF4V9Snf0C>{jnna` z#=Tl0vBnL%(W;>{1t4ZO!bnIQ{hVy=KPkf9ekxuyE~tJz9xz<}@S(7Q0?YZA4ga&>q= zDiShW1o594a@d3^nW<|o2GOsm^c=z>*GlQ|_(ymOviuKq?R;$4vD5A3Wvz?mgOyl? zNqKSv%i3!5*{Ug(HaesF8Bn6!K3RYpiZAtUa2ZWcLRB+#FLmVy6vk$pU^X&qkzq@T zUlZ9$?X&sGoSch+VqYr~i+sYn33NNpVCh@Dmj56A6M$W6XOo(Q*k!h}{S+6yJDcikmf!T&N)Qvb>p%n)yjtNUj??Es zv0sMxRjAhHpn|me4|1nymaGD|Vmr4oq@z=BJTuaSG&0g-sP%J4U01~6cCvT6;|u~q zCjpM{A$$zB7(88>)+8bdEG_$NK|(k&#Zh2_=~Y+^iwYETj(AQk!%Rxj->q=jJD$_i zbNee6M&X1-=AKdXVBI?rYtj?PR)9Hobxg!uLg;?=9y1d+5k$!K0-VIcM=p?l*O_;O zZ}q^qrgFQcF?skY78ui%KKu;8IBxc8+x!8typjcr6>K=r)1lyNZG9zNTdmuA``zyV zoEc7N0^4b3r>vbAwkE!;qF+$*lS*u1XfK0McsCVxM$~6oV&K~7fOr}suo`LA)@#;c z*U+c5TCBAvx%yG9k=rP&SP(9oCzu#J?6o48t#@r4d{;4UODMJP$$A%y+0+1P4d`o| z>sPrro!Mk11dx9c$Om21q3w@8Q?P3xj{DjmeNSx%4TBwU8YGcl!n)y}@0 zZx0w8-}KB5^05vK;hbg5)Ef_j`f1hV*>>|AS^wVJK(J~aYQlD~RWs;Tjg@7qhH{h( zcETmqKD?Q4vw>4u)!uxpEiBu_%|sP80@AXce5e&D#jJf}{0?Nci(AR12t+{b*+> z*lB^#t_^&F*M3dFc{i^@Z&{Q(g_|wnNmSvMy^G#=ylbVr(1j38y^G`SJ)RZwzRFnC z5)VJ2=A=RFBix1c15WTY-F!o^3m+lKGs`52TwDK%YGV7#T)4?}kBT;! ztBi`_*OM7Sot`E1Vs-7Tpe5Y+ZePx z@vZHG{~^j6Fk-j>_EET$HPZZnS`pNB2uL9yGhyKiSAd$AcuJjbZ4QAR54>Euk}(`b z@@3vo{g*SfQONc&))S%R+r{dzTC5)Vmzw2fwl>ZgaiKZF-BAM17pr4yCB3mSwlcms z)EsFKxx4g%(rNc1&|BIZZkL+dDC2X@iQ2YyX%{syI;G}z_V_<)m)gaZNv{5Jb4R<_ z20Ln(Zpd89Wize8=Favo;)Y$D<;OB>L-|Z|;=<2lF>lLep2$4&!ud?A*eZ{DK#2}KW!IZzU2z_woWO{**$x)`}6b z;{a+vY2T7*?Mq}ASR(;3uLOy0Dk8bHSXwv3fjkf_dDCZc>)R>5Ra!T}`Y;#b4%Z8j zI``PP%$;n*|Ib>~AEM9w<6dhw-p)6%8@ssIH)Im54(nXlTkXb>@XIRLcD9DPudVoI z`s>%ZXub9I`x-Gwd~FK;64^RCL(WLmIGte-g($GDBy_T(#tmzRfx|&>{@hO7Fjbh&9;YQKaYeL& z2QPF6qYJtr;ig#@$+|S|R%b-oUB^PJkJ#+USQaOXM3=2{K-D|tz;4Nzbcm~o8J^LQ zZMA=!5}Q&3W`{_Jn6sMJ=#<H8Al8V-J>}xvoY*F#F)@3sGz6AJj^ah{PrPrIq+OK7eao!IJvwW`ML7#K(PgBl zCMQ;T4Ej>095D`r_-CecY41_~n{-s1;_%pN5`a4NgyLCV2awN10~b}+ z*_8y8M7WCgYcRE%;m~LO=V(MEW#*>IRK>w~Ki`IEsbI6a8S;9#24@-)J->EWEyopH zYmPDGcSdjzY{J874=7ww;R=KlN3Ggiyp*YJ`($pj&>ULIf@YQs&74@! z(i2^bg+Jy)f!0dAq!KLUzJ5mxk}Jo~o?BhNP_GkzCxnSUdXp;kosy_WY8aK^6IyOW z4@}KaN+GdcU~|2j9T3)9c@I2nW3-5FIv6*8dMbPcvHg=%dceiha&79VgtDd7JX}mi zZGEmoa+YpJVNHL5-7v;g2@fCdoBPFKSEe}ft*}mXE?~KyMGh65II0+qLKw!pB8P#2 z8nzuz)P=5&d9hnwi^f2j8No)DtkO9LWNe_*ObcA^#eJ?EdE~fx{&Pcn1g)f1lM*x$ z1|-KbRC-bb1S}^OJ}Pd%wITG~cAfE_jpjK$#?#>-ORH;tWm;p6f)DCpjCeTPtvipJ zh7vXFCJUult-@5YMHfnA?u#Bms z@Gu93#&kO5fCvLr8yL-Y&(!S)7#a>@&z>WYr%(j=^;i^F{7KqB+xo~+hw|8aPSs4h zJSuI{f)gPO&_Kbd-CamGp=WOVrpD;_G4y%i`KfXVt6Z@f;vhrh*Tk6vGW;xw zcvPJTnD_-}TKPK<-u^bwCL^|fl}*?Gb0yDeK0ZVOtIK2$#@32d0XhZL^AKV=IjG?o zhH+$-O$UqrUrC_h?BF({?TYSxOwTVW`96}4ht_Tv;i=3Y)Hxx^ZgB_vEhMx^X9qZZ zxj-N~Q217{z+L{j@8=5~zEF5&ds=v{IDpy&B`i`_>O^@NkqJ3>uADNs=!VP{ukB{@Lh zx=k0-c@DpvVSzHjHA7P=p+~Ku6cZFi)>aF_I7MYUnC~7J++#&$#BNRRujFPEL~MOqARGwbwaC+H=~TWIZ7O73#S$j-e=P|KVLa= z-_fu(>!-HL(6B7%YE;bYbUEe?&N1|%-9}(iWKxxWt!EbC-(!W~hxkGx_E(jnE6sd? z_OcJTeSxeCocD&=aS5%H|#4;f`ZdP|x zv9z(u+soKKFJtAX^@ob86v%BtlCGWlpu%5Z2`4s}2s^d4{kaemEoO>{0eRIhVQmZg z=)W{9j`D5XL(&>T^C9yxtaAQ)SG>pI$H7#{U4WL*pBOgMCW9?ea9WVH-1FXf`27nv zv5P!vF>nk}8jk2_-VK^(br z!z8;`d)>Vz2g-q8>8CJUz*3=kop)Q)Is?r?exJ9FoyJ}!g--0%t-YWW(|Z^ACv*wi zY40hng-0b&CpG@WxdjDti26LeS9f^#IdYpW{{9Mi4b$FC;JL~h@cK<@*Iz!pjPgiT zm{0>-C)DsIJnQaeYS6Bizvc2rUEiM`@2#_{_bzW@PTy!|^*xaKiHZ>ryy1#9(AH;n z)Ftv6rqJ4ZEYx^_7I3QmFhD?UnpEY`m08e<|IS);{0?Jl{HT5!W)kZJ-@@Wetb3#6 zwZOluB`=*{Z^wio2&1CF(X#TcEpj*Yflzbk!H2m>qX%y+WM_S7rDXa_GolsEAtkgT z|I4*)C!h{NGA8`DQ}}{p?z8pt0xFm(;OW>|8dN1Wthzit2gjg;;NG8}QUO!AVGBR_&0knX4NSo34xd!@8t9 zA^(6|-D^dPieF=`_!~TIjR&I-&&laSrgU{wB*&X8|9&n^^B+MJf?D*n5!7;GUO`}Y z1KbgNhS)%Ex10IE^IHy0!wTZMOm#pu0%j+G_O&P}|9?`T^Zr)wFL2!{`69&4!=f?1 z5cVJhMXgrzf*>@jT;kNi7&CQKBWk`^cYj(*7pd_T-u(S=SC9g!ghWo2RF0FAeK$qq zbdXNg>fZ1MxIcZ?J9pSiJAwCN+^tEg@`g?ouS>rb^fJ6F}!95 zW?K&i#B1mPSge`kb{w{(@(8<)*e(~=H*g^e0=T-q{{ds%jX^@RjVz5t~pMcxzR;DYHFX?BH)|wkF9XVIF^QUER0v9p>wv zuyI`oQ`ay7%3XTpeXvJUXf}Ac$RdiH(HXFz{)QT&*)L|sv;N2R%GYQgl%v6&ajNZZ zT!eMvy}b0lmDj|oxe2c@)Y`R0vs2SazIdhS6w`Dvb;3s_#1o+4D^cr)fz=wYC9|bd z!VJ2L{@>xXB$RLAk5F|VRf)gHmGgz2-MaKEyp&VvU+1DV5qBJBDH34OU$R1}jzlGo#U)$F+}W9tZif38)KJsy z)^5@rqcxIkTa#U&)_4=LD+3E*0>2}$kf_??v5p{3C>6(1n#>jRA~N+c|7x+Qh^b&stV5O)PWd1|PM6cOI4IbK~5)dH#YPRbU3VxiSsF(go7d zeg?L2i@I^tk#z^7UPHGM!&S%>&)>!bybV^*pB01t|Jkl$o+}( z$w7NktQRAr>7m3Og;dWIQoU$pDX@CJH?X=3s(x~`w!3x%INVr$d}Uj04?^O{YB$zy z;?6|v=Gra%-)_MvCQon%}CR|Mp=TQOw^-k25(#E*o4T$kvJDxrosnrPuCbTPd*dITlaT{#FV?^JDg z8t*~B5Z}HLGBl??Gi;`ZXg!d8Swj(rRCVG68_S5bV!cKR@7H0`iOrT8V~1h~RYvNr za^Ji`pr%0QQoJA=b1N&FJ@JYYLDCp|%?n!A@+9OY$ud}b%m`S|UF(cx(hL>;={Rhc zsH>soxN!Ht0a2pSeQa~h-?SR+qRecZGeC(eM=XLlDy}O5x3o|3x#aB7iUrw2n0E!* z3WLbsSgkh_aCE>tjR$&h{%JfGVL@T`%$l2-*bGS|wNQc}{BvyY;7Ul>8(|rtiqi5~ z1YDSV*Wvv@(Go343k4Ir$U$~ASe0Ag{@NgEN{6ESrh)_eqz<_kNG&}mLG6Mzb-ILf!t zBw-T=W4k2N9?$6pIrP~O<~({p2qV#_nULmNd%#RfEA2d*Ku#NTJJ*OsO)F@7vnbP1 z5bdF63FI5yx0=j+-qx01o?%1I%Yo;S-L+JP) z(*xhkJWL7p%lc^w3t!h&gsj_<3T+=@?41EC!M~)#ou^EJ=a-274hpS7 zZF-k7FQekxh9l^_YYPVxh6@3rV;W@Xu?B`?gyyh6)&EK z?sJ^x;?mGH_d~SAVP8FMh~DWz@gmR`M-{1h_GvG6+RX19G~*<8U8wm=w(k^z`HkHe zzXJu~nW7uv)&$2XfzPx#gg&kARSo_pG@}M$27tnaTf@;im8sU9Q`#=3Sc+^;2UBCn z6Z3*)D__DBY4Qj&Y8|@n`}nai{&%99tJx{sIsK?wbXhG*V@1A3drtEyWWFdJZZIK{ zogQi<5HoK{wd-JiIO;(KwToz)V^rPfk}b)AQ<_IZ)O*%PKn&2#=%Z^XXxO5-gNtZ? zDz;G%*~DmliD?z->x^ljH@%mkF`dEA6_c%{wQW^oicB?a+YuRPX_eJv6^{*|Q*CwH zUf{4JCs2LH!x~;>IbK@ZIM~r%0IRJm82WIK<#dsf{YSNN*n$kq0KTCcv8Q&!zNHp+ zMpMBT?Rb3oye8gY;aclJ*Cd3>UP-I#*es4kZ`iTzaaR4u)rKEel{WiUuT}YLJgA3N zYL`OoCtvvXc%gSq!$3wk>+E;wi2e$VI2TR!?(Tktv{?$EG|ify52_bI^r6?}3PH6;cKYmZHm$hwxs%v|61ED*;JyFN8*29a7Nm$HpQ6E=`35%GHo zmRPX$zLGcc$NyIvjf+Z_Nuc6&Aa(|j9h~Wrl8XZVSU5_>Tpreyi+^=QG=w_K33pv; zxPQyQ4-zf&|1Q;p4au+8mwMVEdindKc0kS14vTV-Y=_a#Gduc{&R4b)`+xVkr1pFus7;nTs36-H*E7GMwIF3b3H-al=iYnoeI21)SQbLAhLk)_ zDb}I|9mp?Jndzk0pyQk6&>9DnlR!k=hTJ%^$($li! z`;s1|UN8@>(H;K}n2iVUvk@~VeuF#yJC$5ia*6Tp-f1+;pB6-na#0#%2fkK798}DC z-|m@rZG|@PcXOe6XFa0@Z|a9x=R71bmEVDt6wXFulhn*Pp|IH}zb;6SFfs&%YEW-9is3~4&4EO}=5)h`a|g>%O+PoaAeF*XQ%Ond zqe8D)Iok4^Vztx+LgHB(C{VM|yyi+M1oDJ~u-1fDo-n<5%>A!1$*{U?8!+jj;KBbz z?%E^&&vexfq;BWI7X?z7on(rmGKnrBYxH&Be=Er%-_%DN%3;2ZM@Z5x)LS zN1oFh(gdrYad0=C0vz$f+^u>|-qN7GlkSqm_z-u{!Apesq9GD0&6!S5ptuurO!kAV z5%zb@aY+(7E%y4efvszr4HmLg0-g*ShzrtdGEvaN>H){{NHH6XQ(#PtKxd@6zK$<< z0l7Zr3Lo}DbDfnZt)TRv$jAY07(Jxd^b~<*g8gEAIaxe8{V&$;`l91?bT>QTfH;Ow z;LS{1{jfl4yHBvpkL7ZzXzD zIu-Wz^xntLpkK9)$F&Q*#noQ)Bq|5)B}DNWTEQenaa@ zynbvoKE>St*RbpE?OI5}Z?d*rq@yz3h=_RGu6b-9ij0H_wzZp#M0(<$Nl9|Etvs2h zuV!cbPg7@t8i-N9CWZW#Dl-W~P}vsZk+3(m=yf)%fbE53wdel=MY#_3!!dt}r@!6Z zD;KuO|JOY0A)<5KJgOr9LpXLJ*`fW#A(0wN{|kEFgtJUZ5a-fHEq2J-&#ML%nW!cnLN({-smrJ;AzTyVqq))C&Ky+npYx1=ZT-v5Vl^%p z;D&O~{3m}v1y@KqV_oWbeqN7uE74)<8wzM9g3puHo%K>u#V(}^eqXJg93-lB^=)?_ zGP{(M!-4XXY@7UbWijQ}BPz?xwU6l@tmVC7KKWHRb)H zu0$I92bA2YM5u!Qvr2wW$;Xxagpz-&x-=<_-$qh<&DVbEVM~T>C{%$2Zm26jXuMz{HQ5E`s^z%=Y z{Gt*&+p>CK*i%7QMJ2;Z%1X?RXs51DD93x0yj#hemApwwMaiv7_A0qW$y<~>M7EQY zRZYs<@3^OW{NYDFaO~k@vvbGp_ixto52)C;an%`$q9Qsf-WY*3J$}CuXX&D==aoz; zvse=Ti~9MuboGO}`W{^!RPrT$c7~6i6<^$07+uosSM=6gS-Yep$)y>*tRs`6DGd$Nm4Mt0TJlrmpVO)wj9o6siwM|H~Ke&KGXrXq*Ri z^^lS>K;=K6t5ID|C=pufy!UL=PYYUoldg=V`Yt`aP05TBTZ?COCF0TlfRcA8IiMW- zbahZya<}5ki-1{LJ5_CIZo`ZOF$@gB{BwHY86{>ZWR_<#*D>A6P7c-3PSL51*8NV& z=_NnATtD9#I&}dzyo%iF-=iToq>A6J#mCP$yP;yGiqLP}Dx{@U& zraSu8Dj^1SxtPInkEl<#qje`RAaG3z&rEKne3Qi7({! zUj|~Ji5SR_=O%^=V>@%aBW~b8u~Nd649;L_XMS?HbW34OzRbkW&gU>6yH?B>r;Edd zLIJmxTmIz>IHoRKEtbj{mWdxudAV}AJcK!#R~#(ncW(D;I2hbr-l@9shsvqa;7NMu z-50yQgFCZcX=k=LoZnXP3L|RMM6T$K?-*~Cyq($d4&Z41hyf0I1t+4k^Rexke&o}M?Eo6PPU@NCYR#ay{i^ve7nA1lu? zW?p&H(p~uPuohEdzVK(Jl$i5g9v@mHEDM2`39PgFH^Y$Bw<(Y?fCO^TYD#(zcJTt`#CMaK=!B4a(jvUSEyVQiZ{W4*u& z+`4D1TfE3^T#LNK9b9c*<}R)!KEo@xIxiZ0mRIi?yn1A=mvJ}8=W#cWJ6E{dGt0)C zmGz346)t~BRDNmv%EZ&^QGpqEE(!O@SfAqyd=V?n z?Zh$>+}jYFu@v5_NV=UQjwAJix6w`d^I>~yY{m;B6?;;2qM#|1m$Za;d${RsZ#U-M zNO)n}yRG(BJ-=1A>)u)`RNii|??ocuUJ`rVHWwS-LR`i^Y$M7!6B!i`2}KWWA7%k_&F8Y)c0lbxWs6Ko09 z@Q0N7Ej(-Z*gZ^qzuwu;&eFzXFLWdX(N2gCHIL3^7OOI=;4sTHnR6^>@o)m#1VL&y z(9{d)CZWwu0NK<)hT>`-{Z4i2&N%MgH%)Dblw@kfX z>JGV8ud&Ppo@Ao-!lYF*GqZjnv)aL~&=ShK3RchD=OCM;8Si$k(QbRpAv0T8!g!qVS7Md2{Sqw-FZ<`$U_P!PyY!Y#&kUsBv_y?Ap>MK|`Lo4ruR?OlM#>jg3-{i^FP*UzoqTzl=+wO3wwdDVYy^`^i4((2l4 zYcIXLniVxWYK6>qM_XRT z2U_(VW}8m2!ajQJT4&e-lb^uM1aol@p7fbZ8zsgO@Ht{FycT?;_K#-zdyRsdW44t>;#Pw zCmXp(X*_lDnI%2MJA}+9FJHZM>FTpjUAU+hgJ*Y|(+Un`^ zk1>&qwA9)^!(*RFlpz<(c&Z3-cFAT?x%Z@pn^SBfTwX_em(*1l2ycvat#k+|#sVBd z5MZ(*(44a036ey}HbMnpMns#LGk7v~5Pb%q zC-(~9AgX9tm!*rNo$G`7Ce00gG$!RMpef>1V*J3^WMn<=IR||ce?;+7VdWI<^pQpz zefT{x&?Pd^Zy7z~b>Qj_JjbdbmoTY`1(@eB&I&lf1D4q;k?;WdIrI_A&uxjexZ9D} zUc-CZD45?pYotqKr`QdWW^2s+4!!_`3J4tJr|=~<`ZR4yrX^qgb2QR>6!ijYxL0)c zb1a=dx%x`2NV-UF!uKJ(zJ6j{@%=m9Aj)UtXKB$obs9;djy95yp?ekWUGfKx;jl_U zKRbma;^K8QMb>SIq(%7M!aW8oX>Yr32?Wc$bPpaEfwIHPz*$K++~qU+SsC*cKC8zr zukty}&xp$QET2b6dTGnx5B-|0SG77XZ1qRAGuh(uAl&@ANP-taM0|3kNst))h<4@z&NlF2wR}4a9BJj9_1D_Eha)G z^>k5nMAL`z`rp~?Mw+dMr`SXGiK2jaiKaz$j~Cc`9t{4wrd$laeryxE$PcW7$DPx8j1;W?At16LD>}JGWXkI>dNaSigVd>ZY zUt-7Bg&EbnlNX4xi`3nq?k08GSbljp(p;PyZl25PE~Zs(Ju9qY$rtE#A{3s{j%BzN zwrew)i`1-{r%pOnTJJ|y6lw$;&8#{Mz3P;7OY+xQ`R3iG=un&huYs5Be8&e{&jH2{Kei2<} zhl+yQF#u|=5ykQ==isu*CIm%7qVSwF3w#g<6mSi(k*1#ZYBH?)lK zMn{{)^pzoimqmhH)eARC7F0dh5G0<#*{D(!pcY2hRZSUol6oJnm#)5ua=Q1k_+k*T= zGg7&PHQ=AX9=}4<{4~F78CB*Ur`M~kZw{<>o z--L{jdTUi&8A|sS>VLBBt;sIxhnu?Qhqx?k!k=33(a5LB6fsUgl9hIb=l`EfQC_ae&2rx^^{sY4ohF-;JHbZZ87^JDc=740 z!)=b#9NYO=HZ^WT5(p>SfpyzIGyGaP7y|D*z-_v9tw}w`g?2{+xTi z#U9}0JhHN3ho1N_bYN3b_jmG|+&>p}214DaaFRYUde{+LKB*T>do0tjw};V$42be2 zbhWvYanAEJMFtk86sbbk><9nk@FXQO*-SGElAH-XQ*!6*f7!>TV;pss(DR2LFNP;i5O=8 zK*yl{&okM=Wh!mgF(E&R4*Azd=p{n(;74O>H_+ZCS@-o1Wak7kxrL`wVOREjl$M0_ z{XfwwkE2VgL>5XX{fUXhnC#qOFB#G&8VxL)kzyC+Bz+_#k)Os?RuFfaS+N&HU6Gl| z#uy*S_)xt;+@+fSpJ^Sv_3U74{d`I^y-lyi)Q$9K1Pfx#A8GOub(&EaO#Ft1n$&R+ zKPH9yW-ejMf#`gL!uBS{i08C0rNGV9eTlt)LDO!0Bt*6n7B1WE@T_gUh&!MB#!7VriXVIB+9Ot2GrRum_Cd2=9kXqRPwo6U{6?CU! F{Rgye9ohf@ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc b/.venv/lib/python3.10/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0eae747fa41a4795a231ab66e154cf51bec921d GIT binary patch literal 243 zcmd1j<>g`k0{2ewG#w!Q7{oyaOhAqU5ElyoiByIZhGxbEj0+hU8B!R788n%q_~TPD zi%UvNGINUKGZK@t{WO_wamB}H<`(1^mBhzKai`?R=a;1x6=kNRu4E_z83!hQCF^J8 z=cekXWMmgw8tLm5lqTh57H8, Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, 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 `timezone` 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. + +### 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. + +We provide a few predefined predicates for common string constraints: + +* `IsLower = Predicate(str.islower)` +* `IsUpper = Predicate(str.isupper)` +* `IsDigit = Predicate(str.isdigit)` +* `IsFinite = Predicate(math.isfinite)` +* `IsNotFinite = Predicate(Not(math.isfinite))` +* `IsNan = Predicate(math.isnan)` +* `IsNotNan = Predicate(Not(math.isnan))` +* `IsInfinite = Predicate(math.isinf)` +* `IsNotInfinite = Predicate(Not(math.isinf))` + +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 propogate 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/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/RECORD b/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/RECORD new file mode 100644 index 0000000..52ddf7b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/RECORD @@ -0,0 +1,10 @@ +annotated_types-0.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +annotated_types-0.6.0.dist-info/METADATA,sha256=78YeruT3b_doh8TbsK7qcbqY4cvCMz_QQRCGUbyAo6M,12879 +annotated_types-0.6.0.dist-info/RECORD,, +annotated_types-0.6.0.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87 +annotated_types-0.6.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083 +annotated_types/__init__.py,sha256=txLoRt8iSiAc-Su37esWpMI0wFjN92V7gE5HdFIeeKI,12151 +annotated_types/__pycache__/__init__.cpython-310.pyc,, +annotated_types/__pycache__/test_cases.cpython-310.pyc,, +annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +annotated_types/test_cases.py,sha256=LfFyURZwr7X3NVfoCrSXSMMxTxJD4o8Xz-Y8qbmY7JU,6327 diff --git a/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/WHEEL new file mode 100644 index 0000000..ba1a8af --- /dev/null +++ b/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.18.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/licenses/LICENSE b/.venv/lib/python3.10/site-packages/annotated_types-0.6.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..d99323a --- /dev/null +++ b/.venv/lib/python3.10/site-packages/annotated_types-0.6.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/.venv/lib/python3.10/site-packages/annotated_types/__init__.py b/.venv/lib/python3.10/site-packages/annotated_types/__init__.py new file mode 100644 index 0000000..2f98950 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/annotated_types/__init__.py @@ -0,0 +1,396 @@ +import math +import sys +from dataclasses import dataclass +from datetime import timezone +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.6.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 BaseMetadata objects. + + `GroupedMetadata` on its own is not metadata and has no meaning. + All it the the constraint 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[BaseMetadata]: + >>> 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[BaseMetadata]: + ... + + 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[BaseMetadata]: # 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 timezone 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, timezone, EllipsisType, None] + + +@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 + ``IsDigit = 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 propogate or discard the resulting exception. + """ + + func: Callable[[Any], bool] + + +@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 +IsDigits = Annotated[_StrType, Predicate(str.isdigit)] +""" +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/.venv/lib/python3.10/site-packages/annotated_types/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/annotated_types/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..addee4d8a6de6bfaabd1a04f5deb477c5ffca9ce GIT binary patch literal 13106 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 b4*nX(aeWf=nbM6>LpOeF7*qda{Kx+S;v>}o literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/annotated_types/__pycache__/test_cases.cpython-310.pyc b/.venv/lib/python3.10/site-packages/annotated_types/__pycache__/test_cases.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..329b70b0bd9c0a04c424fcaf136d49d950c86d43 GIT binary patch literal 5574 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 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)))], + ) + + # predicate types + + yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom']) + yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC']) + yield Case(at.IsDigits[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/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/LICENSE b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/LICENSE new file mode 100644 index 0000000..104eebf --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/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/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/METADATA b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/METADATA new file mode 100644 index 0000000..e02715c --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/METADATA @@ -0,0 +1,104 @@ +Metadata-Version: 2.1 +Name: anyio +Version: 4.3.0 +Summary: High level compatibility layer for multiple asynchronous event loop implementations +Author-email: Alex Grönholm +License: 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: License :: OSI Approved :: MIT License +Classifier: Framework :: AnyIO +Classifier: Typing :: Typed +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: idna >=2.8 +Requires-Dist: sniffio >=1.1 +Requires-Dist: exceptiongroup >=1.0.2 ; python_version < "3.11" +Requires-Dist: typing-extensions >=4.1 ; python_version < "3.11" +Provides-Extra: doc +Requires-Dist: packaging ; extra == 'doc' +Requires-Dist: Sphinx >=7 ; extra == 'doc' +Requires-Dist: sphinx-rtd-theme ; extra == 'doc' +Requires-Dist: sphinx-autodoc-typehints >=1.2.0 ; extra == 'doc' +Provides-Extra: test +Requires-Dist: anyio[trio] ; extra == 'test' +Requires-Dist: coverage[toml] >=7 ; extra == 'test' +Requires-Dist: exceptiongroup >=1.2.0 ; extra == 'test' +Requires-Dist: hypothesis >=4.0 ; extra == 'test' +Requires-Dist: psutil >=5.9 ; extra == 'test' +Requires-Dist: pytest >=7.0 ; extra == 'test' +Requires-Dist: pytest-mock >=3.6.1 ; extra == 'test' +Requires-Dist: trustme ; extra == 'test' +Requires-Dist: uvloop >=0.17 ; (platform_python_implementation == "CPython" and platform_system != "Windows") and extra == 'test' +Provides-Extra: trio +Requires-Dist: trio >=0.23 ; extra == 'trio' + +.. 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. + +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 +* Asynchronous file I/O (using worker threads) +* Signal handling + +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/ +.. _Hypothesis: https://hypothesis.works/ diff --git a/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/RECORD b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/RECORD new file mode 100644 index 0000000..610303b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/RECORD @@ -0,0 +1,82 @@ +anyio-4.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +anyio-4.3.0.dist-info/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 +anyio-4.3.0.dist-info/METADATA,sha256=Xy5N0vn6s_rjN1C0EbX_z1N_lf3bZIJu88RAQxVAsrI,4599 +anyio-4.3.0.dist-info/RECORD,, +anyio-4.3.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 +anyio-4.3.0.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 +anyio-4.3.0.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 +anyio/__init__.py,sha256=CxUxIHOIONI3KpsDLCg-dI6lQaDkW_4Zhtu5jWt1XO8,4344 +anyio/__pycache__/__init__.cpython-310.pyc,, +anyio/__pycache__/from_thread.cpython-310.pyc,, +anyio/__pycache__/lowlevel.cpython-310.pyc,, +anyio/__pycache__/pytest_plugin.cpython-310.pyc,, +anyio/__pycache__/to_process.cpython-310.pyc,, +anyio/__pycache__/to_thread.cpython-310.pyc,, +anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_backends/__pycache__/__init__.cpython-310.pyc,, +anyio/_backends/__pycache__/_asyncio.cpython-310.pyc,, +anyio/_backends/__pycache__/_trio.cpython-310.pyc,, +anyio/_backends/_asyncio.py,sha256=D1ME_t4zfei7sm7Ic8jEQBsAc3uMykvsQjZxhT5aTNg,81968 +anyio/_backends/_trio.py,sha256=87ahML2dsX3uQuCkyIB4E7XFK6jAGpxs5hVlGmHHd8Q,35642 +anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_core/__pycache__/__init__.cpython-310.pyc,, +anyio/_core/__pycache__/_eventloop.cpython-310.pyc,, +anyio/_core/__pycache__/_exceptions.cpython-310.pyc,, +anyio/_core/__pycache__/_fileio.cpython-310.pyc,, +anyio/_core/__pycache__/_resources.cpython-310.pyc,, +anyio/_core/__pycache__/_signals.cpython-310.pyc,, +anyio/_core/__pycache__/_sockets.cpython-310.pyc,, +anyio/_core/__pycache__/_streams.cpython-310.pyc,, +anyio/_core/__pycache__/_subprocesses.cpython-310.pyc,, +anyio/_core/__pycache__/_synchronization.cpython-310.pyc,, +anyio/_core/__pycache__/_tasks.cpython-310.pyc,, +anyio/_core/__pycache__/_testing.cpython-310.pyc,, +anyio/_core/__pycache__/_typedattr.cpython-310.pyc,, +anyio/_core/_eventloop.py,sha256=uCwWwGtN9Tf46nkcWLyku8iYEFWCkSjPW0AkDbnpCM0,4408 +anyio/_core/_exceptions.py,sha256=wUmhDu80qEB7z9EdCqUwVEhNUlNEok4_W2-rC6sCAUQ,2078 +anyio/_core/_fileio.py,sha256=Zdp3L0_T7mMCaYq3bFTCb-udTnIknKpzcLEvHK-Tmbc,19512 +anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435 +anyio/_core/_signals.py,sha256=rDOVxtugZDgC5AhfW3lrwsre2n9Pj_adoRUidBiF6dA,878 +anyio/_core/_sockets.py,sha256=HwOMg0xUPw0T7N-aipxq_4OEM703llh3I9_YIg9a4XM,24048 +anyio/_core/_streams.py,sha256=Z8ZlTY6xom5EszrMsgCT3TphiT4JIlQG-y33CrD0NQY,1811 +anyio/_core/_subprocesses.py,sha256=ZLLNXAtlRGfbyC4sOIltYB1k3NJa3tqk_x_Fsnbcs1M,5272 +anyio/_core/_synchronization.py,sha256=h3o6dWWbzVrcNmi7i2mQjEgRtnIxkGtjmYK7KMpdlaE,18444 +anyio/_core/_tasks.py,sha256=pvVEX2Fw159sf0ypAPerukKsZgRRwvFFedVW52nR2Vk,4764 +anyio/_core/_testing.py,sha256=i97S5rSWIFqfCGPm4mEMdiJaUpVskk-cWEjarWTeXXs,1964 +anyio/_core/_typedattr.py,sha256=QTbaIwZEewhwAKvbBHFBcO_cRhNP_lXjAobEldzExCU,2499 +anyio/abc/__init__.py,sha256=U44_s3BglL8BojWQiq0KuokvCqkunIp-ySH3GyRXxAc,2681 +anyio/abc/__pycache__/__init__.cpython-310.pyc,, +anyio/abc/__pycache__/_eventloop.cpython-310.pyc,, +anyio/abc/__pycache__/_resources.cpython-310.pyc,, +anyio/abc/__pycache__/_sockets.cpython-310.pyc,, +anyio/abc/__pycache__/_streams.cpython-310.pyc,, +anyio/abc/__pycache__/_subprocesses.cpython-310.pyc,, +anyio/abc/__pycache__/_tasks.cpython-310.pyc,, +anyio/abc/__pycache__/_testing.cpython-310.pyc,, +anyio/abc/_eventloop.py,sha256=QOtkEHCkoE8czGu4RNzZ_q-xNjC0nRyoS0QQJ5KTvYU,10097 +anyio/abc/_resources.py,sha256=KBJP3wGbvSfKfTjfOLL4QCJdeiaNwqqF_6FwPsmQssM,763 +anyio/abc/_sockets.py,sha256=XdZ42TQ1omZN9Ec3HUfTMWG_i-21yMjXQ_FFslAZtzQ,6269 +anyio/abc/_streams.py,sha256=GzST5Q2zQmxVzdrAqtbSyHNxkPlIC9AzeZJg_YyPAXw,6598 +anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067 +anyio/abc/_tasks.py,sha256=q3bEbCF46I2tQjYSbRdbaavq0R_HOV9JAjzQr8biprU,2747 +anyio/abc/_testing.py,sha256=EiWEaIVy15lHszO000Xp4FsB13NbBvC1BpUci47B5zs,1829 +anyio/from_thread.py,sha256=UTEY_NsiqQRukO3L3riQx4Eegulj3RyLlbITJz7pvLM,15749 +anyio/lowlevel.py,sha256=0awnMh05kA5WUNaOBoQZSImBj0xLNRlYOuMGGiztWnM,4185 +anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/pytest_plugin.py,sha256=TBgRAfT-Oxy6efhO1Tziq54NND3Jy4dRmwkMmQXSvhI,5386 +anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/streams/__pycache__/__init__.cpython-310.pyc,, +anyio/streams/__pycache__/buffered.cpython-310.pyc,, +anyio/streams/__pycache__/file.cpython-310.pyc,, +anyio/streams/__pycache__/memory.cpython-310.pyc,, +anyio/streams/__pycache__/stapled.cpython-310.pyc,, +anyio/streams/__pycache__/text.cpython-310.pyc,, +anyio/streams/__pycache__/tls.cpython-310.pyc,, +anyio/streams/buffered.py,sha256=UCldKC168YuLvT7n3HtNPnQ2iWAMSTYQWbZvzLwMwkM,4500 +anyio/streams/file.py,sha256=6uoTNb5KbMoj-6gS3_xrrL8uZN8Q4iIvOS1WtGyFfKw,4383 +anyio/streams/memory.py,sha256=bqN9YwAPA6ZtdohOsq_YBpLFlRHR5k-W8y0pD_jznb8,9296 +anyio/streams/stapled.py,sha256=U09pCrmOw9kkNhe6tKopsm1QIMT1lFTFvtb-A7SIe4k,4302 +anyio/streams/text.py,sha256=6x8w8xlfCZKTUWQoJiMPoMhSSJFUBRKgoBNSBtbd9yg,5094 +anyio/streams/tls.py,sha256=ev-6yNOGcIkziIkcIfKj8VmLqQJW-iDBJttaKgKDsF4,12752 +anyio/to_process.py,sha256=lx_bt0CUJsS1eSlraw662OpCjRgGXowoyf1Q-i-kOxo,9535 +anyio/to_thread.py,sha256=WM2JQ2MbVsd5D5CM08bQiTwzZIvpsGjfH1Fy247KoDQ,2396 diff --git a/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/WHEEL new file mode 100644 index 0000000..98c0d20 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/entry_points.txt b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/entry_points.txt new file mode 100644 index 0000000..44dd9bd --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[pytest11] +anyio = anyio.pytest_plugin diff --git a/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/top_level.txt b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/top_level.txt new file mode 100644 index 0000000..c77c069 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio-4.3.0.dist-info/top_level.txt @@ -0,0 +1 @@ +anyio diff --git a/.venv/lib/python3.10/site-packages/anyio/__init__.py b/.venv/lib/python3.10/site-packages/anyio/__init__.py new file mode 100644 index 0000000..7bfe231 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/__init__.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from typing import Any + +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_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 BrokenWorkerProcess as BrokenWorkerProcess +from ._core._exceptions import BusyResourceError as BusyResourceError +from ._core._exceptions import ClosedResourceError as ClosedResourceError +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 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 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 wait_socket_readable as wait_socket_readable +from ._core._sockets import wait_socket_writable as wait_socket_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._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 +key: str +value: Any +for key, value in list(locals().items()): + if getattr(value, "__module__", "").startswith("anyio."): + value.__module__ = __name__ diff --git a/.venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84e29efd2f825e42eaa3b34e8aa957a3f96b74d7 GIT binary patch literal 3038 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/__pycache__/lowlevel.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00006a67050d64f30e13debb96f74c7855a75bf2 GIT binary patch literal 5178 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 wla-e8Pl!(`yCi4P)U*=H|C2y@5SKwMA)1p@Q} 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/__pycache__/to_process.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..020679eb7c5f0d187a468ec056cb969441011325 GIT binary patch literal 6587 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/__pycache__/to_thread.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38435fd1896cecd613f8ae3713620b00d6cfba2e GIT binary patch literal 2621 zcmZuz&yU+g6tFw`dGp@)ee-O&y4rN$c=7Z3 z;diGT=Wo1OJnC@siQ~BXPcWFn+|R#ZzDJcfbjvv#JKTg+PemLKXgubE!HBiHbVB3AOg~Su#BkN| z4r?&{a0TahMXU0)l}}P$G`}JX1oMv1I`yHjhkTnr_kM5< zh{L$7#_G>&u4B9d=W%V{*{|=r`!%-oynY{q^qB(`HRxa9u1Vm){D>KGvXks`K`?0~ zjO-<5w9pUf}`o30R`lo zTm|=3Oo^h2=FIx#PhxIk>y*w0oFqF!Dn3i7KcR|d7Lq>X99QbKldEUQdY??Bh9sn* zDLKXo6GB{HJMC2s_DK|Nshk5|Mv_XRi|JlXIo(B^5`!ZkWg7-E2#k$5Y!ya;Hn}G{ zBq^B~NezP$WB`8w#VEQ*Q(di9raX5x;||lYTw@Byj&cEr+qmR}E4#JHh|XDq7(gC4 zr4-2AZ7GyRI8J<~u%W3}h|fKpj#NY#T_=b$OL*q)LSC~ClTCIJnMv`kJTDFP^(2Xz(J zmr$@Etx~#-4{4s7xpSZeoU=}eOQ}~-8f-A!6}VZzH#KCM@RVu0_DiC+YxDV@t@h!A zrw3cWK(v7H?TC!|6gUBVtBs5)MX)0h*)=k(HZo)oV(pDkF$<*V1PUd&Bc}JiARlyZ zbg$pCsGMX77D|LRP!tY5C{Iwko7zA%PWdiRJDx3vw(NE43X55>`DsNx=9S__N4x zMSTt$???Y)-SzP2d2Zw1#@rk@BI5;e6>pZ0=$W$FBh695}zZzhhl?pZ;RC z@X(fiOZZ7eq9Q8gkiisaDn<2@L`9wrpgzl?br(w!=So5Oo@up`N`J1olggKa$2>M= zX$R(zl;U#bCae~%7zwN0V!>Z%F2fu}pt%jF#-y9Rz3;S23Qt3qB~G113tyHB0k!W+ zbsjBzN2)ilxq!_oG!Tuo5!%k#q8Wz69A1??3>B_X)bvyrYq3mINC4|tmkwf8!$%D> zouI_<`>OEq!vpTLm13|S#!&pbAxKr2RLV)2a}6isQbh}@js}0ANGR_3@u6DK1RJH( zkUue8-~esIRBaq#ML^I(WiB)bPT_x)NtUPlV|>f&x1nh{zSnZ?53Wsb(_Qy`&v(5B K>Z|=vyYoM%z6J~c literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_backends/__init__.py b/.venv/lib/python3.10/site-packages/anyio/_backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4363051c743c229e8193579b759eb8acced4848a GIT binary patch literal 193 zcmd1j<>g`kg5&+-X(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10HKO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKQXT|GhaVG3CK^)ODWcmkI&4@EQycTE2zB1VUwGmQks)$2eQ4G J2}rOo004i}F;4&h literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2769299d6a0ffca0db707d8c1d9430feb7fa47ff GIT binary patch literal 69991 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ð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 (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], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: + self.close() + + def close(self) -> None: + """Shutdown and close event loop.""" + if self._state is not _State.INITIALIZED: + return + try: + loop = self._loop + _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() + 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.""" + try: + return getcoroutinestate(task.get_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 +# + + +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._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 + self._cancel_calls: int = 0 + self._cancelling: int | None = 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: + self._parent_scope._child_scopes.add(self) + self._parent_scope._tasks.remove(host_task) + + self._timeout() + self._active = True + if sys.version_info >= (3, 11): + self._cancelling = self._host_task.cancelling() + + # 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 | None: + 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" + ) + + 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 directly cancelled parent + # scope if this one was shielded + self._restart_cancellation_in_parent() + + if self._cancel_called and exc_val is not None: + for exc in iterate_exceptions(exc_val): + if isinstance(exc, CancelledError): + self._cancelled_caught = self._uncancel(exc) + if self._cancelled_caught: + break + + return self._cancelled_caught + + return None + + def _uncancel(self, cancelled_exc: CancelledError) -> bool: + if sys.version_info < (3, 9) or self._host_task is None: + self._cancel_calls = 0 + return True + + # Undo all cancellations done by this scope + if self._cancelling is not None: + while self._cancel_calls: + self._cancel_calls -= 1 + if self._host_task.uncancel() <= self._cancelling: + return True + + self._cancel_calls = 0 + return f"Cancelled by cancel scope {id(self):x}" in cancelled_exc.args + + def _timeout(self) -> None: + if self._deadline != math.inf: + loop = get_running_loop() + if loop.time() >= self._deadline: + self.cancel() + 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: + if task._must_cancel: # type: ignore[attr-defined] + continue + + # The task is eligible for cancellation if it has started + should_retry = True + 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(): + self._cancel_calls += 1 + if sys.version_info >= (3, 9): + task.cancel(f"Cancelled by cancel scope {id(origin):x}") + else: + task.cancel() + + # 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 _parent_cancelled(self) -> bool: + # Check whether any parent has been cancelled + cancel_scope = self._parent_scope + while cancel_scope is not None and not cancel_scope._shield: + if cancel_scope._cancel_called: + return True + else: + cancel_scope = cancel_scope._parent_scope + + return False + + def cancel(self) -> None: + if not self._cancel_called: + if self._timeout_handle: + self._timeout_handle.cancel() + self._timeout_handle = None + + self._cancel_called = True + 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" + + def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None): + self.parent_id = parent_id + self.cancel_scope = cancel_scope + + +_task_states = WeakKeyDictionary() # type: WeakKeyDictionary[asyncio.Task, TaskState] + + +# +# 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: + 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 + + +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 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() + + 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 | None: + ignore_exception = self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) + if exc_val is not None: + self.cancel_scope.cancel() + if not isinstance(exc_val, CancelledError): + self._exceptions.append(exc_val) + + cancelled_exc_while_waiting_tasks: CancelledError | None = None + while self._tasks: + try: + await asyncio.wait(self._tasks) + except CancelledError as exc: + # This task was cancelled natively; reraise the CancelledError later + # unless this task was already interrupted by another exception + self.cancel_scope.cancel() + if cancelled_exc_while_waiting_tasks is None: + cancelled_exc_while_waiting_tasks = exc + + self._active = False + if self._exceptions: + raise BaseExceptionGroup( + "unhandled errors in a TaskGroup", self._exceptions + ) + + # Raise the CancelledError received while waiting for child tasks to exit, + # unless the context manager itself was previously exited with another + # exception, or if any of the child tasks raised an exception other than + # CancelledError + if cancelled_exc_while_waiting_tasks: + if exc_val is None or ignore_exception: + raise cancelled_exc_while_waiting_tasks + + return ignore_exception + + 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: + 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] + + try: + exc = _task.exception() + except CancelledError as e: + while isinstance(e.__context__, CancelledError): + e = e.__context__ + + exc = e + + if exc is not None: + 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._parent_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) + task = create_task(coro, name=name) + task.add_done_callback(task_done) + + # 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) + 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 + ) + + self.queue.task_done() + + 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.feed_eof() + await AsyncIOBackend.checkpoint() + + +@dataclass(eq=False) +class StreamWriterWrapper(abc.ByteSendStream): + _stream: asyncio.StreamWriter + + async def send(self, item: bytes) -> None: + self._stream.write(item) + await self._stream.drain() + + async def aclose(self) -> None: + 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): + 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: 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 + 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: + 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: + 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 + + 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: + self.read_queue.append(data) + self.read_event.set() + + def eof_received(self) -> bool | None: + 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: + await AsyncIOBackend.checkpoint() + + if ( + not self._protocol.read_event.is_set() + and not self._transport.is_closing() + ): + self._transport.resume_reading() + await self._protocol.read_event.wait() + self._transport.pause_reading() + + 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: + if not self._transport.is_closing(): + self._closed = True + 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: + if not self._transport.is_closing(): + self._closed = True + 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: + if not self._transport.is_closing(): + self._closed = True + 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[Any, asyncio.Event]] = RunVar("read_events") +_write_events: RunVar[dict[Any, asyncio.Event]] = 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)) # type: ignore[attr-defined] + + +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 < 1: + raise ValueError("total_tokens must be >= 1") + + 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 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) + 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 + + # 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 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, + ) -> bool | None: + for sig in self._handled_signals: + self._loop.remove_signal_handler(sig) + return None + + 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 +# + + +def _create_task_info(task: asyncio.Task) -> TaskInfo: + task_state = _task_states.get(task) + if task_state is None: + parent_id = None + else: + parent_id = task_state.parent_id + + return TaskInfo(id(task), parent_id, task.get_name(), task.get_coro()) + + +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: + import uvloop + + loop_factory = uvloop.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 + ) + + @staticmethod + async def _run_tests_and_fixtures( + receive_stream: MemoryObjectReceiveStream[ + tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]] + ], + ) -> None: + with receive_stream: + async for coro, future in receive_stream: + try: + retval = await coro + except BaseException as exc: + if not future.cancelled(): + future.set_exception(exc) + 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", False) + loop_factory = options.get("loop_factory", None) + if loop_factory is None and options.get("use_uvloop", False): + import uvloop + + loop_factory = uvloop.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: + try: + cancel_scope = _task_states[ + current_task() # type: ignore[index] + ].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_capacity_limiter(cls, total_tokens: float) -> abc.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: + 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 = asyncio.Future() + 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) + 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(sniffio.current_async_library_cvar.set, 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(scope: CancelScope) -> T_Retval: + __tracebackhide__ = True + 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: + scope._tasks.discard(task) + + loop = cast(AbstractEventLoop, token) + context = copy_context() + context.run(sniffio.current_async_library_cvar.set, "asyncio") + wrapper = task_wrapper(threadlocals.current_cancel_scope) + f: concurrent.futures.Future[T_Retval] = context.run( + asyncio.run_coroutine_threadsafe, wrapper, 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: + sniffio.current_async_library_cvar.set("asyncio") + f.set_result(func(*args)) + except BaseException as exc: + f.set_exception(exc) + if not isinstance(exc, Exception): + raise + + f: concurrent.futures.Future[T_Retval] = Future() + loop = cast(AbstractEventLoop, token) + 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: str | bytes | Sequence[str | bytes], + *, + shell: bool, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: str | bytes | PathLike | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, + ) -> Process: + await cls.checkpoint() + if shell: + process = await asyncio.create_subprocess_shell( + cast("str | bytes", command), + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + else: + process = await asyncio.create_subprocess_exec( + *command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + + 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) + ) + + @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, + ) -> list[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int], + ] + ]: + 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_socket_readable(cls, sock: socket.socket) -> None: + await cls.checkpoint() + try: + read_events = _read_events.get() + except LookupError: + read_events = {} + _read_events.set(read_events) + + if read_events.get(sock): + raise BusyResourceError("reading from") from None + + loop = get_running_loop() + event = read_events[sock] = asyncio.Event() + loop.add_reader(sock, event.set) + try: + await event.wait() + finally: + if read_events.pop(sock, None) is not None: + loop.remove_reader(sock) + readable = True + else: + readable = False + + if not readable: + raise ClosedResourceError + + @classmethod + async def wait_socket_writable(cls, sock: socket.socket) -> None: + await cls.checkpoint() + try: + write_events = _write_events.get() + except LookupError: + write_events = {} + _write_events.set(write_events) + + if write_events.get(sock): + raise BusyResourceError("writing to") from None + + loop = get_running_loop() + event = write_events[sock] = asyncio.Event() + loop.add_writer(sock.fileno(), event.set) + try: + await event.wait() + finally: + if write_events.pop(sock, None) is not None: + loop.remove_writer(sock) + writable = True + else: + writable = False + + if not writable: + raise ClosedResourceError + + @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 + ) -> ContextManager[AsyncIterator[Signals]]: + return _SignalReceiver(signals) + + @classmethod + def get_current_task(cls) -> TaskInfo: + return _create_task_info(current_task()) # type: ignore[arg-type] + + @classmethod + def get_running_tasks(cls) -> list[TaskInfo]: + return [_create_task_info(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/.venv/lib/python3.10/site-packages/anyio/_backends/_trio.py b/.venv/lib/python3.10/site-packages/anyio/_backends/_trio.py new file mode 100644 index 0000000..1a47192 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_backends/_trio.py @@ -0,0 +1,1169 @@ +from __future__ import annotations + +import array +import math +import socket +import sys +import types +from collections.abc import AsyncIterator, Iterable +from concurrent.futures import Future +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, + Any, + AsyncGenerator, + Awaitable, + Callable, + Collection, + ContextManager, + Coroutine, + Generic, + Mapping, + NoReturn, + Sequence, + 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, + wait_readable, + wait_writable, +) +from trio.socket import SocketType as TrioSocketType +from trio.to_thread import run_sync + +from .. import CapacityLimiterStatistics, EventStatistics, TaskInfo, 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 ResourceGuard +from .._core._tasks import CancelScope as BaseCancelScope +from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType +from ..abc._eventloop import AsyncBackend +from ..streams.memory import MemoryObjectSendStream + +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 | None: + # https://github.com/python-trio/trio-typing/pull/79 + return self.__original.__exit__(exc_type, exc_val, exc_tb) + + def cancel(self) -> None: + self.__original.cancel() + + @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 | None: + try: + return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) + except BaseExceptionGroup as exc: + _, rest = exc.split(trio.Cancelled) + if not rest: + cancelled_exc = trio.Cancelled._create() + raise cancelled_exc from exc + + raise + finally: + 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 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 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 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_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: + return trio.from_thread.run(func, *args) + + @classmethod + def run_sync_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + return trio.from_thread.run_sync(func, *args) + + @classmethod + def create_blocking_portal(cls) -> abc.BlockingPortal: + return BlockingPortal() + + @classmethod + async def open_process( + cls, + command: str | bytes | Sequence[str | bytes], + *, + shell: bool, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: str | bytes | PathLike | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, + ) -> Process: + process = await trio.lowlevel.open_process( # type: ignore[misc] + command, # type: ignore[arg-type] + stdin=stdin, + stdout=stdout, + stderr=stderr, + shell=shell, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + 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, + ) -> list[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int], + ] + ]: + 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_socket_readable(cls, sock: socket.socket) -> None: + try: + await wait_readable(sock) + 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_socket_writable(cls, sock: socket.socket) -> None: + try: + await wait_writable(sock) + except trio.ClosedResourceError as exc: + raise ClosedResourceError().with_traceback(exc.__traceback__) from None + except trio.BusyResourceError: + raise BusyResourceError("writing to") from None + + @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 + ) -> ContextManager[AsyncIterator[Signals]]: + return _SignalReceiver(signals) + + @classmethod + def get_current_task(cls) -> TaskInfo: + task = current_task() + + parent_id = None + if task.parent_nursery and task.parent_nursery.parent_task: + parent_id = id(task.parent_nursery.parent_task) + + return TaskInfo(id(task), parent_id, task.name, task.coro) + + @classmethod + def get_running_tasks(cls) -> list[TaskInfo]: + root_task = current_root_task() + assert root_task + task_infos = [TaskInfo(id(root_task), None, root_task.name, root_task.coro)] + 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( + TaskInfo( + id(task), id(nursery.parent_task), task.name, task.coro + ) + ) + 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/.venv/lib/python3.10/site-packages/anyio/_core/__init__.py b/.venv/lib/python3.10/site-packages/anyio/_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42961606ad234331f1620390fbee24276e17e2a8 GIT binary patch literal 189 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_resources.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08643931de22ae11843911ec396ba4124854ab33 GIT binary patch literal 768 zcmY*XF>ezw6t?d!X__XXNJtDUC$<~7qh+E(sHh!a$v_4~mXmXKa#noy)%GdVBDs?5sC&YhZf;_k4UL3v0O>B z^44qpS7s@*x6G(YXKV%MH<>3yW=xDSRkFIHH@iB3-MX!rt+cFzp^_|f1zU5F9T?vo z*;8;nVT-QN^@9)i65rrkgwZ9s@ov!@5b+wKckmBTfUcYXJVFP^JX(M-_q~VV)*|oX zYc~Wt5z4TT$dEY3xmHqDCfsrhIc$VkLt8K!8b>|uHkGG}%UNi1ZosNOB43a<&0DDv2h=--@IE>#bVDt`8eVzHWo|y1gb-w@GtoF6;Yi0_jviho_YgOGm`GN9TR)>~`=ze*9bCgK!uH z4aug_+O<;e!W8Y)-87w6&~}!l+O@g%$t2snhtv`?H;w29rBQZg8o2zwk_UYh9Yucm3Nif>K zbX7*-rcb0)mRPQ&!R_#sDP?+WnI=|gJm^mNQWD{Od#{zW?6ZAKBv~?j8CDtYESXJ+ zyOzvJdd?)>bWL?hw=iVW(af&2yn1l^{^_k!r*)mPv(zEmE?1+0-y^5N01X>_4?c!p zgP#Gi2+2Kk_5jz!5^X`Vl<_r}OHhTQ;4D)b%W|k8MLi!rE{G=AhvTgmtg3S`c*vq< z1hZLnF`6779iP0P%|_MziqjZ~1kXLwN~)ECw9*LjN+eh){a*~P<%Nrkrx}!-32J;= z$E2zUa+S}SHWl0`f(xQ0(ixB81D8}?7@&$7z{dl#Dhh?{Yll;!LYIQ4my7a+V#}cEY4KUVw#o`Ja>sau4T$DCb@@e$=QEc!v4-0I3oCy;nRj%SBRhq?hQ4BcqlVBhagMlFxRPl?_|hjt;O{-&2CixticOA_raZ1z(n1WWytMr599_rI{| zRLtusvt@ygsoUt8_7a9zt&_;B;Olv=H-3gL$IkOy(Uo8?+@$#l8w7*KAjD5&ulWz6 C4_cQ1 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_sockets.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba36c44b7ca38d560398d7a3a80098b2bb6396c3 GIT binary patch literal 19703 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 QWdnA}?R9)_kM*AY3piFrqW}N^ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_subprocesses.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13b3806c829c812bb7b29073cd6593d031b92708 GIT binary patch literal 4991 zcmdT|TW=f372XTEq)1AZ6vdaMZN^R=n}tpKQWz~^74 z>6xKr8B~!}0h&GpedtS31cCkNztKMQKg?^M`~%XudTGy@T~aGsNdvU#g#>rc&h4Bz zbI$p`WimTkvEcLP-yZ4ze#x@F#E1N+3=coCEL;8&1Zq(`vSPb!+bBDc6T59UF0>1A zv0XH6Zsf(KcFD+vs2tCU~p}i0S@1~ zNqJ3(MCkdqlXw_0HEjls&hm+6|?baq^ZYG?GSFvd+6HIYaW@ui=uOU}_}z?vWQ= ze8-q~H$X??rv$%Q_+h;7U_`$UJs;b2_SaV5#;E(Gwp~`%*c#hnPTAa6&e$2da^9PwXC%yZiCL-&|i979@|gsRD+pOdOY(a(}>THD|=73!JdLuuy)+ZcwRl9jg@>8 zaumNmhu=4j+{usp)cS?9UEQvY3*rl~r%J0EuJ}UL)U2Ar=N$+9QytfK3cs?|p|O=~ zH?5FibN;C!c$vWG{ShZVC+s1l755{O#TW^pnaELZnC1wKp=8q!6&Z0AMg#;HY4Sxj zDrTidgGk2wNG7coY4t}uXm$4%XowN-rUP3;U-~0arIvm)dzVi2Z1ItkN z%mE!)q3WKQZp$bAFk)vTsAMGR-D80=&gf#^c3)5mrR3kE^ks`z*WOwAU=3{k*7lf^ z)*@k_bh~R}#JVt9_@QK^#U4U%{4y6EFBjx4P6Q86{V<6{h=4fcP+KM0gvbGV(((f5 zPr*Ybmec@Z&zVFW+FB)bZ98R#fjKT&pni+$NGt2 z1Oj*xTT`2|Y{@Hv;%)Z4Uy&NXLU9UMVDB*U0eOtxkVEi8SW^NsLy>Td$*F<|z6ddd zCFzSKHWMIwU+47$DQjxzHe|Z>_8@e+UT>ZPim7(^G0;7N=p1eh^H;W+o{+DJfHh z*-Q)?NxnH=vb~z1>q79zY1EmF$6U?33=0N(h;<+fBA)O^OeFbWO3M{uHDGzXyR?sg zWY~p(PT5240<4M?fLpqN!4)7^n0yK#Ahi7sA?*?fAKMD>Z5s;p1?y4uA`rFf007(W z*m-P^-6ytf-S;k8@Z>zPJ_WG53?ray+c)d3@L;|!ZeqyjGBA$^el!A#Bfbyq;w|j- zdZT`y8BQ_c8&B=_p>zWsERb06o?5%CIY?sGq=Sw7Kfcgx3`e~vl!Im;5(|h_<53dI z#)fD%9zakwqp;T;ZmB`SFE-AfYf4akb_h(zUuUxE^Q|yx!rFp0J9`<;WMjCcYZMZm zcT)Wq!8loii}R6Z&)YTI`TM;4=s4t6Cp($ObOkR!D#X(q`e z;i9- zL7OgRj?j);*B%f=!xf>bCqjw_&N_>iCXTJ<9EV!vkKp2bGo_p1aJh|7Nrz#gymEXao3@CgTC8PX%C>d}wlEH{Ku+3l{LCFB#ag-4Cgy}WN z_9i^m=W}bDJ(+b5TKik9hyYN3T~|7t{s>;)S*IhA(&$4$0)L$Z=0BN+-wT9`mLS6s z@JeZE2MD5}C{7{;f`+c_k%AOw4dNQGM2OU$+QPqa1Tq7GZ~q2EwTp|R741rg0S!@6 zk_^q^Y0vztB2&ONz=g+|JE`e$>GI_`p`(ahL4qI=V{6uuQv>pG)Lyb{MsmE#DdBzY Mug-gW&x_Ch0Vhv{+yDRo literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_synchronization.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d47a270c1baf4aa07e718c708f483f646a63acb5 GIT binary patch literal 21165 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 Voti&3`@rm%@f(r#d9~;5e*)@jgr5Ka literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_tasks.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f77be848cecb514d46f53d2e15743c398b3f465f GIT binary patch literal 5855 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 QS?^m`>u&Q>eWBI*4~rSL-2eap literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d8af7bc293fbfe2aa7e1a131ff643532e632ae5 GIT binary patch literal 2745 zcmZ`*OK;mo5Z)!J7cIXM=lvpzwg?+X%A-9rXo3a-n)spsanS+_j4j1oMYJhW-d!cI zpcXBhdw)O>pgkJszv!X=VXr;qoSRRbS(=XQxHLQ(?#}MKzL{Y@KkpNG{`vh}|F0S$ z|KiK+6eVFaMqs5Ws7ecd0?PM|QMe&x%c#N0LK8Fr{2djc~DJNZr z)2_>%uE#I&Io943bO-3BMQUfe6M~vON~? z3P+QEB4m*F?FOEjIWvkRNU-wQ$MS`MRkj)=eXwGuI1U>1&PW6^H#{9-n4|PLSh6vr zL}?jh(NGkoaiLJVhOwGmf9zI>{{AbK8QIeZC>CO=oEl}-8v$^w3!H{`85CCr^tpx)F0 zTAAWXb?O1FaROLzI)=8wx>-V~#$#!dh^aL`W5b+}Q^A;NGPXUAQuLBB*#KqMP3xic zN}?xW)p$yz{gd{L*B@u`9+BrkaQ~5MOiFblRQza zE!l3p6xqvmn)KSE9X-giyRF-|+A7iF<_O9udLdLBP?Y3t29XzSriFr(zG#hhOr5bL zOEhC=L7&3Fd$ko>wSPXHESCk+D&;cdr4SL_-WApMbYG}J1;3Jj%Of53cb$6yPoj-liI4S@B8~Sgupexr!-Ou5D2Cmpbvd1Fo*Ft9x9NN(CHYv37gjB zt4Fh4?0#e|hRa&(0W*clut6$rKS@uGjk8xW8r>?@cyzM#As@wNC#)B>umDm;u`D8o zaFk0(ux#WqkkBhKe;F69Ai=N!C@hcXOa61<_YT$(O`$JC_>n6}&Hynr#&{k>&>(&) z%{9bNB2MKeNIpY?36(dHd`P+F5N{TwSmX+AtP_uVzVG-8e${su+ycUARt*0~o)T~G z3%u=;Kj@#>Wa#7v+drS#lCsm|pw%3iJw?Uc3!(s%WQUaCnsp{zR5#XDf+1NfH+MTu|5!)bG(TYuxQ zz&`UE)uhPJ8jOo41iq4>Glb6Ms~_RB2ByAF(jZFHz;?w0A7R7?_|=16_j4I2XyST+ z9k+9k33C?r85}GuX1z3r4X7Si?moBVIywp_T%L43^I5@jLvsuBU6tJ<)*kT96X0@MWsHuNbOu`4)C2UbN R$&%BgO=rRNZ}?Cd{{i-hi%0+f literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/_core/__pycache__/_typedattr.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..265f0895d9bd55b114240b088a3318d33a34ca54 GIT binary patch literal 3302 zcmaJ@TaV*J7Ot|L#7U>`!@!8k)^b@U&?MZ1pam<22Cdj-TZkF$YCRg6imNg)?MtT0 z?j}({h>Vs;egHy($N3Yy>;wP7uRQV0+i0cTbIOjBo*rSz<+{1fcP`&Km2Pf!2s}T3 z`{?LDZ9;y*!TMvv;9Wwf{t7yR2pW-?dX!?{imcf7?AY-fGq$5f-1M4p%WK81=f-WX z4fBp@M4foU+n_|YL~}vCE__??-IQAk;%$pv(GeSW9dG9^M0CaGT_QFYmbVL|EwK%w zZ5Zu|o$I8x_bZ?vJz8w=BuO)#g=wODR^cA;DB{CN7OlVY$s|l}_ngAMmQ0J*jp;=G zgR7!33KJd`Zh9(JlydPaEl;|F8^pCNQ{gbrfPYu^fo;$(^@e9rP#pFbef}fXXF-?9b9r_fOQI ze=3vHK@<)LlW8_ilh^vMygblhCSRKH;Dq0ndcc!um=63PRdV1P@hH7NnHJk-hf_k=SenUnSL*Q=LbG{)C@fu*1Repp9 z`*(-Ib3LC(6+~QXHcHilW??}ZMPNL1d%t6TI2y~~M6+znGbX{eQ)X-utZd2BQMID; zVR`hJYw!oE$yR~XH|HtTws4NqL4$U_&K)l)_R7FQ;TxI$!%*GJFu(^!s zhDHMyyS^VLVdgI_;`=?ju!Be|^mF0jISG&DJzBJV-x$sJ%P`!54eD`duE48t)TLdz zM=jc+&i|~hww&2B7rfiQD9ZI-;Yy~N7(QB{+*mh)k@3vMH&DO zlwNFBxB?kPOKgTGPr<4(DEFX;uOXyM9D2E_aC{+v(XsEMV?Tn@wD01m1*1!1vmUv!4Wa&s*nyb_u8Uo8?d9U~d1HL6($i2#H9LBbYsprjZhEqc zlR7=iMyx)d5>(!<#p69k6op)~$2VjFDZZE2M8| zk`@0DCJhaci`O7EnPiF#%EppCC?639RpzaLm-*4`hRmX*o}`I@n5_>zgT}=Cd)b-v*#ZkGyMnuDcZF~)CT+?AbXb&_Ln~X4SkHc<{mvR zVOa_Vsvb6Vc`2bajF{J91aA8E|Y4kyn+?0F&qP!Tu7K zdI1LNMQjkmJ$nsQe>q#iGlV{Xxi@kCC2WwjY73eR=esa@gnY)$v(}t^M&|SiROEkx z2^^Bq>EjeYP%^hND<|qvNYQjbh4nS0?^dVooBy;<2V<41wZRWqrS>~{0=+Pi zqF0tA^nF$Iku@gbmlV1kLS=q9o!27gaKaUjS4=-N@mY&zS7R9uA>@IVoE@6Xaro(% z=bZ#K_0t|Ow2oec6~Xle3u`@DNvc#S<&=O;MJ+jnG^%M6j#!dbN%Ygns+|1^mf&HpPp0$x^%#mxvHxvEj?l135AGxYFLnR>mMk sYl9o_nx=y8hd;H2kq%o!~g&Q literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py b/.venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py new file mode 100644 index 0000000..a9c6e82 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_eventloop.py @@ -0,0 +1,163 @@ +from __future__ import annotations + +import math +import sys +import threading +from collections.abc import Awaitable, Callable, Generator +from contextlib import contextmanager +from importlib import import_module +from typing import TYPE_CHECKING, Any, TypeVar + +import sniffio + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +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() + + +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 + + """ + try: + asynclib_name = sniffio.current_async_library() + except sniffio.AsyncLibraryNotFoundError: + pass + else: + 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 sniffio.current_async_library_cvar.get(None) is None: + # Since we're in control of the event loop, we can cache the name of the async + # library + token = sniffio.current_async_library_cvar.set(backend) + + try: + backend_options = backend_options or {} + return async_backend.run(func, args, {}, backend_options) + finally: + if token: + sniffio.current_async_library_cvar.reset(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_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]: + threadlocals.current_async_backend = backend_class + threadlocals.current_token = token + try: + yield + finally: + del threadlocals.current_async_backend + del threadlocals.current_token + + +def get_async_backend(asynclib_name: str | None = None) -> AsyncBackend: + if asynclib_name is None: + asynclib_name = sniffio.current_async_library() + + modulename = "anyio._backends._" + asynclib_name + try: + module = sys.modules[modulename] + except KeyError: + module = import_module(modulename) + + return getattr(module, "backend_class") diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py b/.venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py new file mode 100644 index 0000000..571c3b8 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_exceptions.py @@ -0,0 +1,73 @@ +from __future__ import annotations + + +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 :func:`run_sync_in_process` if the worker process terminates abruptly or + otherwise misbehaves. + """ + + +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 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.""" diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_fileio.py b/.venv/lib/python3.10/site-packages/anyio/_core/_fileio.py new file mode 100644 index 0000000..d054be6 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_fileio.py @@ -0,0 +1,645 @@ +from __future__ import annotations + +import os +import pathlib +import sys +from collections.abc import Callable, Iterable, Iterator, Sequence +from dataclasses import dataclass +from functools import partial +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + AnyStr, + AsyncIterator, + Final, + Generic, + overload, +) + +from .. import to_thread +from ..abc import AsyncResource + +if TYPE_CHECKING: + 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) -> bytes: + return await to_thread.run_sync(self._fp.readinto, b) + + async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> bytes: + 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. + + 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_mount` + * :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.rmdir` + * :meth:`~pathlib.Path.samefile` + * :meth:`~pathlib.Path.stat` + * :meth:`~pathlib.Path.touch` + * :meth:`~pathlib.Path.unlink` + * :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() + + def match(self, path_pattern: str) -> bool: + return self._path.match(path_pattern) + + def is_relative_to(self, other: str | PathLike[str]) -> bool: + try: + self.relative_to(other) + return True + except ValueError: + return False + + async def is_junction(self) -> bool: + return await to_thread.run_sync(self._path.is_junction) + + 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) + ) + + def glob(self, pattern: str) -> AsyncIterator[Path]: + gen = self._path.glob(pattern) + 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) + + 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) + + def iterdir(self) -> AsyncIterator[Path]: + gen = self._path.iterdir() + return _PathIterator(gen) + + 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: + return Path(self._path.relative_to(*other, 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)) + + def rglob(self, pattern: str) -> AsyncIterator[Path]: + gen = self._path.rglob(pattern) + 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/.venv/lib/python3.10/site-packages/anyio/_core/_resources.py b/.venv/lib/python3.10/site-packages/anyio/_core/_resources.py new file mode 100644 index 0000000..b9a5344 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/anyio/_core/_signals.py b/.venv/lib/python3.10/site-packages/anyio/_core/_signals.py new file mode 100644 index 0000000..115c749 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_signals.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from collections.abc import AsyncIterator +from signal import Signals +from typing import ContextManager + +from ._eventloop import get_async_backend + + +def open_signal_receiver(*signals: Signals) -> ContextManager[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/.venv/lib/python3.10/site-packages/anyio/_core/_sockets.py b/.venv/lib/python3.10/site-packages/anyio/_core/_sockets.py new file mode 100644 index 0000000..0f0a314 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_sockets.py @@ -0,0 +1,716 @@ +from __future__ import annotations + +import errno +import os +import socket +import ssl +import stat +import sys +from collections.abc import Awaitable +from ipaddress import IPv6Address, ip_address +from os import PathLike, chmod +from socket import AddressFamily, SocketKind +from typing import Any, Literal, cast, overload + +from .. import to_thread +from ..abc import ( + ConnectedUDPSocket, + ConnectedUNIXDatagramSocket, + IPAddressType, + IPSockAddrType, + SocketListener, + SocketStream, + UDPSocket, + UNIXDatagramSocket, + UNIXSocketStream, +) +from ..streams.stapled import MultiListener +from ..streams.tls import 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 sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup + +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 OSError: if the connection attempt 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: + # 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: list[tuple[socket.AddressFamily, str]] = [] + for af, *rest, 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])) + else: + if isinstance(addr_obj, IPv6Address): + target_addrs = [(socket.AF_INET6, addr_obj.compressed)] + else: + target_addrs = [(socket.AF_INET, addr_obj.compressed)] + + oserrors: list[OSError] = [] + async with create_task_group() as tg: + for i, (af, addr) in enumerate(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 + + 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 + + """ + 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 list of listener objects + + """ + asynclib = get_async_backend() + backlog = min(backlog, 65536) + local_host = str(local_host) if local_host is not None else None + gai_res = await getaddrinfo( + local_host, + local_port, + family=family, + type=socket.SocketKind.SOCK_STREAM if sys.platform == "win32" else 0, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + listeners: list[SocketListener] = [] + try: + # The set() is here to work around a glibc bug: + # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 + sockaddr: tuple[str, int] | tuple[str, int, int, int] + for fam, kind, *_, sockaddr in sorted(set(gai_res)): + # Workaround for an 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 + if sys.platform != "win32" and kind is not SocketKind.SOCK_STREAM: + continue + + raw_socket = socket.socket(fam) + raw_socket.setblocking(False) + + # For Windows, enable exclusive address use. For others, enable address + # reuse. + if sys.platform == "win32": + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) + else: + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + if reuse_port: + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + + # If only IPv6 was requested, disable dual stack operation + if fam == socket.AF_INET6: + raw_socket.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) + + # Workaround for #554 + if "%" in sockaddr[0]: + addr, scope_id = sockaddr[0].split("%", 1) + sockaddr = (addr, sockaddr[1], 0, int(scope_id)) + + raw_socket.bind(sockaddr) + raw_socket.listen(backlog) + listener = asynclib.create_tcp_listener(raw_socket) + listeners.append(listener) + except BaseException: + for listener in listeners: + await listener.aclose() + + raise + + return MultiListener(listeners) + + +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 + ] + + +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) + + +def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: + """ + Wait until the given socket has data to be read. + + 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 readable + :raises ~anyio.BusyResourceError: if another task is already waiting for the socket + to become readable + + """ + return get_async_backend().wait_socket_readable(sock) + + +def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: + """ + 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_socket_writable(sock) + + +# +# 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 | bytes | None + if path is not None: + path_str = os.fspath(path) + + # 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 diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_streams.py b/.venv/lib/python3.10/site-packages/anyio/_core/_streams.py new file mode 100644 index 0000000..aa6b0c2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_streams.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import math +from typing import Tuple, 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/.venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py b/.venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py new file mode 100644 index 0000000..5d5d7b7 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_subprocesses.py @@ -0,0 +1,140 @@ +from __future__ import annotations + +from collections.abc import AsyncIterable, Mapping, Sequence +from io import BytesIO +from os import PathLike +from subprocess import DEVNULL, PIPE, CalledProcessError, CompletedProcess +from typing import IO, Any, cast + +from ..abc import Process +from ._eventloop import get_async_backend +from ._tasks import create_task_group + + +async def run_process( + command: str | bytes | Sequence[str | bytes], + *, + input: bytes | None = None, + stdout: int | IO[Any] | None = PIPE, + stderr: int | IO[Any] | None = PIPE, + check: bool = True, + cwd: str | bytes | PathLike[str] | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, +) -> 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 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 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) + :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() + + async with await open_process( + command, + stdin=PIPE if input else DEVNULL, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) 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: str | bytes | Sequence[str | bytes], + *, + stdin: int | IO[Any] | None = PIPE, + stdout: int | IO[Any] | None = PIPE, + stderr: int | IO[Any] | None = PIPE, + cwd: str | bytes | PathLike[str] | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, +) -> 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 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) + :return: an asynchronous process object + + """ + if isinstance(command, (str, bytes)): + return await get_async_backend().open_process( + command, + shell=True, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + else: + return await get_async_backend().open_process( + command, + shell=False, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py b/.venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py new file mode 100644 index 0000000..b274a31 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_synchronization.py @@ -0,0 +1,649 @@ +from __future__ import annotations + +import math +from collections import deque +from dataclasses import dataclass +from types import TracebackType + +from sniffio import AsyncLibraryNotFoundError + +from ..lowlevel import cancel_shielded_checkpoint, checkpoint, checkpoint_if_cancelled +from ._eventloop import get_async_backend +from ._exceptions import BusyResourceError, WouldBlock +from ._tasks import CancelScope +from ._testing import TaskInfo, get_current_task + + +@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 AsyncLibraryNotFoundError: + 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 + + 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() + + return self._internal_event + + def set(self) -> None: + self._event.set() + + def is_set(self) -> bool: + return self._internal_event is not None and 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: + _owner_task: TaskInfo | None = None + + def __init__(self) -> None: + self._waiters: deque[tuple[TaskInfo, 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() + + async def acquire(self) -> None: + """Acquire the lock.""" + await checkpoint_if_cancelled() + try: + self.acquire_nowait() + except WouldBlock: + task = get_current_task() + event = Event() + token = task, event + self._waiters.append(token) + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(token) + elif self._owner_task == task: + self.release() + + raise + + assert self._owner_task == task + else: + try: + await cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def acquire_nowait(self) -> None: + """ + Acquire the lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + task = get_current_task() + if self._owner_task == task: + raise RuntimeError("Attempted to acquire an already held Lock") + + if self._owner_task is not None: + raise WouldBlock + + self._owner_task = task + + def release(self) -> None: + """Release the lock.""" + if self._owner_task != get_current_task(): + raise RuntimeError("The current task is not holding this lock") + + if self._waiters: + self._owner_task, event = self._waiters.popleft() + event.set() + else: + del self._owner_task + + def locked(self) -> bool: + """Return True if the lock is currently held.""" + return self._owner_task is not None + + def statistics(self) -> LockStatistics: + """ + Return statistics about the current state of this lock. + + .. versionadded:: 3.0 + """ + return LockStatistics(self.locked(), self._owner_task, len(self._waiters)) + + +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() + 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() + + 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 __init__(self, initial_value: int, *, max_value: int | None = None): + 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._value = initial_value + self._max_value = max_value + self._waiters: deque[Event] = deque() + + 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.""" + await checkpoint_if_cancelled() + try: + self.acquire_nowait() + except WouldBlock: + event = Event() + self._waiters.append(event) + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(event) + else: + self.release() + + raise + else: + try: + await cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def acquire_nowait(self) -> None: + """ + Acquire the underlying lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + if self._value == 0: + raise WouldBlock + + self._value -= 1 + + def release(self) -> None: + """Increment the semaphore value.""" + if self._max_value is not None and self._value == self._max_value: + raise ValueError("semaphore released too many times") + + if self._waiters: + self._waiters.popleft().set() + else: + self._value += 1 + + @property + def value(self) -> int: + """The current value of the semaphore.""" + return self._value + + @property + def max_value(self) -> int | None: + """The maximum value of the semaphore.""" + return self._max_value + + def statistics(self) -> SemaphoreStatistics: + """ + Return statistics about the current state of this semaphore. + + .. versionadded:: 3.0 + """ + return SemaphoreStatistics(len(self._waiters)) + + +class CapacityLimiter: + def __new__(cls, total_tokens: float) -> CapacityLimiter: + try: + return get_async_backend().create_capacity_limiter(total_tokens) + except AsyncLibraryNotFoundError: + 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, + ) -> bool | 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. + + """ + 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, + ) -> bool | 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, + ) -> bool | None: + self._guarded = False + return None diff --git a/.venv/lib/python3.10/site-packages/anyio/_core/_tasks.py b/.venv/lib/python3.10/site-packages/anyio/_core/_tasks.py new file mode 100644 index 0000000..2f21ea2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_tasks.py @@ -0,0 +1,158 @@ +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) -> None: + """Cancel this scope immediately.""" + 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 | None: + 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/.venv/lib/python3.10/site-packages/anyio/_core/_testing.py b/.venv/lib/python3.10/site-packages/anyio/_core/_testing.py new file mode 100644 index 0000000..1dae3b1 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/_core/_testing.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Awaitable, Generator +from typing import Any + +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 _unwrap(self) -> TaskInfo: + return self + + +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 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/.venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py b/.venv/lib/python3.10/site-packages/anyio/_core/_typedattr.py new file mode 100644 index 0000000..74c6b8f --- /dev/null +++ b/.venv/lib/python3.10/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: + return self.extra_attributes[attribute]() + except KeyError: + if default is undefined: + raise TypedAttributeLookupError("Attribute not found") from None + else: + return default diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__init__.py b/.venv/lib/python3.10/site-packages/anyio/abc/__init__.py new file mode 100644 index 0000000..1ca0fcf --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/__init__.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from typing import Any + +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 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 Listener as Listener +from ._streams import ObjectReceiveStream as ObjectReceiveStream +from ._streams import ObjectSendStream as ObjectSendStream +from ._streams import ObjectStream as ObjectStream +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 +key: str +value: Any +for key, value in list(locals().items()): + if getattr(value, "__module__", "").startswith("anyio.abc."): + value.__module__ = __name__ diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b164781e869e7133ba8858e42ce0507b5a02415 GIT binary patch literal 2138 zcmbuA+iu%N5Qa(Xe70prKA#VX9GkSAG;LZpiIWsX03$Ul8z=^82})dBthuDJyK*64 z703fLkC0sUN%{`F?Nwf(7e!}QwqrZFiv;}o_MhQ!xjS4%rBdF&&)`7=%|pl| zFrv8{+~PH;X&y!%g;C8T$YU_3`4;jxjBBnTPr!ucQRGRO)I5ef1yh>Gk*8r=^91q? z%xIoOo`qS>Q^<2Lr+FHA9_BUAATPjz=2_%LSkyd+yaY>{=aH9TS@S}$!f(TE&5OYu zUWdBoCFE6D)w~?so zYsox!D*fagrG($?DxK7~c73T>$OK+i>^lu5n9Ffo!a3~GT-AA%+|^0d4zJART3YpL zXzk$niX_hX`i}}r`pQ|(ZNyfE` zqo0N^Y7c#`T$#*k74q7-xF~yNF^7L@{)QWQ^T`JL_O&9#bMK8a+n>%pj$&VuHc5slVK?7U1OQHM$lWM<^$^+W>i5~ohxpv&UCI#r|7)>RJqK=@G91VOa^s6OBn$ok5)bErO861i%Nsfg67DR!hNKzsxlT=6s zNrp(OD1cS;ib^p|-U!Jpk{Zb<$r#Bv$ppzH$rQ;n$qdOX$sEZ%$pQ+L9NBGl`kTb0 zSVS*QI|_G4iY3ZgrmU=^aEIuzS7=ysTDabpLq|(nM4^AC&mM7yE~t~NlH4U(LxJM? z1^v3~WEGA?#2wYfH{TN$I&sBuuAF1I8OZ=oia3pX=ms)QVHDp|}F&1@oT*31zzZ6^On{`WtDRaQd) literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_eventloop.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..789e9cce849813757947f9c6ac5abd6267354d8b GIT binary patch literal 12311 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_resources.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6881606f4b4a4921ccf7a2e828bc4cb58d23d2ce GIT binary patch literal 1440 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_streams.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2347af40d4f8a7aa7e55cd72ca70dcc2fc3d230d GIT binary patch literal 7501 zcmcgx-ESOM6`$E}Z*0eL96L^&Wb)O zb+T4fQ4$FW3Gsx)6QU9l@(X_g0wKXG&+`aRea>4X6n^K-$Bw;gr=k*T?cF=)+&TB& zbI_FVX*NNxikf@G8#l+fUw0?GNplkYh8S~?dQ;{U_nYo9 zZ`z#JH901ZJl4(Q_#GD$V)9oda|ZpR=ue@4;4a3JY%*_;P$UYr8$6vjacXs19s zEfzpqkn=3z6t^c?PSrdO{uyx={Ik54in##FIbnceq?9wDoEH~BxgZzh8O(lGHZkit ztY@K9n%7JN&vX2IhM&*l`6NG|<>w1{o-d5Qi04y<@t5#?x-kASX1pjaVa7{)^z@Rr zd{2o^kMLj-Z`F;>tkrVhK9w)7hFjAHsc{17x1SpN0mg`y@u3W6d;10$p{3&L2R>f^yp&43<%{<^cOxY&5AV;?D6twv%Gu~e@&_u|c7#-)!>VZh ziPf<0+waRT=qX!*Ft%=m4{ocV*NtoI?K_e5;>vp44%Ufh2iul%EI*1HMDwv!l9BXM zmQ6b=ekyoaAxnM@9jTeR(9Dw1%`)t(BC1a+W(BrY7Y+2PvWEVcXg;aH2J7MobTt{D z`M_7wbw~^EZTwW)(fiVt&bCZ8X zBb=)7&~aU(??_kVe9wyPEqV)U;1z9RsaPlt?_zVXE2&z{iEBzmJ>@^Uc&K{s(Mf-3 zlf7gg>eKfoexB0teyrWqcJ;MgG;t-AZbt#qG;W^#WN9n#(y75LTKSy*Rmgw-j^)D?*vQMhP~8= zlfb;gR<|FIwc8dctKB|}IiHdjRP>#f58YEMe@9JW{LtnaApVUu_Yyjv>N|~(wcl%> zX?Fm=?`S{5W-D5x_W_pl7nOdlKh)Go4Baiq^~C0+B6yFd??yqFPZpj;=Nb6w6c_{j zs0A8FoABkMsNFt~$EV|HN^QkU$I8@29KxP{t zuSuPWEXE)yWO`m|l*C_FmJ`D4KVkj1Zn^=CHbabCN(E}!aL6okUon#7F}AGG*pM(k z`KaqUwiCJid{&Zdv#6Z3Z=wQ@r4zvJ_e)Mh7#$UOyn+DBP=@ryK~it1;DPi@HI$&N27c+zpp;%ye z0`ta!5RZ6)P@Q6Hg`7xDLlJyrab+#=rA^?JeW;&#r@D*>_~q+Gza)Ja7D5^%k)4r) zb){5TS%(kE%sY9)J>nMO5;| zw}?TIzH{zi<7?5#wZ%#zCO<*7g!gu9>I%tNq~(W>TC-tOqK#hRv z7Ov5V$5SmO4&kO6`T`EIM^zcl(@`fSN9GCHMp^J)Pe_6?;lqLH7X$omY3E=3I@t*w zC!srjt_7WI9ml1LLO3=jiAB6Gfc=kyo)O{*knp2wG$PfffoukJ7M-5r^ha2cl}H%m zG*$;$3Q`o;O{xQDkfTsm|H;uFPVW9TLR8laprofm=b+azcd;w*!)fo}%7)lwCpOVlAd ztAe-!&|Yh3nHP+wwp-#a1rsHEb`jLFUSe5SlDKWu= zOVSOz5+<3eWrR2tSOCTM^t|sR1p}9II1L(|Bl)22vvLL}MjaHV8xG2HScWV8&1mbY zfwG@!TQ5*a`U(j1jW^$Ts5$6{OPoa8qmo+6DnFrNl>Y6U z9@5C5=!&bn_o3OcvP+%IXEUfbYPO4Dd`iqqXbzYysflpaqNBp{tVeC0HZJ3m;DxE! zFN>*Ida?#mJTC|%jwvMKNZE|Vf9Jsu866qS}ROB$nHqYHojSn zq&MqSBTegyI748Q1vPaQTvS1mv`~r#X=s1tz@mrMOsKvWERr;J1=0qH`6A=qxtAXo zhasvgl6#_jlC0P$1fS*ol}0|8U_Fi-THzrpuunq2Fp5^$cV2dn-qaFH=IdHy6{SlFLC)810JZ4K5jgjfIxzFy(@ zuD*e%WR;^3i(=IuXhdQ6Jo_N*sc#aW%anoY2AlmZxS!F8Th!3g&?fU>b^+XCFq4(B z5``_kT&2)e<(gt5ZoKP+2=Y?x+!(UGAh|V7vR+q4Mjr`?h0x!{Es<{r9t9oT{-U(y z8|>CvTt{?40;ryy$S$t$B{zsyaXs7rFm6V;Uv6*G1@p71{I1#f*q{Qrpy@K!pM9vm zN7E>kJ0RpXw|elB4BSD%nEO~Js(2)+1e9T9DWp$W377%ysc6XuKxMk0Wy9iBhi-uq zeemt;h9uNQU64!R>x4u{pbwOjFE;g~fgTb(rDucnGFp6b&2+cT>w^AsxfE;;n%ua8 z8#)|U6iGp`!mz}(t-xj#q?2abv2h`SQH#0U6no1F_P&F&P~W3wV4(!SaTUR5TmF?e zY~YibUBSG;;N)Skruh9kxe%%f2d57H6(WqPuiqucV9tS8+y>*%_=a@jiuxK5P%2G7 zS43Z1e3>r9Iz3!;<3dc8K#R+`Lgt!1K57T9o7pZ=37+E`Zp)!qMZTnJ)YPdVgfWld zGF-`4TRtKup#R$NMXx!P(&?fd>35{m5gOiXtMp$hp_%|8uC>|f)FeqfN)46z$wko& z_2^!Jt79$>xiaFkmBR@G8#_KnCG#v?YH%e$c$Q`=Ni;D}5Ag?~#+(~wG8~yRU<}JT zmQo86CNdJg#|j^HLUH5mIWvZ0?EtLNYpoEPY literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_subprocesses.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..beb563062eb7aa479a02ed673e21355b099505a0 GIT binary patch literal 2995 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 VYBsE8vu)W{({%7}u2#-3{Q+*>$%X&` literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/abc/__pycache__/_testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a6f833e205e6346e792d54e052b36c656c6aa25 GIT binary patch literal 2619 zcmd5;OLN;c5GE-~qGZW-Yu9$uBu3uVG^P4D#nb7;@nkYR)Q7~=13fMVA|Q(~9|}O) zmL|9Q+UbAj&A+7oftMb7>Nz)^x(iCO_p#fU3l7hLS_x4U4{Y}O4Jzx}e=eNZ)w zKX5TS%CLB97^Zp+6K-%bG$PY8O`Kby13n-{f0*<-qD5zsYauRgK>UH}B{51EJEFSqw%GWu3ry z9{a4XvXG@h5k@4)g7}z-QxT^mOp?A!o}UUiAU?Q9BE|(td*I%25B>v1lFn=4r{pXE zX{Jypv|hy`F{?#0^NJK{CS%{6aU19O?4jovg15#i!}L_lmM!meBat|p@&+r1|x+s`^-pnC0Y5VP19?l1|Idm`H|n19+1gHF3Y0KDR_-7mjrs~{Dh_nCjf zj)iKocn~CQ*74gETnDs{-Tol2Q3{R=N$Cf0rm}$8=5YNgZ0>YJ?uc`rrhw<@2GYZ4 zOo`{`zUX869FezVKYQ4vz~F?YbD^B|>k9ae?M)#2K_$6B5@y1_ZX zCulc|{n5io!XLV>`ve#nB)Om!73t3DU{ICki@uUpN*hIHJ-MG_dl0_4NwtWZFbiyI%4MKMP zjl%97av}z2iR1*l$RfxNMbe}whecYT6w=<6sv_Zc&{Rl2-73f+5Fy7Z!}lRIGEuMu zCtaCDntjc$slt7Y+-0di_7ez>yoF?1B2t684uwp$4hRh$2L(62(cs6Tt0AE`id2L{AcswyfdrQ~T#&`@e#PxD>#R;Yqsh&zJ%gc?Z0`j>Hm1 zckJkAD8C0}xN$A~;|+N&g6eEy`^NBZ_LCOv5?bt|n5rzhx75G=Q|6q6=b=D_Y?O z&U8QA!kOOrG48BLT~#-ctB=1um2c0;?=O&JEx`NQ@<$8gpQ5~u9XE#SkHbb7c8R=<*P6;pa7jw+$=Zy3#ZSTz?tJ`4a#4g| zZL)#{zUd6<0Ld%xDs(tmLk@oQ={}*4U1W3ad{e~XTkQJ^Z?J~pSgYoixoSGrM(HmW Cn6lge literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py b/.venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py new file mode 100644 index 0000000..4470d83 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_eventloop.py @@ -0,0 +1,392 @@ +from __future__ import annotations + +import math +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import AsyncIterator, Awaitable, Mapping +from os import PathLike +from signal import Signals +from socket import AddressFamily, SocketKind, socket +from typing import ( + IO, + TYPE_CHECKING, + Any, + Callable, + ContextManager, + Sequence, + TypeVar, + overload, +) + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if TYPE_CHECKING: + from typing import Literal + + from .._core._synchronization import CapacityLimiter, Event + 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") + + +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: + """ + + @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_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 + @overload + async def open_process( + cls, + command: str | bytes, + *, + shell: Literal[True], + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: str | bytes | PathLike[str] | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, + ) -> Process: + pass + + @classmethod + @overload + async def open_process( + cls, + command: Sequence[str | bytes], + *, + shell: Literal[False], + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: str | bytes | PathLike[str] | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, + ) -> Process: + pass + + @classmethod + @abstractmethod + async def open_process( + cls, + command: str | bytes | Sequence[str | bytes], + *, + shell: bool, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: str | bytes | PathLike[str] | None = None, + env: Mapping[str, str] | None = None, + start_new_session: bool = False, + ) -> 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, + ) -> list[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int], + ] + ]: + pass + + @classmethod + @abstractmethod + async def getnameinfo( + cls, sockaddr: IPSockAddrType, flags: int = 0 + ) -> tuple[str, str]: + pass + + @classmethod + @abstractmethod + async def wait_socket_readable(cls, sock: socket) -> None: + pass + + @classmethod + @abstractmethod + async def wait_socket_writable(cls, sock: socket) -> None: + pass + + @classmethod + @abstractmethod + def current_default_thread_limiter(cls) -> CapacityLimiter: + pass + + @classmethod + @abstractmethod + def open_signal_receiver( + cls, *signals: Signals + ) -> ContextManager[AsyncIterator[Signals]]: + pass + + @classmethod + @abstractmethod + def get_current_task(cls) -> TaskInfo: + pass + + @classmethod + @abstractmethod + def get_running_tasks(cls) -> list[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/.venv/lib/python3.10/site-packages/anyio/abc/_resources.py b/.venv/lib/python3.10/site-packages/anyio/abc/_resources.py new file mode 100644 index 0000000..9693835 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_resources.py @@ -0,0 +1,31 @@ +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. + """ + + 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/.venv/lib/python3.10/site-packages/anyio/abc/_sockets.py b/.venv/lib/python3.10/site-packages/anyio/abc/_sockets.py new file mode 100644 index 0000000..b321225 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_sockets.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +import socket +from abc import abstractmethod +from collections.abc import Callable, Collection, Mapping +from contextlib import AsyncExitStack +from io import IOBase +from ipaddress import IPv4Address, IPv6Address +from socket import AddressFamily +from types import TracebackType +from typing import Any, Tuple, TypeVar, Union + +from .._core._typedattr import ( + TypedAttributeProvider, + TypedAttributeSet, + typed_attribute, +) +from ._streams import ByteStream, Listener, UnreliableObjectStream +from ._tasks import TaskGroup + +IPAddressType = Union[str, IPv4Address, IPv6Address] +IPSockAddrType = Tuple[str, int] +SockAddrType = Union[IPSockAddrType, str] +UDPPacketType = Tuple[bytes, IPSockAddrType] +UNIXDatagramPacketType = Tuple[bytes, str] +T_Retval = TypeVar("T_Retval") + + +class _NullAsyncContextManager: + async def __aenter__(self) -> None: + pass + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool | None: + return None + + +class SocketAttribute(TypedAttributeSet): + #: the address family of the underlying socket + family: AddressFamily = typed_attribute() + #: the local socket address of the underlying socket + local_address: SockAddrType = typed_attribute() + #: for IP addresses, the local port the underlying socket is bound to + local_port: int = typed_attribute() + #: the underlying stdlib socket object + raw_socket: socket.socket = typed_attribute() + #: the remote address the underlying socket is connected to + remote_address: SockAddrType = typed_attribute() + #: for IP addresses, the remote port the underlying socket is connected to + 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`. + """ + + +class UNIXSocketStream(SocketStream): + @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`. + """ + + @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`. + """ + + 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`. + """ + + +class UNIXDatagramSocket( + UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider +): + """ + Represents an unconnected Unix datagram socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + 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`. + """ diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/_streams.py b/.venv/lib/python3.10/site-packages/anyio/abc/_streams.py new file mode 100644 index 0000000..8c63868 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_streams.py @@ -0,0 +1,203 @@ +from __future__ import annotations + +from abc import 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 + +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 + + @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 + + @abstractmethod + async def receive(self, max_bytes: int = 65536) -> bytes: + """ + Receive at most ``max_bytes`` bytes from the peer. + + .. note:: Implementors 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 = Union[ + UnreliableObjectReceiveStream[bytes], ByteReceiveStream +] +#: Type alias for all unreliable bytes-oriented send streams. +AnyUnreliableByteSendStream = Union[UnreliableObjectSendStream[bytes], ByteSendStream] +#: Type alias for all unreliable bytes-oriented streams. +AnyUnreliableByteStream = Union[UnreliableObjectStream[bytes], ByteStream] +#: Type alias for all bytes-oriented receive streams. +AnyByteReceiveStream = Union[ObjectReceiveStream[bytes], ByteReceiveStream] +#: Type alias for all bytes-oriented send streams. +AnyByteSendStream = Union[ObjectSendStream[bytes], ByteSendStream] +#: Type alias for all bytes-oriented streams. +AnyByteStream = 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) + """ diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py b/.venv/lib/python3.10/site-packages/anyio/abc/_subprocesses.py new file mode 100644 index 0000000..ce0564c --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/anyio/abc/_tasks.py b/.venv/lib/python3.10/site-packages/anyio/abc/_tasks.py new file mode 100644 index 0000000..7ad4938 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_tasks.py @@ -0,0 +1,97 @@ +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, TypeVar, overload + +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) +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 + """ + + 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. + + :param func: a coroutine function + :param args: positional arguments to call the function with + :param name: name of the task, for the purposes of introspection and debugging + :return: the value passed to ``task_status.started()`` + :raises RuntimeError: if the task finishes without calling + ``task_status.started()`` + + .. 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 | None: + """Exit the task group context waiting for all tasks to finish.""" diff --git a/.venv/lib/python3.10/site-packages/anyio/abc/_testing.py b/.venv/lib/python3.10/site-packages/anyio/abc/_testing.py new file mode 100644 index 0000000..4d70b9e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/abc/_testing.py @@ -0,0 +1,66 @@ +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/.venv/lib/python3.10/site-packages/anyio/from_thread.py b/.venv/lib/python3.10/site-packages/anyio/from_thread.py new file mode 100644 index 0000000..4a98703 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/from_thread.py @@ -0,0 +1,476 @@ +from __future__ import annotations + +import sys +import threading +from collections.abc import Awaitable, Callable, Generator +from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait +from contextlib import AbstractContextManager, contextmanager +from inspect import isawaitable +from types import TracebackType +from typing import ( + Any, + AsyncContextManager, + ContextManager, + Generic, + Iterable, + TypeVar, + cast, + overload, +) + +from ._core import _eventloop +from ._core._eventloop import get_async_backend, get_cancelled_exc_class, threadlocals +from ._core._synchronization import Event +from ._core._tasks import CancelScope, create_task_group +from .abc import AsyncBackend +from .abc._tasks import TaskStatus + +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 run( + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], *args: Unpack[PosArgsT] +) -> T_Retval: + """ + Call a coroutine function from a worker thread. + + :param func: a coroutine function + :param args: positional arguments for the callable + :return: the return value of the coroutine function + + """ + try: + async_backend = threadlocals.current_async_backend + token = threadlocals.current_token + except AttributeError: + raise RuntimeError( + "This function can only be run from an AnyIO worker thread" + ) from None + + return async_backend.run_async_from_thread(func, args, token=token) + + +def run_sync( + func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] +) -> 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 + :return: the return value of the callable + + """ + try: + async_backend = threadlocals.current_async_backend + token = threadlocals.current_token + except AttributeError: + raise RuntimeError( + "This function can only be run from an AnyIO worker thread" + ) from None + + return async_backend.run_sync_from_thread(func, args, token=token) + + +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: AsyncContextManager[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 = threading.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 | None: + 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 == threading.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() + + 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() and self._event_loop_thread_id not in ( + None, + threading.get_ident(), + ): + self.call(scope.cancel) + + try: + retval_or_awaitable = func(*args, **kwargs) + if isawaitable(retval_or_awaitable): + with CancelScope() as scope: + if future.cancelled(): + scope.cancel() + else: + 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. + + Implementors 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: AsyncContextManager[T_co] + ) -> ContextManager[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) + + +@contextmanager +def start_blocking_portal( + backend: str = "asyncio", backend_options: dict[str, Any] | 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 + :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 future.set_running_or_notify_cancel(): + future.set_result(portal_) + await portal_.sleep_until_stopped() + + future: Future[BlockingPortal] = Future() + with ThreadPoolExecutor(1) as executor: + run_future = executor.submit( + _eventloop.run, # type: ignore[arg-type] + run_portal, + backend=backend, + backend_options=backend_options, + ) + try: + wait( + cast(Iterable[Future], [run_future, future]), + return_when=FIRST_COMPLETED, + ) + except BaseException: + future.cancel() + run_future.cancel() + raise + + if future.done(): + portal = future.result() + cancel_remaining_tasks = False + try: + yield portal + except BaseException: + cancel_remaining_tasks = True + raise + finally: + try: + portal.call(portal.stop, cancel_remaining_tasks) + except RuntimeError: + pass + + run_future.result() + + +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: + async_backend: AsyncBackend = threadlocals.current_async_backend + except AttributeError: + raise RuntimeError( + "This function can only be run from an AnyIO worker thread" + ) from None + + async_backend.check_cancelled() diff --git a/.venv/lib/python3.10/site-packages/anyio/lowlevel.py b/.venv/lib/python3.10/site-packages/anyio/lowlevel.py new file mode 100644 index 0000000..a9e10f4 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/lowlevel.py @@ -0,0 +1,163 @@ +from __future__ import annotations + +import enum +from dataclasses import dataclass +from typing import Any, Generic, Literal, TypeVar, overload +from weakref import WeakKeyDictionary + +from ._core._eventloop import get_async_backend + +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() + + +def current_token() -> object: + """ + Return a backend specific token object that can be used to get back to the event + loop. + + """ + return get_async_backend().current_token() + + +_run_vars: WeakKeyDictionary[Any, dict[str, Any]] = WeakKeyDictionary() +_token_wrappers: dict[Any, _TokenWrapper] = {} + + +@dataclass(frozen=True) +class _TokenWrapper: + __slots__ = "_token", "__weakref__" + _token: object + + +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 + + +class RunVar(Generic[T]): + """ + Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop. + """ + + __slots__ = "_name", "_default" + + NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET + + _token_wrappers: set[_TokenWrapper] = 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[str, T]: + token = current_token() + try: + return _run_vars[token] + except KeyError: + run_vars = _run_vars[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._name] + 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._name, RunVar.NO_VALUE_SET)) + current_vars[self._name] = 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._name] + except KeyError: + pass + else: + self._current_vars[self._name] = token._value + + token._redeemed = True + + def __repr__(self) -> str: + return f"" diff --git a/.venv/lib/python3.10/site-packages/anyio/py.typed b/.venv/lib/python3.10/site-packages/anyio/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/anyio/pytest_plugin.py b/.venv/lib/python3.10/site-packages/anyio/pytest_plugin.py new file mode 100644 index 0000000..a8dd6f3 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/pytest_plugin.py @@ -0,0 +1,149 @@ +from __future__ import annotations + +from collections.abc import Iterator +from contextlib import ExitStack, contextmanager +from inspect import isasyncgenfunction, iscoroutinefunction +from typing import Any, Dict, Tuple, cast + +import pytest +import sniffio + +from ._core._eventloop import get_all_backends, get_async_backend +from .abc import TestRunner + +_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 sniffio.current_async_library_cvar.get(None) is None: + # Since we're in control of the event loop, we can cache the name of the + # async library + token = sniffio.current_async_library_cvar.set(backend_name) + _runner_stack.callback(sniffio.current_async_library_cvar.reset, 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_configure(config: Any) -> None: + config.addinivalue_line( + "markers", + "anyio: mark the (coroutine function) test to be run " + "asynchronously via anyio.", + ) + + +def pytest_fixture_setup(fixturedef: Any, request: Any) -> None: + def wrapper(*args, anyio_backend, **kwargs): # type: ignore[no-untyped-def] + backend_name, backend_options = extract_backend_and_options(anyio_backend) + if has_backend_arg: + kwargs["anyio_backend"] = anyio_backend + + with get_runner(backend_name, backend_options) as runner: + if isasyncgenfunction(func): + yield from runner.run_asyncgen_fixture(func, kwargs) + else: + yield runner.run_fixture(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: + has_backend_arg = "anyio_backend" in fixturedef.argnames + fixturedef.func = wrapper + if not has_backend_arg: + fixturedef.argnames += ("anyio_backend",) + + +@pytest.hookimpl(tryfirst=True) +def pytest_pycollect_makeitem(collector: Any, name: Any, obj: Any) -> None: + if collector.istestfunction(obj, name): + inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj + if iscoroutinefunction(inner_func): + marker = collector.get_closest_marker("anyio") + own_markers = getattr(obj, "pytestmark", ()) + if 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: + runner.run_test(pyfuncitem.obj, testargs) + + return True + + return None + + +@pytest.fixture(scope="module", params=get_all_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] diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__init__.py b/.venv/lib/python3.10/site-packages/anyio/streams/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b17c49759c2da8929749e8e55b0c5be4ef720267 GIT binary patch literal 191 zcmd1j<>g`kg5&+-X(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10LKO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKQXT|Ghe^Bq$o8pw^%TZlX-=vg$nIh$ IAi=@_02{3^vH$=8 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/buffered.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c319b2d085f92d56da7364088b0a0ee54c825893 GIT binary patch literal 4100 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/memory.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..764a80f74a1a88c162f21b924dfcde14a4c6b319 GIT binary patch literal 8889 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 F?*LCmhdKZN literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/stapled.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bbd2c6c22225146c2407309b4b53da9f10bdd65 GIT binary patch literal 5390 zcmd5=OLN@D5yoqGvEY(iK17j{EW?tMcoTZpvYm$&*^wQgD6!_p_VdR2Ahv^f7vs@Nr#H)cD^Zn8MUR2~|f`iPi!w)EzxE93w0^1zD#D z#jxa*By9v{Sa!;xHJo$i!g*&tTyPe`MQ2e} z_!KK0sm>X^O}v+QiIti4H}$5%rdZ_*g;n_Mk&c$LBQ4Wx1}!t(;%8PAzCh)Xfj-M4 zeP&q|eX8iQgg#X&WuFx`x31LYzonJe)O5;gx1+>M{HPt*^whlJ1%cNLcv`ySbvk}~ zD>c{oZkM-P9KFlTOT1R##ne~-u)Uv_Zt^x4ek(2A+wbuEp7>TH#%4PA(SE}3@)q~^ z_xtJ1I2*3lyRRyW zW#hULg-yTBV>@{i*-a?Oj^&bK+ixe4?b$IlA>gZa(`UYbVz5(QFxs7RfLhhuLL^Jum2j zso%C+Ud-)i6QZ@E_GaL>l3aqT9Zz_nJ-*9!j170QHC>gQsDikTELP4pGJI_F`?8HO z$>g2HMpUq!>D0)yVv1^J@+IbMZ~#;#Er;G`E(sE+I`o|u1y8!7ofc$Wi)^`n5v}9- zicDq^#OLaPvZFjv57ejXEjWo!ly&8qy7o*H%V;z3>{_ zQOFx?`{C|;Z#U|lZZq)X?Z&3x_Hfeby~vO24@INC$J=|2z;8A>`^k3Hey4urtw!u8 z{LPNndgyKOxZ$<;{iu=K4Bpbv>YaUIW1b)2iOJ5j$Mb4$<%Aj5a~V?uJj2vji`x9u zML(xyom@2ezjZ}iL?f1d7B5OaY@HG22AH4`V+098~|#Fd)crXLGC)HECgVazCZUw@~yhOj=Yw44kS`afKLAj1%P6 zCeB07;Vw14gJKXv#@3SgX+f@O;#A~|#ZQTcoa$#pOoODcwYHS}yBp@Djgc{Xd*vr&)JJ=<^5dWvUTWJOjYk5)F> z8DMD2atc7%i#gsdaTC67o-IghU1lbH*>XC4ryC@GKYQ^0b;65<)DHA*17XPwBS+SN zI;(I3Vvj&1kSvgo%z`qQj5LTaE}(G;Ol?Pm$}*gdNNSJGDM2w|=q&(fz~d+gGFHT3 zIH`o=+a54B`ubwnB3(=v?E#@n$e(QcF(&NKcLLXY;y9+~UTb^6F9-FqF7CEkJdO$2 z_XUx&VKO0*PhjQ1j{_VpzlRBg%ok{39l`hfs5>fE4%Yiz$m;Hbt6>8Gbjwz!d+2k z2sCKD^JDf_9~-llmbSe%3%Gc(GDLg>m1f8r(;wO#uF9Mon zJYSLac0hctG8O+n@Gs<0ho1B!<=q@^|Kr@DK~NETwGImh2DDk&F`zH)DSGbC{}Ea< za3ATT@cc?XI<7y0e(C-*9?BtV`kElThXCsQ48X*Qp@TBDXWk zr9Pz3Q<3=%wEhK;#7GjEPg|N+sl2qx5|>l^8Xz)~h0QL01t3`vwA<QsXV; literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc b/.venv/lib/python3.10/site-packages/anyio/streams/__pycache__/text.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b03bc767ae4298ae71ae387089bcfccf89b19cd GIT binary patch literal 6327 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 QUN@&FROLtJy9d?(1( 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 + + 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) diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/file.py b/.venv/lib/python3.10/site-packages/anyio/streams/file.py new file mode 100644 index 0000000..f492464 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/streams/file.py @@ -0,0 +1,148 @@ +from __future__ import annotations + +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/.venv/lib/python3.10/site-packages/anyio/streams/memory.py b/.venv/lib/python3.10/site-packages/anyio/streams/memory.py new file mode 100644 index 0000000..bc2425b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/streams/memory.py @@ -0,0 +1,283 @@ +from __future__ import annotations + +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 ..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 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, list[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() + container: list[T_co] = [] + self._state.waiting_receivers[receive_event] = container + + try: + await receive_event.wait() + finally: + self._state.waiting_receivers.pop(receive_event, None) + + if container: + return container[0] + else: + raise EndOfStream + + 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() + + +@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 + + if self._state.waiting_receivers: + receive_event, container = self._state.waiting_receivers.popitem(last=False) + container.append(item) + receive_event.set() + elif 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 self._state.waiting_senders.pop(send_event, None): + 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() diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/stapled.py b/.venv/lib/python3.10/site-packages/anyio/streams/stapled.py new file mode 100644 index 0000000..80f64a2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/streams/stapled.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +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/.venv/lib/python3.10/site-packages/anyio/streams/text.py b/.venv/lib/python3.10/site-packages/anyio/streams/text.py new file mode 100644 index 0000000..f1a1127 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/streams/text.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +import codecs +from collections.abc import Callable, Mapping +from dataclasses import InitVar, dataclass, field +from typing import Any + +from ..abc import ( + AnyByteReceiveStream, + AnyByteSendStream, + AnyByteStream, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, +) + + +@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, + } diff --git a/.venv/lib/python3.10/site-packages/anyio/streams/tls.py b/.venv/lib/python3.10/site-packages/anyio/streams/tls.py new file mode 100644 index 0000000..e913eed --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/streams/tls.py @@ -0,0 +1,338 @@ +from __future__ import annotations + +import logging +import re +import ssl +import sys +from collections.abc import Callable, Mapping +from dataclasses import dataclass +from functools import wraps +from typing import Any, Tuple, TypeVar + +from .. import ( + BrokenResourceError, + EndOfStream, + aclose_forcefully, + get_cancelled_exc_class, +) +from .._core._typedattr import TypedAttributeSet, typed_attribute +from ..abc import AnyByteStream, ByteStream, Listener, TaskGroup + +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") +_PCTRTT = Tuple[Tuple[str, str], ...] +_PCTRTTT = 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() + ssl_object = ssl_context.wrap_bio( + bio_in, bio_out, server_side=server_side, server_hostname=hostname + ) + 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 "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, + } diff --git a/.venv/lib/python3.10/site-packages/anyio/to_process.py b/.venv/lib/python3.10/site-packages/anyio/to_process.py new file mode 100644 index 0000000..1ff06f0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/to_process.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +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( + 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: + # 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/.venv/lib/python3.10/site-packages/anyio/to_thread.py b/.venv/lib/python3.10/site-packages/anyio/to_thread.py new file mode 100644 index 0000000..5070516 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/anyio/to_thread.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +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/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/LICENSE.rst b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/METADATA b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/METADATA new file mode 100644 index 0000000..7a6bbb2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/METADATA @@ -0,0 +1,103 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.7 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Chat: https://discord.gg/pallets diff --git a/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/RECORD b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/RECORD new file mode 100644 index 0000000..7bc97df --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/RECORD @@ -0,0 +1,39 @@ +click-8.1.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.1.7.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.7.dist-info/METADATA,sha256=qIMevCxGA9yEmJOM_4WHuUJCwWpsIEVbCPOhs45YPN4,3014 +click-8.1.7.dist-info/RECORD,, +click-8.1.7.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92 +click-8.1.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=YDDbjm406dTOA0V8bTtdGnhN7zj5j-_dFRewZF_pLvw,3138 +click/__pycache__/__init__.cpython-310.pyc,, +click/__pycache__/_compat.cpython-310.pyc,, +click/__pycache__/_termui_impl.cpython-310.pyc,, +click/__pycache__/_textwrap.cpython-310.pyc,, +click/__pycache__/_winconsole.cpython-310.pyc,, +click/__pycache__/core.cpython-310.pyc,, +click/__pycache__/decorators.cpython-310.pyc,, +click/__pycache__/exceptions.cpython-310.pyc,, +click/__pycache__/formatting.cpython-310.pyc,, +click/__pycache__/globals.cpython-310.pyc,, +click/__pycache__/parser.cpython-310.pyc,, +click/__pycache__/shell_completion.cpython-310.pyc,, +click/__pycache__/termui.cpython-310.pyc,, +click/__pycache__/testing.cpython-310.pyc,, +click/__pycache__/types.cpython-310.pyc,, +click/__pycache__/utils.cpython-310.pyc,, +click/_compat.py,sha256=5318agQpbt4kroKsbqDOYpTSWzL_YCZVUQiTT04yXmc,18744 +click/_termui_impl.py,sha256=3dFYv4445Nw-rFvZOTBMBPYwB1bxnmNk9Du6Dm_oBSU,24069 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=j6oEWtGgGna8JarD6WxhXmNnxLnfRjwXglbBc-8jr7U,114086 +click/decorators.py,sha256=-ZlbGYgV-oI8jr_oH4RpuL1PFS-5QmeuEAsLDAYgxtw,18719 +click/exceptions.py,sha256=fyROO-47HWFDjt2qupo7A3J32VlpM-ovJnfowu92K3s,9273 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=LKyYQE9ZLj5KgIDXkrcTHQRXIggfoivX14_UVIn56YA,19067 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=Ty3VM_ts0sQhj6u7eFTiLwHPoTgcXTGEAUg2OpLqYKw,18460 +click/termui.py,sha256=H7Q8FpmPelhJ2ovOhfCRhjMtCpNyjFXryAMLZODqsdc,28324 +click/testing.py,sha256=1Qd4kS5bucn1hsNIRryd0WtTMuCpkA93grkWxT8POsU,16084 +click/types.py,sha256=TZvz3hKvBztf-Hpa2enOmP4eznSPLzijjig5b_0XMxE,36391 +click/utils.py,sha256=1476UduUNY6UePGU4m18uzVHLt1sKM2PP3yWsQhbItM,20298 diff --git a/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/WHEEL new file mode 100644 index 0000000..2c08da0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/top_level.txt b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click-8.1.7.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/.venv/lib/python3.10/site-packages/click/__init__.py b/.venv/lib/python3.10/site-packages/click/__init__.py new file mode 100644 index 0000000..9a1dab0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/__init__.py @@ -0,0 +1,73 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" +from .core import Argument as Argument +from .core import BaseCommand as BaseCommand +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import MultiCommand as MultiCommand +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .parser import OptionParser as OptionParser +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + +__version__ = "8.1.7" diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06246120527b3544ed2d5b73d38877b8196dc0b4 GIT binary patch literal 2627 zcmc)MM_S`Z6bEnv&X}CD8k(j_HmS+U#HIuAHL!UbeX>;8H7HG$3{4+kwsVfT%pAbm zSbP7`JG&&7wb_Sh+3_FX?LYCd^ zHhVe9v2*AaXkoXYTcMTRif)58b{o1K+S%>s4(MQapgW>Bm)-03dHvAO?n4j20J|SO2!rea^bicO2hqbY%pO9IzzBO7Jqn}j5%d_0u}9Gc z80<0kjW-VCYy&+36YMwcTW=C3+2igzZwjW^6YhI&8m8HA(K9f^o^bxjEV1X&%dpJOqgP;sU2s2mtFX#mK(E0X zdl9`3>+B`;25hjG(VMWzUO{ic7W)Hw8@Ac2=pEQ$uc3Egm%WbOgFW^JdLQ=Lo9H4G z*<0uXIACw158;r#;~sg(aLnFCpTG%w4}A)!?0xh{_{c7z&)|%Gfc^xZ(1-BZIl78X zAOEOj4_#^B8B!aTp`{nP!nk~lDuHi!fm6kn^mQneaE#KU5mkhtBgd5`BM76=Qd$^M zV0hM@$UZ0;Nxy8^f#+GiW4O}C!M2iNq>bCEpEquNSKbLDz**GO?0U|S(UdkymKILd zQb85Ze7TU~ z=YP7PmM*Gt)f0Y%Za%<;4(nHl&D1M9o_H9zuCOB+`1Rv{B)-#`iBr6|5Rv;@btCzD zV)7z<8lAbcl;w#?C>)lyURO=oFDrK0fqyHNXVEz(7O}oiqWm;_b49q}YkwD&)(kDJ zO-I;)vZ8<{PrjU(<6}7K(`BZ)9h82-QElXhKsm4TwcZP*|GRRr6ezmE_5;g#uGEdT z$^!dZv9Er6&pkQp`S~_mdHWoHx5e|VWKN_jj+NpIZT~8@#$ECADY^6D3g5VwvSoSh z=QCP9VgXJ9s!+Xi7to@td17eto*s zwp*^Od5i1&xL4^6DybEQrX#6h9n>sI-%^jJj+C%G>};b>dJA5=GC?SOp65qmJ-?V= zJD>hiOPQt<*rr*F<6aet9>NNrzcCf3NKhmxQWR;53nM z8$~-s2Sq1E7ezNk4@NC3p7)_vz0})B(N8fzF-S2)F-$Q+F^U1%dRgfEON~*lfr0zN z4N8`))f;LhL*89#92=0tz3Ek@n!tv7OEF3Dj$(@9J;gM|48<(P9K}3E9;23s@ZHp^ zKphJdixf)~%M>dVA1GES)+p8~HYheJwkWnSYKdwj@k)27W0zu&VxOW&aez^4HqGbH zzxhW@eWn8x|3IOFU#tbEa`)@TQXwB!ORm(F!YytC-xm2Ffz-`{lO EzcF#N!2kdN literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/_compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a86d9f4526e7ee435e35da9986c3521e7187894 GIT binary patch literal 15685 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 H2OavqxRd3P literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/_textwrap.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57deaf949b59203ed4feb67506e43dbd8f90f694 GIT binary patch literal 1561 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 VolC#Y#kCBDsYtctlhm^R^S@37>4E?N literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/core.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bc311dfec2649f80c9db45664fc6aef1cb5ab97 GIT binary patch literal 91155 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/decorators.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..074f61e45426e9a07c3d6723c859f5991bc4dc2a GIT binary patch literal 17225 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/globals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8f39fa9dda0ab78cafa8a667414d7e030c5e6c51 GIT binary patch literal 2446 zcmZ`*-HsbI6dq3|*=+Ww-EB*E+X6=7FQ}cAB7}$#0k|0&r9ZB8E5s9IH_#WIrP{6W3J>JMxZbUUrSiz@ zE`q(mFY*oE;7gCIk4SgP&1~|TSmt%;ukgi9Zy4~ExgES;wXLG9yTmW?vwZDw&|T%1 z`8q!by)*m@KaWww@}^hD!yd%Dz+Z!J&T?|kYrg&*(0iRGDXLOMOg<+tgwev5O077s zw~Crcq)6?HH7mkz5-T*5-``@=h#!iY7B<(Z4&a*zKb$|<$9D_fztGCPd)_nBc?ONH z!dN4>u6c346|1pm@p$jYPj9rsEFZ|k#I0eHvNRImR3#?d)2(nK(n(7ugI0EEW0igs zet5lQ0ME6IMSE-{Oe>N}wAUI*H2`>Fc37Mn3EPWutpR^8DmS!*kbGzYU$4MV_`kq) z9WgFq+O?$uUTaeVTrr$01UOUptFrq zM+2R0H>7kYP7IA$N(X}GMsUguWptk%QmYyi9u`Hyyb_}%i>kq{h%6myHKr^*+>eD8 z^NC`m^&u?9S1Hc24nfFUce@Cg=62Ev95v!iI1oA@-3tF%29Hg5N46%(3BWukwa z@mY{Cq!YjnTV$LI-fq*6!|P@IcE&Ut)3VgsG#OGOEYjEC(K!S|WM#3@36nWcZfL)w zQZRvUs^-V-z~Y%6d+?klERk#=%d-=}{gCAnNt#grKCqZ(i4l~Y7Nji>-~{jHsZGY> zrq)XLL+9s;|M^RJrf=B@_bS`@}3d`iViwinSO8w5T?jP z(+o7?DC)f)Pa@mv6%9Dl8TCbtWtm8MlW1J`m7NsJm~Hb~xdsjf^<=}>SKudt_r!xX zw*^$8atlvEf1SYl(|7KQv6=vKOd_i?D#b)VHDOKTREfFMtT?z1dr`?$b_|o#KNP%T z2@G>wH(!<&qugnjiICV4b0}qw#ux)WjP>zghP2=hWl90FtES zL;#aOSZ}tOPr%(E%k?UxtzY+R1THBG6HRgpvdLYXH5h9A@8JrsNkTBV48lBih7O=W zhmO0unrlVP9%dkV8ZWA1(Z*UZj$=HVVrA$4otwR_uWxSM-tK(WT`PTiaP^B6rOFh( z6;QFD^KQjiPD4UzsTgspN)Guz8YdY7|Kt)ZmB0!bjMQBZKtvq zZ%?Y@csq`_-FSOSJ&m`g@pck#&!`i4JAt=T%DHNlPS(EUT2|rOVl#=BJF44?qa>~A zG*(fkn?|)HYSr{Y+**%nQN6RW9<9`pG>#g&vmB+1Y^++%`IAYZvy!gVbP^9oS!2cXYHICrND~P6`WgJJvNGA3r$y7`n5uIjsnLn?wt7n#Q+M?g}OrEp$2xtL8Ea z?7ED-O(Sy-T`nr=#tBwywqHiTd8bL#X^cO!rkfbF9nG&tuj_cBqt~M=<>>92Hq%+I zHQOnkSQXHM6S}gVE@I!Vb{gp#m;73%+g7!-*=d&}p-JpYtGV3df^aJJjsi)vL4=?* zU0zw|gg}*ACi}v3&pm$z$>(=|yc}I@wIXRmGDKIAj&hW%ywqNDQea%ed(Uau%2&ai;`?Z+ z7w?+(Zr@dQ*V512Jd9lKhNGYFJDc8J8TGzxTkX$Dxu?JWp7oyHa8#)Bcf!=~ySMFE zEPTpg)x>T4T|3S99n9QednIlA zc5-CU>Q0*Dy86yt=e)IGVSNSWRqg5SuYam)O zNw>XHtKT3?kH8_{nVapj>uu|*g`912o|QW5U<3Yp2kov} zYt{$$Y{|`XD;*qABh6f7vchHV{eUy|48{c~dI^^Lf%V{9XBRum@maNafy{>_qjmb;`W6Bh<@+ zY9mhTi!XCAQ%D>;vxbp+yve0gQ$?CsAZL`ht+<_qgL;*DoN387E12d`j$X}t`DA9_GRt+h ztnvWbm{k_HF6Vg^C!a?W7DL;^zax&95AD#w!8p@6oP&1gh4!?AGX8T4w)Y?5;UZc_ zDAmvM({5)aeeAhh;^^GUJ}A+k)P~)+Nws=PIeqAtq+M##M6kXMv^_3u&ASD}wpb(W zY-u@qFL|><5t;QNcb77ynbcZfeH`y;&dV2+8K1vde?D1hHPb5Qyv*rQzc0$-rm@&* zTXRb?x1Qe86Uc3oHIy-=H(A$bk?Gsy#3bLhmkdu%^uci{W_sKHjTFqWuZFJjp`FhEf`D=1}7Od#F(KIJ&mLjw|Iqrv* ztfFN?l$gQ66zv&Xb9Pyfq#8i9?QF)(;uHLDcVeg+n~%6+GB z8A=0ab(|h`bwS2++<|j*$zm(MRhCnlI~~nKT~wX+$y5NdQERrMX2S>s(;EQYY?EnQ zP#nt9sgYT%Sbq9#)6P*rT! zAkKJLnCTfnpF#O@S+u${^FXN^=gvh215F*jV8{$>t(s+?Iv(GuahB1^<#kGg_;^XC z!p7eoRvtec9UoR-|4jy4UjNP~k8^x5#5pXZwmjJHbJ10^bC7m2Nh6B{#b&R8k9-Qe zTlx%$qZDMmoJTgjwg_ZTfb21pF`Q&pz@}3j1Y+q3ZL`8#wN`h4SH5f*5bATN(O+OS zAnX>fqMPb3v1|m(hApRe?$-tyB}b5iyQZ7~^1-tmz)%r#!V8NJraaGa9_Sa*ppIwT zkJx$vPtrpYTNQ9=#mU=wJZdi~T=}uPnz-Xv z@^L{G;|b_|lWOV?^tnn=?LxayO{?9isBGB0GincP+eu|ZqWfT!?)oGgBnltk*_JA=zy8z`ySFl-$y#p50Do7_-b{M`ba65?LB?Dy$aA% zph)mnR9^&n)wmxLw_%KJ%5gLf*Ms6q|X0^qO?s;y3Yfnc6wZW2Sl z8n}!TK~jAVTa~#rrSvn%37P7bnd3&vZtGW=dkIOY00k&+HRMHKWbxygQncvLAjy2J zp&Rcc(gmncFSpmdW0J#5QsLlvZ{tTJq6q3+#0>^f2?-!2ad>p#YN1^BZD)gOSqWnQ2SNMhVXSa1v(C8#>;m z>~f!KYIcynyk8Jg%-iQQq`3j?PBNAv%${#qH#|9#) zK75Fu%moIeC<-n-7)G%1q%{|q1;$xysDpG;31FqK*0hmm@33Knq%`5503?&TO_nh50_OQf{QIXTAI*gMtz;hcbRZ7 zfek&!T#bpqhX2hr^`I&XJ`pX*cK?JYq2D63j@gcX3`pSsDI9O=SHhN$-~x~70y{m8 zWP}U$kkd)S4UeiJ)VDyvtSJSWj6vfZXENXqQq=IrJfBN=gu0rbuAx$9SXtCGcg)b9 zoI>U^Hj(HRbksZ%h;EV7Qn2FyxGn$9FVJcuHw!=S+bW7jJYC8?Zlg2rYw#ABo#tp; zj#$1Wpuwg77eB*&3aulyEdG&Qq|4+2n|;^bx{DQ8J*(WEL!oB5w^SI6GezYZC_Rx6)ftR2v!y57^IM^WsC=m7 z`_OYzM&%e&cy`4hM-bmg2eykNSRGIYapu$NP`rCEa}&6l*-~;u9Yvcx>R24A zC(z%_eApvYk$MvKd)0B&4@(0HVR@B(>KT-ti1(WsnN6rps#EB3U`LOV`ZP)pN{FkR z6^*RsS;JZTEQpPc&yG=$SEN*;HgMR|4r{|ut+#5)ARq(F7+OUWp(BRDVA3)aAttAE z9gH*Z`3~K!gNix6X*$t5o~PNK$Vjy)L6igJEQb0jVr=*nieMo& zn)u+wE0<-&q3_g$d0J>hUm5(coR*BFnmVqtH{1cVycr`KM956&Mpg#Peofa_=z3=S zXT8%MnBy{O6PBxKGYY~BaXV?!$Bi*ZD?m4J-(WRx9?-vlVbNFSF%H~~0)XNQrXP1y zhn2xZ*%`=75c|NVWEjTr@KGHNl)HqnI#~MAz!ryt>D=H1;7B$>rE{{xb93Jpw`uv3 z36ac2YZ6(L7@awE8Hj@oe*@3-LPtC)1Lv|hki?5+ObKGu@W(tK!LF|&BX|X4f@%m| zb5%%ik-_`m7?M)_m2yEjS5lA0^dd`rLApRBu|Iq5wFmZ@2hN!@0HhZ%cy<75?5x2s zqPGBQAr4)9yxIPy_-o*k6or|V9Ppop-N?$z@*^WJn`DFP(8kMr8Dxl_{L&U|8|gw5 zfU0CKDg!t013wgJCJirmp6%YgH|3L8Ok{3kd{OZ+mf!{E##%dfY-~Ahv(odZB1*e> z5{2YF3o#~a=bezYIaDKuQ7LGA@SwpuhM2h*Y~=3JvUd78W5eLDC!RJ~-l*~W;d$%k zQIrN-N@201^px@-ruxBpaQHm6~dKK zbkSHrb@=|!w$@%}WM*zotg1Qq_y$>HO`%{k#@w8-vrMC{HrL!7d24P?EU!6)Q$~Hb zvN`x#<`4sx?+t)2!erWMvtd}x&>7Y#SR;lO;XSQhtlc@kv~e z1!g~u-&*D^DNI(w$2bS=v#`PjfybZta!|mtvVYk51=rF7W@oZOdaRjL&8jU;q z2*|tm+EqNs3=#o(-^9?i!n9NcX820Z7Dmgo`@x`0U}n_p$qf&@j$y)zT;7 zM{?nRItk$MaAtB|?L9bAAJ=s3rC<}VB934Q$!>XJJ%y0K)X#e-{*MjDOo(YF%sn+!zKlbEo3JE;j~L{~c%hoV zWUbozki>oMWv~Fy+B4<1oee()@iTG*{C4lT#xd8o4_O;QKfpGBmWKk@-042zW}CU; z2ID|N^b7j#eRm@Vho5P633r-sQ%NCKwlo2Q!oLRv=v^2V8@Yb4S?uS~esDa93(0{X z0J$43@G8T$aTUgEeKAgObz>4D9L5|lC~d+`MP+}uPh&6I(2^5(8lYK3MH$hMB{VNh zibj*=cs~)>R`ichsJTTlnsHGJ3EV|lwy(-*$Ou&`e~9Cfov3?=t4%L6C)^bp?h@7Q zeU=Ix$nd|l7@KN+#+H`aNomB3H>SFz`&i1Y5LpzX{UE& zJAue9jRw&qz-^vf-eef*OmrqGcxe@m9!CNn$Of!8954O2a=ilB_zi>+t-g=T3kV$k z6c!#e*A0eD9EATva4dp+%K3tYG4jc8kzBxm0g%*$3#U^A7}<;02|z^orJR1N@1-CT z_=Vx@gZR&H7I4kL#yIj-Ap{@ZV+)?$u#d}dAf-YZbJ{5M^B@*ncw?KstLG8wv2RYx zSJ(Q1UdL#Y_%`ONg3YOZU@lt>13Bb(;rZO`YsSS(&IeVHh_0DH_pY%fZZu%(JbH~u z#6-yC3UdMtBQnwVSVk%kRLH!gPO}Y%r@$=_LTCYz#T2)$?50ExE4y}@yH0)4=+2)= zDboW=8JWd@Nm8Np;32HY%RAG~UcnPjEL%qqrReUL8aik_V2ksxkUIt_?;U*{0gcAa zCJe$zI7p~>8>*0$D0&6X{{|UsKL`Q$Ufd;sc;CYTM<_!OMbD%nVsR@5alAAj>fk1% z3;mA=@51>{@_^$Np#KK@D@5f%jHdUiAebP{-*)t?u$C?5$vq)!sQ_W{D!vy;tlC3< z@D+}*IiYa>gn}JkEy|ccICDo5rTm7xe;EW$H}7ok8M7N>9MOnx!5>Afabz!)hi2Df znhpK-0DW_jvaFlfmo3CLX;gtR@z6J)?XEUjwS}sf(gtb_zED^SzGS#wJ-i#P=U7Ui zq(w$Og&Z6#LTP`>QXw9Jo)TZ_+OOmhsYt7IVeh~mA>4l;5uHc7z@36y1SE3A`FFl z#c}Jlk4U!O#oJP(lKWKHybZSvF)y?w5n)QG9&bLnkWq*q-*;(ykh$d+((4230}^JW zIQWou=g~9+6^}$r3eeC!M3eE)eYe!U+ri;~a+F0Axc*O8z=d;bW)3w-d zvf<;Q<>3>WGbokxpW{y!z=KOGhtfEksCVED7dKWSmpQeIVxtC-SF=KVs~!)uGLpAp zV-Xs8)=yr0=gO!yY$we#}8Aw~epn0&|m0 zet;y)@n+~-2T@6R+G5(b_9Z~jqBT$yN^JG}|1&c? zLsE_%KXi#XJTr6V%sK!0uit;Bvu#^m!|!K5*wuLYRZaUhI*I=ZI5~sEJ!fdzo0`ys z-qI@Szh2S#+^CrNZ?vpctCG?+VG662Ud>c8Tu-5%tz@~LMm<-_aXo{2zLMv97WI+J z2-kC{7b*p==TYBQ*~ayeR&jN-GRpNrYixCUWjpHIoUAB1=E}IU1Le+!u}2f5&JHn# zV>^y<=cz_P><~NOvnmr`*2Gg{;yq1F+%qb>#IDM2vAeQI?5XUns z?8n)DXWu=u@-)s5h-YyA44?1Exh)Rj{2-qnz?+{DlPGOxAKw4$`$pxU^R#oo*)OJk zVpizRvphb&Ph)hZ#B-;#oGwm@L(V~Q7%iT2cHr4@=U^i(rbX$!ROOI(o@YS!g1+}? z4NDvmM=_hjV#djdvQxk_(|Bf99K+QTUp>yx(bX5ki@5qcUp;|dj__N;r?TQD@deyJ z`b0VopBZ;@jlB4x_!8RBZ0PUhV4P*VVb;ky1)k#$DjQibCr;v-V?w{Gl}`VhxND)L z`a99$5A~6AHP@N%tghDDf||~E+SC-)!t1@3*BstTztQ!Y zoi^^|F4tsj)$tsOlhNqpYNsdb4la$k-B#19*5p#v^<=ZXglm>lU+(y3z18%yb?+|S zbp2dcc9yDb^yL@ooz-p&eO7PRq(9PZ4VfgeLXYC2&1RTabaH72AP32&wYKw0~y0}9#oTC3%Va-vm0raAk`>uL!X7Zbfjq@J@EKybU$;E_6aoqEr!-E28_v&~m{Qi(_7 zOS9qW_U)$Zw27B&tXq@&@s?|zz1(RDHyRz$Bu1v#>Ly+kyFO>XRcrNln3!6OHx?J| zJ56tyhdS&sdQ+?m8!WAs=x8`MUbV%=SfeUWH=>ndwK@B$SMz!<#w;A7wsW`X@oUv^ zeZ9IMO>mu`cA4oVNfsD87-uO3)~-pf$^5$$;)g|H_6Czw>n*IEBy}%$Qt=duQciB8 zdXb7zD#obTj>1pz5akZkEBp%d;QAKz_)wF3arx2B+2zivGb@&Fz5DVDv*m8@W~=Eg z&o-LvTD$I)`<(?y?wYsUX}?%Ler(oldd^I@R=-tSa@<*PQT^5| zzcDuEa(B%yCN4TOGkWb@g9Y^9fg0nL?+_z9T8rijq zA#~U^qhjUEoFzs@%1N!HMcT=T3~E^?18tqtzbaqY@&>~0Ip{citA~auK zSP;@Nzc?R}`;zCZ)=F5cD^6EBE;!Y-YjI}0&3s0@0+m)1H4l<@v(xjK!}w;|zP9Wz zhY6=qgH{~2Y`Ty{TqEx{+vwrJLCo@2XRr{1i!0u8Z@-dm9JqudF-YH<;&ql<@{ z4UC2!NATr6v#)kgifyB%w*D1)?w7 zLf1m&;fa7;b=mAPMWEVlHzBAY(TB3e^CI;a&^A)g)MeS8CuYZV9UA7OXv#^fh+3Y> zMziJMG%*lb4$=)|(|DEI@l}BaB#ng?4c@jvpWnJeMsLm@E>_5J%wYD-UbE%RKnpiX zRgg}_T6Nk(Eh;)haSRt!Xu3!7fM?fxuGd+$X+AMZx>%Q{q*W(XsoD%_!B#7zNWIf* z(UN1}o|^1K%TMuCe2cpEEtsS{eq0~rLGHlfA6NjM9t9MvuLzX z8ll?R4aFkpl(#icOzKFx6iDfk??QtVz=+>_+!}!=RjgPXH@hdB3{L)D0AMGx1 z``QPX&vVm(h&k0puU#*>(>bCQj>VQcPIHLpIQDG5)&A4FoX-sBWUgi+F+@aMFkS;CX>f9$c% zYZY}gH#wz-k?b*GXzDAJlKAY%S=f4R)ou-JL4xYqGqcg4w(5j^j8D-^BkE<7m=PuI znRY@!xtnK;v2IXG0pr3!oO#RcwMppUFMJ}&?3p)tAQ%My-}2p?-$Z@Zguv5@S8X9> z=os2UF~=0~r~@q%#xOOfUi!GdXo;G9Pi%vo?)jRt0&pWg-uW?@>tVQqu(hGVGVEObf2RY0tFqT4h9SwwkfFN~{|Q`i2H@Xhu(yy{3U9 z2*G;SyQR2IP2TiKUBuLE>Ey4sqC7;Blwg>lUu#bXu?qu2_T*o`8xc(#E%f^ zGdSG;K@mpdz@8D0JJw3dNdrFxfCl_ji=CTvE-c`|DO}AtX_R@!gVRnLF?(8M1tFLe zr(2Z~;HFt8-7rK!Y}7Eg)Y&Q9*p5_`m6T$u>^-zT2N*)EX-TCm^Wc9kNc zd5A0lkhQ-7m_w*2U^)WXNU&9esiM9OkY5l-mF=?#`))>$ut?MbAW#LYcbWhTJGUJv zDOimnX}}Q*dsyxWhW4WHkG#l8n_y_9zGBdoYfmpOD%BK)ts%oKE|!u3_oss#Be~xI z^ZmbrgiMBV*#`AokOAhz5p#3)m&(WZ4o71Cs3Jxcumxlfs(33%jUv>A1eP3zsPniZ zpQD1~J!`ASODPrkZPoKI#Nz0RVy}Ou-byI?6A2!RLeV+_hv5%)K+E8ufw&Y~dfJLE zbb(lT#kg-$w&#I?YnDj8Z>{UX8t8wfiS(Z{Fx~$ufhiO}gwU?yy2!G?96|dF`{o*h zC;_K{m`p)Ze9DnkAOM~B&FgPJ?`x0r83rGL;-?y|+LBut35^V%Myzf~2Z3krCIgp# zMmnH=-SJarug+h(6vWDY&aE{Z4sK(yC`a%)8Y18McbYh%2M1D!n0F;f7PU&yjOa&C zFwJOfDR9RDlwk$9;!lV+M*l}|)ufVSLVzK9B+7Fnf^&fcMNAU{RYZVuCep`w{?LGUXZk8(w&* zE7nW0nLiRRJznbm0uQ(Zfmj&?^LqND{+=WaV{JE4(Zq91MZ%yJ74Pd0v}+gZVS!|nXtTxq>GEsEiTTu-Wn1RYHfz$?-Leii2nm@4S_~x z?1v98hUs;6pFoCc_@W2?x+{yzYb8Ojtz2b(6>qv(JO}ZP}p%`vWZE9Od-8{&VCKC2Jt{N z1GutAtu3(}4OO+?v#y|zY71l#GY4H>1B_Q$FSJ36h~QD$+2 zVf1%I4Ti7b>`!Pdzl=4NucAN#*t_eSpx_3X^GB0x<6=jH=BDw;&it4TW3c~|m<-u4 z%2jMabVHGp#90u>zrD!X-;U!ufW4hntc1#}unvM0);mk>WIAN!r%U?`jS9O5V#3%=1W_uUo>r4|yc0ykzzN zC2lE(w!r4h8s>-;9Mm83jX^RCi4?fhF(PfWx|AAs?Leg`*@U+d!1&@S+n$Kf!}mgE zLe!A@iubaK5{vBSJGJ`q7F`V2BSA27*NAA8m~|&mEJ1DE$gJx`ILaLS(0CWhiI=RT z%gbm{GJK`tG0f<`f=c+9ujk=3 zT%>MaN8wv5ohIBfZ#ZYNct)OJy%M4H3ltT3_R$6&F_i0pd>q_ItBWTk*(o0CHb zj=LQA=0qN0Yf+3iqx_7eLh8!ccOkiz?GV3Fzktwnc|K6<{k_aSq2VA^1J<{xN!hn3 zU&0x?g~SYKS?HLj8T=j!gdkc=TW6!ZgzaY^DCgRIAF9DK?_(d$KwnASPe0J09*lt@ zw4N?c4vhO5Rv+d%Ot(ng(%c#T5BCduY;Z1L_Of11r0?kh^M2pJ{u?-(;lcNE$$O>z z0&ledpML`b>l-um{sdzxfXL6Cz4~hPtqWJKUV38zD7KEx8J+-t_s736eO(+WT`vd! zaN_GH`tzG;178aKIZWS1#0uk1*T%LMpnmWJ+V+X^iSjkP#zaKlKQm8xRLai^cp-30 ziN@h$N0p9?FT=)Hl}mX)4^Is|Pg!{1l)biZUA}brf;@?tVlGZi)|X|KPXr8@nr--aNpIILR_n`7{Z=&yt&fr9Qvi%T z9Y$VHKOQ$}N5^ghY)^lW4J-f4>|-OB###R3{=PWBm6LrX)Ft}mOfcIQ6{(SZ(KS!M zr`@I1-fG>&7=&zLW3r$%aW?vkrr!o@vg&cM@r2ARW|G0+9v%x~jt-R$Sc2%=`at-<-U8qn{S=2>e; zbW8;NYpq*fkM7*j9;O!j{1Ar?>YTomL^0IGaQF8sE~|5LSXD`PDbxyfS~GdJcMkBRs$0lCh~PXPmi;Es^3WGEwp! zDy~z(c9Sg#8ESu9z-o2)CLz1=9NN^F?c@#Ao~Jp`&^UdLT~G#OWqi*8Yi~i){W^}s zkC^lfjt|Kl-pVvUv1e${6L8f$R6paYz&xQaq54O#E2@ANdF*&1Q(*y1B@8p~k5pn> zUq$_KbwgSoEy})$w2IoLfsseQxIoA*F3WeR@Tgd$V#D$gu>?Ah162CY#NPes87VR` zWbDB}F-BsBGUOPp8el7I$`rx>lDQzS(tudonK3RqNLQc4YF%0;Vzp^R67kV);`29e~X80m&O>sx5|4UFl-0xBWv955ydlI}c_Y2@$XE*86R z5h;*Rbe~}3sR?X6B}+E1cj)J{AQLBUP=KTiNzJkH6Pi+f0|@m1B!>~V_FxAOHp!w+ zTW57rc?K!NQffg;^e0^^OcXzVj9Rc%%V{@tDyFN+mr8Mg!o=>`07#MII!S4o_wU|;D#Ke zVcS&jj;JRw;CE;OX*5ggd-ZXne;_gR&&Gw3qPuwMbF$%gFdz>jli#KZ(3!tI5pP_> z{x5hqDeQ;D_HgBN$?sC*d)&BMyIpIxXxFdWM+?6Nds7*Wf3o4A^@UN@u`L@LvRAZq zxRcnft)GH}2@W!9s~FOiFu_{0=h)`YEha{`7zNl!UMrU@+;&YExC+^>g@`z(UI1>u zyP}WMmLPN4aM_6m-udDBI^1Sj}0ac#lj#2CS&3MeK15w{a>u zEx^8#4VB+Vf%*@q&KHuh=V(h}TzasLI?aF5) zolDwEiG7%aTqcB!v@I$2c^n*h0!G#0TpMmi0Gc7)hHoKsxA+x+(*&&Er?|~{z&`Fu zN|?8d?n?vhep+4i;D+>cTtRGyFD0zbOX$z=avofgdj`%%0LGHWL?lOwzyFIN{z~b5 z5I}tf5n-$#DA3sGI|hoPfXdT^-rYI-Qu{V`7&2xS z;=6(Pkj&8*2M{~h=N*Z8Bv}{0)ICEU8KlB<}oEF2kFfF%~R!q!sD{*pVgmN>%GWsce zK;a-kfT?X<^QSg&w<6L%MZBH1^a2*&GIkn8lw7o2opZe3j=(UGRUCsG(iRc(=24~6TP;N59ot5Q#w!V<;_jK zq|j6P{WPA-u9!43_u?SCZUKbOt`J0rs~_m=X4}l+lQxXNba&H#e8RQ}qFs)qb3;wK z+{EeuWLkqlrmvTv^WvXcv37-qWrc~aO&Bmj8+Jp&+*+t~kTK)jWT)L)1B}*cb?!vj zVd}_L`Eh(GB03J+S$tK2uRkPGF+i@!Q$r#OcpLU^1G%Ss!A5)VsXn4ZKk5s^&%UGO zbII2=e><{f%~lhiabQO%cCECR;AZ(`5^za=0LHtB0O&99zcPjycJ5U1fsd@IFC%xU zD*%BYMu5Q}N_>N#E9EMM_?Le4Em(K0Qp8*ddJLPAjQN?sEGoIp(4|y;8J}=eMu%BF zHk_M3L1Q6hoAXmVr%akzUlo-MfXXT|c^hO@UP80~B#AtSO18Kgp_*mjQw$vA3 zK%9-+__%?R$na1MxgSWh9()@LESiE^q^ryaI`BHAlyB?uNYwTS`9&&}4Ll_Hr|S@P zDF5Pm8bS}XFi77sy|nU*Yd$xznIK@`tF0O>I?5@^g7skyk}8AP)aT z&+2mtQ!viqEIvaL`;mT{QC8#%W=a|57f`a!Pb1-kRHP){_Va{)vRCG^#bB2R&6)dI z4qinw6%!HkB>$KScEyrjnEVQEOv7zbAJvQ!=Z^uj7*7MZFaW<25c@crA{YZcSc=;# z-21qKM-<$To%fUtBZxwh6UKlS3Azj%Op*Xe{){AfV2dotw6QD6YQ_b6K7uQLst5l% z$P#>wnlMcDBGv9t@iY|-ef~Dp-lO98si5Q*!?8Ml_&ONvb<#XU8tc=R* n;Yr}+A0OB`k)POO=ZxL)zUX@>BbEQ9@iJWvbAb~^@#Fsk#Ttv> literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/termui.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab3dc0c2d710aecf93328a203d094f44ddf5258b GIT binary patch literal 26147 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50a02fb5233cf2dd6f68a21af958a32a5f870970 GIT binary patch literal 15220 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%0ATC_S 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/click/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15e391eee23c3a3e0dbec658f6d47adf605e0c72 GIT binary patch literal 18860 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 S%6}>E$@n&|?iBLl_x>O3k 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: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write("") # type: ignore + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[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.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: t.Optional[str], + errors: t.Optional[str], + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.Optional[t.BinaryIO]], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: t.Optional[str], + errors: t.Optional[str], + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: t.Union[str, "os.PathLike[str]", int], + mode: str, + encoding: t.Optional[str], + errors: t.Optional[str], +) -> 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: "t.Union[str, os.PathLike[str]]", + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, +) -> t.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: t.Optional[int] = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[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: t.Optional[t.Type[BaseException]], *_: t.Any) -> 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.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi( # noqa: F811 + stream: t.TextIO, color: t.Optional[bool] = None + ) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] + ) -> t.Optional[t.TextIO]: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.Optional[t.TextIO]], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.Optional[t.TextIO]]: + cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.Optional[t.TextIO]: + 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: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: t.Mapping[ + str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] +] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/.venv/lib/python3.10/site-packages/click/_termui_impl.py b/.venv/lib/python3.10/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..f744657 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/_termui_impl.py @@ -0,0 +1,739 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" +import contextlib +import math +import os +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +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: t.Optional[t.Iterable[V]], + length: t.Optional[int] = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + label: t.Optional[str] = None, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: 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(t.Iterable[V], range(length)) + self.iter: t.Iterable[V] = iter(iterable) + self.length = length + self.pos = 0 + self.avg: t.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: t.Optional[int] = None + self.entered: bool = False + self.current_item: t.Optional[V] = None + self.is_hidden: bool = not isatty(self.file) + self._last_line: t.Optional[str] = None + + def __enter__(self) -> "ProgressBar[V]": + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self.render_finish() + + def __iter__(self) -> t.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + import shutil + + if self.is_hidden: + # Only output the label as it changes if the output is not a + # TTY. Use file=stderr if you expect to be piping stdout. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) # type: ignore + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> t.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if self.is_hidden: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # 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) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system(f'more "{filename}"') == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + stdin = t.cast(t.BinaryIO, c.stdin) + encoding = get_best_encoding(stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + stdin.write(text.encode(encoding, "replace")) + except (OSError, KeyboardInterrupt): + pass + else: + stdin.close() + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager( + generator: t.Iterable[str], cmd: str, color: t.Optional[bool] +) -> None: + """Page through text by invoking a program on a temporary file.""" + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + os.system(f'{cmd} "{filename}"') + finally: + os.close(fd) + os.unlink(filename) + + +def _nullpager( + stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if os.system(f"which {editor} >/dev/null 2>&1") == 0: + return editor + return "vi" + + def edit_file(self, filename: str) -> None: + import subprocess + + editor = self.get_editor() + environ: t.Optional[t.Dict[str, str]] = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: + import tempfile + + if not text: + data = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url.replace('"', "")) + args = f'explorer /select,"{url}"' + else: + url = url.replace('"', "") + wait_str = "/WAIT" if wait else "" + args = f'start {wait_str} "" "{url}"' + return os.system(args) + elif CYGWIN: + if locate: + url = os.path.dirname(_unquote_file(url).replace('"', "")) + args = f'cygstart "{url}"' + else: + url = url.replace('"', "") + wait_str = "-w" if wait else "" + args = f'cygstart {wait_str} "{url}"' + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + func: t.Callable[[], str] + + if echo: + func = msvcrt.getwche # type: ignore + else: + func = msvcrt.getwch # type: ignore + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import tty + import termios + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + f: t.Optional[t.TextIO] + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/.venv/lib/python3.10/site-packages/click/_textwrap.py b/.venv/lib/python3.10/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/_textwrap.py @@ -0,0 +1,49 @@ +import textwrap +import typing as t +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: t.List[str], + cur_line: t.List[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> t.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/.venv/lib/python3.10/site-packages/click/_winconsole.py b/.venv/lib/python3.10/site-packages/click/_winconsole.py new file mode 100644 index 0000000..6b20df3 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/_winconsole.py @@ -0,0 +1,279 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +import io +import sys +import time +import typing as t +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self): + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> t.Optional[t.TextIO]: + if ( + get_buffer is not None + and encoding in {"utf-16-le", None} + and errors in {"strict", None} + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/.venv/lib/python3.10/site-packages/click/core.py b/.venv/lib/python3.10/site-packages/click/core.py new file mode 100644 index 0000000..cc65e89 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/core.py @@ -0,0 +1,3042 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + import typing_extensions as te + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: "Context", incomplete: str +) -> t.Iterator[t.Tuple[str, "Command"]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(MultiCommand, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_multicommand( + base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + f"{hint}. Command {base_command.name!r} is set to chain and" + f" {cmd_name!r} was added as a subcommand but it in itself is a" + f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" + f" within a chained {type(base_command).__name__} named" + f" {base_command.name!r})." + ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( + ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: t.Sequence["Parameter"], + declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item: "Parameter") -> t.Tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: t.Type["HelpFormatter"] = HelpFormatter + + def __init__( + self, + command: "Command", + parent: t.Optional["Context"] = None, + info_name: t.Optional[str] = None, + obj: t.Optional[t.Any] = None, + auto_envvar_prefix: t.Optional[str] = None, + default_map: t.Optional[t.MutableMapping[str, t.Any]] = None, + terminal_width: t.Optional[int] = None, + max_content_width: t.Optional[int] = None, + resilient_parsing: bool = False, + allow_extra_args: t.Optional[bool] = None, + allow_interspersed_args: t.Optional[bool] = None, + ignore_unknown_options: t.Optional[bool] = None, + help_option_names: t.Optional[t.List[str]] = None, + token_normalize_func: t.Optional[t.Callable[[str], str]] = None, + color: t.Optional[bool] = None, + show_default: t.Optional[bool] = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: t.Dict[str, t.Any] = {} + #: the leftover arguments. + self.args: t.List[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: t.Optional[t.MutableMapping[str, t.Any]] = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: t.Optional[str] = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: t.Optional[int] = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: t.Optional[int] = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: t.List[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Optional[ + t.Callable[[str], str] + ] = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: t.Optional[bool] = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: t.Optional[bool] = show_default + + self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: t.Dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> "Context": + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> t.Dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: t.ContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> "Context": + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: + """Finds the closest object of a given type.""" + node: t.Optional["Context"] = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: t.Type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[False]" = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> "te.NoReturn": + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> "te.NoReturn": + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> "te.NoReturn": + """Exits the application with a given exit code.""" + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: "Command") -> "Context": + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + @t.overload + def invoke( + __self, # noqa: B902 + __callback: "t.Callable[..., V]", + *args: t.Any, + **kwargs: t.Any, + ) -> V: + ... + + @t.overload + def invoke( + __self, # noqa: B902 + __callback: "Command", + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + ... + + def invoke( + __self, # noqa: B902 + __callback: t.Union["Command", "t.Callable[..., V]"], + *args: t.Any, + **kwargs: t.Any, + ) -> t.Union[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. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + """ + if isinstance(__callback, Command): + other_cmd = __callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + __callback = 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: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = __self + + with augment_usage_errors(__self): + with ctx: + return __callback(*args, **kwargs) + + def forward( + __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902 + ) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(__cmd, Command): + raise TypeError("Callback is not a command.") + + for param in __self.params: + if param not in kwargs: + kwargs[param] = __self.params[param] + + return __self.invoke(__cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class BaseCommand: + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: t.Type[Context] = Context + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: t.MutableMapping[str, t.Any] = context_settings + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire structure + below this command. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + :param ctx: A :class:`Context` representing this command. + + .. versionadded:: 8.0 + """ + return {"name": self.name} + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get help") + + def make_context( + self, + info_name: t.Optional[str], + args: t.List[str], + parent: t.Optional[Context] = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class( + self, info_name=info_name, parent=parent, **extra # type: ignore + ) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invocable by default") + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. Other + command classes will return more completions. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, MultiCommand) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx.protected_args + ) + + return results + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: "te.Literal[True]" = True, + **extra: t.Any, + ) -> "te.NoReturn": + ... + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: + ... + + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) 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: t.MutableMapping[str, t.Any], + prog_name: str, + complete_var: t.Optional[str] = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. 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 Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + + :param deprecated: issues a message indicating that + the command is deprecated. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, + callback: t.Optional[t.Callable[..., t.Any]] = None, + params: t.Optional[t.List["Parameter"]] = None, + help: t.Optional[str] = None, + epilog: t.Optional[str] = None, + short_help: t.Optional[str] = None, + options_metavar: t.Optional[str] = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool = False, + ) -> None: + super().__init__(name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: t.List["Parameter"] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + info_dict.update( + params=[param.to_info_dict() for param in self.get_params(ctx)], + help=self.help, + epilog=self.epilog, + short_help=self.short_help, + hidden=self.hidden, + deprecated=self.deprecated, + ) + return info_dict + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> t.List["Parameter"]: + rv = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + rv = [*rv, help_option] + + return rv + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> t.List[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> t.Optional["Option"]: + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + + if not help_options or not self.add_help_option: + return None + + def show_help(ctx: Context, param: "Parameter", value: str) -> None: + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help=_("Show this message and exit."), + ) + + def make_parser(self, ctx: Context) -> OptionParser: + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + message = _( + "DeprecationWarning: The command {name!r} is deprecated." + ).format(name=self.name) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: The result callback to attach to this multi + command. This can be set or changed later with the + :meth:`result_callback` decorator. + :param attrs: Other command arguments described in :class:`Command`. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name: t.Optional[str] = None, + invoke_without_command: bool = False, + no_args_is_help: t.Optional[bool] = None, + subcommand_metavar: t.Optional[str] = None, + chain: bool = False, + result_callback: t.Optional[t.Callable[..., t.Any]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(__value, *args, **kwargs): # type: ignore + inner = old_callback(__value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv + + return decorator + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx.protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx.protected_args, *ctx.args] + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: t.List[str] + ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError + + def list_commands(self, ctx: Context) -> t.List[str]: + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is + the most common way to implement nesting in Click. + + :param name: The name of the group command. + :param commands: A dict mapping names to :class:`Command` objects. + Can also be a list of :class:`Command`, which will use + :attr:`Command.name` to create the dict. + :param attrs: Other command arguments described in + :class:`MultiCommand`, :class:`Command`, and + :class:`BaseCommand`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + """ + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: t.Optional[t.Type[Command]] = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: t.Optional[str] = None, + commands: t.Optional[ + t.Union[t.MutableMapping[str, Command], t.Sequence[Command]] + ] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: t.MutableMapping[str, Command] = commands + + def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: + ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: + ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Optional[t.Callable[..., t.Any]] = 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.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Optional[t.Callable[..., t.Any]] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'group(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> "Group": + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> t.List[str]: + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + + See :class:`MultiCommand` and :class:`Command` for the description of + ``name`` and ``attrs``. + """ + + def __init__( + self, + name: t.Optional[str] = None, + sources: t.Optional[t.List[MultiCommand]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + #: The list of registered multi commands. + self.sources: t.List[MultiCommand] = sources or [] + + def add_source(self, multi_cmd: MultiCommand) -> None: + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> t.List[str]: + rv: t.Set[str] = set() + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> t.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The 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: a string or list of strings that are environment variables + that should be checked. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + required: bool = False, + default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, + callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, + nargs: t.Optional[int] = None, + multiple: bool = False, + metavar: t.Optional[str] = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, + shell_complete: t.Optional[ + t.Callable[ + [Context, "Parameter", str], + t.Union[t.List["CompletionItem"], t.List[str]], + ] + ] = None, + ) -> None: + self.name: t.Optional[str] + self.opts: t.List[str] + self.secondary_opts: t.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 = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={nargs}." + ) + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self.default, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(self) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, t.Any] + ) -> t.Tuple[t.Any, ParameterSource]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + def check_iter(value: t.Any) -> t.Iterator[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 + + 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: # t.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: # t.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: + if value is None: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + if self.envvar is None: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] + ) -> t.Tuple[t.Any, t.List[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + return value, args + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + pass + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast(t.List["CompletionItem"], results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page. Normally, environment variables are not + shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + show_default: t.Union[bool, str, None] = None, + prompt: t.Union[bool, str] = False, + confirmation_prompt: t.Union[bool, str] = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: t.Optional[bool] = None, + flag_value: t.Optional[t.Any] = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + help: t.Optional[str] = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + default_is_missing = "default" not in attrs + super().__init__(param_decls, type=type, multiple=multiple, **attrs) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + self.default: t.Union[t.Any, t.Callable[[], t.Any]] + + if is_flag and default_is_missing and not self.required: + if multiple: + self.default = () + else: + self.default = False + + if flag_value is None: + flag_value = not self.default + + self.type: types.ParamType + if is_flag and type is None: + # Re-guess the type from the flag value instead of the + # default. + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = is_flag + self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError("Could not determine name for option") + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: t.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar()}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + var_str = ( + envvar + if isinstance(envvar, str) + else ", ".join(str(d) for d in envvar) + ) + extra.append(_("env var: {var}").format(var=var_str)) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or (show_default and (default_value is not None)): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = split_opt( + (self.opts if self.default else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + else: + default_string = str(default_value) + + if default_string: + extra.append(_("default: {default}").format(default=default_string)) + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra.append(range_str) + + if self.required: + extra.append(_("required")) + + if extra: + extra_str = "; ".join(extra) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return t.cast(Option, param).flag_value + + return None + + return super().get_default(ctx, call=call) + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + ) + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, "Parameter"] + ) -> t.Tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + and any(v is _flag_needs_value for v in value) + ): + value = [self.flag_value if v is _flag_needs_value else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the constructor of :class:`Parameter`. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: t.Sequence[str], + required: t.Optional[bool] = None, + **attrs: t.Any, + ) -> None: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() # type: ignore + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [self.make_metavar()] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar()}'" + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/.venv/lib/python3.10/site-packages/click/decorators.py b/.venv/lib/python3.10/site-packages/click/decorators.py new file mode 100644 index 0000000..d9bba95 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/decorators.py @@ -0,0 +1,561 @@ +import inspect +import types +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +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=t.Union[_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.Any, 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: t.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.Optional[T] + 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 # type: ignore[return-value] + + +def pass_meta_key( + key: str, *, doc_description: t.Optional[str] = None +) -> "t.Callable[[t.Callable[te.Concatenate[t.Any, 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.Any, 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 # type: ignore[return-value] + + +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: t.Optional[str], + cls: t.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: t.Type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: + ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: + ... + + +def command( + name: t.Union[t.Optional[str], _AnyCallable] = None, + cls: t.Optional[t.Type[CmdType]] = None, + **attrs: t.Any, +) -> t.Union[Command, t.Callable[[_AnyCallable], t.Union[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 with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Optional[t.Callable[[_AnyCallable], t.Any]] = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast(t.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) + + cmd = cls( + name=name or f.__name__.lower().replace("_", "-"), + 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: t.Optional[str], + cls: t.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: t.Type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: + ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: + ... + + +def group( + name: t.Union[str, _AnyCallable, None] = None, + cls: t.Optional[t.Type[GrpType]] = None, + **attrs: t.Any, +) -> t.Union[Group, t.Callable[[_AnyCallable], t.Union[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(t.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: t.Optional[t.Type[Argument]] = 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: t.Optional[t.Type[Option]] = 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: t.Optional[str] = None, + *param_decls: str, + package_name: t.Optional[str] = None, + prog_name: t.Optional[str] = None, + message: t.Optional[str] = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. On Python < 3.8, the ``importlib_metadata`` + backport must be installed. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + metadata: t.Optional[types.ModuleType] + + try: + from importlib import metadata # type: ignore + except ImportError: + # Python < 3.8 + import importlib_metadata as metadata # type: ignore + + try: + version = metadata.version(package_name) # type: ignore + except metadata.PackageNotFoundError: # type: ignore + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--help`` option which immediately prints the help page + and exits the program. + + This is usually unnecessary, as the ``--help`` option is added to + each command automatically unless ``add_help_option=False`` is + passed. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) diff --git a/.venv/lib/python3.10/site-packages/click/exceptions.py b/.venv/lib/python3.10/site-packages/click/exceptions.py new file mode 100644 index 0000000..fe68a36 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/exceptions.py @@ -0,0 +1,288 @@ +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +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: t.Optional[t.Union[t.Sequence[str], str]] +) -> t.Optional[str]: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: + if file is None: + file = get_text_stderr() + + echo(_("Error: {message}").format(message=self.format_message()), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: t.Optional["Command"] = self.ctx.command if self.ctx else None + + def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: t.Optional[str] = None, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + param_type: t.Optional[str] = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: t.Optional[str] = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: t.Optional[str] = None, + possibilities: t.Optional[t.Sequence[str]] = None, + ctx: t.Optional["Context"] = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: t.Optional["Context"] = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: 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/.venv/lib/python3.10/site-packages/click/formatting.py b/.venv/lib/python3.10/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +import typing as t +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: t.Optional[int] = None + + +def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: + widths: t.Dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: t.Iterable[t.Tuple[str, str]], col_count: int +) -> t.Iterator[t.Tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: t.List[t.Tuple[int, bool, str]] = [] + buf: t.List[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: t.Optional[int] = None, + max_width: t.Optional[int] = None, + ) -> None: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer: t.List[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage( + self, prog: str, args: str = "", prefix: t.Optional[str] = None + ) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: t.Sequence[t.Tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> t.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> t.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/.venv/lib/python3.10/site-packages/click/globals.py b/.venv/lib/python3.10/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/globals.py @@ -0,0 +1,68 @@ +import typing as t +from threading import local + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: "te.Literal[False]" = False) -> "Context": + ... + + +@t.overload +def get_current_context(silent: bool = ...) -> t.Optional["Context"]: + ... + + +def get_current_context(silent: bool = False) -> t.Optional["Context"]: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: "Context") -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/.venv/lib/python3.10/site-packages/click/parser.py b/.venv/lib/python3.10/site-packages/click/parser.py new file mode 100644 index 0000000..5fa7adf --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/parser.py @@ -0,0 +1,529 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + + +def _unpack_args( + args: t.Sequence[str], nargs_spec: t.Sequence[int] +) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] + spos: t.Optional[int] = None + + def _fetch(c: "te.Deque[V]") -> t.Optional[V]: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def split_opt(opt: str) -> t.Tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +def split_arg_string(string: str) -> t.List[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +class Option: + def __init__( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: t.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: t.Optional[str], nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], + state: "ParsingState", + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class ParsingState: + def __init__(self, rargs: t.List[str]) -> None: + self.opts: t.Dict[str, t.Any] = {} + self.largs: t.List[str] = [] + self.rargs = rargs + self.order: t.List["CoreParameter"] = [] + + +class OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx: t.Optional["Context"] = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args: 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: t.Dict[str, Option] = {} + self._long_opt: t.Dict[str, Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: t.List[Argument] = [] + + def add_option( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument( + self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 + ) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: t.List[str] + ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: t.Optional[str], state: ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we 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 + ) -> t.Any: + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) diff --git a/.venv/lib/python3.10/site-packages/click/py.typed b/.venv/lib/python3.10/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/click/shell_completion.py b/.venv/lib/python3.10/site-packages/click/shell_completion.py new file mode 100644 index 0000000..dc9e00b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/shell_completion.py @@ -0,0 +1,596 @@ +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import BaseCommand +from .core import Context +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .parser import split_arg_string +from .utils import echo + + +def shell_complete( + cli: BaseCommand, + ctx_args: t.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: t.Optional[str] = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: t.Optional[str] = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +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: BaseCommand, + ctx_args: t.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) -> t.Dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions( + self, args: t.List[str], incomplete: str + ) -> t.List[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import subprocess + + output = subprocess.run( + ["bash", "-c", 'echo "${BASH_VERSION}"'], stdout=subprocess.PIPE + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + 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) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +ShellCompleteType = t.TypeVar("ShellCompleteType", bound=t.Type[ShellComplete]) + + +_available_shells: t.Dict[str, t.Type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: t.Optional[str] = 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) -> t.Optional[t.Type[ShellComplete]]: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + # 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: t.List[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: BaseCommand, + ctx_args: t.MutableMapping[str, t.Any], + prog_name: str, + args: t.List[str], +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + ctx = cli.make_context(prog_name, args.copy(), **ctx_args) + args = ctx.protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, MultiCommand): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) + args = ctx.protected_args + ctx.args + else: + sub_ctx = ctx + + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + sub_ctx = cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx.protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: t.List[str], incomplete: str +) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/.venv/lib/python3.10/site-packages/click/termui.py b/.venv/lib/python3.10/site-packages/click/termui.py new file mode 100644 index 0000000..db7a4b2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/termui.py @@ -0,0 +1,784 @@ +import inspect +import io +import itertools +import sys +import typing as t +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.Optional[t.Any] = None, + show_choices: bool = True, + type: t.Optional[ParamType] = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text: str, + default: t.Optional[t.Any] = None, + hide_input: bool = False, + confirmation_prompt: t.Union[bool, str] = False, + type: t.Optional[t.Union[ParamType, t.Any]] = None, + value_proc: t.Optional[t.Callable[[str], t.Any]] = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306 + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: t.Optional[bool] = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], + color: t.Optional[bool] = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast(t.Iterable[str], text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +def progressbar( + iterable: t.Optional[t.Iterable[V]] = None, + length: t.Optional[int] = None, + label: t.Optional[str] = None, + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, +) -> "ProgressBar[V]": + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + Added the ``update_min_steps`` parameter. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. Added the ``update`` method to + the object. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # 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: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 +) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bold: t.Optional[bool] = None, + dim: t.Optional[bool] = None, + underline: t.Optional[bool] = None, + overline: t.Optional[bool] = None, + italic: t.Optional[bool] = None, + blink: t.Optional[bool] = None, + reverse: t.Optional[bool] = None, + strikethrough: t.Optional[bool] = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.AnyStr]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +def edit( + text: t.Optional[t.AnyStr] = None, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + filename: t.Optional[str] = None, +) -> t.Optional[t.AnyStr]: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + ed.edit_file(filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Optional[t.Callable[[bool], str]] = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> t.ContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: t.Optional[str] = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/.venv/lib/python3.10/site-packages/click/testing.py b/.venv/lib/python3.10/site-packages/click/testing.py new file mode 100644 index 0000000..e0df0d2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/testing.py @@ -0,0 +1,479 @@ +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from .core import BaseCommand + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> t.List[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> t.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]], 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.""" + + def __init__( + self, + runner: "CliRunner", + stdout_bytes: bytes, + stderr_bytes: t.Optional[bytes], + return_value: t.Any, + exit_code: int, + exception: t.Optional[BaseException], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = None, + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The value returned from the invoked command. + #: + #: .. versionadded:: 8.0 + self.return_value = return_value + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self) -> str: + """The (standard) output as unicode string.""" + return self.stdout + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__( + self, + charset: str = "utf-8", + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + echo_stdin: bool = False, + mix_stderr: bool = True, + ) -> None: + self.charset = charset + self.env: t.Mapping[str, t.Optional[str]] = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli: "BaseCommand") -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None + ) -> t.Mapping[str, t.Optional[str]]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + color: bool = False, + ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + ``stderr`` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + bytes_output = io.BytesIO() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, bytes_output) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + bytes_output, encoding=self.charset, name="", mode="w" + ) + + bytes_error = None + if self.mix_stderr: + sys.stderr = sys.stdout + else: + bytes_error = io.BytesIO() + sys.stderr = _NamedTextIOWrapper( + bytes_error, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(prompt or "") + val = text_input.readline().rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return text_input.readline().rstrip("\r\n") + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (bytes_output, bytes_error) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: "BaseCommand", + args: t.Optional[t.Union[str, t.Sequence[str]]] = None, + input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + catch_exceptions: bool = True, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: t.Optional[BaseException] = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() # type: ignore + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: t.Optional[t.Union[str, "os.PathLike[str]"]] = None + ) -> t.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + try: + shutil.rmtree(dt) + except OSError: # noqa: B014 + pass diff --git a/.venv/lib/python3.10/site-packages/click/types.py b/.venv/lib/python3.10/site-packages/click/types.py new file mode 100644 index 0000000..2b1d179 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/types.py @@ -0,0 +1,1089 @@ +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 + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[t.Optional[str]] = None + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: "Parameter") -> t.Optional[str]: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: "Parameter") -> t.Optional[str]: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> t.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> "t.NoReturn": + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name: str = func.__name__ + self.func = func + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = 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): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: + self.choices = choices + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + choices_str = "|".join(self.choices) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: "Parameter") -> str: + return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + normed_value = normed_value.casefold() + normed_choices = { + normed_choice.casefold(): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + choices_str = ", ".join(map(repr, self.choices)) + self.fail( + ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: t.Optional[t.Sequence[str]] = None): + self.formats: t.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[t.Type[t.Any]] + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: "te.Literal[1, -1]", open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + if not open: + return bound + + # Could use Python 3.9's math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: t.Optional[bool] = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: "t.Union[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: t.Union[str, "os.PathLike[str]", t.IO[t.Any]], + param: t.Optional["Parameter"], + ctx: t.Optional["Context"], + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("t.Union[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: # noqa: B014 + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +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: t.Optional[t.Type[t.Any]] = 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) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result( + self, value: "t.Union[str, os.PathLike[str]]" + ) -> "t.Union[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: "t.Union[str, os.PathLike[str]]", + param: t.Optional["Parameter"], + ctx: t.Optional["Context"], + ) -> "t.Union[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: + # os.path.realpath doesn't resolve symlinks on Windows + # until Python 3.8. Use pathlib for now. + import pathlib + + rv = os.fsdecode(pathlib.Path(rv).resolve()) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=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}' 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 + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: t.Sequence[t.Union[t.Type[t.Any], ParamType]]) -> None: + self.types: t.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/.venv/lib/python3.10/site-packages/click/utils.py b/.venv/lib/python3.10/site-packages/click/utils.py new file mode 100644 index 0000000..d536434 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/click/utils.py @@ -0,0 +1,624 @@ +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, t.Optional[R]]": + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> t.Optional[R]: + 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: t.Union[str, "os.PathLike[str]"], + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "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.Optional[t.IO[t.Any]] + 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: # noqa: E402 + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> "LazyFile": + return self + + def __exit__( + self, + exc_type: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self.close_intelligently() + + def __iter__(self) -> t.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO[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: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> t.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.Any]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # 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: t.Optional[t.Union[str, bytes]] = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: "te.Literal['stdin', 'stdout', 'stderr']", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[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 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: "t.Union[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: t.Optional[str] = None, _main: t.Optional[ModuleType] = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # 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: t.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> t.List[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/.venv/lib/python3.10/site-packages/distutils-precedence.pth b/.venv/lib/python3.10/site-packages/distutils-precedence.pth new file mode 100644 index 0000000..7f009fe --- /dev/null +++ b/.venv/lib/python3.10/site-packages/distutils-precedence.pth @@ -0,0 +1 @@ +import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE new file mode 100644 index 0000000..50d4fa5 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE @@ -0,0 +1,73 @@ +The MIT License (MIT) + +Copyright (c) 2022 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. + + +This project contains code copied from the Python standard library. +The following is the required license notice for those parts. + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA new file mode 100644 index 0000000..e202ce2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA @@ -0,0 +1,155 @@ +Metadata-Version: 2.1 +Name: exceptiongroup +Version: 1.2.0 +Summary: Backport of PEP 654 (exception groups) +Author-email: Alex Grönholm +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Typing :: Typed +Requires-Dist: pytest >= 6 ; extra == "test" +Project-URL: Changelog, https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst +Project-URL: Issue Tracker, https://github.com/agronholm/exceptiongroup/issues +Project-URL: Source code, https://github.com/agronholm/exceptiongroup +Provides-Extra: test + +.. image:: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml/badge.svg + :target: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml + :alt: Build Status +.. image:: https://coveralls.io/repos/github/agronholm/exceptiongroup/badge.svg?branch=main + :target: https://coveralls.io/github/agronholm/exceptiongroup?branch=main + :alt: Code Coverage + +This is a backport of the ``BaseExceptionGroup`` and ``ExceptionGroup`` classes from +Python 3.11. + +It contains the following: + +* The ``exceptiongroup.BaseExceptionGroup`` and ``exceptiongroup.ExceptionGroup`` + classes +* A utility function (``exceptiongroup.catch()``) for catching exceptions possibly + nested in an exception group +* Patches to the ``TracebackException`` class that properly formats exception groups + (installed on import) +* An exception hook that handles formatting of exception groups through + ``TracebackException`` (installed on import) +* Special versions of some of the functions from the ``traceback`` module, modified to + correctly handle exception groups even when monkey patching is disabled, or blocked by + another custom exception hook: + + * ``traceback.format_exception()`` + * ``traceback.format_exception_only()`` + * ``traceback.print_exception()`` + * ``traceback.print_exc()`` +* A backported version of ``contextlib.suppress()`` from Python 3.12.1 which also + handles suppressing exceptions inside exception groups + +If this package is imported on Python 3.11 or later, the built-in implementations of the +exception group classes are used instead, ``TracebackException`` is not monkey patched +and the exception hook won't be installed. + +See the `standard library documentation`_ for more information on exception groups. + +.. _standard library documentation: https://docs.python.org/3/library/exceptions.html + +Catching exceptions +=================== + +Due to the lack of the ``except*`` syntax introduced by `PEP 654`_ in earlier Python +versions, you need to use ``exceptiongroup.catch()`` to catch exceptions that are +potentially nested inside an exception group. This function returns a context manager +that calls the given handler for any exceptions matching the sole argument. + +The argument to ``catch()`` must be a dict (or any ``Mapping``) where each key is either +an exception class or an iterable of exception classes. Each value must be a callable +that takes a single positional argument. The handler will be called at most once, with +an exception group as an argument which will contain all the exceptions that are any +of the given types, or their subclasses. The exception group may contain nested groups +containing more matching exceptions. + +Thus, the following Python 3.11+ code: + +.. code-block:: python3 + + try: + ... + except* (ValueError, KeyError) as excgroup: + for exc in excgroup.exceptions: + print('Caught exception:', type(exc)) + except* RuntimeError: + print('Caught runtime error') + +would be written with this backport like this: + +.. code-block:: python3 + + from exceptiongroup import ExceptionGroup, catch + + def value_key_err_handler(excgroup: ExceptionGroup) -> None: + for exc in excgroup.exceptions: + print('Caught exception:', type(exc)) + + def runtime_err_handler(exc: ExceptionGroup) -> None: + print('Caught runtime error') + + with catch({ + (ValueError, KeyError): value_key_err_handler, + RuntimeError: runtime_err_handler + }): + ... + +**NOTE**: Just like with ``except*``, you cannot handle ``BaseExceptionGroup`` or +``ExceptionGroup`` with ``catch()``. + +Suppressing exceptions +====================== + +This library contains a backport of the ``contextlib.suppress()`` context manager from +Python 3.12.1. It allows you to selectively ignore certain exceptions, even when they're +inside exception groups:: + + from exceptiongroup import suppress + + with suppress(RuntimeError): + raise ExceptionGroup("", [RuntimeError("boo")]) + +Notes on monkey patching +======================== + +To make exception groups render properly when an unhandled exception group is being +printed out, this package does two things when it is imported on any Python version +earlier than 3.11: + +#. The ``traceback.TracebackException`` class is monkey patched to store extra + information about exception groups (in ``__init__()``) and properly format them (in + ``format()``) +#. An exception hook is installed at ``sys.excepthook``, provided that no other hook is + already present. This hook causes the exception to be formatted using + ``traceback.TracebackException`` rather than the built-in rendered. + +If ``sys.exceptionhook`` is found to be set to something else than the default when +``exceptiongroup`` is imported, no monkeypatching is done at all. + +To prevent the exception hook and patches from being installed, set the environment +variable ``EXCEPTIONGROUP_NO_PATCH`` to ``1``. + +Formatting exception groups +--------------------------- + +Normally, the monkey patching applied by this library on import will cause exception +groups to be printed properly in tracebacks. But in cases when the monkey patching is +blocked by a third party exception hook, or monkey patching is explicitly disabled, +you can still manually format exceptions using the special versions of the ``traceback`` +functions, like ``format_exception()``, listed at the top of this page. They work just +like their counterparts in the ``traceback`` module, except that they use a separately +patched subclass of ``TracebackException`` to perform the rendering. + +Particularly in cases where a library installs its own exception hook, it is recommended +to use these special versions to do the actual formatting of exceptions/tracebacks. + +.. _PEP 654: https://www.python.org/dev/peps/pep-0654/ + diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD new file mode 100644 index 0000000..6277dcd --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD @@ -0,0 +1,18 @@ +exceptiongroup-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +exceptiongroup-1.2.0.dist-info/LICENSE,sha256=blBw12UDHgrUA6HL-Qrm0ZoCKPgC4yC3rP9GCqcu1Hw,3704 +exceptiongroup-1.2.0.dist-info/METADATA,sha256=HZmM9fFOVM8mE2DYVKBJYGaC9zgTtqItGx171R8Xui4,6603 +exceptiongroup-1.2.0.dist-info/RECORD,, +exceptiongroup-1.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +exceptiongroup/__init__.py,sha256=7DHS0hDk-RIs3IQc3SbZVB0-1MhiSCJ9XgvEyEloL7M,1049 +exceptiongroup/__pycache__/__init__.cpython-310.pyc,, +exceptiongroup/__pycache__/_catch.cpython-310.pyc,, +exceptiongroup/__pycache__/_exceptions.cpython-310.pyc,, +exceptiongroup/__pycache__/_formatting.cpython-310.pyc,, +exceptiongroup/__pycache__/_suppress.cpython-310.pyc,, +exceptiongroup/__pycache__/_version.cpython-310.pyc,, +exceptiongroup/_catch.py,sha256=kmx01LkEZI5-pmxh9ATEO4vzqAtkn7njV-5Z-F0Kp-I,4669 +exceptiongroup/_exceptions.py,sha256=f-WOXHw-lVWAAZjGY8c-KFxofCvDcEl4XeMDeqcgMyg,11010 +exceptiongroup/_formatting.py,sha256=mumIgRk61thv7wP6WzCpVNsGPhYZGWffJeGzQngFL0s,21005 +exceptiongroup/_suppress.py,sha256=8ymKx5AFcO15F47NfnRI-G98mn4ZBXuyt4qiLd5zD3Q,1338 +exceptiongroup/_version.py,sha256=zMnMemknXglcJs59xkicNzeEJTVgYd1omSfLWj76yWw,411 +exceptiongroup/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__init__.py b/.venv/lib/python3.10/site-packages/exceptiongroup/__init__.py new file mode 100644 index 0000000..d8e36b2 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/__init__.py @@ -0,0 +1,46 @@ +__all__ = [ + "BaseExceptionGroup", + "ExceptionGroup", + "catch", + "format_exception", + "format_exception_only", + "print_exception", + "print_exc", + "suppress", +] + +import os +import sys + +from ._catch import catch +from ._version import version as __version__ # noqa: F401 + +if sys.version_info < (3, 11): + from ._exceptions import BaseExceptionGroup, ExceptionGroup + from ._formatting import ( + format_exception, + format_exception_only, + print_exc, + print_exception, + ) + + if os.getenv("EXCEPTIONGROUP_NO_PATCH") != "1": + from . import _formatting # noqa: F401 + + BaseExceptionGroup.__module__ = __name__ + ExceptionGroup.__module__ = __name__ +else: + from traceback import ( + format_exception, + format_exception_only, + print_exc, + print_exception, + ) + + BaseExceptionGroup = BaseExceptionGroup + ExceptionGroup = ExceptionGroup + +if sys.version_info < (3, 12, 1): + from ._suppress import suppress +else: + from contextlib import suppress diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aeff3709f23a194c312d97257948bd2920295927 GIT binary patch literal 888 zcmZuvO>fgM7`ENCNt5)0vC-|qiAxVO3{FUB0;Xzk*(Mkg^2JIMx6NuN!A_@@KfzxB zZu}Dd04HBL^)GPZb@r)gmh#x|=kxe=icZHzuzr6VOm`fF{#xVqYJl+?KK%z^hEnts zQWGGPsDlxlo1!UO)WwLCQ!i~TkQ#&66>aHLUj{U&vpf;X4(-S; z?aChQ$v*8v1^)gZZU4Zjzi6mEs0ze}3~30FhumkIfC1ag`@rmpt$XT$fdfO$90KzM zdUV7iIiLezB_FN!j@Z7jhuxuPHr~dXkIxfcR#}lBsA5@~?j5_C#8omk{b`|OTrqx? zZMN=uSdojB>6I$WZ|AkI9mdnkvQ%8_HB1#9t});cD?98VHtrc$8gvZF+IrT3brWTi z6tQPV!BZjCwBTB30nowt^Zxkw zVr@a$_XlpzZacLkevgdZlTL)fcbD8IN6RQ&to-y|SSqybQ4{pB50ho{+wg zu6ma89`&X*;}y@(3<3_8$C5)wpD|gaOJUFLO2rAE#L0rT+12=J)y7YXyyEAT$R@v# zdTbdi{7a&FA$gR}7hhgJk4EKkA~HRXrdb~62_JneGCf+TXmkd=5fn$|s+t%1i_z}0 zNM{v)S^`@<<2t&&%FO;65rZpc6=S1vWxQ7x68G%$=qCUk@&XTsB*Z@H<89n^L);=B M-X@Og)V@CX5B7ZR)c^nh literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc b/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_catch.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97225f4353fd358b6c747b88124599e543641767 GIT binary patch literal 3274 zcmZuz-EJGl72cWs;qphcEX#7_y6L7si?DUb#x39&a0{oZ{DUHD5T^~iuCZBhM-rvw zlAak_Cb2XEDfhYQU0cAuF_1Ut8}uFawpV@yp{@FzS(1@bFTt6!b7sz-Idi^m&R}V& zX5sngH&=Fky<%DaqL;Iejh8!?#nj&*Bv!&wtItBlNaiUIx#{iDMsKH1-woZq7kd3l zSTS>))bCfrs*&Ba)~|(D0#KU1P+r{*?kGGYUaaV5)GA*9#PvR`z6%v}I&oL~v>eR5(ftBCJN^CywiXr)MPYy=IE;Q$! zMO=S{VPS#mBfeSB=5|2=_c#RrDPRjUUC`xy;}IuMy$JgLKgMC zI7?C?qkcR*xiQ<@V?7$C;<1MBkI#AZZgkqi(RSKXd!3zL7H3`2 zo(y`beIPsSXCiynNqgI!;aKktvR}48{6$CgwD@3%pyL!&N6f>xOJVFpUD|PbIL79q zUe?o5gsim``CDU?i}Q%I=i0)PLXTutI9r2Ebm@fV56Sd5`*a}C4&_A%W)m$YFU@5$ zATQ&!s78@Mp2#SoSMyx7=d6OoV80N=2=wdYRI6 z%yJ2yP`tYFNQo#a>JUqeMN!Kwqk9!|S!psULr&RL#vSJ^p3`~1gCRwe zeXquR=9qttbMy`7+nn)#d!ED3vz_Z{-62OnYuZDi4eYGc=M(__vDMo$^`upLqOU1#w?(2 z?j5sf<&l-KL+cAG`^aej#H^{$tjSvL=N=B{Zf?JHbN>~XHuE5RxxZhbw=b+mNYttS z!q2Xk{UO=+$LY*M{kxTC=B~}>9$LEkvX;Y^e4*D?PHd>2V8!W+ljXhn3!nT$Kc(Z%h#B}_banGuSup^Im13)=ag{7&y}sh znq1kGav%dO#~|N84}$WvgNYX$_Vivbx!w*I%sErapg&SN*cL$?sBzW}c1Bs3n6)h% zI59~WZY{|llT0Zmi4h7HG}2dvtA=S$7ar(dWJ%$H;Hj@IGFHi-()0?lb||{KsP|NN z0ItzJ;Im4^Z(J_yRAjAcnY5Izp$`*=l)`2v4!?td3aijWgnCs}W=t7Y`i83EffQ<# z>Y_4R^u0Wn@4@yB{MBb@YTRQD?(h}XM4}_L(Khhorw&Fa;TwGQt0r4x{#X38hU8y{ zj@$e{j*I!HjtxjKfP?eXYs`VA$@+q+zK`9l7B?g=m+@uDSI|j9Tg#UQrazzogVi6B zL>QDmqQ=Y&Ahn!QPa!QwX=bZJY@Nk@B7s^I^#{o)CAkqrPe*ZDYUCO%TBqhG)KDPK z1ZTknvIzyTw7Hvn(0AjS)w z0FH$W;w)HTEa;}OQbGlQKE{DeQ-uXIQ4Dq_>+>U980pSRw#j{S;S*VG&MN^^P?dCH zl<&8Ko(fR%1z0pV6iGYyqY|^P2Xq^WIBB;UB}353$PP8{qbVH1DcxFXv~9dJbRg+= zEnHJT75?0rl3ghMTAsW~CaC5Km&rslkkNc!@m$e|{BF_c z8lhrmgfa-AlT<3n56~308mr<$caWwaKB|`6@pf0*q^JE$3RO{?UD>G8BxN?DLd+&B zBzur?Hj;`DNmppmcqXKREfi-v1KjwF98hKSh#5kEUU(YJ8rRQ+W`Xp=zg<$rZ;0X* ZaZtnZxzAP&2`+=!5D?yEO}qJr{{eQ;L{XXnW_+pO~kvg%b{8)vIUs!%nheCKqdfd(O)Gnph{^~JsC zKKk5q&;8B=Y)?+w3O@hzcSkn0?i<I{ z)2JBS)*HE|Suwe8H1bWWVl@ku0=IJwyE##rXcjBQ=455EIaQfzPFJRzGnE-t@h0SD ztY>1(Y-JYhDUtW)ge3}}>y>%5Y_ujm*D8llFM5ZQo&~ff(W0Is!V!nW;U`Ars5mVa z#S&_Zw-s?r9DkySIrcY)RW$lx3H*qhe16iPOU1XGv8pBN=c0- z+*Yd{xIw+$@=ID|-E-!}$ znq2$zqg&ORKe~1E#~-fTj`Fv?mM81A$XI*4?L~PiKXzqg)LcJ^toB1sHrlShvc{^{ z*o@|?H(cMl^{D1;6BldMT6+yI%5AheEfE!J?T4Kn=7&4~#`> zYk{$+ftCx*P}x+4`Z>-j$cIW`fqo$<2uT@^gyE$w2UhTw8f`&dzx9Ze{!%Gc@& z6eN$akzM!uha(q2z-7_OuSe=5R+qRqMFR_0w{R67ZOdyfqv_Kdwa*--`zr1*gqxgR zb+g_GJXyZlXxH3^f32L(>Yf@%J$pTpW9hz&)uAk&a9n4z)2fj+oOe>Sa!4X2n`K2OnNfLjuNCjyc?@H#V=AfVr*IRx-+8*Utr6L_L68h z6Y1s*iQ>?>Eg!=epCoAKrc~qkly0kYYEiWe>$kRQX|jy28lKFDq==8||0haMso>UE zG@({>@z$?MgMj5viWNirKorF!usP?M;)<9O(@%^&wUS5chhkRDam(@w;%%`Yj&RFH z>#A59YP|#ePWr?(af<2{8uc!a{|wKWKpmAfr=bhYS|!9q*f_afl%oaV~NS zMNLQ1{}9-cMuDdK|Aq=(wLsm|{3%>pHPGqeeW84*@r71G1_u8K`j`@G{)r$bbnZ1n z&;atYKhbveT>~o_K^`kz!U!YOzfeT(OCGs%nt-IE$Qu9>Q{(|8S^^|D0(%!Qf&LpW3 zq1A3(@S5Af({^)ko;BRe79x zS*~P;)7zYT9!vHwU_{Sv(@{*U*o?-i&R+`!Lk* zQbwjM!v1kY2DI9XjFooF%Xn;LZwUZ!u&Vz7D(U5)r^_FzU*MX@5OCkX_0_+O?RqX$ z1pEX4*cR+_6&}KU^JzX*zv8F>7c7Shc57e(ak1*Ht@F+n?iO+KPB-tIV-wg@OXTSh z(TAsJjU1``K6sK>P(=BAuI~nclE6cIC=dBWSvJt;v$VCb z2bB!#-Hsi@EYOqZ4}Wk!x8qir?+zr?k+jSy)!9^R~wx?R=@iP z_l$snJVrh?-s0Ci;U5WRT5z5-=o<@3;eZ7_; zCwt4#c%g6IpZth+LBJj#-=C$m0pk2Q(db!4(fi)Oi_IQYqHq+2rhv>&H_(9=H% zmyc2|w|;N2en$+2?%^F~fYHM1NniNN{00>Q#yxcxpt!5Ulc0d97($u0lwE{2_sQ!y zx0?&#V+1+{NMY`&L4dexhNe(Ds(d9hp5{W6ATl(=94O}nyri93@=LJVTilRQhRRbjG_W2*u>1KiU!`vg-xj_L_{Ou!>Rr-TK3FT+?4-*-CNYwgmu&U; z{0ZkHQy>-b(Bm-M?f7KrCJ=GATY>i|Kx4964WwK1HV`5+Ff+RGMLA9Lt!7))H|w5= zU%>%7tsdq0(u^R8q^`fg<6lBynFbp=L$hJf$mmg20mJv1g($<+4Af!nK&L;{wcaN& zE`Im*KYu`&O!Ra;bLw=<`*3l9>jd9myHO8*jae~3iz$ume{iC;t z5QDDJ|K(2PUF_lS@kkd%uXa#gDHHMk#qK}!*_CHd``6Prxc@CB!4?lHk>6Jwzr!p3 zP(mk9AjP=RE&7@L+CdzlwB*-<)@5!IxvqgE+1M6=2;2mS=9nY7J!be6dfrN%!h?! zWFZ+@06JP>f%X#nY~#`KE@U7H9p$G~RH(Q^#ZOQGQL_+OnQyv5?H(N4p*Wzj&}z5F z&^Z=BGCY}4nHU;|Ja~U0#?H#@P-k^4oZbaP|A@!`Aqs1rVG^K8U^n`pG%yMkHdW!=NGlRh8OBq7KX@<6TaOA)D0yh7P=;TOc_N{|J4|@);pb|UV@E){X z4gLXA;qVV;5mYJnk@yO=su4mjOWF!YHlqDw5Vl=Mh%c&#|7pxq$3Ko=-7{m$lQeP2!% z0XDW-t>&?`Pq4J0o_tYI%L6kTBYx72k-rPZ!8%xuH-j)16dmEL&RZ~6dg{5ZcHW73 zHR8~m0!_)1e_<$u#DMg+!RG|=N%91j;{wV4IAjJmDZpt8@_ytSR4h_KF=@$&gIDfn z>J6f5@d%>!>pzZ1vk$g{dOYG!hp1~Q^)H5~AE#6bgz-LJ;ggg)Ja({db!hBh-HjpY zVBOjf^-Q|1h^c(bH&g1?5Vf9C?-O+zwAfL2Yt?qQ(Mv{wxj)-;*lBLXv z{1J-C+LmqPXM)G^xv{@HNxkH8vRe~_xuj-5GvL|s?>9BC(ZEuJQ1?0w;lvF2$`|m& z@TwTk|zcs$xd*pEjqTZJH7aR@8|%NQ$s<~ zNfd97{PmGQv@s;COW?UyzO& zmn(QV?M+N?+GbryB8G!|k!Fw56dzEdf`3YOVw6wTg82M647 z-!NE<`zP3@$`18Eq=HQ+If#-|Y~u{(W9mJb7T2l98cgP4n#AIuVk!7-Sl6_HHJr+^ zCCnGqg}n98Y)n?bAm@hY*JS>^Umm3zi*5-ui0d>F&ZN|rh{}4X^IFA3pY5DZ?JO3w1{J#Mv5CWl^M1?~|nTlm9NF+nDVyTg=BI|1G#9V{CVu2Nv c83=1eb&$|1!ll52beFB$_QIU<)1}&f1L#9Gk^lez literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc b/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_formatting.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de96428ab5c486fddf5bfc0e3998d5dc7b15ae57 GIT binary patch literal 12225 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 E1w$Es_W%F@ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc b/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_suppress.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2875ab9ec4fa10617cbe587ea10be34e8800c8d GIT binary patch literal 1132 zcmZ8g!A{#i5Zztdi7|l|M9Vc*FZH2zp{F8*D5yoMR8)zctV)aH-4GMUHoF@{qHrnP z`wQ)nFX=z{+7rLfQ)e6kp(E{hW_Nby&6{ztwB!+x-#^y7TMi+A(3uw-oLyLY2b3U! zW+cKd%jkebj1oysEn)SEdM0e)WcI*`97+y|Xo%)D5lzXitf(RA5%Jwyc!M1Jw0i!& zqm7CavtQ&!UYO5u9-m0%vs()yZWmEeP!PJh7i;<9B9Wy@i~K+p!!m)BN5a6{g{5DC zk|d&nL`=}g5=>avB(f12e4QyMfa3z3h04{#vQ$#*@%CPv^vgn-cF}EbC0VTX)^Rcg zm!+Lx7I@t5s$$UoGBUj)Z@&#THiL~IL8vo9EVvF}Y2Wfe?{0U1~L@A{@J_DFerzeEY-cRo91zz$Y5NgI_Rq~IG6c(2pGe% z1_hYjggQ0ybqOT_t2(@Y`vlnw`K*|r991soX`UL+k#mi}Jvv^wkC>f4DiO=YwU1YD zK(ILFf>9&)slvKzd#aYetrj?!&}_x|GPrdrn~qoKQr#UV_~c9)VBk#Dxjun0f#wd0 zYG6)NlY2_9m|DgOL*Fp)UQXCgYeG)xFZzvL+LzA6sc*f&sEPBP3I+pU9e(}j+m)AU zJ?zvyR|}9qVb03YWtJMhQP)y6fkQJYWo@LnHkE@royr-+Ch1i+Op*D&V&GO@Ah#>< zpk4#zdNyq_n|kaib*W8lX0u0ZPvZ~$CN?II2a@y3<9twvVTN{#^Rr=`-JLW!7e&Ik zLPpgSRO_g4e&!U?ubQB+MfFU&#HKEDt(H~qLpn>3bmcuvyuwkaTIW(}`0Zduy2S%I b^`*H4b-udE?)DVw4$jA2suq;nqHESa$yW>b literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc b/.venv/lib/python3.10/site-packages/exceptiongroup/__pycache__/_version.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25d9515a5fa3b2d838c8ad67d39443478da210ed GIT binary patch literal 515 zcmYjNO>Pr06!v(2GEF+7YziD93+%S6kfI8y3Q&PUMH3{vu_oh}%#eva*iJ-x2@b#s zI0<*~mQ}963Oi~A&+_;4{N(3nRTO>X;HeR^_=l7Cx_xPW&q1>m6htosiE%#q?t1dZWp>v!a;XnBv9ED)Bdv>#)vWk5{&;)+VZx`g zoA+avsreVEtb4?HDW$Td^)EA=>onXSeokirdLDiveG+tlKNYRj8mOpOUteBO(rxB# zV`{o+WGO2kcd9XDr778h+|st0({5*LC0~&9Gin+O&%3f(l}j)bzE#kLwo9!x9ewx{ h((PP6S}U<>;W7+rPCaBeiB6)^D8V_-qr<|-(O-EFhA#jB literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/_catch.py b/.venv/lib/python3.10/site-packages/exceptiongroup/_catch.py new file mode 100644 index 0000000..4a39b41 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/_catch.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +import inspect +import sys +from collections.abc import Callable, Iterable, Mapping +from contextlib import AbstractContextManager +from types import TracebackType +from typing import TYPE_CHECKING, Any + +if sys.version_info < (3, 11): + from ._exceptions import BaseExceptionGroup + +if TYPE_CHECKING: + _Handler = Callable[[BaseException], Any] + + +class _Catcher: + def __init__(self, handler_map: Mapping[tuple[type[BaseException], ...], _Handler]): + self._handler_map = handler_map + + def __enter__(self) -> None: + pass + + def __exit__( + self, + etype: type[BaseException] | None, + exc: BaseException | None, + tb: TracebackType | None, + ) -> bool: + if exc is not None: + unhandled = self.handle_exception(exc) + if unhandled is exc: + return False + elif unhandled is None: + return True + else: + if isinstance(exc, BaseExceptionGroup): + try: + raise unhandled from exc.__cause__ + except BaseExceptionGroup: + # Change __context__ to __cause__ because Python 3.11 does this + # too + unhandled.__context__ = exc.__cause__ + raise + + raise unhandled from exc + + return False + + def handle_exception(self, exc: BaseException) -> BaseException | None: + excgroup: BaseExceptionGroup | None + if isinstance(exc, BaseExceptionGroup): + excgroup = exc + else: + excgroup = BaseExceptionGroup("", [exc]) + + new_exceptions: list[BaseException] = [] + for exc_types, handler in self._handler_map.items(): + matched, excgroup = excgroup.split(exc_types) + if matched: + try: + try: + raise matched + except BaseExceptionGroup: + result = handler(matched) + except BaseExceptionGroup as new_exc: + if new_exc is matched: + new_exceptions.append(new_exc) + else: + new_exceptions.extend(new_exc.exceptions) + except BaseException as new_exc: + new_exceptions.append(new_exc) + else: + if inspect.iscoroutine(result): + raise TypeError( + f"Error trying to handle {matched!r} with {handler!r}. " + "Exception handler must be a sync function." + ) from exc + + if not excgroup: + break + + if new_exceptions: + if len(new_exceptions) == 1: + return new_exceptions[0] + + return BaseExceptionGroup("", new_exceptions) + elif ( + excgroup and len(excgroup.exceptions) == 1 and excgroup.exceptions[0] is exc + ): + return exc + else: + return excgroup + + +def catch( + __handlers: Mapping[type[BaseException] | Iterable[type[BaseException]], _Handler] +) -> AbstractContextManager[None]: + if not isinstance(__handlers, Mapping): + raise TypeError("the argument must be a mapping") + + handler_map: dict[ + tuple[type[BaseException], ...], Callable[[BaseExceptionGroup]] + ] = {} + for type_or_iterable, handler in __handlers.items(): + iterable: tuple[type[BaseException]] + if isinstance(type_or_iterable, type) and issubclass( + type_or_iterable, BaseException + ): + iterable = (type_or_iterable,) + elif isinstance(type_or_iterable, Iterable): + iterable = tuple(type_or_iterable) + else: + raise TypeError( + "each key must be either an exception classes or an iterable thereof" + ) + + if not callable(handler): + raise TypeError("handlers must be callable") + + for exc_type in iterable: + if not isinstance(exc_type, type) or not issubclass( + exc_type, BaseException + ): + raise TypeError( + "each key must be either an exception classes or an iterable " + "thereof" + ) + + if issubclass(exc_type, BaseExceptionGroup): + raise TypeError( + "catching ExceptionGroup with catch() is not allowed. " + "Use except instead." + ) + + handler_map[iterable] = handler + + return _Catcher(handler_map) diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py b/.venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py new file mode 100644 index 0000000..82a129c --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py @@ -0,0 +1,327 @@ +from __future__ import annotations + +from collections.abc import Callable, Sequence +from functools import partial +from inspect import getmro, isclass +from typing import TYPE_CHECKING, Generic, Type, TypeVar, cast, overload + +if TYPE_CHECKING: + from typing import Self + +_BaseExceptionT_co = TypeVar("_BaseExceptionT_co", bound=BaseException, covariant=True) +_BaseExceptionT = TypeVar("_BaseExceptionT", bound=BaseException) +_ExceptionT_co = TypeVar("_ExceptionT_co", bound=Exception, covariant=True) +_ExceptionT = TypeVar("_ExceptionT", bound=Exception) + + +def check_direct_subclass( + exc: BaseException, parents: tuple[type[BaseException]] +) -> bool: + for cls in getmro(exc.__class__)[:-1]: + if cls in parents: + return True + + return False + + +def get_condition_filter( + condition: type[_BaseExceptionT] + | tuple[type[_BaseExceptionT], ...] + | Callable[[_BaseExceptionT_co], bool], +) -> Callable[[_BaseExceptionT_co], bool]: + if isclass(condition) and issubclass( + cast(Type[BaseException], condition), BaseException + ): + return partial(check_direct_subclass, parents=(condition,)) + elif isinstance(condition, tuple): + if all(isclass(x) and issubclass(x, BaseException) for x in condition): + return partial(check_direct_subclass, parents=condition) + elif callable(condition): + return cast("Callable[[BaseException], bool]", condition) + + raise TypeError("expected a function, exception type or tuple of exception types") + + +class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]): + """A combination of multiple unrelated exceptions.""" + + def __new__( + cls, __message: str, __exceptions: Sequence[_BaseExceptionT_co] + ) -> Self: + if not isinstance(__message, str): + raise TypeError(f"argument 1 must be str, not {type(__message)}") + if not isinstance(__exceptions, Sequence): + raise TypeError("second argument (exceptions) must be a sequence") + if not __exceptions: + raise ValueError( + "second argument (exceptions) must be a non-empty sequence" + ) + + for i, exc in enumerate(__exceptions): + if not isinstance(exc, BaseException): + raise ValueError( + f"Item {i} of second argument (exceptions) is not an exception" + ) + + if cls is BaseExceptionGroup: + if all(isinstance(exc, Exception) for exc in __exceptions): + cls = ExceptionGroup + + if issubclass(cls, Exception): + for exc in __exceptions: + if not isinstance(exc, Exception): + if cls is ExceptionGroup: + raise TypeError( + "Cannot nest BaseExceptions in an ExceptionGroup" + ) + else: + raise TypeError( + f"Cannot nest BaseExceptions in {cls.__name__!r}" + ) + + instance = super().__new__(cls, __message, __exceptions) + instance._message = __message + instance._exceptions = __exceptions + return instance + + def add_note(self, note: str) -> None: + if not isinstance(note, str): + raise TypeError( + f"Expected a string, got note={note!r} (type {type(note).__name__})" + ) + + if not hasattr(self, "__notes__"): + self.__notes__: list[str] = [] + + self.__notes__.append(note) + + @property + def message(self) -> str: + return self._message + + @property + def exceptions( + self, + ) -> tuple[_BaseExceptionT_co | BaseExceptionGroup[_BaseExceptionT_co], ...]: + return tuple(self._exceptions) + + @overload + def subgroup( + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> ExceptionGroup[_ExceptionT] | None: + ... + + @overload + def subgroup( + self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] + ) -> BaseExceptionGroup[_BaseExceptionT] | None: + ... + + @overload + def subgroup( + self, __condition: Callable[[_BaseExceptionT_co | Self], bool] + ) -> BaseExceptionGroup[_BaseExceptionT_co] | None: + ... + + def subgroup( + self, + __condition: type[_BaseExceptionT] + | tuple[type[_BaseExceptionT], ...] + | Callable[[_BaseExceptionT_co | Self], bool], + ) -> BaseExceptionGroup[_BaseExceptionT] | None: + condition = get_condition_filter(__condition) + modified = False + if condition(self): + return self + + exceptions: list[BaseException] = [] + for exc in self.exceptions: + if isinstance(exc, BaseExceptionGroup): + subgroup = exc.subgroup(__condition) + if subgroup is not None: + exceptions.append(subgroup) + + if subgroup is not exc: + modified = True + elif condition(exc): + exceptions.append(exc) + else: + modified = True + + if not modified: + return self + elif exceptions: + group = self.derive(exceptions) + group.__cause__ = self.__cause__ + group.__context__ = self.__context__ + group.__traceback__ = self.__traceback__ + return group + else: + return None + + @overload + def split( + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> tuple[ + ExceptionGroup[_ExceptionT] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ]: + ... + + @overload + def split( + self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] + ) -> tuple[ + BaseExceptionGroup[_BaseExceptionT] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ]: + ... + + @overload + def split( + self, __condition: Callable[[_BaseExceptionT_co | Self], bool] + ) -> tuple[ + BaseExceptionGroup[_BaseExceptionT_co] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ]: + ... + + def split( + self, + __condition: type[_BaseExceptionT] + | tuple[type[_BaseExceptionT], ...] + | Callable[[_BaseExceptionT_co], bool], + ) -> ( + tuple[ + ExceptionGroup[_ExceptionT] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ] + | tuple[ + BaseExceptionGroup[_BaseExceptionT] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ] + | tuple[ + BaseExceptionGroup[_BaseExceptionT_co] | None, + BaseExceptionGroup[_BaseExceptionT_co] | None, + ] + ): + condition = get_condition_filter(__condition) + if condition(self): + return self, None + + matching_exceptions: list[BaseException] = [] + nonmatching_exceptions: list[BaseException] = [] + for exc in self.exceptions: + if isinstance(exc, BaseExceptionGroup): + matching, nonmatching = exc.split(condition) + if matching is not None: + matching_exceptions.append(matching) + + if nonmatching is not None: + nonmatching_exceptions.append(nonmatching) + elif condition(exc): + matching_exceptions.append(exc) + else: + nonmatching_exceptions.append(exc) + + matching_group: Self | None = None + if matching_exceptions: + matching_group = self.derive(matching_exceptions) + matching_group.__cause__ = self.__cause__ + matching_group.__context__ = self.__context__ + matching_group.__traceback__ = self.__traceback__ + + nonmatching_group: Self | None = None + if nonmatching_exceptions: + nonmatching_group = self.derive(nonmatching_exceptions) + nonmatching_group.__cause__ = self.__cause__ + nonmatching_group.__context__ = self.__context__ + nonmatching_group.__traceback__ = self.__traceback__ + + return matching_group, nonmatching_group + + @overload + def derive(self, __excs: Sequence[_ExceptionT]) -> ExceptionGroup[_ExceptionT]: + ... + + @overload + def derive( + self, __excs: Sequence[_BaseExceptionT] + ) -> BaseExceptionGroup[_BaseExceptionT]: + ... + + def derive( + self, __excs: Sequence[_BaseExceptionT] + ) -> BaseExceptionGroup[_BaseExceptionT]: + eg = BaseExceptionGroup(self.message, __excs) + if hasattr(self, "__notes__"): + # Create a new list so that add_note() only affects one exceptiongroup + eg.__notes__ = list(self.__notes__) + + return eg + + def __str__(self) -> str: + suffix = "" if len(self._exceptions) == 1 else "s" + return f"{self.message} ({len(self._exceptions)} sub-exception{suffix})" + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.message!r}, {self._exceptions!r})" + + +class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception): + def __new__(cls, __message: str, __exceptions: Sequence[_ExceptionT_co]) -> Self: + return super().__new__(cls, __message, __exceptions) + + if TYPE_CHECKING: + + @property + def exceptions( + self, + ) -> tuple[_ExceptionT_co | ExceptionGroup[_ExceptionT_co], ...]: + ... + + @overload # type: ignore[override] + def subgroup( + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> ExceptionGroup[_ExceptionT] | None: + ... + + @overload + def subgroup( + self, __condition: Callable[[_ExceptionT_co | Self], bool] + ) -> ExceptionGroup[_ExceptionT_co] | None: + ... + + def subgroup( + self, + __condition: type[_ExceptionT] + | tuple[type[_ExceptionT], ...] + | Callable[[_ExceptionT_co], bool], + ) -> ExceptionGroup[_ExceptionT] | None: + return super().subgroup(__condition) + + @overload + def split( + self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] + ) -> tuple[ + ExceptionGroup[_ExceptionT] | None, ExceptionGroup[_ExceptionT_co] | None + ]: + ... + + @overload + def split( + self, __condition: Callable[[_ExceptionT_co | Self], bool] + ) -> tuple[ + ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None + ]: + ... + + def split( + self: Self, + __condition: type[_ExceptionT] + | tuple[type[_ExceptionT], ...] + | Callable[[_ExceptionT_co], bool], + ) -> tuple[ + ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None + ]: + return super().split(__condition) diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py b/.venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py new file mode 100644 index 0000000..e3835e4 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py @@ -0,0 +1,603 @@ +# traceback_exception_init() adapted from trio +# +# _ExceptionPrintContext and traceback_exception_format() copied from the standard +# library +from __future__ import annotations + +import collections.abc +import sys +import textwrap +import traceback +from functools import singledispatch +from types import TracebackType +from typing import Any, List, Optional + +from ._exceptions import BaseExceptionGroup + +max_group_width = 15 +max_group_depth = 10 +_cause_message = ( + "\nThe above exception was the direct cause of the following exception:\n\n" +) + +_context_message = ( + "\nDuring handling of the above exception, another exception occurred:\n\n" +) + + +def _format_final_exc_line(etype, value): + valuestr = _safe_string(value, "exception") + if value is None or not valuestr: + line = f"{etype}\n" + else: + line = f"{etype}: {valuestr}\n" + + return line + + +def _safe_string(value, what, func=str): + try: + return func(value) + except BaseException: + return f"<{what} {func.__name__}() failed>" + + +class _ExceptionPrintContext: + def __init__(self): + self.seen = set() + self.exception_group_depth = 0 + self.need_close = False + + def indent(self): + return " " * (2 * self.exception_group_depth) + + def emit(self, text_gen, margin_char=None): + if margin_char is None: + margin_char = "|" + indent_str = self.indent() + if self.exception_group_depth: + indent_str += margin_char + " " + + if isinstance(text_gen, str): + yield textwrap.indent(text_gen, indent_str, lambda line: True) + else: + for text in text_gen: + yield textwrap.indent(text, indent_str, lambda line: True) + + +def exceptiongroup_excepthook( + etype: type[BaseException], value: BaseException, tb: TracebackType | None +) -> None: + sys.stderr.write("".join(traceback.format_exception(etype, value, tb))) + + +class PatchedTracebackException(traceback.TracebackException): + def __init__( + self, + exc_type: type[BaseException], + exc_value: BaseException, + exc_traceback: TracebackType | None, + *, + limit: int | None = None, + lookup_lines: bool = True, + capture_locals: bool = False, + compact: bool = False, + _seen: set[int] | None = None, + ) -> None: + kwargs: dict[str, Any] = {} + if sys.version_info >= (3, 10): + kwargs["compact"] = compact + + is_recursive_call = _seen is not None + if _seen is None: + _seen = set() + _seen.add(id(exc_value)) + + self.stack = traceback.StackSummary.extract( + traceback.walk_tb(exc_traceback), + limit=limit, + lookup_lines=lookup_lines, + capture_locals=capture_locals, + ) + self.exc_type = exc_type + # Capture now to permit freeing resources: only complication is in the + # unofficial API _format_final_exc_line + self._str = _safe_string(exc_value, "exception") + try: + self.__notes__ = getattr(exc_value, "__notes__", None) + except KeyError: + # Workaround for https://github.com/python/cpython/issues/98778 on Python + # <= 3.9, and some 3.10 and 3.11 patch versions. + HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ()) + if sys.version_info[:2] <= (3, 11) and isinstance(exc_value, HTTPError): + self.__notes__ = None + else: + raise + + if exc_type and issubclass(exc_type, SyntaxError): + # Handle SyntaxError's specially + self.filename = exc_value.filename + lno = exc_value.lineno + self.lineno = str(lno) if lno is not None else None + self.text = exc_value.text + self.offset = exc_value.offset + self.msg = exc_value.msg + if sys.version_info >= (3, 10): + end_lno = exc_value.end_lineno + self.end_lineno = str(end_lno) if end_lno is not None else None + self.end_offset = exc_value.end_offset + elif ( + exc_type + and issubclass(exc_type, (NameError, AttributeError)) + and getattr(exc_value, "name", None) is not None + ): + suggestion = _compute_suggestion_error(exc_value, exc_traceback) + if suggestion: + self._str += f". Did you mean: '{suggestion}'?" + + if lookup_lines: + # Force all lines in the stack to be loaded + for frame in self.stack: + frame.line + + self.__suppress_context__ = ( + exc_value.__suppress_context__ if exc_value is not None else False + ) + + # Convert __cause__ and __context__ to `TracebackExceptions`s, use a + # queue to avoid recursion (only the top-level call gets _seen == None) + if not is_recursive_call: + queue = [(self, exc_value)] + while queue: + te, e = queue.pop() + + if e and e.__cause__ is not None and id(e.__cause__) not in _seen: + cause = PatchedTracebackException( + type(e.__cause__), + e.__cause__, + e.__cause__.__traceback__, + limit=limit, + lookup_lines=lookup_lines, + capture_locals=capture_locals, + _seen=_seen, + ) + else: + cause = None + + if compact: + need_context = ( + cause is None and e is not None and not e.__suppress_context__ + ) + else: + need_context = True + if ( + e + and e.__context__ is not None + and need_context + and id(e.__context__) not in _seen + ): + context = PatchedTracebackException( + type(e.__context__), + e.__context__, + e.__context__.__traceback__, + limit=limit, + lookup_lines=lookup_lines, + capture_locals=capture_locals, + _seen=_seen, + ) + else: + context = None + + # Capture each of the exceptions in the ExceptionGroup along with each + # of their causes and contexts + if e and isinstance(e, BaseExceptionGroup): + exceptions = [] + for exc in e.exceptions: + texc = PatchedTracebackException( + type(exc), + exc, + exc.__traceback__, + lookup_lines=lookup_lines, + capture_locals=capture_locals, + _seen=_seen, + ) + exceptions.append(texc) + else: + exceptions = None + + te.__cause__ = cause + te.__context__ = context + te.exceptions = exceptions + if cause: + queue.append((te.__cause__, e.__cause__)) + if context: + queue.append((te.__context__, e.__context__)) + if exceptions: + queue.extend(zip(te.exceptions, e.exceptions)) + + def format(self, *, chain=True, _ctx=None): + if _ctx is None: + _ctx = _ExceptionPrintContext() + + output = [] + exc = self + if chain: + while exc: + if exc.__cause__ is not None: + chained_msg = _cause_message + chained_exc = exc.__cause__ + elif exc.__context__ is not None and not exc.__suppress_context__: + chained_msg = _context_message + chained_exc = exc.__context__ + else: + chained_msg = None + chained_exc = None + + output.append((chained_msg, exc)) + exc = chained_exc + else: + output.append((None, exc)) + + for msg, exc in reversed(output): + if msg is not None: + yield from _ctx.emit(msg) + if exc.exceptions is None: + if exc.stack: + yield from _ctx.emit("Traceback (most recent call last):\n") + yield from _ctx.emit(exc.stack.format()) + yield from _ctx.emit(exc.format_exception_only()) + elif _ctx.exception_group_depth > max_group_depth: + # exception group, but depth exceeds limit + yield from _ctx.emit(f"... (max_group_depth is {max_group_depth})\n") + else: + # format exception group + is_toplevel = _ctx.exception_group_depth == 0 + if is_toplevel: + _ctx.exception_group_depth += 1 + + if exc.stack: + yield from _ctx.emit( + "Exception Group Traceback (most recent call last):\n", + margin_char="+" if is_toplevel else None, + ) + yield from _ctx.emit(exc.stack.format()) + + yield from _ctx.emit(exc.format_exception_only()) + num_excs = len(exc.exceptions) + if num_excs <= max_group_width: + n = num_excs + else: + n = max_group_width + 1 + _ctx.need_close = False + for i in range(n): + last_exc = i == n - 1 + if last_exc: + # The closing frame may be added by a recursive call + _ctx.need_close = True + + if max_group_width is not None: + truncated = i >= max_group_width + else: + truncated = False + title = f"{i + 1}" if not truncated else "..." + yield ( + _ctx.indent() + + ("+-" if i == 0 else " ") + + f"+---------------- {title} ----------------\n" + ) + _ctx.exception_group_depth += 1 + if not truncated: + yield from exc.exceptions[i].format(chain=chain, _ctx=_ctx) + else: + remaining = num_excs - max_group_width + plural = "s" if remaining > 1 else "" + yield from _ctx.emit( + f"and {remaining} more exception{plural}\n" + ) + + if last_exc and _ctx.need_close: + yield _ctx.indent() + "+------------------------------------\n" + _ctx.need_close = False + _ctx.exception_group_depth -= 1 + + if is_toplevel: + assert _ctx.exception_group_depth == 1 + _ctx.exception_group_depth = 0 + + def format_exception_only(self): + """Format the exception part of the traceback. + The return value is a generator of strings, each ending in a newline. + Normally, the generator emits a single string; however, for + SyntaxError exceptions, it emits several lines that (when + printed) display detailed information about where the syntax + error occurred. + The message indicating which exception occurred is always the last + string in the output. + """ + if self.exc_type is None: + yield traceback._format_final_exc_line(None, self._str) + return + + stype = self.exc_type.__qualname__ + smod = self.exc_type.__module__ + if smod not in ("__main__", "builtins"): + if not isinstance(smod, str): + smod = "" + stype = smod + "." + stype + + if not issubclass(self.exc_type, SyntaxError): + yield _format_final_exc_line(stype, self._str) + elif traceback_exception_format_syntax_error is not None: + yield from traceback_exception_format_syntax_error(self, stype) + else: + yield from traceback_exception_original_format_exception_only(self) + + if isinstance(self.__notes__, collections.abc.Sequence): + for note in self.__notes__: + note = _safe_string(note, "note") + yield from [line + "\n" for line in note.split("\n")] + elif self.__notes__ is not None: + yield _safe_string(self.__notes__, "__notes__", func=repr) + + +traceback_exception_original_format = traceback.TracebackException.format +traceback_exception_original_format_exception_only = ( + traceback.TracebackException.format_exception_only +) +traceback_exception_format_syntax_error = getattr( + traceback.TracebackException, "_format_syntax_error", None +) +if sys.excepthook is sys.__excepthook__: + traceback.TracebackException.__init__ = ( # type: ignore[assignment] + PatchedTracebackException.__init__ + ) + traceback.TracebackException.format = ( # type: ignore[assignment] + PatchedTracebackException.format + ) + traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] + PatchedTracebackException.format_exception_only + ) + sys.excepthook = exceptiongroup_excepthook + +# Ubuntu's system Python has a sitecustomize.py file that imports +# apport_python_hook and replaces sys.excepthook. +# +# The custom hook captures the error for crash reporting, and then calls +# sys.__excepthook__ to actually print the error. +# +# We don't mind it capturing the error for crash reporting, but we want to +# take over printing the error. So we monkeypatch the apport_python_hook +# module so that instead of calling sys.__excepthook__, it calls our custom +# hook. +# +# More details: https://github.com/python-trio/trio/issues/1065 +if getattr(sys.excepthook, "__name__", None) in ( + "apport_excepthook", + # on ubuntu 22.10 the hook was renamed to partial_apport_excepthook + "partial_apport_excepthook", +): + # patch traceback like above + traceback.TracebackException.__init__ = ( # type: ignore[assignment] + PatchedTracebackException.__init__ + ) + traceback.TracebackException.format = ( # type: ignore[assignment] + PatchedTracebackException.format + ) + traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] + PatchedTracebackException.format_exception_only + ) + + from types import ModuleType + + import apport_python_hook + + assert sys.excepthook is apport_python_hook.apport_excepthook + + # monkeypatch the sys module that apport has imported + fake_sys = ModuleType("exceptiongroup_fake_sys") + fake_sys.__dict__.update(sys.__dict__) + fake_sys.__excepthook__ = exceptiongroup_excepthook + apport_python_hook.sys = fake_sys + + +@singledispatch +def format_exception_only(__exc: BaseException) -> List[str]: + return list( + PatchedTracebackException( + type(__exc), __exc, None, compact=True + ).format_exception_only() + ) + + +@format_exception_only.register +def _(__exc: type, value: BaseException) -> List[str]: + return format_exception_only(value) + + +@singledispatch +def format_exception( + __exc: BaseException, + limit: Optional[int] = None, + chain: bool = True, +) -> List[str]: + return list( + PatchedTracebackException( + type(__exc), __exc, __exc.__traceback__, limit=limit, compact=True + ).format(chain=chain) + ) + + +@format_exception.register +def _( + __exc: type, + value: BaseException, + tb: TracebackType, + limit: Optional[int] = None, + chain: bool = True, +) -> List[str]: + return format_exception(value, limit, chain) + + +@singledispatch +def print_exception( + __exc: BaseException, + limit: Optional[int] = None, + file: Any = None, + chain: bool = True, +) -> None: + if file is None: + file = sys.stderr + + for line in PatchedTracebackException( + type(__exc), __exc, __exc.__traceback__, limit=limit + ).format(chain=chain): + print(line, file=file, end="") + + +@print_exception.register +def _( + __exc: type, + value: BaseException, + tb: TracebackType, + limit: Optional[int] = None, + file: Any = None, + chain: bool = True, +) -> None: + print_exception(value, limit, file, chain) + + +def print_exc( + limit: Optional[int] = None, + file: Any | None = None, + chain: bool = True, +) -> None: + value = sys.exc_info()[1] + print_exception(value, limit, file, chain) + + +# Python levenshtein edit distance code for NameError/AttributeError +# suggestions, backported from 3.12 + +_MAX_CANDIDATE_ITEMS = 750 +_MAX_STRING_SIZE = 40 +_MOVE_COST = 2 +_CASE_COST = 1 +_SENTINEL = object() + + +def _substitution_cost(ch_a, ch_b): + if ch_a == ch_b: + return 0 + if ch_a.lower() == ch_b.lower(): + return _CASE_COST + return _MOVE_COST + + +def _compute_suggestion_error(exc_value, tb): + wrong_name = getattr(exc_value, "name", None) + if wrong_name is None or not isinstance(wrong_name, str): + return None + if isinstance(exc_value, AttributeError): + obj = getattr(exc_value, "obj", _SENTINEL) + if obj is _SENTINEL: + return None + obj = exc_value.obj + try: + d = dir(obj) + except Exception: + return None + else: + assert isinstance(exc_value, NameError) + # find most recent frame + if tb is None: + return None + while tb.tb_next is not None: + tb = tb.tb_next + frame = tb.tb_frame + + d = list(frame.f_locals) + list(frame.f_globals) + list(frame.f_builtins) + if len(d) > _MAX_CANDIDATE_ITEMS: + return None + wrong_name_len = len(wrong_name) + if wrong_name_len > _MAX_STRING_SIZE: + return None + best_distance = wrong_name_len + suggestion = None + for possible_name in d: + if possible_name == wrong_name: + # A missing attribute is "found". Don't suggest it (see GH-88821). + continue + # No more than 1/3 of the involved characters should need changed. + max_distance = (len(possible_name) + wrong_name_len + 3) * _MOVE_COST // 6 + # Don't take matches we've already beaten. + max_distance = min(max_distance, best_distance - 1) + current_distance = _levenshtein_distance( + wrong_name, possible_name, max_distance + ) + if current_distance > max_distance: + continue + if not suggestion or current_distance < best_distance: + suggestion = possible_name + best_distance = current_distance + return suggestion + + +def _levenshtein_distance(a, b, max_cost): + # A Python implementation of Python/suggestions.c:levenshtein_distance. + + # Both strings are the same + if a == b: + return 0 + + # Trim away common affixes + pre = 0 + while a[pre:] and b[pre:] and a[pre] == b[pre]: + pre += 1 + a = a[pre:] + b = b[pre:] + post = 0 + while a[: post or None] and b[: post or None] and a[post - 1] == b[post - 1]: + post -= 1 + a = a[: post or None] + b = b[: post or None] + if not a or not b: + return _MOVE_COST * (len(a) + len(b)) + if len(a) > _MAX_STRING_SIZE or len(b) > _MAX_STRING_SIZE: + return max_cost + 1 + + # Prefer shorter buffer + if len(b) < len(a): + a, b = b, a + + # Quick fail when a match is impossible + if (len(b) - len(a)) * _MOVE_COST > max_cost: + return max_cost + 1 + + # Instead of producing the whole traditional len(a)-by-len(b) + # matrix, we can update just one row in place. + # Initialize the buffer row + row = list(range(_MOVE_COST, _MOVE_COST * (len(a) + 1), _MOVE_COST)) + + result = 0 + for bindex in range(len(b)): + bchar = b[bindex] + distance = result = bindex * _MOVE_COST + minimum = sys.maxsize + for index in range(len(a)): + # 1) Previous distance in this row is cost(b[:b_index], a[:index]) + substitute = distance + _substitution_cost(bchar, a[index]) + # 2) cost(b[:b_index], a[:index+1]) from previous row + distance = row[index] + # 3) existing result is cost(b[:b_index+1], a[index]) + + insert_delete = min(result, distance) + _MOVE_COST + result = min(insert_delete, substitute) + + # cost(b[:b_index+1], a[:index+1]) + row[index] = result + if result < minimum: + minimum = result + if minimum > max_cost: + # Everything in this row is too big, so bail early. + return max_cost + 1 + return result diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py b/.venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py new file mode 100644 index 0000000..6741563 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py @@ -0,0 +1,40 @@ +import sys +from contextlib import AbstractContextManager + +if sys.version_info < (3, 11): + from ._exceptions import BaseExceptionGroup + + +class suppress(AbstractContextManager): + """Backport of :class:`contextlib.suppress` from Python 3.12.1.""" + + def __init__(self, *exceptions): + self._exceptions = exceptions + + def __enter__(self): + pass + + def __exit__(self, exctype, excinst, exctb): + # Unlike isinstance and issubclass, CPython exception handling + # currently only looks at the concrete type hierarchy (ignoring + # the instance and subclass checking hooks). While Guido considers + # that a bug rather than a feature, it's a fairly hard one to fix + # due to various internal implementation details. suppress provides + # the simpler issubclass based semantics, rather than trying to + # exactly reproduce the limitations of the CPython interpreter. + # + # See http://bugs.python.org/issue12029 for more details + if exctype is None: + return + + if issubclass(exctype, self._exceptions): + return True + + if issubclass(exctype, BaseExceptionGroup): + match, rest = excinst.split(self._exceptions) + if rest is None: + return True + + raise rest + + return False diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/_version.py b/.venv/lib/python3.10/site-packages/exceptiongroup/_version.py new file mode 100644 index 0000000..ba0e352 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/exceptiongroup/_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 = '1.2.0' +__version_tuple__ = version_tuple = (1, 2, 0) diff --git a/.venv/lib/python3.10/site-packages/exceptiongroup/py.typed b/.venv/lib/python3.10/site-packages/exceptiongroup/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/METADATA b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/METADATA new file mode 100644 index 0000000..bc62379 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/METADATA @@ -0,0 +1,532 @@ +Metadata-Version: 2.3 +Name: fastapi +Version: 0.110.1 +Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production +Project-URL: Homepage, https://github.com/tiangolo/fastapi +Project-URL: Documentation, https://fastapi.tiangolo.com/ +Project-URL: Repository, https://github.com/tiangolo/fastapi +Author-email: Sebastián Ramírez +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Framework :: AsyncIO +Classifier: Framework :: FastAPI +Classifier: Framework :: Pydantic +Classifier: Framework :: Pydantic :: 1 +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: 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 +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers +Classifier: Topic :: Software Development +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Typing :: Typed +Requires-Python: >=3.8 +Requires-Dist: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 +Requires-Dist: starlette<0.38.0,>=0.37.2 +Requires-Dist: typing-extensions>=4.8.0 +Provides-Extra: all +Requires-Dist: email-validator>=2.0.0; extra == 'all' +Requires-Dist: httpx>=0.23.0; extra == 'all' +Requires-Dist: itsdangerous>=1.1.0; extra == 'all' +Requires-Dist: jinja2>=2.11.2; extra == 'all' +Requires-Dist: orjson>=3.2.1; extra == 'all' +Requires-Dist: pydantic-extra-types>=2.0.0; extra == 'all' +Requires-Dist: pydantic-settings>=2.0.0; extra == 'all' +Requires-Dist: python-multipart>=0.0.7; 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: uvicorn[standard]>=0.12.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/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.8+ 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 on an internal development team, building production applications. + +## 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)
+ +--- + +## **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 + +Python 3.8+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## 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 +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### 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 server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### 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 3.8+**. + +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. + +## 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. + +## Optional Dependencies + +Used by Pydantic: + +* email_validator - for email validation. +* pydantic-settings - for settings management. +* pydantic-extra-types - for extra types to be used with Pydantic. + +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()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install "fastapi[all]"`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/RECORD b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/RECORD new file mode 100644 index 0000000..ffba134 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/RECORD @@ -0,0 +1,91 @@ +fastapi-0.110.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +fastapi-0.110.1.dist-info/METADATA,sha256=aOPlukMP9l1KQLsvqnZN053v4lVrFxjNnKvDKTJ_Rtk,24966 +fastapi-0.110.1.dist-info/RECORD,, +fastapi-0.110.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi-0.110.1.dist-info/WHEEL,sha256=uNdcs2TADwSd5pVaP0Z_kcjcvvTUklh2S7bxZMF8Uj0,87 +fastapi-0.110.1.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086 +fastapi/__init__.py,sha256=1TIwvzs3NSS3SQGExm8yD2CgWyHOHf0zsBpPY6kf434,1081 +fastapi/__pycache__/__init__.cpython-310.pyc,, +fastapi/__pycache__/_compat.cpython-310.pyc,, +fastapi/__pycache__/applications.cpython-310.pyc,, +fastapi/__pycache__/background.cpython-310.pyc,, +fastapi/__pycache__/concurrency.cpython-310.pyc,, +fastapi/__pycache__/datastructures.cpython-310.pyc,, +fastapi/__pycache__/encoders.cpython-310.pyc,, +fastapi/__pycache__/exception_handlers.cpython-310.pyc,, +fastapi/__pycache__/exceptions.cpython-310.pyc,, +fastapi/__pycache__/logger.cpython-310.pyc,, +fastapi/__pycache__/param_functions.cpython-310.pyc,, +fastapi/__pycache__/params.cpython-310.pyc,, +fastapi/__pycache__/requests.cpython-310.pyc,, +fastapi/__pycache__/responses.cpython-310.pyc,, +fastapi/__pycache__/routing.cpython-310.pyc,, +fastapi/__pycache__/staticfiles.cpython-310.pyc,, +fastapi/__pycache__/templating.cpython-310.pyc,, +fastapi/__pycache__/testclient.cpython-310.pyc,, +fastapi/__pycache__/types.cpython-310.pyc,, +fastapi/__pycache__/utils.cpython-310.pyc,, +fastapi/__pycache__/websockets.cpython-310.pyc,, +fastapi/_compat.py,sha256=i_LwkpFVbNCuraFRbc1UmNNocX63BAwjjBXgF59JJVQ,23027 +fastapi/applications.py,sha256=owRSmdslsJhJCDxxatkfMdewlaiE-9DPbwQ7alyexgU,176342 +fastapi/background.py,sha256=rouLirxUANrcYC824MSMypXL_Qb2HYg2YZqaiEqbEKI,1768 +fastapi/concurrency.py,sha256=AYLnS4judDUmXsNRICtoKSP0prfYDcS8ehBtYW9JhQQ,1403 +fastapi/datastructures.py,sha256=b2PEz77XGq-u3Ur1Inwk0AGjOsQZO49yF9C7IPJ15cY,5766 +fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +fastapi/dependencies/__pycache__/__init__.cpython-310.pyc,, +fastapi/dependencies/__pycache__/models.cpython-310.pyc,, +fastapi/dependencies/__pycache__/utils.cpython-310.pyc,, +fastapi/dependencies/models.py,sha256=-n-YCxzgVBkurQi49qOTooT71v_oeAhHJ-qQFonxh5o,2494 +fastapi/dependencies/utils.py,sha256=rynOrwW6BKSv0bTVDCY1ag4kRsOzJwmmzO31sRKsTzA,30241 +fastapi/encoders.py,sha256=WHaTCzLqLl7fLW9cmdPWSmr7FGREToBrYKVHv18lfxM,10994 +fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332 +fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969 +fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54 +fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58 +fastapi/middleware/__pycache__/__init__.cpython-310.pyc,, +fastapi/middleware/__pycache__/cors.cpython-310.pyc,, +fastapi/middleware/__pycache__/gzip.cpython-310.pyc,, +fastapi/middleware/__pycache__/httpsredirect.cpython-310.pyc,, +fastapi/middleware/__pycache__/trustedhost.cpython-310.pyc,, +fastapi/middleware/__pycache__/wsgi.cpython-310.pyc,, +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-310.pyc,, +fastapi/openapi/__pycache__/constants.cpython-310.pyc,, +fastapi/openapi/__pycache__/docs.cpython-310.pyc,, +fastapi/openapi/__pycache__/models.cpython-310.pyc,, +fastapi/openapi/__pycache__/utils.cpython-310.pyc,, +fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153 +fastapi/openapi/docs.py,sha256=INQd4dFFyOwckrtlrkMbWzsyI1a4wvz8c7S_u0vYgOo,10356 +fastapi/openapi/models.py,sha256=DEmsWA-9sNqv2H4YneZUW86r1nMwD920EiTvan5kndI,17763 +fastapi/openapi/utils.py,sha256=PUuz_ISarHVPBRyIgfyHz8uwH0eEsDY3rJUfW__I9GI,22303 +fastapi/param_functions.py,sha256=nz8maacuwRVLGjnjBD3thpn40mp8IKs0lCeKmxrbw24,63865 +fastapi/params.py,sha256=LzjihAvODd3w7-GddraUyVtH1xfwR9smIoQn-Z_g4mg,27807 +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=dcQBjxUsO9KT0pmp1ewJzM8qD3wjcZi1BrnyyqYELoE,174150 +fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881 +fastapi/security/__pycache__/__init__.cpython-310.pyc,, +fastapi/security/__pycache__/api_key.cpython-310.pyc,, +fastapi/security/__pycache__/base.cpython-310.pyc,, +fastapi/security/__pycache__/http.cpython-310.pyc,, +fastapi/security/__pycache__/oauth2.cpython-310.pyc,, +fastapi/security/__pycache__/open_id_connect_url.cpython-310.pyc,, +fastapi/security/__pycache__/utils.cpython-310.pyc,, +fastapi/security/api_key.py,sha256=1MwaTMyqmRh0nIIDICsP6iG9Rdwbzh-BG0SFWKRc8no,9368 +fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141 +fastapi/security/http.py,sha256=Cb7DbOPWpnzvKZTwCdxWRXxa2txZBdeeAdT0tlRdQgY,13506 +fastapi/security/oauth2.py,sha256=lWemX4CLAvanR6-jiQxFtOyHjHbzEnNbpytA_WXgZcw,21583 +fastapi/security/open_id_connect_url.py,sha256=8vizZ2tGqEp1ur8SwtVgyHJhGAJ5AqahgcvSpaIioDI,2722 +fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293 +fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69 +fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76 +fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66 +fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383 +fastapi/utils.py,sha256=LNep9q7ZeTQqK9-KvagV5CWn48KXwExnZGSpDsXT_Tg,8204 +fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222 diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/REQUESTED b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/WHEEL new file mode 100644 index 0000000..0309176 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.22.4 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/licenses/LICENSE b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.dist-info/licenses/LICENSE new file mode 100644 index 0000000..3e92463 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi-0.110.1.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/.venv/lib/python3.10/site-packages/fastapi/__init__.py b/.venv/lib/python3.10/site-packages/fastapi/__init__.py new file mode 100644 index 0000000..5a77101 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/__init__.py @@ -0,0 +1,25 @@ +"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" + +__version__ = "0.110.1" + +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/.venv/lib/python3.10/site-packages/fastapi/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38dc0c3cd74089b275cdcb7679e65e51cf410b43 GIT binary patch literal 1074 zcmaiz$!^;)5QgPMwk+>^mS)j4fNLe~DL_$lNrUuKq)FNWL;-;oX`3)5DkPQEd5Jzp z-=xprYfpKFqK6KdG{~(I^!uBIBXKwu^?JpD>*x2i$)W2wzl`ztS^?t~Jn9b!agaj_ zs6bZ8Dql%f(Q3gVE-7+1DWam~5-%kl@+^D2ocPGMT;`ReimH}<;2Nq~uJC%&Kn=@P z;3jHXt^v1D%W@sKjoOwQz#Y`F+yw5TuH_bR5A`g!f%~X$xdS{v1It~$maL<7%RRo4 zY@$ueef}ibLR*#xd^_1eJC@ggchN5J`nj{War5~YEB*TPeK3(Yq1Qsrhrx_ZXF*2g zM92iEF&zdJt3{wiz$upLFqps^W5$9&P*O}50VD^R6eN!|6X}h&KRP&o=N4M*>=l+J zrLoS{ZQ;)J?q3U$<{KQ(r&8o8xxi|!z*YH_ae>J(;}op=$;HL#yKgbgOl5F%zR>Zx zi04#4_PTEbSwOV(R){$>3%w(n(Uh2q?tLxy81`h6PT-@dG?7!RXYgD6m{V!im(OXO zOQsEbXY?|sN*nhXRhdYYDeObT&P1+l0srA^Akuv>j+lx?n$lQ**bA0k6cG_e(Xtvv zS5zw4NE9I-nj$&XP{_#s?bay&R7^lEM+>1M%iLnev!cF War)BCml}e&j=NGbcj13`tMC`Z%^#Wo literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/_compat.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/_compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b49809feeb843575e42c40298b845fa14c77894 GIT binary patch literal 17633 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/applications.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/applications.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ede1db06d62d83ae1c40292e63d2ffaa26e18fb GIT binary patch literal 68387 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/background.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/background.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7faa60bdf59f25066d18e0eb01d682824f5a2542 GIT binary patch literal 2165 zcmcIlO^@6(7)aS5ZD0V1{UFyU=>N1b5us$1P?i+~t zw0Gv174=yE?vTRC-4X56LFPX}nL~X#e7qK~K0zLe*C6DPG;olcJ%mOW#x_m`=PcE^ zD6z=!!Fk+Ro4~Q25si;>&hY`mDP+hfCYfdu6D*mkM5!2_5e3Jrv?diRHP!+&L4oJ6 z3rF_gHX{@lLNZJa#9ZSXzNHbfr(b?Xl-}OGg{ept&Vj_Uun}zHHpoVwR29Cy_-i~FHUCnU;Uk%AmO#DpEKi96cgzZs^DV5j+{6V_icHz{ zAed~~o^O#J}rt5 ztk$C~{Gj#vC^&a%l$S2VN2Y3a4Dhp4q4Osq|!PRbM;0F2~6 z=fA8_Vk@-uJkT9jo|g>?rB-YFBFLLfHXVSKC>ZWW+(v3LmrT!Pi5~l{l;tHUQx=|zT!n`+3h%S>e#G;Gs9~e`!gt<|6cEU@3fLHULM;fd zLv3MoA}@f?x8PBxf>&NWy}V>hOIPQuGFh+vBq>S3lB6Cb39!nXoAp|f+?x~Lo(z%% z$Tvyk3fPnIia^r5homtt;nmtn)%vd2+iX+DIjFsCMC^3QtX?sbxl9Hn6~N>p&vD;$ z-I3#(&!6`5hqvbb=B>NGx))yi#metYR_ne#sq%8#_%@-$8^HOJGp$*;R2Qe!4z$H0&Zcvv;b*=z=2w#jfAxm}saYyX1=rVkz1DO2Q2XwBVle0QVw7ivsz AIRF3v literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/concurrency.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/concurrency.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a538f3a98e345c14ee7b1a236f7744d8bf11cf6 GIT binary patch literal 1027 zcmZWo&2G~`5Z+n;#CFoO6_mD8#feLhi1|5z5CT;Qkf4`Vt?sxUYqr%txJju zMcfcqUV%5^8TQJluh0WwHi<+KyYlSp?9A-=`(}%U1&`qP`E9lL-Xi3e-pr2%Zl2;- zeL<0s1TvCC0HAf6(cB1(+ziaz3ap9E$n3zzGc&XEM$nkptjx*Xz@6we>R#YY^akq9 zpb3OoiE{x#i$UTtleN}K;xU7@5~D}gNzY80N$azT9t(-FO*#vgSPSWZx)xP6kK=+% zb|UkLM+Z!F4Ap+7%`X^dB9etr?aisjo2iFt?9?UOjl>qFSlo=tC{AVlI?Ypw;h>!`97q|?`FKqcf^BSF z>cTq^G_n~)p0Lp(92Ck8Lx%8+FjVgIlbDq1uDUpqiDKs3|0@^scNCARa41N%?if31$-!F3JC;h>@hxh$%Io!|Es_*ww9`TrU zPm8qb4us!5V*JR@(tW?IWxwDLy7%t-6>@q9i5_5!RDLh2WK^a;c1}DLg7LWSmbKdW zx0C**dJ#*gZlR#(jz{4Jw1I*ROW=*ov1ysm9y{ms%640@G#2aV*l8@GJ*6=_%kMklK dX6%V3uG&D+BG6JTG~%) zPo|j^gfZkqQE=e^6iIQ)jT;oHN^ybWZ_t$sIj0J$IK=$EC$+j~ao`ZD(2Tx*%lE$b zy>EXCM@Fg&p1=O|K4Zt8x~Eczw0 z=HO9~riwTB9;@wx4S zc>w(pHj4h}wr0-r3LD#2%_D4_A7K;xNK0pvZ0ezI9%a)vl={pkIIU72N(#%tW>R_4 z4Q#P_^|hpO!S+0R)#HhN(RJdaay8~c_A9ToV>b+JFVSyqws}$}c-t0-O2CdLb12hO^FnJDGlo$1g`=kan-w0rR*>#`;6IZLhWNGgL*CF?|gQWb?Orpgpk zy9FyT3tZ<#USis|+R_dxyvz#c6^vE*5PBu1=i|j}yeh{_`FL554+FQ7j}7ghQO(DP z&y${YUIX?>I?6`bSWACTX{l_SO+2ibBSVwyX;ubS6a_w&QgpY{MzYAdQ}7o;DUk zVKCn20po$QSvT5bc^ux85xUwkHp7l#3+xxU!J6D@t>f9kxWjnsPEKk`;yHEzJZ{A6 z+_;l6Xc4mw0(T^9b{q?LwG#s=G;GI#J4ke4Zx~SwH?svZu5HHa#3!9|an%c*d)Rx) zfYIYXn}JhbqHS6o&%gpnHsG8=7A>472!k^c%Wy)*vx8iRiy1!L+pt%|PE4YK+`y+? z{pMvvgXL>i4Hi0)Byv5Kr*Ro9L~kvw$8kG4*KD?cXSdx(?ApOv=!Fd@^qX-9?(W)N zGgHDD;yY^Av#n2@FfP4q`)!Y>%DHprPFtQ&Zru{0Z^WBz60YmFLlGOfcc=IgBip!# zlJUDF`CBsj(IH)8x7)^ZMuxOluco6fV7So^qj+(lnX^|$Kh>ib5adIPUNpq$dvM?z$5F)8`4-?jU8ti+BJ;zPT*+lm&VL4$C z^B^Y6$Z2M%OGauleOisAmf>53pXf+Hc6T{f5GjcsA}kpq-`fyw>Vz>yrO5W+C#6)i zD~>jhUZ{;&q-^8;bQ<7YHAd%sbxZv~y^1VzMM2ckx_`;(y)L(kLVsZU{;oON8;CRk z(jt=irm+!rJQkdavv}gdEy+{tRQ?o{V5<8DKY7y7ScR)^*ltX9z!K!?BM7=^8CrIM~5p9Q|*T}hALBcIY9R$y$C}oDe9&xWFj^gYes>zULIi4Lwmi3|X zuhr%{j@e}E_wGM?w%KTRRy{Xbhr0!K;P6H_bfd;S(QG{6!Gosft~S$9@J!?Brz`EJ)qGXv`0MLEa2`Gsmp90wnXPG_lW z;siS4FoBZH(?R(mg1Rz|_S~DiDdPMd z{iaFfG5+))Mfh>P;j7_;G(#GL+wJ2tsDzDxza6LUfb^I8^@i(t29gxZ2j&ovJ zYWm_`B~t>4qo;%?N$R_lu!OPuG`?);0L03c8mrq{G#YD6jSE}qw)#uu*SJ>v5NQBhYAfAim)>q8qoOM7@3jOo zb-4S0vvWpWPpU48O3KC#Po{3fw(xiy^FDe~mA9-*LWH=oQEr1#$@4w~CUzZKJdLrR z;f+cFRc%t$)$UZESfeMiWX|f3TDZKmJ5p4*&Z(ADz~bIR?fl#%-OoFBtj9&jLA#-d zF9Wq+5?{fO_$q;~5%@X*y4TBszFtUA@+=LUBOuk+*Wpl4ef$@g%@0*oyVHI48#z)^ zYq{KGRwVDQd(>A14XHlL*jwuR$kR+?g$?$?VFwj@whjeRdgl03dyo}3`qSsbR{=E(Grrl*c(k5r5upVrzYRtWOfj{j&&Co{hZz30^?I+x2ktf z?O>N&YX3EmT-Xr~-@_}>AvQiGUSU1TU3dz3eF|NOcMLz`8`RFM;UyaQZ&)6X6crv= zbs6CE7~Zi0aidP#YT_7vR_Y5$#j>cBwXCEnHP}HdZzVO$y5F(AY^H2kxFK1VI6xZ~ z2+RQ_W0qy7pCoX-M63~I8ZE$@l7bt=Vv4#&S#HScMJ8cENkCALgx;xu!o_nvWP-k4 zh!O#EJwXx_X9?EPca)9pE zRLDg?2dFB#svXzVlBzwbJet$z)M-^yN7c$BP1iIHZTvlwf1hd9(SK-1^ndOuUFppJ(^I?`Hp>rjL*=6?Ypa8jzbbqH-pcKVwd6t5Ozp z30kQiOG>D#kn~eskg23`SBBRTb;|@~R34%hd5}4lT~8ZUdb3VL@~%Kk+0C3oeV5jC zjh$CnF;3Jb2vAuslZ2S2)(io%Rarcl6DflhZaF-ND8r=rhf+^^Cr>TZ%l z(};sSX3#bDSN;9J>aV~4`X{W{s|r4U@jH9kpC4D0zae1jXAgk4@kD0}igHtN6i4+G zEB#e16|m-Me!(jEx}~c$Uhs;3$tuad?v;JRGGxE#Rs5<|^=nqm@3Z>+x>fi4t$u&N z8j$lPZ_ppIhWue`Si)s*mp@{S$iCt2_D8Kz*{^te{4s0HAGgN+z1CiTpS925Z|(OF zSO@%r)J<~sI9hUu?cf>zx9hLn)?t)%md$0J%tYfm@?@jm(tKlEF zj!SsJd)1$`CjArE2?-B+Q~tCy?Vq$x0v>XPy;J^a>$HEyI^(})y@s(}>=0A$y^iN> zTN_uL5q7SvJG-6Hk96z2vxk*1a)`ab-lSQ~j5*_&x!@}7qO;f8_mT2@Dm%u`p(QHk z<*%Ckp3Q#0$2^a?SO2LvvX_+&xmu7 z=&(ujPvCi*y~PgW_Y9r}JLgvZK(#Kjz3du)-1ND6BBUX4vJ&sx@0t@qMZCvizdwyy?8cra||lbL_Dy?K%N? zKRXJ(C!Iz%c6`g&tJ&Bj#^!)?B7>(gcshemX7H&DKApj5GWa#X`*+ewa(+F-I-9+9 zE`vv4ml5Z@^TtO-Yu-_BD2)rhq#d=;(2|xVvJu<4bZK>!ve-_5%R^=4r>@m;c~E=7&Er#*-IWv^jQ*Ff7gvfVqEJ8Hw}Nr{^`ug>DPcr|FvJwm5)#g5o}p~FbU;!Nm;9P*UF;U@Qz%7X2) zIp20Yvd|6I;!Ipw6)Z|BDR4s&dgXEugu)igNeZ)J>z68Q+9)Ko>$hevFDzc2X?}1z zDGW-Z;MY= z{tBi)Rrn-+zWDz1a_F;ZXZikvH%?Dab-GKQ8!b<_-M|i7Y-%lZqpACRdTNCQE7P94 zG~HPh%VBV4>eR{U$QA5F$8O!X@3LsRZAZfHxYI0XL0TS7byhh7uyP1bM4}n0gp-QH zTFn*P>#}duAUX*ARD*k}quwv_n$Tk9F`Q2n(%*(=|1p%Vn)u8~mXT?jnd6yuWV(Sc z!?r1w8E3~LGYC!gs1pV(5R+y|qYvGPnQbq$MO9K+Tz2tRWOgIg?t13KWfqtZ8G+_Z z7({~GZor(Jg9uH|I&fzYG#9!)<8Eu>(d5a7q=lC`gFFy|-DTXISn3LhAf!|R&gC>R zR?bu^z8lru( zY)T4pt;@};j!7(up>1}!>ob_b_TlKMfw07>1uk8>WMXk>>o&7xoXGT@IC5(0+8J+Os~anZB=CC9#W0pri4(<=OR^uHbHy1;(+ znh_WTP6S?>aJI3K)ZQkpXLlk?Hk!fnj8u!2d)UCa+(o%%b`o3Cyh3l0#HFtbn^Wa) zU_Pf;?xeBu8!0XjG8rNnoLiW=HaqwJjpmhG&Ba^S=aNBksN6@IzTKJXv5=0pig-ws z=p-7U2=%eLu3}GXPnB8acK!R>y0%`3)wobp#+6uWtLK!0a#49;#MtGjkOfW(CB@WT ziU>D;)X@1Q8XU{xOmk_q+4Aft^Qs8wBwJF>5VkEqa`k)ZKv=XBy}Get)Qv; zi^0N(s;hh!1B>%XAzZq*c1e0PZBP0vE@N*69qe$-v6e6q8{h#ejLYu#Zd_YPH)D!! znn~FWT3**-YwJCPuCF?FAlw$h)twCE4sB)}Cpgt6(TySm0FciyO?fgzG!!v#TV_23 z+b;7QIh&E&E(d$`U&)bS{BOyTk=rJRfi<)}*N*H?9@BGM<(iUBa;$GJ4AK(>ZPRV{ zm<47s!>*teiuVPuZQeII0LOL&AD`RNdD=8 zFlk1iB)mZ-$M%@L!qTHexs~d^X&rhhe zAAX}Iy@>xKU2HQYmZf5Rn@j`I1JCwa%gkSGMs}Oo*S5#HxilJoZ69pcABi@OmWQrb zmb-<*m3ap=v9Ejd%rjbCMQAVB*bS}wChh?^o_rkt?vm@d0)9c1Zv6VYms9DoV=S5^ z>f3f0?o)Kw(Iw0Fw!Cv9>L77!yDbyKArK;1ZA3*R-;mHr*+@Ajd&Eq4Y=|hAo}ZD~ zvV&vUR!&0%flI6bkL506=vsOTe*I)^Rd7n@pS|exz7JC9innUF>_MG-XDAW=<}qT8a3gwJp^S9x4muR+G! zaqUSZE zV0|z)_-CLyAcn!^vv}aisAD`;KT)Gbo zj@IZC^}&I77idW@5(lI_SHyu{-x3Ei4TqrN?)6c!T0APbeGu>7^e#}FUn>cnM%MRy zs08PAMI8D>UHyGkSszoCwO1kAcs%}Oe>_IqfopEy?#Xa}l;Ku4@x>Cq$w3;7A?;Ol!eS&phZ&J9`dRz;R1c!qrLW|44L_r8M5Tb zeIBkd7LmP@YRr5o3B^Fuv4y>aYEhb#MBPp&csHrKk&CJfm8p^fGMPlDA|$7v&yNy9 z`7XmzB)C;=HnC!D_inS9l)4?P2;)>gNCrtuss`qYqn?T7lDA1z>-yZNxdA67JCY3O zUd!L4rcN{pC=Bsa1fC{Pzt2{qq$*G7h|bkSM?p;_738*SjM8g9K*(=VgCj`+-A;!E z4*w2~T&9r<@&G0)l8L^8QchC+fU0G4oTJRRm(LO6PD`?rN&B)}aFYyY4d&2><&113 zN(^{&lQgulcbp7D#WZ}#oTk*QfL3a6)zUZRxK+;qnT%~xkh<%1apyA-+p1@_%_=}T znKw~cQevcBwC%3WKfpU}JP`t(VzhO&PaRYTwJLtK7o(b?j;e-QRdr2Q`*BCFs@m7S zrC%9UV{=r~)Y2DKV<$|^Jg?SDph9$s7d=My463LGd}S20|1fm@%l;B5fY#=>^o3?@ zLd3-|v>)i|7^oO{w$9~!{kic%ulH-v30%PMg;pR9Q%$H>C24-3ebx5@?U%hAQYxkA z(n<|uVPSE8etu!G@ecnGCQA(RbAe)CQfq~thq?rc*^#WMq>fk4N@|>{HHpqpsORL| zC>D3@v{KKh48_aTP)(UrcEzjI)X*eULRv;qm{YMN-3}UOoN}(T3KL0ZPfBn;L`FVH zXhYNtQ?rYj5o&f*GfEBpJ(uX+uIunIbgg<;R-PjNjrcf?8J(<7A~(C$pMwZ-D8%!9 zgfp};7^HtJM0`KS`2m{Td?Tew)n-n0YHKK!w8!oPP)6&3f?uS|8&Ape>mFVm<;9yh3t zXb1JZC2cqM#|vH4zAC}HOS<-Dsi^&XwWNKam$iR`7ynAHXwUVk_OE(P`xm`W`)9qb zJ=6QO&-DTApY%cPAN3*aAN1kW&vkfj`hDp$?cfL~@7Jnd88vN0t7v^%72gW=^gqgX zf%YQ%R!ZqEN#W<(a1Z?V+P>_KbpCI(V?FR+Yo~hPUuYM4;Gb%W`8s*-_I1X@H^^9ZEWG4h;|lO#%T?VMvChCI~MCrCmj|m!z`0 za^gY(9Jtq@uh1TQ?JM-sXW+G`zCsUnXIHYU#yyk*NAt5gJM+!A%xblY0nZ;leKNUU zFpNKyvH93wd<(Dm4FoX=Vn%`jgp`gMPRzhetiaN?$qI=b*jl$(F)0Nltru81sRR|R z+pL;6fur>zt0ncIo@@nM+Ac9SX#|a=88pEzQ-@S&g;eR*#3l}@{b&W-E3XOOI(X}3 z3%onTr6pKvkt%6`w@J3ady6y%MtkQksM~0x+&vOm8jTnYX*$jbjO_-cS-wG9C&U$+-wsdRS6kX91)3 zY&bmVydBe-ItCoYRca{1`EJnf9a1sNQbF_5l?IVJYFBuFZ!i45cW~H$+8GQUKiThu zo!+oJe3{>VF$nMN?tT*<^!K|@Uxv@S{r$(oZoiio`LeUzq;JQ$&8eL8bc_`itH*?Y z7`X8}yy78<_edHGL=Z8~&39O$1vc|!@sKweg&38HQCn$qh^sLj6`d{L#(^lR_lt}kLqznVqk z%z zvbr`J+0Q^x$Vxy~;syHI{KYs&FZ zz)`4ZX!tF)|gZ+4;f2n9Gk!=~=wf`6)Zm*3El(46nx=w{86FJR?+v@njK zpX+W2`hdIeL3n1UYYc3_Js^Rlu7RRn1Q)Mu<%KcJ1mzB-&@J)Xpg}(hq2;hY>c?AG z6#k#i?m!+<0)fvg(?RYf|6Co=3f$GWz177R`uL!^c3-hTaCIrT1tO?jMdvbRLX-7+ z$GR}V)u4kNpc7|QO6sj?BY07Tn%ALK6N0NEgYC`0^6HD_(A9JT_c{z3d{wySf<{j< wP7h6YxMaXb*p(h88JRQs2*Fz6fp82LIjf(GT+}jg86$kDUtGD^wCWfC0OPrj`Tzg` literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/exceptions.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7bef599204b8aad4bfe9d979d07bf95469a45b5 GIT binary patch literal 6249 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 To73N$dw&jp3)7|P!kqOVueA-B literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/logger.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/logger.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db55ac2be97be4535d3c81a9a53d5a345df13c4e GIT binary patch literal 242 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 PW|sJpnNz8y!Q}q}0-*3u literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/requests.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/requests.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6822205ad313e83313712ce2af02847737e1393 GIT binary patch literal 272 zcmd1j<>g`kf)oAXX?;NYF^GcarasIF#rGn literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/responses.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/responses.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e906aa75ae6fb4b159f3389f283b38975cf831e4 GIT binary patch literal 1949 zcmds2&2QX96!-XRztb&E+Y>NC2z8~z=Hmhgp@u4fly(#Crb02QEXOmObz^(nnQ>rO zoM^8V{{kHIpK#zW@C|X|+yjV9dC!}zHdS-r%6RAb_uh=&%=`H_v!d5)8_<6J>E`5j z*D(G-XSFrKxeZeQ4z5yXBm2(0w^){BllrG3QHz zwOQw>!8+V|Vg)_$yQ~L(ulCniYitbG{)CE*0jaF5d!GEBHL0F*I!%tJn+2B> zA+sotIV~S4k<&Cel98NIEvVu$iPB`wDT{Q35zOVa>$D>tF`5a=q?O%wR#n7AJO zb|+GLYk!wA5i1Hy&^x8lBBRT4=_W;9H|T~dU$K9b)i1>{RyOrip0}N zlpl*!c(KU*h@IkwnIG3VHIP{xz2FDu^=deMd=ZTYGG?>${7+9doth z(O*)fykdsztI+ZbE+!7mm?1Y;vPf$1Xhy67ML``P$y-g3$l| zZ$cOH|DyC-EwTr!TrTnVVD$A82cetLtuNpTe`bQnt>N4|C+AX?U!)#X?utSuA|Kd* zYGP#{Rt)-k`v>80Zy1gbM&Z}nhvVQHM#kHt-K~4O!FD)&aDV?$z5#Pz)ddP>1G>UL zoj$Qim$)zH*DtQTRHj4)tz^K1BWroR1qjc#d=m|NgDaJ*X9e7VwLpVwaDrvZwdRm* zap5az;cPq((m{jTlnpev8`(m01x(f1%?cs)wv<9jiec1qz0T{lQ#C(Z9GcGwOjEbO abd9drh2oZvS$j=lzA$Z!A?n-fy?+7YU;%~z literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/routing.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/routing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3410fa1c078a12159d9d764376039974082e7881 GIT binary patch literal 56501 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 C3wPxJ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/staticfiles.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/staticfiles.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c0c429455c0e8a30d92c9d3ef62ba7a836220226 GIT binary patch literal 245 zcmYjKIS#@w5VS*sKu9!*H>AMJQ6V8j10@X|4KneDSaD(#8zlGy@8BoAftHFdP_dz6 zq@CH>k#=mS(_)0jt)DJQU$yy1L}o$byF`j9Zdk#$oHG?|SloEimBswo-UJzRveE|q zI*ztIA7o`P1QfJUlGaI8f4j4)LGq)|4l-LHs4PED#~|EkZ?w-K)uk*G6j!Ug$SV+M xEYD!{9^55lww#F35WEgJa5Bl|0X?LWikybOI^izQ=B%*lWN^-@)7Sl7_66yTL8$-$ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/templating.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/templating.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adcafbef35a7864931ccc4dda6f019813d552338 GIT binary patch literal 247 zcmd1j<>g`kf)oAXX+A*uF^Gc(44TX@fuanW zjJNo`GV`($jY3j$3vv=mQj7gGnW99BOA?E6QcFrw^-3V(nR)3&AOlx26fpxSF!3u+ zKO;XkRX-&oyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+* zKhIdt&_KU9vm{lwATc>RF+H_dKP?exV?m}q!Zy8v%3B;Zx%nxjIjMGxKr4$u)(bEI E0DTEUSO5S3 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/testclient.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/testclient.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49e5d4acaa6dae4f559ffe106fb0ac8b1f8dcfaf GIT binary patch literal 242 zcmd1j<>g`kf)oAXX-+`;F^Gc(44TX@fuanW zjJLQ#Qj1HRb23x&O8hjLqC|>I5{q(DOG;ApN`Ml{V2L7-St}Wen1K|S_!Xz0k)NBY zpOTSXXlbOcS5TUilUbahpO%@In3tTYSCyYxte0J+uUD3uSEiqnnWSG(S(1^TXRK#v ypkJI>lB!#fn4F!Mo?5J*mI$=5AX6VU2AP8INplo!htj5 zIV$lWJcF;Ccm+<3w?e{_f1ZE*pUK2=Kbcen$ItI~mtQC$zk>LGIG*YdGhFkEL-eePg<_PuIlGLSn$55AC|w z(2Diu)t$V9zSYF>EPkOyA5B# p*e?0#_#oT;r!@l}<8$4Mt%4VLX~;N56r`s2X&ud?n%<)i=wGzhnwJ0o literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4cc3684004bc8298fadec1a91747a3a413da7c1 GIT binary patch literal 5896 zcmaJ_&2!vFb_W_53)|e zU@&T6NRt6CE7!(3IH|4Ly~K7ERh6pL{sTGYyoaPJw^ZSnoOI10n>exHP?*B;&E?Wwe@Jio51=? zbSR$mCgUk@DxUVH@n<^Nz*y-n{BpqvP=j??imk zJE{71tByUWiY7r*%zK$VA@^L=#iRt}-AHw*Ua71HH!{{WR!sr6m#SH#aT*rU9Q{{&- zYX)>Jte+J%Q56kwgmysx2>LWWhh5HzSsLX>F?R~}F}yp4dLA`);K#*j4i2&7bZ45M zzQ6^@Yw~5YzlL=6&ZBgZUOe!(aTw@|ubp;`=4Vd!u9Xm-$)n-Qo>?4zwFM z$q)DfMlSI4;MEeA;;MO|JqBr5yu~kI)^=&zoRw&^a)wpQbRB5Ve0cB3))eTrj1%LdiTRyZ~2SwytVk#8%u8&#v9$O z!n_`~vtsOKKMR&4aWm-k!tP38zt_vcq#HzqaYtl@d3UQPipu+4j1^`(NHb7BbWa59 zKNVXoHv71EGFGfxKcPb6E32kgd*a_@mpIw=w@O2 zPJ30v!P}xMWI#0Dk}{D+?fotnovK3PT3v%`D@%8;Sy<{Bm+s&9 zj8~|*OvRP^_lqioMrZeoi}&w8`8}pxGf;#Vz{Qh)M(fGHpukCtu$wiQJb|7!)$U74 zVm!e9?=<-$-hK69Yc+{Qi?6Of{L!UWv)5ma!gRF-%>>=HXl^HA+FX~d=7#8Qw4!ji z)!WKelkVl_#S5(z!aLs!+UvoJNLw9POwbEk{Va^qW^b!F3Cmng_?90;QL-tx-$~>_ z7S3V+w2s2oP2FauZR?Y|d>I3U*$cAOZ%LM5q~LziclvZ8!!k`y)@AbdY@4+-pEiV$+o(?Iqn*xJm|1_jVAbB6Y)#t3>IBXm^z$n`$wX=mgzv0+)l>m0aZ&oEx%g zqLP=Xc!dTm*`oFZDqJcqQbF#g7HnU-QPOn-xstlD!smE7<-P-NdDR6_wb$KjHOSoH zLl_*f6u62dcZg;s_lo7Fd!yrSC4G<;Za)R2Vs;4%>b?7n`;sWg;W&ScNX}Su2 ze|CEys|A+>co*EIq$@sZsLk3z7lSDQxw|p|RqULtif5-%Hs^L^6032N??GlZ!)#T( zAiH;y-T;_gF4_q&8uC%TAOMZ~G)w$^jTnLIM8MrRk>XW%HOqSGtF58;H?uJ4t|U>? zY$tIm>w_5Vxi!@NdBs_4NjYGnCPzs}b0`X{-vj0gIZmDW?LHz$EL5nF zyJL^F>)J>49WxuxP3&)c2C!Hg&CRumtJ=fYvqRux0(4BQte`!aSNuuTQ>dpCMSTSI5!7?2=TIL-eH8UE`K!OuIy$d#>l2&$*AX-E?ikwh^4H)7 z^?;v>KabvVygiQk1nLv0Poh4F+C}Z6K7|_3?hB6rUwH*lqq`z>u{qp&o_oIPuA`{nPU*t{Ag?I238 zp)p+9I9+<&aV#z|lY(4PT@BJ8%cOjr#;2*6rDB8%iaCXWC@JZ5Bo>N)zVA7H$!Y5Q zg$0o8i&VZzD-=4Dv3oTTM)XIRQ$YN^2u)rIpr;hU@4_*>@j);ZSh*Q&rJl1dl+>%O zi>-27Zy1vibiJ{j6bFK^H{MIq?BIX{M1wNdQslOkbT#M+Z>pE{`VpmugAG9lp@ckL zxuZ7<>{>w{6e(Br>^=yP(-wNit0AHd6h&!NsVzz0yK)dt-);-nai2W|_=>YMC^L>Go6Gd^W?>)h>k<3*=(Fjg8cgu)@T%pC`SJ zPNuElVwJ(K;kO2?Ui%!D`MLHbp@Xq&auWgEcx;f*BaByawp)3OIbW&~*sZm+EeGJ+ zEOWa-*b)AI=L`C4ukK%lbj~pAQ2k{{KV%0|=y(C`<#$5B#^ju3KZsU!j|O zM7$#D8X@P={tjO3>*pQ31uBt7pe3afXlmEMB^4B-GJ7|YxgsSsT(VzufGR;ZC#2t8*AU?wu(L5tG`OkZkLiVE&FaauSb@;aCx?m~sB4m81q z=&9rQgOtSs^RTW5sN_c|3IiZjR1_pWCq)_H{XgMJ>0&m4TTfkQdp2WFC(N>4M|;L} znE9V-ZsBx72`D3OiV^W~CIi(@zhzWIS-wq_$?$W8&0L?w?I33e-6L>yEjMr*VCiIT zFa*Cl+QTZP6AgX)-&DGN3!e|*s5rEX1n?K%y<`6(b(go`)@fUGIVHP283G}*t)`<0 z+(iben00~TZkD)!^UNo|4!)P%0k@}nwBQ3e?;(|yo46Y+s2sH8BW*_jsDbB}Tb#T}IS4>y;RAiVELS2pKw|u`+JL0P^Tai*e%z0>gU=g}-FTn8S(ch%ZBIh{Lak~|_6PYU|V*CZ##mN45CWLxAVqqa3!W1N(RnkI9*d{3< zl2s~fDkz1JgcB;GD5{(IrX)p2(%oPF2!%I33^2GT$AGIcO&O#2bRkez0C|X7gt?NE zEtRKuGsA_%8c?j?h6R8-(z%>L;n~AumN^Y2F-Q*vM{la+D^*tz?@)OdA6_Q9DMCpq zkJ9WaK{=h06e%fpD#m^P+2sxikUT@91{f&JC z2h{TnZtbhMD)l3AjgUP34GIU}N$UE7ULUd9S$zU`j5_`%5CmDqQ)Co-^Oc!HtUA1j zP;LGJ<(>sh88g^7$R@saD(rtPi+yEP+5cF$msmCS2j)2c#jaT2(A*i!W2W;p`yuuA YALcxr9Dm7XlMY55&~psuo0-Y~15(WZM*si- literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/__pycache__/websockets.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/__pycache__/websockets.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90fdf6e269b55ac20111a4061fd9503c6c3bc010 GIT binary patch literal 320 zcmYk0Jx;_h5QXg|ivaB+B#^iQDX{sekPxDv-X;Z73M9vw5G#&tZ11Aw5}bpZaE2{t zsJH?Z<1H3On&Zj<)7r1!;`|nZ^g(aTP^`d0EuQAquY{Mqn?{gv|%R zr(1lUq(FHmev&xJ&m-^c2)ylw=j%((+@jGc^t@9>7zymvs=x-%*%Hi>Yt?YKioG>g r?BbjU72(VYIfy3+yc3x16#vU*ZnfUM8Ew1Ja7!^Q?4V4^lpfMw5?ECn literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/_compat.py b/.venv/lib/python3.10/site-packages/fastapi/_compat.py new file mode 100644 index 0000000..35d4a87 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/_compat.py @@ -0,0 +1,634 @@ +from collections import deque +from copy import copy +from dataclasses import dataclass, is_dataclass +from enum import Enum +from typing import ( + Any, + Callable, + Deque, + Dict, + FrozenSet, + List, + Mapping, + Sequence, + Set, + Tuple, + Type, + Union, +) + +from fastapi.exceptions import RequestErrorModel +from fastapi.types import IncEx, ModelNameMap, UnionType +from pydantic import BaseModel, create_model +from pydantic.version import VERSION as PYDANTIC_VERSION +from starlette.datastructures import UploadFile +from typing_extensions import Annotated, Literal, get_args, get_origin + +PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.") + + +sequence_annotation_to_type = { + Sequence: list, + List: list, + list: list, + Tuple: tuple, + tuple: tuple, + Set: set, + set: set, + FrozenSet: frozenset, + frozenset: frozenset, + Deque: deque, + deque: deque, +} + +sequence_types = tuple(sequence_annotation_to_type.keys()) + +if PYDANTIC_V2: + from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError + from pydantic import TypeAdapter + 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 + 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 + + 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 + ) + + Required = PydanticUndefined + Undefined = PydanticUndefined + UndefinedType = PydanticUndefinedType + evaluate_forwardref = eval_type_lenient + Validator = Any + + class BaseConfig: + pass + + class ErrorWrapper(Exception): + pass + + @dataclass + class ModelField: + field_info: FieldInfo + name: str + mode: Literal["validation", "serialization"] = "validation" + + @property + def alias(self) -> str: + a = self.field_info.alias + return a if a is not None else self.name + + @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: + self._type_adapter: TypeAdapter[Any] = TypeAdapter( + Annotated[self.field_info.annotation, self.field_info] + ) + + 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(), 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 get_annotation_from_field_info( + annotation: Any, field_info: FieldInfo, field_name: str + ) -> Any: + return annotation + + def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]: + return errors # type: ignore[return-value] + + def _model_rebuild(model: Type[BaseModel]) -> None: + model.model_rebuild() + + def _model_dump( + model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any + ) -> Any: + return model.model_dump(mode=mode, **kwargs) + + def _get_model_config(model: BaseModel) -> Any: + return model.model_config + + def get_schema_from_model_field( + *, + field: ModelField, + schema_generator: GenerateJsonSchema, + 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 else "validation" + ) + # 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_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: + return {} + + def get_definitions( + *, + fields: List[ModelField], + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, + ) -> Tuple[ + Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + Dict[str, Dict[str, Any]], + ]: + override_mode: Union[Literal["validation"], None] = ( + None if separate_input_output_schemas else "validation" + ) + inputs = [ + (field, override_mode or field.mode, field._type_adapter.core_schema) + for field in fields + ] + field_mapping, definitions = schema_generator.generate_definitions( + inputs=inputs + ) + return field_mapping, definitions # type: ignore[return-value] + + def is_scalar_field(field: ModelField) -> bool: + from fastapi import params + + return field_annotation_is_scalar( + field.field_info.annotation + ) and not isinstance(field.field_info, params.Body) + + def is_sequence_field(field: ModelField) -> bool: + return field_annotation_is_sequence(field.field_info.annotation) + + def is_scalar_sequence_field(field: ModelField) -> bool: + return field_annotation_is_scalar_sequence(field.field_info.annotation) + + def is_bytes_field(field: ModelField) -> bool: + return is_bytes_or_nonable_bytes_annotation(field.type_) + + def is_bytes_sequence_field(field: ModelField) -> bool: + return 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 + ) + assert issubclass(origin_type, sequence_types) # type: ignore[arg-type] + return sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return] + + def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: + error = ValidationError.from_exception_data( + "Field required", [{"type": "missing", "loc": loc, "input": {}}] + ).errors()[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 + +else: + from fastapi.openapi.constants import REF_PREFIX as REF_PREFIX + from pydantic import AnyUrl as Url # noqa: F401 + from pydantic import ( # type: ignore[assignment] + BaseConfig as BaseConfig, # noqa: F401 + ) + from pydantic import ValidationError as ValidationError # noqa: F401 + from pydantic.class_validators import ( # type: ignore[no-redef] + Validator as Validator, # noqa: F401 + ) + from pydantic.error_wrappers import ( # type: ignore[no-redef] + ErrorWrapper as ErrorWrapper, # noqa: F401 + ) + from pydantic.errors import MissingError + from pydantic.fields import ( # type: ignore[attr-defined] + SHAPE_FROZENSET, + SHAPE_LIST, + SHAPE_SEQUENCE, + SHAPE_SET, + SHAPE_SINGLETON, + SHAPE_TUPLE, + SHAPE_TUPLE_ELLIPSIS, + ) + from pydantic.fields import FieldInfo as FieldInfo + from pydantic.fields import ( # type: ignore[no-redef,attr-defined] + ModelField as ModelField, # noqa: F401 + ) + from pydantic.fields import ( # type: ignore[no-redef,attr-defined] + Required as Required, # noqa: F401 + ) + from pydantic.fields import ( # type: ignore[no-redef,attr-defined] + Undefined as Undefined, + ) + from pydantic.fields import ( # type: ignore[no-redef, attr-defined] + UndefinedType as UndefinedType, # noqa: F401 + ) + from pydantic.schema import ( + field_schema, + get_flat_models_from_fields, + get_model_name_map, + model_process_schema, + ) + from pydantic.schema import ( # type: ignore[no-redef] # noqa: F401 + get_annotation_from_field_info as get_annotation_from_field_info, + ) + from pydantic.typing import ( # type: ignore[no-redef] + evaluate_forwardref as evaluate_forwardref, # noqa: F401 + ) + from pydantic.utils import ( # type: ignore[no-redef] + lenient_issubclass as lenient_issubclass, # noqa: F401 + ) + + GetJsonSchemaHandler = Any # type: ignore[assignment,misc] + JsonSchemaValue = Dict[str, Any] # type: ignore[misc] + CoreSchema = Any # type: ignore[assignment,misc] + + sequence_shapes = { + SHAPE_LIST, + SHAPE_SET, + SHAPE_FROZENSET, + SHAPE_TUPLE, + SHAPE_SEQUENCE, + SHAPE_TUPLE_ELLIPSIS, + } + sequence_shape_to_type = { + SHAPE_LIST: list, + SHAPE_SET: set, + SHAPE_TUPLE: tuple, + SHAPE_SEQUENCE: list, + SHAPE_TUPLE_ELLIPSIS: list, + } + + @dataclass + class GenerateJsonSchema: # type: ignore[no-redef] + ref_template: str + + class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef] + pass + + def with_info_plain_validator_function( # type: ignore[misc] + function: Callable[..., Any], + *, + ref: Union[str, None] = None, + metadata: Any = None, + serialization: Any = None, + ) -> Any: + return {} + + def get_model_definitions( + *, + flat_models: Set[Union[Type[BaseModel], Type[Enum]]], + model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str], + ) -> Dict[str, Any]: + definitions: Dict[str, Dict[str, Any]] = {} + for model in flat_models: + m_schema, m_definitions, m_nested_models = model_process_schema( + model, model_name_map=model_name_map, ref_prefix=REF_PREFIX + ) + definitions.update(m_definitions) + model_name = model_name_map[model] + if "description" in m_schema: + m_schema["description"] = m_schema["description"].split("\f")[0] + definitions[model_name] = m_schema + return definitions + + def is_pv1_scalar_field(field: ModelField) -> bool: + from fastapi import params + + field_info = field.field_info + if not ( + field.shape == SHAPE_SINGLETON # type: ignore[attr-defined] + and not lenient_issubclass(field.type_, BaseModel) + and not lenient_issubclass(field.type_, dict) + and not field_annotation_is_sequence(field.type_) + and not is_dataclass(field.type_) + and not isinstance(field_info, params.Body) + ): + return False + if field.sub_fields: # type: ignore[attr-defined] + if not all( + is_pv1_scalar_field(f) + for f in field.sub_fields # type: ignore[attr-defined] + ): + return False + return True + + def is_pv1_scalar_sequence_field(field: ModelField) -> bool: + if (field.shape in sequence_shapes) and not lenient_issubclass( # type: ignore[attr-defined] + field.type_, BaseModel + ): + if field.sub_fields is not None: # type: ignore[attr-defined] + for sub_field in field.sub_fields: # type: ignore[attr-defined] + if not is_pv1_scalar_field(sub_field): + return False + return True + if _annotation_is_sequence(field.type_): + return True + return False + + def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]: + use_errors: List[Any] = [] + for error in errors: + if isinstance(error, ErrorWrapper): + new_errors = ValidationError( # type: ignore[call-arg] + errors=[error], model=RequestErrorModel + ).errors() + use_errors.extend(new_errors) + elif isinstance(error, list): + use_errors.extend(_normalize_errors(error)) + else: + use_errors.append(error) + return use_errors + + def _model_rebuild(model: Type[BaseModel]) -> None: + model.update_forward_refs() + + def _model_dump( + model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any + ) -> Any: + return model.dict(**kwargs) + + def _get_model_config(model: BaseModel) -> Any: + return model.__config__ # type: ignore[attr-defined] + + def get_schema_from_model_field( + *, + field: ModelField, + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + field_mapping: Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + separate_input_output_schemas: bool = True, + ) -> Dict[str, Any]: + # This expects that GenerateJsonSchema was already used to generate the definitions + return field_schema( # type: ignore[no-any-return] + field, model_name_map=model_name_map, ref_prefix=REF_PREFIX + )[0] + + def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: + models = get_flat_models_from_fields(fields, known_models=set()) + return get_model_name_map(models) # type: ignore[no-any-return] + + def get_definitions( + *, + fields: List[ModelField], + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, + ) -> Tuple[ + Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + Dict[str, Dict[str, Any]], + ]: + models = get_flat_models_from_fields(fields, known_models=set()) + return {}, get_model_definitions( + flat_models=models, model_name_map=model_name_map + ) + + def is_scalar_field(field: ModelField) -> bool: + return is_pv1_scalar_field(field) + + def is_sequence_field(field: ModelField) -> bool: + return field.shape in sequence_shapes or _annotation_is_sequence(field.type_) # type: ignore[attr-defined] + + def is_scalar_sequence_field(field: ModelField) -> bool: + return is_pv1_scalar_sequence_field(field) + + def is_bytes_field(field: ModelField) -> bool: + return lenient_issubclass(field.type_, bytes) + + def is_bytes_sequence_field(field: ModelField) -> bool: + return field.shape in sequence_shapes and lenient_issubclass(field.type_, bytes) # type: ignore[attr-defined] + + def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: + return copy(field_info) + + def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: + return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return,attr-defined] + + def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: + missing_field_error = ErrorWrapper(MissingError(), loc=loc) # type: ignore[call-arg] + new_error = ValidationError([missing_field_error], RequestErrorModel) + return new_error.errors()[0] # type: ignore[return-value] + + def create_body_model( + *, fields: Sequence[ModelField], model_name: str + ) -> Type[BaseModel]: + BodyModel = create_model(model_name) + for f in fields: + BodyModel.__fields__[f.name] = f # type: ignore[index] + return BodyModel + + +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 _normalize_errors(errors) + ] + + return updated_loc_errors + + +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: + 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)) # type: ignore[arg-type] + + +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)) + + 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) + ) diff --git a/.venv/lib/python3.10/site-packages/fastapi/applications.py b/.venv/lib/python3.10/site-packages/fastapi/applications.py new file mode 100644 index 0000000..4446cac --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/applications.py @@ -0,0 +1,4585 @@ +from enum import Enum +from typing import ( + Any, + Awaitable, + Callable, + Coroutine, + Dict, + List, + Optional, + Sequence, + Type, + TypeVar, + Union, +) + +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.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.requests import Request +from starlette.responses import HTMLResponse, JSONResponse, Response +from starlette.routing import BaseRoute +from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send +from typing_extensions import Annotated, Doc, 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.io/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 + default value would be a `dict` with a `url` value of `/`. + + 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-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, + **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.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 woudln'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.io/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 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, + ) + 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[..., Coroutine[Any, Any, Response]], + *, + 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-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-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-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-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-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-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-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-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.put("/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 fastapi import FastAPI, Request + + app = FastAPI() + + + @app.middleware("http") + async def add_process_time_header(request: Request, call_next): + 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/.venv/lib/python3.10/site-packages/fastapi/background.py b/.venv/lib/python3.10/site-packages/fastapi/background.py new file mode 100644 index 0000000..203578a --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/background.py @@ -0,0 +1,59 @@ +from typing import Any, Callable + +from starlette.background import BackgroundTasks as StarletteBackgroundTasks +from typing_extensions import Annotated, Doc, 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/.venv/lib/python3.10/site-packages/fastapi/concurrency.py b/.venv/lib/python3.10/site-packages/fastapi/concurrency.py new file mode 100644 index 0000000..894bd3e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/concurrency.py @@ -0,0 +1,39 @@ +from contextlib import asynccontextmanager as asynccontextmanager +from typing import AsyncGenerator, ContextManager, TypeVar + +import anyio +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: ContextManager[_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, None, 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/.venv/lib/python3.10/site-packages/fastapi/datastructures.py b/.venv/lib/python3.10/site-packages/fastapi/datastructures.py new file mode 100644 index 0000000..cf8406b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/datastructures.py @@ -0,0 +1,204 @@ +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Iterable, + Optional, + Type, + TypeVar, + cast, +) + +from fastapi._compat import ( + PYDANTIC_V2, + CoreSchema, + GetJsonSchemaHandler, + JsonSchemaValue, + with_info_plain_validator_function, +) +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 +from typing_extensions import Annotated, Doc + + +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 __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]: + yield cls.validate + + @classmethod + def validate(cls: Type["UploadFile"], v: Any) -> Any: + if not isinstance(v, StarletteUploadFile): + raise ValueError(f"Expected UploadFile, received: {type(v)}") + return v + + @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) + + if not PYDANTIC_V2: + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update({"type": "string", "format": "binary"}) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + return {"type": "string", "format": "binary"} + + @classmethod + def __get_pydantic_core_schema__( + cls, source: Type[Any], handler: Callable[[Any], CoreSchema] + ) -> CoreSchema: + 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/.venv/lib/python3.10/site-packages/fastapi/dependencies/__init__.py b/.venv/lib/python3.10/site-packages/fastapi/dependencies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1053f0a2f93dfd15be6dd78985f2f1ee8f124458 GIT binary patch literal 198 zcmd1j<>g`kf)oAXX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10VKO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKP|DiB(We2KczG$ O)ehu@VkRKL!TGt+irLFO!q9A$*?3qP$SXJaza8V5Cj(p5|fiJmfKZ5ZQ5I^+(8rh zmfZOR{DJTzIP)9o$_Wv62oONwz3L?NNQ)TprvRdbuu?_b?tqPn$)_fQR@Z? zJm75F0xqZ(ESD^YeP#KZ|A4dxfG>oG)b8>KS)F+osY^YDe@?l&M~{XV0p}j zy7WFQC`;c8Bv_2nnym%QMHu2G0Hy^x)dJ$`pa)?FHJHgPW*=w= z+SF8`1)1jZ#8VhfW6S&_d!di9mDNGkSn8O8JHgo*Jq5>-?tW6DaF zQ?O(Liy0bHj7qS47$$jAg`oqV6()dfc>49DhZteBKFWR6-NCzgl(8_BUKoPNMT)c^ zhF2F+y4>L?mRkrmfHXwKIa)^jW&?V-2BD~-;{@8k(Fif`5uM!g^zJ>i_dhSc2vY0xgx6mG&@PpzwHqHUmCu;#<;&<=B_ zM4job)_bdYYc+4L=Kg9PtmYkFQkbMmSzlz zEBhRiR8&hrDk$X6r)(mMc+UQ_dN`}9GK`BnXEA1Y^TvQPQ5Lya>9Z7bb^?KX!iz;t z!zvPU(Y$fk&`DCB*zhCuQbs@d=FxV?<1T+I6yc=IE!$E@D#$+03-ek zlFuTXLpYD{9K!PmFCbh%z>t(SXVrq|u?`HjK8yhjOaxUNz5t@uOXEaa7KqYOlwKQU zM^U6U%f6zF+A8-IW!83iq$sOymFE;?*B(e{)onnh_5t0x1L)OVz;?X_=+`~KPVE48 zYZtIrZv$@CeL$c-=~ew|Q0)Nammi*JH+1Y%EL*!+ww4LM_jrp1yBlv{IIJqCc(mb^ z&6M>vW^S0!sum@@2ev49#V8aGR!LX6FPyW};edC*gpb$g0UthElZUwQ!P0~^3x_}_ zdwZUKzuWplIyq0S_cwXDDV;-~Z=>EA5F8_7SsStLa;$u+%<&zh3y^wCvw z7tUb$6cqqeO%rP76S{rdGsr)lN&faM@|S0myIza@={e*N&n3Ux9=X$PlizHg{Azc| zFLsywZ1>1d_7?fk-X=eIeeyjSknijra+~aSzvZaG<)JU_>aXGIXU+)@y F=U))U2-N@p literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/dependencies/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6613efa8f0a5bb7027b355557eb8ac2b95a377c4 GIT binary patch literal 18569 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 lK+=C None: + self.path_params = path_params or [] + self.query_params = query_params or [] + self.header_params = header_params or [] + self.cookie_params = cookie_params or [] + self.body_params = body_params or [] + self.dependencies = dependencies or [] + self.security_requirements = security_schemes or [] + self.request_param_name = request_param_name + self.websocket_param_name = websocket_param_name + self.http_connection_param_name = http_connection_param_name + self.response_param_name = response_param_name + self.background_tasks_param_name = background_tasks_param_name + self.security_scopes = security_scopes + self.security_scopes_param_name = security_scopes_param_name + self.name = name + self.call = call + self.use_cache = use_cache + # Store the path to be able to re-generate a dependable from it in overrides + self.path = path + # Save the cache key at creation to optimize performance + self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or [])))) diff --git a/.venv/lib/python3.10/site-packages/fastapi/dependencies/utils.py b/.venv/lib/python3.10/site-packages/fastapi/dependencies/utils.py new file mode 100644 index 0000000..4f98417 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/dependencies/utils.py @@ -0,0 +1,818 @@ +import inspect +from contextlib import AsyncExitStack, contextmanager +from copy import copy, deepcopy +from typing import ( + Any, + Callable, + Coroutine, + Dict, + ForwardRef, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) + +import anyio +from fastapi import params +from fastapi._compat import ( + PYDANTIC_V2, + ErrorWrapper, + ModelField, + Required, + Undefined, + _regenerate_error_with_loc, + copy_field_info, + create_body_model, + evaluate_forwardref, + field_annotation_is_scalar, + get_annotation_from_field_info, + 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, SecurityRequirement +from fastapi.logger import logger +from fastapi.security.base import SecurityBase +from fastapi.security.oauth2 import OAuth2, SecurityScopes +from fastapi.security.open_id_connect_url import OpenIdConnect +from fastapi.utils import create_response_field, get_path_param_names +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, QueryParams, UploadFile +from starlette.requests import HTTPConnection, Request +from starlette.responses import Response +from starlette.websockets import WebSocket +from typing_extensions import Annotated, 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 check_file_field(field: ModelField) -> None: + field_info = field.field_info + if isinstance(field_info, params.Form): + try: + # __version__ is available in both multiparts, and can be mocked + from multipart import __version__ # type: ignore + + assert __version__ + try: + # parse_options_header is only available in the right multipart + from multipart.multipart import parse_options_header # type: ignore + + 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_param_sub_dependant( + *, + param_name: str, + depends: params.Depends, + path: str, + security_scopes: Optional[List[str]] = None, +) -> Dependant: + assert depends.dependency + return get_sub_dependant( + depends=depends, + dependency=depends.dependency, + path=path, + name=param_name, + security_scopes=security_scopes, + ) + + +def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant: + assert callable( + depends.dependency + ), "A parameter-less dependency must have a callable dependency" + return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path) + + +def get_sub_dependant( + *, + depends: params.Depends, + dependency: Callable[..., Any], + path: str, + name: Optional[str] = None, + security_scopes: Optional[List[str]] = None, +) -> Dependant: + security_requirement = None + security_scopes = security_scopes or [] + if isinstance(depends, params.Security): + dependency_scopes = depends.scopes + security_scopes.extend(dependency_scopes) + if isinstance(dependency, SecurityBase): + use_scopes: List[str] = [] + if isinstance(dependency, (OAuth2, OpenIdConnect)): + use_scopes = security_scopes + security_requirement = SecurityRequirement( + security_scheme=dependency, scopes=use_scopes + ) + sub_dependant = get_dependant( + path=path, + call=dependency, + name=name, + security_scopes=security_scopes, + use_cache=depends.use_cache, + ) + if security_requirement: + sub_dependant.security_requirements.append(security_requirement) + return sub_dependant + + +CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] + + +def get_flat_dependant( + dependant: Dependant, + *, + skip_repeats: bool = False, + visited: Optional[List[CacheKey]] = None, +) -> Dependant: + if visited is None: + visited = [] + visited.append(dependant.cache_key) + + 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(), + security_schemes=dependant.security_requirements.copy(), + use_cache=dependant.use_cache, + path=dependant.path, + ) + 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 + ) + 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.security_requirements.extend(flat_sub.security_requirements) + return flat_dependant + + +def get_flat_params(dependant: Dependant) -> List[ModelField]: + flat_dependant = get_flat_dependant(dependant, skip_repeats=True) + return ( + flat_dependant.path_params + + flat_dependant.query_params + + flat_dependant.header_params + + flat_dependant.cookie_params + ) + + +def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: + signature = inspect.signature(call) + globalns = getattr(call, "__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) + return annotation + + +def get_typed_return_annotation(call: Callable[..., Any]) -> Any: + signature = inspect.signature(call) + annotation = signature.return_annotation + + if annotation is inspect.Signature.empty: + return None + + globalns = getattr(call, "__globals__", {}) + return get_typed_annotation(annotation, globalns) + + +def get_dependant( + *, + path: str, + call: Callable[..., Any], + name: Optional[str] = None, + security_scopes: Optional[List[str]] = None, + use_cache: bool = True, +) -> Dependant: + path_param_names = get_path_param_names(path) + endpoint_signature = get_typed_signature(call) + signature_params = endpoint_signature.parameters + dependant = Dependant( + call=call, + name=name, + path=path, + security_scopes=security_scopes, + use_cache=use_cache, + ) + for param_name, param in signature_params.items(): + is_path_param = param_name in path_param_names + type_annotation, depends, param_field = analyze_param( + param_name=param_name, + annotation=param.annotation, + value=param.default, + is_path_param=is_path_param, + ) + if depends is not None: + sub_dependant = get_param_sub_dependant( + param_name=param_name, + depends=depends, + path=path, + security_scopes=security_scopes, + ) + dependant.dependencies.append(sub_dependant) + continue + if add_non_field_param_to_dependency( + param_name=param_name, + type_annotation=type_annotation, + dependant=dependant, + ): + assert ( + param_field is None + ), f"Cannot specify multiple FastAPI annotations for {param_name!r}" + continue + assert param_field is not None + if is_body_param(param_field=param_field, is_path_param=is_path_param): + dependant.body_params.append(param_field) + else: + add_param_to_fields(field=param_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 + + +def analyze_param( + *, + param_name: str, + annotation: Any, + value: Any, + is_path_param: bool, +) -> Tuple[Any, Optional[params.Depends], Optional[ModelField]]: + 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 + 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 + if isinstance(fastapi_annotation, FieldInfo): + # Copy `field_info` because we mutate `field_info.default` below. + field_info = copy_field_info( + field_info=fastapi_annotation, annotation=use_annotation + ) + assert field_info.default is Undefined or field_info.default is Required, ( + 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 = Required + elif isinstance(fastapi_annotation, params.Depends): + depends = fastapi_annotation + + 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 + elif isinstance(value, FieldInfo): + assert field_info is None, ( + "Cannot specify FastAPI annotations in `Annotated` and default value" + f" together for {param_name!r}" + ) + field_info = value + if PYDANTIC_V2: + field_info.annotation = type_annotation + + if depends is not None and depends.dependency is None: + # Copy `depends` before mutating it + depends = copy(depends) + depends.dependency = type_annotation + + 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}" + elif field_info is None and depends is None: + default_value = value if value is not inspect.Signature.empty else Required + if is_path_param: + # We might check here that `default_value is Required`, 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 + if field_info is not None: + 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 = get_annotation_from_field_info( + use_annotation, + field_info, + param_name, + ) + 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_response_field( + name=param_name, + type_=use_annotation_from_field_info, + default=field_info.default, + alias=alias, + required=field_info.default in (Required, Undefined), + field_info=field_info, + ) + + return type_annotation, depends, field + + +def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool: + if is_path_param: + assert is_scalar_field( + field=param_field + ), "Path params must be of one of the supported types" + return False + elif is_scalar_field(field=param_field): + return False + elif isinstance( + param_field.field_info, (params.Query, params.Header) + ) and is_scalar_sequence_field(param_field): + return False + else: + assert isinstance( + param_field.field_info, params.Body + ), f"Param: {param_field.name} can only be a request body, using Body()" + return True + + +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) + + +def is_coroutine_callable(call: Callable[..., Any]) -> bool: + if inspect.isroutine(call): + return inspect.iscoroutinefunction(call) + if inspect.isclass(call): + return False + dunder_call = getattr(call, "__call__", None) # noqa: B004 + return inspect.iscoroutinefunction(dunder_call) + + +def is_async_gen_callable(call: Callable[..., Any]) -> bool: + if inspect.isasyncgenfunction(call): + return True + dunder_call = getattr(call, "__call__", None) # noqa: B004 + return inspect.isasyncgenfunction(dunder_call) + + +def is_gen_callable(call: Callable[..., Any]) -> bool: + if inspect.isgeneratorfunction(call): + return True + dunder_call = getattr(call, "__call__", None) # noqa: B004 + return inspect.isgeneratorfunction(dunder_call) + + +async def solve_generator( + *, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any] +) -> Any: + if is_gen_callable(call): + cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values)) + elif is_async_gen_callable(call): + cm = asynccontextmanager(call)(**sub_values) + return await stack.enter_async_context(cm) + + +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[Tuple[Callable[..., Any], Tuple[str]], Any]] = None, + async_exit_stack: AsyncExitStack, +) -> Tuple[ + Dict[str, Any], + List[Any], + Optional[StarletteBackgroundTasks], + Response, + Dict[Tuple[Callable[..., Any], Tuple[str]], Any], +]: + values: Dict[str, Any] = {} + errors: List[Any] = [] + if response is None: + response = Response() + del response.headers["content-length"] + response.status_code = None # type: ignore + dependency_cache = dependency_cache or {} + sub_dependant: Dependant + for sub_dependant in dependant.dependencies: + sub_dependant.call = cast(Callable[..., Any], sub_dependant.call) + sub_dependant.cache_key = cast( + Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key + ) + 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, + security_scopes=sub_dependant.security_scopes, + ) + + 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, + ) + ( + sub_values, + sub_errors, + background_tasks, + _, # the subdependency returns the same response we have + sub_dependency_cache, + ) = solved_result + dependency_cache.update(sub_dependency_cache) + if sub_errors: + errors.extend(sub_errors) + continue + if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache: + solved = dependency_cache[sub_dependant.cache_key] + elif is_gen_callable(call) or is_async_gen_callable(call): + solved = await solve_generator( + call=call, stack=async_exit_stack, sub_values=sub_values + ) + elif is_coroutine_callable(call): + solved = await call(**sub_values) + else: + solved = await run_in_threadpool(call, **sub_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 + required_params=dependant.body_params, received_body=body + ) + 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.security_scopes + ) + return values, errors, background_tasks, response, dependency_cache + + +def request_params_to_args( + required_params: Sequence[ModelField], + received_params: Union[Mapping[str, Any], QueryParams, Headers], +) -> Tuple[Dict[str, Any], List[Any]]: + values = {} + errors = [] + for field in required_params: + if is_scalar_sequence_field(field) and isinstance( + received_params, (QueryParams, Headers) + ): + value = received_params.getlist(field.alias) or field.default + else: + value = received_params.get(field.alias) + field_info = field.field_info + assert isinstance( + field_info, params.Param + ), "Params must be subclasses of Param" + loc = (field_info.in_.value, field.alias) + if value is None: + if field.required: + errors.append(get_missing_field_error(loc=loc)) + else: + values[field.name] = deepcopy(field.default) + continue + v_, errors_ = field.validate(value, values, loc=loc) + if isinstance(errors_, ErrorWrapper): + errors.append(errors_) + elif isinstance(errors_, list): + new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=()) + errors.extend(new_errors) + else: + values[field.name] = v_ + return values, errors + + +async def request_body_to_args( + required_params: List[ModelField], + received_body: Optional[Union[Dict[str, Any], FormData]], +) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]: + values = {} + errors: List[Dict[str, Any]] = [] + if required_params: + field = required_params[0] + field_info = field.field_info + embed = getattr(field_info, "embed", None) + field_alias_omitted = len(required_params) == 1 and not embed + if field_alias_omitted: + received_body = {field.alias: received_body} + + for field in required_params: + loc: Tuple[str, ...] + if field_alias_omitted: + loc = ("body",) + else: + loc = ("body", field.alias) + + value: Optional[Any] = None + if received_body is not None: + if (is_sequence_field(field)) and isinstance(received_body, FormData): + value = received_body.getlist(field.alias) + else: + try: + value = received_body.get(field.alias) + except AttributeError: + errors.append(get_missing_field_error(loc)) + continue + if ( + value is None + or (isinstance(field_info, params.Form) and value == "") + or ( + isinstance(field_info, params.Form) + and is_sequence_field(field) + and len(value) == 0 + ) + ): + if field.required: + errors.append(get_missing_field_error(loc)) + else: + values[field.name] = deepcopy(field.default) + continue + 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) # type: ignore[arg-type] + 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) + + v_, errors_ = field.validate(value, values, loc=loc) + + if isinstance(errors_, list): + errors.extend(errors_) + elif errors_: + errors.append(errors_) + else: + values[field.name] = v_ + return values, errors + + +def get_body_field(*, dependant: Dependant, name: str) -> Optional[ModelField]: + flat_dependant = get_flat_dependant(dependant) + if not flat_dependant.body_params: + return None + first_param = flat_dependant.body_params[0] + field_info = first_param.field_info + embed = getattr(field_info, "embed", None) + body_param_names_set = {param.name for param in flat_dependant.body_params} + if len(body_param_names_set) == 1 and not embed: + check_file_field(first_param) + return first_param + # If one field requires to embed, all have to be embedded + # in case a sub-dependency is evaluated with a single unique body field + # That is combined (embedded) with other body fields + for param in flat_dependant.body_params: + setattr(param.field_info, "embed", True) # noqa: B010 + 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_response_field( + name="body", + type_=BodyModel, + required=required, + alias="body", + field_info=BodyFieldInfo(**BodyFieldInfo_kwargs), + ) + check_file_field(final_field) + return final_field diff --git a/.venv/lib/python3.10/site-packages/fastapi/encoders.py b/.venv/lib/python3.10/site-packages/fastapi/encoders.py new file mode 100644 index 0000000..2f9c4a4 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/encoders.py @@ -0,0 +1,341 @@ +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 Any, Callable, Dict, List, Optional, Tuple, Type, Union +from uuid import UUID + +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 typing_extensions import Annotated, Doc + +from ._compat import PYDANTIC_V2, Url, _model_dump + + +# Taken from Pydantic v1 as is +def isoformat(o: Union[datetime.date, datetime.time]) -> str: + return o.isoformat() + + +# Taken from Pydantic v1 as is +# TODO: pv2 should this return strings instead? +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: # type: ignore[operator] + 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): + # TODO: remove when deprecating Pydantic v1 + encoders: Dict[Any, Any] = {} + if not PYDANTIC_V2: + encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined] + if custom_encoder: + encoders.update(custom_encoder) + obj_dict = _model_dump( + obj, + mode="json", + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_none=exclude_none, + exclude_defaults=exclude_defaults, + ) + if "__root__" in obj_dict: + obj_dict = obj_dict["__root__"] + return jsonable_encoder( + obj_dict, + exclude_none=exclude_none, + exclude_defaults=exclude_defaults, + # TODO: remove when deprecating Pydantic v1 + custom_encoder=encoders, + sqlalchemy_safe=sqlalchemy_safe, + ) + if dataclasses.is_dataclass(obj): + 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, 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) + + 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/.venv/lib/python3.10/site-packages/fastapi/exception_handlers.py b/.venv/lib/python3.10/site-packages/fastapi/exception_handlers.py new file mode 100644 index 0000000..6c2ba7f --- /dev/null +++ b/.venv/lib/python3.10/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 HTTP_422_UNPROCESSABLE_ENTITY, 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=HTTP_422_UNPROCESSABLE_ENTITY, + 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/.venv/lib/python3.10/site-packages/fastapi/exceptions.py b/.venv/lib/python3.10/site-packages/fastapi/exceptions.py new file mode 100644 index 0000000..44d4ada --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/exceptions.py @@ -0,0 +1,176 @@ +from typing import Any, Dict, Optional, Sequence, Type, Union + +from pydantic import BaseModel, create_model +from starlette.exceptions import HTTPException as StarletteHTTPException +from starlette.exceptions import WebSocketException as StarletteWebSocketException +from typing_extensions import Annotated, Doc + + +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 ValidationException(Exception): + def __init__(self, errors: Sequence[Any]) -> None: + self._errors = errors + + def errors(self) -> Sequence[Any]: + return self._errors + + +class RequestValidationError(ValidationException): + def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None: + super().__init__(errors) + self.body = body + + +class WebSocketRequestValidationError(ValidationException): + pass + + +class ResponseValidationError(ValidationException): + def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None: + super().__init__(errors) + self.body = body + + def __str__(self) -> str: + message = f"{len(self._errors)} validation errors:\n" + for err in self._errors: + message += f" {err}\n" + return message diff --git a/.venv/lib/python3.10/site-packages/fastapi/logger.py b/.venv/lib/python3.10/site-packages/fastapi/logger.py new file mode 100644 index 0000000..5b2c4ad --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/logger.py @@ -0,0 +1,3 @@ +import logging + +logger = logging.getLogger("fastapi") diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__init__.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/__init__.py new file mode 100644 index 0000000..620296d --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/__init__.py @@ -0,0 +1 @@ +from starlette.middleware import Middleware as Middleware diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b324b3ed78cb5a7a3ff8e0e313640bc6ce3dc2a GIT binary patch literal 251 zcmd1j<>g`kf)oAXX;wh`F^Gc(44TX@fuanW zjJLRaGgDG>Qp*#IQvEcUqC|>I5{q(DOG;Apa^Vt1AhT976fpxSF!3v0KO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKP?exV?m}q!Z!W*_{_Y_lK6PNg34PQHo5sJr8%i~j6l1KLGBP> F003(pL#zM* literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/cors.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/cors.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..169aa153724ae0dc3042e9996688d25392078abe GIT binary patch literal 256 zcmd1j<>g`kf)oAXY5qX^F^Gc(44TX@fuanW zjJNol{eyyiGgDG>Qp*#IQvEcUq9lt;5{q(DOG;Apa^Vts$@xXaMIb|0G88cbDKPOX zSwAB`H&s6+BfHSjNMEm@G$|*uI72@zGcPeOIaRMJKeJdbyGUQJEH$r8KPNLuzo4=t zBR|hr&(J`>II|>Gw;(Y&J25@ASU)WhXl+5JKEg_Ukd=A`mA5!-a`RJ4b5iXXf%X=I I+#tXJ0Om_YX#fBK literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/gzip.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/gzip.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e53646fe582c97db4a1964eae72dca1b2717089 GIT binary patch literal 256 zcmd1j<>g`kf)oAXY5qX^F^Gc(44TX@fuanW zjJNpQqcRJ8GgDG>Qp*#IQvEcUq9lt;5{q(DOG;Apa^Vts=~bBpMIb|0G88cbDKPOX zSwAB`H&s6+BfHSjNMEm@G$|*uI72@zGcPeOIaRMJKeJdbyGUQJEH$r8KPNLuzo4=t zBR|hr&(J`>II|>Gw;(Y&J25@ASU)WhXl+5JKEg_Ukd=A`mA5!-a`RJ4b5iXXf%X=I I+#tXJ02k0jvH$=8 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/httpsredirect.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0ed28d9334f5394abd73d1205bc4701b3cadd88 GIT binary patch literal 283 zcmY*TF-`+95VS81LW-0wJ>3;}6R407qND*Kk}92Z-ow`U&c^Emg-`Gfe!?5lQsoP& zvWF0ak#x4o?N+^L<sN1%QLwq?p%If2Mtaf8g_Ob+Gf@t9ycMO~j_>C4 z$JrAam$1tB&KQrcI^jcEEY2wF5ht$V>h%{jNro9InS_EU8m#Yg< zakcc0EYz;kU4`l`I8sdlwZ?7@-Yp?+vJKs(nofXR#`CDFMn5A#tvNqB_{)ZW*(z?f RC)aH-D~~sl3s7HXBn~7oP|^SZ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/middleware/__pycache__/trustedhost.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab958b9362ff0a68af4d8d8b452078537faf5959 GIT binary patch literal 277 zcmYk0u}%Xq42F~If{-e8L9DDd5VtTPA;ic63ryY8#z(>>mk{TQ%1iJZya~_Hm5Eni z!dIlWmi$}4{Y#(Yczi6lzCKQy!1H@BhgGq;<)#UX5k`6ug`kf)oAXY5qX^F^Gc(44TX@fuanW zjJNp0gWWxSGgDG>Qp*#IQvEcUq9lt;5{q(DOG;Apa^Vts<;CflMIb|0G88cbDKPOX zSwAB`H&s6+BfHSjNMEm@G$|*uI72@zGcPeOIaRMJKeJdbyGUQJEH$r8KPNLuzo4=t zBR|hr&(J`>II|>Gw;(Y&J25@ASU)WhXl+5JKEg_Ukd=A`mA5!-a`RJ4b5iXXf%X=I I+#tXJ0P6uoasU7T literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/cors.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/cors.py new file mode 100644 index 0000000..8dfaad0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/cors.py @@ -0,0 +1 @@ +from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/gzip.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/gzip.py new file mode 100644 index 0000000..bbeb2cc --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/gzip.py @@ -0,0 +1 @@ +from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/httpsredirect.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/httpsredirect.py new file mode 100644 index 0000000..b7a3d8e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/httpsredirect.py @@ -0,0 +1,3 @@ +from starlette.middleware.httpsredirect import ( # noqa + HTTPSRedirectMiddleware as HTTPSRedirectMiddleware, +) diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/trustedhost.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/trustedhost.py new file mode 100644 index 0000000..08d7e03 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/trustedhost.py @@ -0,0 +1,3 @@ +from starlette.middleware.trustedhost import ( # noqa + TrustedHostMiddleware as TrustedHostMiddleware, +) diff --git a/.venv/lib/python3.10/site-packages/fastapi/middleware/wsgi.py b/.venv/lib/python3.10/site-packages/fastapi/middleware/wsgi.py new file mode 100644 index 0000000..c4c6a79 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/middleware/wsgi.py @@ -0,0 +1 @@ +from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__init__.py b/.venv/lib/python3.10/site-packages/fastapi/openapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11e2f1beb4f2169e835ee674326eed0e43b70e16 GIT binary patch literal 193 zcmd1j<>g`kf)oAXX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10HKO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKP|DiB(We9 HBv=>#g#a;X literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/constants.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/constants.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4ba4821659af1519fdeb1b44fcb29b0c433255a GIT binary patch literal 351 zcmZutyH3ME5In~wL=h>FKs0nzDe&^BkWfUx2ac3riyQ*nSdM+cR_wbY=R}GT-#|@G z#h>sE*YX!soT(@nX=iq3o89G|P8(@_zV1xlw0_m*FB;mM>5^NTQk0-~BS47}7)c{& zB<2`(tzJ`))SBNX7p`hLc!&vBmhX*;GOsXEmW%t2GW}apZSO(M3&9y>r34wLw1^~B zyZ^?|1y5-Ha@{q9%@HQ9=ZwR<0dd1~&v^*iH~2F2H4W~Ajk+gzs0T$$Z5~0UseC3g)F0G`~VggW3d1L literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/docs.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/docs.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f8a4aa323950fe0025226fcfc18647794713aa7 GIT binary patch literal 9593 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 W@)Z953rkZ@N%N0dz4UjNn*R%Xes<9S literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/models.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f657dddd5f3ba31cca1d9c799d0dc3ac400dc7c7 GIT binary patch literal 19921 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 IO)1p<{}S3;RR910 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/openapi/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4139b251c52d496bace2ab607b7085e284afaa6e GIT binary patch literal 11633 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/constants.py b/.venv/lib/python3.10/site-packages/fastapi/openapi/constants.py new file mode 100644 index 0000000..d724ee3 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/openapi/constants.py @@ -0,0 +1,3 @@ +METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"} +REF_PREFIX = "#/components/schemas/" +REF_TEMPLATE = "#/components/schemas/{model}" diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/docs.py b/.venv/lib/python3.10/site-packages/fastapi/openapi/docs.py new file mode 100644 index 0000000..67815e0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/openapi/docs.py @@ -0,0 +1,344 @@ +import json +from typing import Any, Dict, Optional + +from fastapi.encoders import jsonable_encoder +from starlette.responses import HTMLResponse +from typing_extensions import Annotated, Doc + +swagger_ui_default_parameters: Annotated[ + Dict[str, Any], + Doc( + """ + Default configurations for Swagger UI. + + You can use it as a template to add any other configurations needed. + """ + ), +] = { + "dom_id": "#swagger-ui", + "layout": "BaseLayout", + "deepLinking": True, + "showExtensions": True, + "showCommonExtensions": True, +} + + +def get_swagger_ui_html( + *, + openapi_url: Annotated[ + str, + Doc( + """ + The OpenAPI URL that Swagger UI 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. + """ + ), + ], + 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.9.0/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.9.0/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""" + <!DOCTYPE html> + <html> + <head> + <link type="text/css" rel="stylesheet" href="{swagger_css_url}"> + <link rel="shortcut icon" href="{swagger_favicon_url}"> + <title>{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@next/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/.venv/lib/python3.10/site-packages/fastapi/openapi/models.py b/.venv/lib/python3.10/site-packages/fastapi/openapi/models.py new file mode 100644 index 0000000..5f3bdbb --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/openapi/models.py @@ -0,0 +1,611 @@ +from enum import Enum +from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union + +from fastapi._compat import ( + PYDANTIC_V2, + CoreSchema, + GetJsonSchemaHandler, + JsonSchemaValue, + _model_rebuild, + with_info_plain_validator_function, +) +from fastapi.logger import logger +from pydantic import AnyUrl, BaseModel, Field +from typing_extensions import Annotated, 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: CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + return {"type": "string", "format": "email"} + + @classmethod + def __get_pydantic_core_schema__( + cls, source: Type[Any], handler: Callable[[Any], CoreSchema] + ) -> CoreSchema: + return with_info_plain_validator_function(cls._validate) + + +class Contact(BaseModel): + name: Optional[str] = None + url: Optional[AnyUrl] = None + email: Optional[EmailStr] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class License(BaseModel): + name: str + identifier: Optional[str] = None + url: Optional[AnyUrl] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Info(BaseModel): + title: str + summary: Optional[str] = None + description: Optional[str] = None + termsOfService: Optional[str] = None + contact: Optional[Contact] = None + license: Optional[License] = None + version: str + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class ServerVariable(BaseModel): + enum: Annotated[Optional[List[str]], Field(min_length=1)] = None + default: str + description: Optional[str] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Server(BaseModel): + url: Union[AnyUrl, str] + description: Optional[str] = None + variables: Optional[Dict[str, ServerVariable]] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Reference(BaseModel): + ref: str = Field(alias="$ref") + + +class Discriminator(BaseModel): + propertyName: str + mapping: Optional[Dict[str, str]] = None + + +class XML(BaseModel): + name: Optional[str] = None + namespace: Optional[str] = None + prefix: Optional[str] = None + attribute: Optional[bool] = None + wrapped: Optional[bool] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class ExternalDocumentation(BaseModel): + description: Optional[str] = None + url: AnyUrl + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Schema(BaseModel): + # 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 generales 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[str] = 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +# 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] + + if PYDANTIC_V2: # type: ignore [misc] + __pydantic_config__ = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class ParameterInType(Enum): + query = "query" + header = "header" + path = "path" + cookie = "cookie" + + +class Encoding(BaseModel): + contentType: Optional[str] = None + headers: Optional[Dict[str, Union["Header", Reference]]] = None + style: Optional[str] = None + explode: Optional[bool] = None + allowReserved: Optional[bool] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class MediaType(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class ParameterBase(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Parameter(ParameterBase): + name: str + in_: ParameterInType = Field(alias="in") + + +class Header(ParameterBase): + pass + + +class RequestBody(BaseModel): + description: Optional[str] = None + content: Dict[str, MediaType] + required: Optional[bool] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Link(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Response(BaseModel): + description: str + headers: Optional[Dict[str, Union[Header, Reference]]] = None + content: Optional[Dict[str, MediaType]] = None + links: Optional[Dict[str, Union[Link, Reference]]] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Operation(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class PathItem(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class SecuritySchemeType(Enum): + apiKey = "apiKey" + http = "http" + oauth2 = "oauth2" + openIdConnect = "openIdConnect" + + +class SecurityBase(BaseModel): + type_: SecuritySchemeType = Field(alias="type") + description: Optional[str] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +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(BaseModel): + refreshUrl: Optional[str] = None + scopes: Dict[str, str] = {} + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class OAuthFlowImplicit(OAuthFlow): + authorizationUrl: str + + +class OAuthFlowPassword(OAuthFlow): + tokenUrl: str + + +class OAuthFlowClientCredentials(OAuthFlow): + tokenUrl: str + + +class OAuthFlowAuthorizationCode(OAuthFlow): + authorizationUrl: str + tokenUrl: str + + +class OAuthFlows(BaseModel): + implicit: Optional[OAuthFlowImplicit] = None + password: Optional[OAuthFlowPassword] = None + clientCredentials: Optional[OAuthFlowClientCredentials] = None + authorizationCode: Optional[OAuthFlowAuthorizationCode] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +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(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class Tag(BaseModel): + name: str + description: Optional[str] = None + externalDocs: Optional[ExternalDocumentation] = None + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +class OpenAPI(BaseModel): + 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 + + if PYDANTIC_V2: + model_config = {"extra": "allow"} + + else: + + class Config: + extra = "allow" + + +_model_rebuild(Schema) +_model_rebuild(Operation) +_model_rebuild(Encoding) diff --git a/.venv/lib/python3.10/site-packages/fastapi/openapi/utils.py b/.venv/lib/python3.10/site-packages/fastapi/openapi/utils.py new file mode 100644 index 0000000..5bfb5ac --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/openapi/utils.py @@ -0,0 +1,530 @@ +import http.client +import inspect +import warnings +from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast + +from fastapi import routing +from fastapi._compat import ( + GenerateJsonSchema, + JsonSchemaValue, + 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_dependant, get_flat_params +from fastapi.encoders import jsonable_encoder +from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE +from fastapi.openapi.models import OpenAPI +from fastapi.params import Body, Param +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 starlette.responses import JSONResponse +from starlette.routing import BaseRoute +from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY +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 = {} + operation_security = [] + for security_requirement in flat_dependant.security_requirements: + security_definition = jsonable_encoder( + security_requirement.security_scheme.model, + by_alias=True, + exclude_none=True, + ) + security_name = security_requirement.security_scheme.scheme_name + security_definitions[security_name] = security_definition + operation_security.append({security_name: security_requirement.scopes}) + return security_definitions, operation_security + + +def get_openapi_operation_parameters( + *, + all_route_params: Sequence[ModelField], + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + field_mapping: Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + separate_input_output_schemas: bool = True, +) -> List[Dict[str, Any]]: + parameters = [] + for param in all_route_params: + field_info = param.field_info + field_info = cast(Param, field_info) + if not field_info.include_in_schema: + continue + param_schema = get_schema_from_model_field( + field=param, + schema_generator=schema_generator, + model_name_map=model_name_map, + field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, + ) + parameter = { + "name": param.alias, + "in": field_info.in_.value, + "required": param.required, + "schema": param_schema, + } + if field_info.description: + parameter["description"] = field_info.description + if field_info.openapi_examples: + parameter["examples"] = jsonable_encoder(field_info.openapi_examples) + elif field_info.example != Undefined: + parameter["example"] = jsonable_encoder(field_info.example) + if field_info.deprecated: + parameter["deprecated"] = field_info.deprecated + parameters.append(parameter) + return parameters + + +def get_openapi_operation_request_body( + *, + body_field: Optional[ModelField], + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + field_mapping: Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + 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, + schema_generator=schema_generator, + 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( + "fastapi.openapi.utils.generate_operation_id() was deprecated, " + "it is not used internally, and will be removed soon", + DeprecationWarning, + 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], + schema_generator: GenerateJsonSchema, + model_name_map: ModelNameMap, + field_mapping: Dict[ + Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ], + 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) + all_route_params = get_flat_params(route.dependant) + operation_parameters = get_openapi_operation_parameters( + all_route_params=all_route_params, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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 = str(HTTP_422_UNPROCESSABLE_ENTITY) + 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, +) -> 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) + schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE) + field_mapping, definitions = get_definitions( + fields=all_fields, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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, + schema_generator=schema_generator, + 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 + return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore diff --git a/.venv/lib/python3.10/site-packages/fastapi/param_functions.py b/.venv/lib/python3.10/site-packages/fastapi/param_functions.py new file mode 100644 index 0000000..6722a7d --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/param_functions.py @@ -0,0 +1,2360 @@ +from typing import Any, Callable, Dict, List, Optional, Sequence, Union + +from fastapi import params +from fastapi._compat import Undefined +from fastapi.openapi.models import Example +from typing_extensions import Annotated, Doc, 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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[ + bool, + 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). + """ + ), + ] = False, + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Annotated[ + Union[str, 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[ + Optional[bool], + 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, +) -> 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) + + +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 + intentionaly 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 Depends, 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/.venv/lib/python3.10/site-packages/fastapi/params.py b/.venv/lib/python3.10/site-packages/fastapi/params.py new file mode 100644 index 0000000..b40944d --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/params.py @@ -0,0 +1,777 @@ +import warnings +from enum import Enum +from typing import Any, Callable, Dict, List, Optional, Sequence, Union + +from fastapi.openapi.models import Example +from pydantic.fields import FieldInfo +from typing_extensions import Annotated, deprecated + +from ._compat import PYDANTIC_V2, Undefined + +_Unset: Any = Undefined + + +class ParamTypes(Enum): + query = "query" + header = "header" + path = "path" + cookie = "cookie" + + +class Param(FieldInfo): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = None, + include_in_schema: bool = True, + json_schema_extra: Union[Dict[str, Any], None] = None, + **extra: Any, + ): + self.deprecated = deprecated + if example is not _Unset: + warnings.warn( + "`example` has been deprecated, please use `examples` instead", + category=DeprecationWarning, + 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_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=DeprecationWarning, + stacklevel=4, + ) + current_json_schema_extra = json_schema_extra or extra + if PYDANTIC_V2: + 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 + else: + kwargs["regex"] = pattern or regex + kwargs.update(**current_json_schema_extra) + 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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): + def __init__( + self, + default: Any = Undefined, + *, + default_factory: Union[Callable[[], Any], None] = _Unset, + annotation: Optional[Any] = None, + embed: bool = False, + media_type: str = "application/json", + alias: Optional[str] = None, + alias_priority: Union[int, None] = _Unset, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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 + self.deprecated = deprecated + if example is not _Unset: + warnings.warn( + "`example` has been deprecated, please use `examples` instead", + category=DeprecationWarning, + 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_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 depreacated, please use `pattern` instead", + category=DeprecationWarning, + stacklevel=4, + ) + current_json_schema_extra = json_schema_extra or extra + if PYDANTIC_V2: + 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 + else: + kwargs["regex"] = pattern or regex + kwargs.update(**current_json_schema_extra) + + 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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, + embed=True, + 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): + 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, + # TODO: update when deprecating Pydantic v1, import these types + # validation_alias: str | AliasPath | AliasChoices | None + validation_alias: Union[str, 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: Optional[bool] = 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 Depends: + def __init__( + self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True + ): + self.dependency = dependency + self.use_cache = use_cache + + def __repr__(self) -> str: + attr = getattr(self.dependency, "__name__", type(self.dependency).__name__) + cache = "" if self.use_cache else ", use_cache=False" + return f"{self.__class__.__name__}({attr}{cache})" + + +class Security(Depends): + def __init__( + self, + dependency: Optional[Callable[..., Any]] = None, + *, + scopes: Optional[Sequence[str]] = None, + use_cache: bool = True, + ): + super().__init__(dependency=dependency, use_cache=use_cache) + self.scopes = scopes or [] diff --git a/.venv/lib/python3.10/site-packages/fastapi/py.typed b/.venv/lib/python3.10/site-packages/fastapi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/fastapi/requests.py b/.venv/lib/python3.10/site-packages/fastapi/requests.py new file mode 100644 index 0000000..d16552c --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/fastapi/responses.py b/.venv/lib/python3.10/site-packages/fastapi/responses.py new file mode 100644 index 0000000..6c8db6f --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/fastapi/routing.py b/.venv/lib/python3.10/site-packages/fastapi/routing.py new file mode 100644 index 0000000..fa13518 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/routing.py @@ -0,0 +1,4385 @@ +import asyncio +import dataclasses +import email.message +import inspect +import json +from contextlib import AsyncExitStack +from enum import Enum, IntEnum +from typing import ( + Any, + Callable, + Coroutine, + Dict, + List, + Optional, + Sequence, + Set, + Tuple, + Type, + Union, +) + +from fastapi import params +from fastapi._compat import ( + ModelField, + Undefined, + _get_model_config, + _model_dump, + _normalize_errors, + lenient_issubclass, +) +from fastapi.datastructures import Default, DefaultPlaceholder +from fastapi.dependencies.models import Dependant +from fastapi.dependencies.utils import ( + get_body_field, + get_dependant, + get_parameterless_sub_dependant, + get_typed_return_annotation, + solve_dependencies, +) +from fastapi.encoders import jsonable_encoder +from fastapi.exceptions import ( + FastAPIError, + RequestValidationError, + ResponseValidationError, + WebSocketRequestValidationError, +) +from fastapi.types import DecoratedCallable, IncEx +from fastapi.utils import ( + create_cloned_field, + create_response_field, + generate_unique_id, + get_value_or_default, + is_body_allowed_for_status_code, +) +from pydantic import BaseModel +from starlette import routing +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, + request_response, + websocket_session, +) +from starlette.routing import Mount as Mount # noqa +from starlette.types import ASGIApp, Lifespan, Scope +from starlette.websockets import WebSocket +from typing_extensions import Annotated, Doc, deprecated + + +def _prepare_response_content( + res: Any, + *, + exclude_unset: bool, + exclude_defaults: bool = False, + exclude_none: bool = False, +) -> Any: + if isinstance(res, BaseModel): + read_with_orm_mode = getattr(_get_model_config(res), "read_with_orm_mode", None) + if read_with_orm_mode: + # Let from_orm extract the data from this model instead of converting + # it now to a dict. + # Otherwise, there's no way to extract lazy data that requires attribute + # access instead of dict iteration, e.g. lazy relationships. + return res + return _model_dump( + res, + by_alias=True, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + elif isinstance(res, list): + return [ + _prepare_response_content( + item, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + for item in res + ] + elif isinstance(res, dict): + return { + k: _prepare_response_content( + v, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + for k, v in res.items() + } + elif dataclasses.is_dataclass(res): + return dataclasses.asdict(res) + return res + + +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, +) -> Any: + if field: + errors = [] + if not hasattr(field, "serialize"): + # pydantic v1 + response_content = _prepare_response_content( + response_content, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + 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_) + elif errors_: + errors.append(errors_) + if errors: + raise ResponseValidationError( + errors=_normalize_errors(errors), body=response_content + ) + + if hasattr(field, "serialize"): + return field.serialize( + value, + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + return jsonable_encoder( + 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, +) -> Callable[[Request], Coroutine[Any, Any, Response]]: + assert dependant.call is not None, "dependant.call must be a function" + is_coroutine = asyncio.iscoroutinefunction(dependant.call) + 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 + async with AsyncExitStack() as file_stack: + 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, + ) + 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 + errors: List[Any] = [] + async with AsyncExitStack() as async_exit_stack: + solved_result = await solve_dependencies( + request=request, + dependant=dependant, + body=body, + dependency_overrides_provider=dependency_overrides_provider, + async_exit_stack=async_exit_stack, + ) + values, errors, background_tasks, sub_response, _ = solved_result + if not errors: + raw_response = await run_endpoint_function( + dependant=dependant, values=values, is_coroutine=is_coroutine + ) + if isinstance(raw_response, Response): + if raw_response.background is None: + raw_response.background = background_tasks + response = raw_response + else: + response_args: Dict[str, Any] = {"background": 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 sub_response.status_code + ) + if current_status_code is not None: + response_args["status_code"] = current_status_code + if sub_response.status_code: + response_args["status_code"] = sub_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, + ) + 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(sub_response.headers.raw) + if errors: + validation_error = RequestValidationError( + _normalize_errors(errors), body=body + ) + raise validation_error + if response is None: + raise FastAPIError( + "No response object was returned. 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" + ) + return response + + return app + + +def get_websocket_app( + dependant: Dependant, dependency_overrides_provider: Optional[Any] = None +) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]: + async def app(websocket: WebSocket) -> None: + async with AsyncExitStack() as async_exit_stack: + # TODO: remove this scope later, after a few releases + # This scope fastapi_astack is no longer used by FastAPI, kept for + # compatibility, just in case + websocket.scope["fastapi_astack"] = async_exit_stack + solved_result = await solve_dependencies( + request=websocket, + dependant=dependant, + dependency_overrides_provider=dependency_overrides_provider, + async_exit_stack=async_exit_stack, + ) + values, errors, _, _2, _3 = solved_result + if errors: + raise WebSocketRequestValidationError(_normalize_errors(errors)) + assert dependant.call is not None, "dependant.call must be a function" + await dependant.call(**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) + for depends in self.dependencies[::-1]: + self.dependant.dependencies.insert( + 0, + get_parameterless_sub_dependant(depends=depends, path=self.path_format), + ) + + self.app = websocket_session( + get_websocket_app( + dependant=self.dependant, + dependency_overrides_provider=dependency_overrides_provider, + ) + ) + + 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 + self.response_field = create_response_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}" + response_field = create_response_field(name=response_name, type_=model) + 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) + for depends in self.dependencies[::-1]: + self.dependant.dependencies.insert( + 0, + get_parameterless_sub_dependant(depends=depends, path=self.path_format), + ) + self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id) + 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, + ) + + 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-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[List[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) + + 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-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-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-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-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-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-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-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-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/.venv/lib/python3.10/site-packages/fastapi/security/__init__.py b/.venv/lib/python3.10/site-packages/fastapi/security/__init__.py new file mode 100644 index 0000000..3aa6bf2 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/fastapi/security/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/security/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d8459f39af5e080a6b102e04ef4ccc4a84939d2 GIT binary patch literal 833 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/fastapi/security/__pycache__/http.cpython-310.pyc b/.venv/lib/python3.10/site-packages/fastapi/security/__pycache__/http.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7dea8b2c237f3815d4eac6f8f3caa7a30b26836 GIT binary patch literal 10866 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 z
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 Optional[str]: + api_key = request.query_params.get(self.model.name) + if not api_key: + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + return 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, + ): + self.model: APIKey = APIKey( + **{"in": APIKeyIn.header}, # type: ignore[arg-type] + name=name, + description=description, + ) + self.scheme_name = scheme_name or self.__class__.__name__ + self.auto_error = auto_error + + async def __call__(self, request: Request) -> Optional[str]: + api_key = request.headers.get(self.model.name) + if not api_key: + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + return 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, + ): + self.model: APIKey = APIKey( + **{"in": APIKeyIn.cookie}, # type: ignore[arg-type] + name=name, + description=description, + ) + self.scheme_name = scheme_name or self.__class__.__name__ + self.auto_error = auto_error + + async def __call__(self, request: Request) -> Optional[str]: + api_key = request.cookies.get(self.model.name) + if not api_key: + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + return api_key diff --git a/.venv/lib/python3.10/site-packages/fastapi/security/base.py b/.venv/lib/python3.10/site-packages/fastapi/security/base.py new file mode 100644 index 0000000..c43555d --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/fastapi/security/http.py b/.venv/lib/python3.10/site-packages/fastapi/security/http.py new file mode 100644 index 0000000..b45bee5 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/security/http.py @@ -0,0 +1,420 @@ +import binascii +from base64 import b64decode +from typing import Optional + +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, HTTP_403_FORBIDDEN +from typing_extensions import Annotated, Doc + + +class HTTPBasicCredentials(BaseModel): + """ + The HTTP Basic credendials 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(scheme=scheme, 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 HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) + + +class HTTPBasic(HTTPBase): + """ + HTTP Basic authentication. + + ## 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 + + async def __call__( # type: ignore + self, request: Request + ) -> Optional[HTTPBasicCredentials]: + authorization = request.headers.get("Authorization") + scheme, param = get_authorization_scheme_param(authorization) + if self.realm: + unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'} + else: + unauthorized_headers = {"WWW-Authenticate": "Basic"} + if not authorization or scheme.lower() != "basic": + if self.auto_error: + raise HTTPException( + status_code=HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers=unauthorized_headers, + ) + else: + return None + invalid_user_credentials_exc = HTTPException( + status_code=HTTP_401_UNAUTHORIZED, + detail="Invalid authentication credentials", + headers=unauthorized_headers, + ) + try: + data = b64decode(param).decode("ascii") + except (ValueError, UnicodeDecodeError, binascii.Error): + raise invalid_user_credentials_exc # noqa: B904 + username, separator, password = data.partition(":") + if not separator: + raise invalid_user_credentials_exc + 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 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 HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + if scheme.lower() != "bearer": + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, + detail="Invalid authentication credentials", + ) + else: + return None + return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) + + +class HTTPDigest(HTTPBase): + """ + HTTP Digest 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, 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 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 HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + if scheme.lower() != "digest": + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, + detail="Invalid authentication credentials", + ) + return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) diff --git a/.venv/lib/python3.10/site-packages/fastapi/security/oauth2.py b/.venv/lib/python3.10/site-packages/fastapi/security/oauth2.py new file mode 100644 index 0000000..9720cac --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/security/oauth2.py @@ -0,0 +1,638 @@ +from typing import Any, Dict, List, Optional, Union, cast + +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, HTTP_403_FORBIDDEN + +# TODO: import from typing when deprecating Python 3.9 +from typing_extensions import Annotated, Doc + + +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 caracters (`:`) 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(), + 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, + ): + 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 caracters (`:`) 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 + + async def __call__(self, request: Request) -> Optional[str]: + authorization = request.headers.get("Authorization") + if not authorization: + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + 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, + ): + if not scopes: + scopes = {} + flows = OAuthFlowsModel( + password=cast(Any, {"tokenUrl": tokenUrl, "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 HTTPException( + status_code=HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers={"WWW-Authenticate": "Bearer"}, + ) + 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 HTTPException( + status_code=HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers={"WWW-Authenticate": "Bearer"}, + ) + 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/.venv/lib/python3.10/site-packages/fastapi/security/open_id_connect_url.py b/.venv/lib/python3.10/site-packages/fastapi/security/open_id_connect_url.py new file mode 100644 index 0000000..c8cceb9 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/security/open_id_connect_url.py @@ -0,0 +1,84 @@ +from typing import Optional + +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_403_FORBIDDEN +from typing_extensions import Annotated, Doc + + +class OpenIdConnect(SecurityBase): + """ + OpenID Connect authentication class. An instance of it would be used as a + dependency. + """ + + 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 + + async def __call__(self, request: Request) -> Optional[str]: + authorization = request.headers.get("Authorization") + if not authorization: + if self.auto_error: + raise HTTPException( + status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + else: + return None + return authorization diff --git a/.venv/lib/python3.10/site-packages/fastapi/security/utils.py b/.venv/lib/python3.10/site-packages/fastapi/security/utils.py new file mode 100644 index 0000000..fa7a450 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/security/utils.py @@ -0,0 +1,10 @@ +from typing import Optional, Tuple + + +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/.venv/lib/python3.10/site-packages/fastapi/staticfiles.py b/.venv/lib/python3.10/site-packages/fastapi/staticfiles.py new file mode 100644 index 0000000..299015d --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/staticfiles.py @@ -0,0 +1 @@ +from starlette.staticfiles import StaticFiles as StaticFiles # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/templating.py b/.venv/lib/python3.10/site-packages/fastapi/templating.py new file mode 100644 index 0000000..0cb8684 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/templating.py @@ -0,0 +1 @@ +from starlette.templating import Jinja2Templates as Jinja2Templates # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/testclient.py b/.venv/lib/python3.10/site-packages/fastapi/testclient.py new file mode 100644 index 0000000..4012406 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/testclient.py @@ -0,0 +1 @@ +from starlette.testclient import TestClient as TestClient # noqa diff --git a/.venv/lib/python3.10/site-packages/fastapi/types.py b/.venv/lib/python3.10/site-packages/fastapi/types.py new file mode 100644 index 0000000..3205654 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/types.py @@ -0,0 +1,10 @@ +import types +from enum import Enum +from typing import Any, Callable, Dict, Set, Type, 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]] diff --git a/.venv/lib/python3.10/site-packages/fastapi/utils.py b/.venv/lib/python3.10/site-packages/fastapi/utils.py new file mode 100644 index 0000000..53b2fa0 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/fastapi/utils.py @@ -0,0 +1,229 @@ +import re +import warnings +from dataclasses import is_dataclass +from typing import ( + TYPE_CHECKING, + Any, + Dict, + MutableMapping, + Optional, + Set, + Type, + Union, + cast, +) +from weakref import WeakKeyDictionary + +import fastapi +from fastapi._compat import ( + PYDANTIC_V2, + BaseConfig, + ModelField, + PydanticSchemaGenerationError, + Undefined, + UndefinedType, + Validator, + lenient_issubclass, +) +from fastapi.datastructures import DefaultPlaceholder, DefaultType +from pydantic import BaseModel, create_model +from pydantic.fields import FieldInfo +from typing_extensions import Literal + +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)) + + +def create_response_field( + name: str, + type_: Type[Any], + class_validators: Optional[Dict[str, Validator]] = None, + default: Optional[Any] = Undefined, + required: Union[bool, UndefinedType] = Undefined, + model_config: Type[BaseConfig] = BaseConfig, + field_info: Optional[FieldInfo] = None, + alias: Optional[str] = None, + mode: Literal["validation", "serialization"] = "validation", +) -> ModelField: + """ + Create a new response field. Raises if type_ is invalid. + """ + class_validators = class_validators or {} + if PYDANTIC_V2: + field_info = field_info or FieldInfo( + annotation=type_, default=default, alias=alias + ) + else: + field_info = field_info or FieldInfo() + kwargs = {"name": name, "field_info": field_info} + if PYDANTIC_V2: + kwargs.update({"mode": mode}) + else: + kwargs.update( + { + "type_": type_, + "class_validators": class_validators, + "default": default, + "required": required, + "model_config": model_config, + "alias": alias, + } + ) + try: + return ModelField(**kwargs) # type: ignore[arg-type] + except (RuntimeError, PydanticSchemaGenerationError): + raise fastapi.exceptions.FastAPIError( + "Invalid args for response field! Hint: " + f"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/" + ) from None + + +def create_cloned_field( + field: ModelField, + *, + cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None, +) -> ModelField: + if PYDANTIC_V2: + return field + # cloned_types caches already cloned types to support recursive models and improve + # performance by avoiding unnecessary cloning + if cloned_types is None: + cloned_types = _CLONED_TYPES_CACHE + + original_type = field.type_ + if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"): + original_type = original_type.__pydantic_model__ + use_type = original_type + if lenient_issubclass(original_type, BaseModel): + original_type = cast(Type[BaseModel], original_type) + use_type = cloned_types.get(original_type) + if use_type is None: + use_type = create_model(original_type.__name__, __base__=original_type) + cloned_types[original_type] = use_type + for f in original_type.__fields__.values(): + use_type.__fields__[f.name] = create_cloned_field( + f, cloned_types=cloned_types + ) + new_field = create_response_field(name=field.name, type_=use_type) + new_field.has_alias = field.has_alias # type: ignore[attr-defined] + new_field.alias = field.alias # type: ignore[misc] + new_field.class_validators = field.class_validators # type: ignore[attr-defined] + new_field.default = field.default # type: ignore[misc] + new_field.required = field.required # type: ignore[misc] + new_field.model_config = field.model_config # type: ignore[attr-defined] + new_field.field_info = field.field_info + new_field.allow_none = field.allow_none # type: ignore[attr-defined] + new_field.validate_always = field.validate_always # type: ignore[attr-defined] + if field.sub_fields: # type: ignore[attr-defined] + new_field.sub_fields = [ # type: ignore[attr-defined] + create_cloned_field(sub_field, cloned_types=cloned_types) + for sub_field in field.sub_fields # type: ignore[attr-defined] + ] + if field.key_field: # type: ignore[attr-defined] + new_field.key_field = create_cloned_field( # type: ignore[attr-defined] + field.key_field, # type: ignore[attr-defined] + cloned_types=cloned_types, + ) + new_field.validators = field.validators # type: ignore[attr-defined] + new_field.pre_validators = field.pre_validators # type: ignore[attr-defined] + new_field.post_validators = field.post_validators # type: ignore[attr-defined] + new_field.parse_json = field.parse_json # type: ignore[attr-defined] + new_field.shape = field.shape # type: ignore[attr-defined] + new_field.populate_validators() # type: ignore[attr-defined] + return new_field + + +def generate_operation_id_for_path( + *, name: str, path: str, method: str +) -> str: # pragma: nocover + warnings.warn( + "fastapi.utils.generate_operation_id_for_path() was deprecated, " + "it is not used internally, and will be removed soon", + DeprecationWarning, + 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 + + +def match_pydantic_error_url(error_type: str) -> Any: + from dirty_equals import IsStr + + return IsStr(regex=rf"^https://errors\.pydantic\.dev/.*/v/{error_type}") diff --git a/.venv/lib/python3.10/site-packages/fastapi/websockets.py b/.venv/lib/python3.10/site-packages/fastapi/websockets.py new file mode 100644 index 0000000..55a4ac4 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/LICENSE.txt b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..8f080ea --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/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/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/METADATA b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/METADATA new file mode 100644 index 0000000..cf12a82 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/METADATA @@ -0,0 +1,193 @@ +Metadata-Version: 2.1 +Name: h11 +Version: 0.14.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.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: System :: Networking +Requires-Python: >=3.7 +License-File: LICENSE.txt +Requires-Dist: typing-extensions ; python_version < "3.8" + +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.7-3.10) 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/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/RECORD b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/RECORD new file mode 100644 index 0000000..eeaa1c4 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/RECORD @@ -0,0 +1,52 @@ +h11-0.14.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +h11-0.14.0.dist-info/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 +h11-0.14.0.dist-info/METADATA,sha256=B7pZ0m7WBXNs17vl6hUH9bJTL9s37DaGvY31w7jNxSg,8175 +h11-0.14.0.dist-info/RECORD,, +h11-0.14.0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +h11-0.14.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 +h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 +h11/__pycache__/__init__.cpython-310.pyc,, +h11/__pycache__/_abnf.cpython-310.pyc,, +h11/__pycache__/_connection.cpython-310.pyc,, +h11/__pycache__/_events.cpython-310.pyc,, +h11/__pycache__/_headers.cpython-310.pyc,, +h11/__pycache__/_readers.cpython-310.pyc,, +h11/__pycache__/_receivebuffer.cpython-310.pyc,, +h11/__pycache__/_state.cpython-310.pyc,, +h11/__pycache__/_util.cpython-310.pyc,, +h11/__pycache__/_version.cpython-310.pyc,, +h11/__pycache__/_writers.cpython-310.pyc,, +h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 +h11/_connection.py,sha256=eS2sorMD0zKLCFiB9lW9W9F_Nzny2tjHa4e6s1ujr1c,26539 +h11/_events.py,sha256=LEfuvg1AbhHaVRwxCd0I-pFn9-ezUOaoL8o2Kvy1PBA,11816 +h11/_headers.py,sha256=RqB8cd8CN0blYPzcLe5qeCh-phv6D1U_CHj4hs67lgQ,10230 +h11/_readers.py,sha256=EbSed0jzwVUiD1nOPAeUcVE4Flf3wXkxfb8c06-OTBM,8383 +h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 +h11/_state.py,sha256=k1VL6SDbaPkSrZ-49ewCXDpuiUS69_46YhbWjuV1qEY,13300 +h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 +h11/_version.py,sha256=LVyTdiZRzIIEv79UyOgbM5iUrJUllEzlCWaJEYBY1zc,686 +h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 +h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 +h11/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +h11/tests/__pycache__/__init__.cpython-310.pyc,, +h11/tests/__pycache__/helpers.cpython-310.pyc,, +h11/tests/__pycache__/test_against_stdlib_http.cpython-310.pyc,, +h11/tests/__pycache__/test_connection.cpython-310.pyc,, +h11/tests/__pycache__/test_events.cpython-310.pyc,, +h11/tests/__pycache__/test_headers.cpython-310.pyc,, +h11/tests/__pycache__/test_helpers.cpython-310.pyc,, +h11/tests/__pycache__/test_io.cpython-310.pyc,, +h11/tests/__pycache__/test_receivebuffer.cpython-310.pyc,, +h11/tests/__pycache__/test_state.cpython-310.pyc,, +h11/tests/__pycache__/test_util.cpython-310.pyc,, +h11/tests/data/test-file,sha256=ZJ03Rqs98oJw29OHzJg7LlMzyGQaRAY0r3AqBeM2wVU,65 +h11/tests/helpers.py,sha256=a1EVG_p7xU4wRsa3tMPTRxuaKCmretok9sxXWvqfmQA,3355 +h11/tests/test_against_stdlib_http.py,sha256=cojCHgHXFQ8gWhNlEEwl3trmOpN-5uDukRoHnElqo3A,3995 +h11/tests/test_connection.py,sha256=ZbPLDPclKvjgjAhgk-WlCPBaf17c4XUIV2tpaW08jOI,38720 +h11/tests/test_events.py,sha256=LPVLbcV-NvPNK9fW3rraR6Bdpz1hAlsWubMtNaJ5gHg,4657 +h11/tests/test_headers.py,sha256=qd8T1Zenuz5GbD6wklSJ5G8VS7trrYgMV0jT-SMvqg8,5612 +h11/tests/test_helpers.py,sha256=kAo0CEM4LGqmyyP2ZFmhsyq3UFJqoFfAbzu3hbWreRM,794 +h11/tests/test_io.py,sha256=uCZVnjarkRBkudfC1ij-KSCQ71XWJhnkgkgWWkKgYPQ,16386 +h11/tests/test_receivebuffer.py,sha256=3jGbeJM36Akqg_pAhPb7XzIn2NS6RhPg-Ryg8Eu6ytk,3454 +h11/tests/test_state.py,sha256=rqll9WqFsJPE0zSrtCn9LH659mPKsDeXZ-DwXwleuBQ,8928 +h11/tests/test_util.py,sha256=VO5L4nSFe4pgtSwKuv6u_6l0H7UeizF5WKuHTWreg70,2970 diff --git a/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/WHEEL new file mode 100644 index 0000000..5bad85f --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/top_level.txt b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/top_level.txt new file mode 100644 index 0000000..0d24def --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11-0.14.0.dist-info/top_level.txt @@ -0,0 +1 @@ +h11 diff --git a/.venv/lib/python3.10/site-packages/h11/__init__.py b/.venv/lib/python3.10/site-packages/h11/__init__.py new file mode 100644 index 0000000..989e92c --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..667dc485061b810cd0ee0ef28569f8838a83a03e GIT binary patch literal 1010 zcma))&2G~`5XbF&+DY7eH~j<-TykhkfeR8sl-Qz?(zvoyKIXD=;|;OuwNu-v)V>5S zzzgs&yue<2;uSct<5HkVl~~EY-JRW?`HyEJO{+*^eEZy+Ul%3m8aIEBoY=e;U-Cu3 zlRP<)m<%$@L5}4iFQY9N6j%|8tOO-ihB8w?VJfJs0u@$;YIY|d)R+buTZ1)LhdOIO zgEgVaTF_!`XtNGq45Kilv(%45u1-wTAjZM;fR~OBP8`$dmwDsQg<%jS)Z+!iO7JXqfWuD4a(zbJ3j}*fd#2VM2M?rspe~q+Gc*^{c!z9FNS&6lY6> z5^k-DDID3hW%I(w7@NF%GZNba+UPZEI=`tue10oj6mHJ>#llP7LzKGCp!G zTiT{`Y)u@KmmJf6XWG1Z^IT+h>p-O48b>oXIF6$Cu)O5TOBQ*nfWDGNoCHhIQ69_B)s9w^m7J3Q351jU$p8QV literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_abnf.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..604e243a28e775f0d9c2534616c1795e8dae2567 GIT binary patch literal 1254 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_events.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64afbfffe3852995cb30005731a52d6ec7ff7239 GIT binary patch literal 10154 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 WEB3Np`5CSTu6lM|g%7QMTK_-bG)n9M literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_headers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e267ca6678c83eff4d20ffd60399b48c25f06eb7 GIT binary patch literal 5572 zcmbtYNpl;=6`r0A1Aq%iYNJF+BUnm^n2V$w5<8+|N7iO5jAAKedt}uVh;9&L4raif zfn*|JDiu1HR8p?w5MQaPTvYijKISsloLrTgDmkPQE8pt@2rjZO0cslE{a(Mzb4yW4F-ZayC z4x|?#ea4$%+6P)RX=>uw)?KF2SJ95=w2!oiJ=KJ^dxAU9n0JzTqP%;G7oRbVXVrLY zZ+!Z;#!I~Xna0b)76oxeoN4N_+N`!?cyppC%>8qN(b=3sjm{4F2crS4Y0hfiIbrcJ zF~`Tn44;_Q_@tO?+PuQ2J~MZicV1D?DeCkdb!J2@PIDLQi(*ckBaPs62QrR<%OV-y z!gHK>yz^=YC&U@7G{u=&4Ldl=Pkm;37xpN#IYr5K_-TFy)GD9jXEEb8O@5A_$INS- zJtvQ+fcC_^%m6_S7CuwHh3(z|86CuO6&NJtM*zAg^Au{V>w-btN{NYFU zZ~8ax+`RGL-PPNf^@}Koqpy%YT20SN%|L|QkLqoamGl0Sde{{;BXicaQjrABt!(;U z+^C25Wt_&1IJ_xkEHeje0k5Z`#F@7AB zX>K6|C$hpFQRhM?^}p$wR&w!q+YRCW#W2_qZVC?P@A2)ms2vlgeVd|Cae8_QrlfNU4qL0o_} zn1iuy8oNrWd?E(Ke7mq_5lR=I1`->sM_kDoS>WatG-FB2#9|O(XGxF-Bqwfn>M}^M z%Vc1jbXVL#BF!rWD7MG1)U+h)Pkkg)JDIP!hqVq& z{x+=#jQ>WhS=n!P!!TC_co_9ATv^}uYJOH0KD=fhGfB79EZvrST&0|Wk%kd!I0Dv3*-~= zESmjFb5dsE$l-vKuHlFJ1|H?Y3Ob~FhoOc34Sl!+mYIY!H9c2e1>@lz*uF0|eLng;Z2o&AE-np)c3pK zPsr>Fb69U?T%cJyUi$pn)mP|gldjvGV_$HPZ-n21iq(@bEe|R3auP#vVxCG4tM!Oc>)U#L zP=}7i3)(h8raFL1^K)HZ!=zlHX0#O*oD)$j+qk!S!pEiS4-2v1k|Yvq>hdl8-1+fp6VX4`- z)#xgX`qp-#Z|&O8v~3IP%?({jZgCsu&E75W!ZSu^Zre$nzO%!)vth{lX^|Iq7}h$w zC9EUeWoRqy7)St~NZ1@oz>LMq(D_B*l)u94 z7*(l%&>`Dad$J*S5-WZWT4hM%Q}D-8*+*v5@xHF`VtVyf@6_Ee6zeGI@_bbFnET5M za=SNsh@$XJk&+3DcZ@|wJ;b#$Q_9If>bO#J>khn>=(}`sYw5UzUaV(aT zXtD`^^or(7kxdT9Dr7WKLKPiBF{&o{Lt0^}5**I&gh495Ly{<{nbCJPfl{b?JT>A%Cd&d*pB}32oL(jq-uV zUV+S?!I0cXV;aCyHpWcT!JRoV_?kM6j$xjDsWsWO>gz8Z-L!O!?U#<_FkOA^uT68B zO=FeX!~wLSh|r~}(1uhJ+E5JuoN;k=q5=RSn0-`T@)8h&IR6e2NnNJ;ZWL800fzY(u^+CA4gm`sJnHQ-7A%BwRO3eJV$s`@# ztVF?83X%p@MZ*vM#dO$9#=uJzcnLm&{T94r$m4xum%(FpQ&)a~7vQHd@RjD-uKrBx z;~iVkP63~dQAKU$E+U^~7OJLDsC1|~Bmc;UAj(xV-o(f!s&e@`QQoJu#XU2QI0XoC zz$yO$zpAdx5;A$AbLaKZ~k_s~a8$(twIs$s+B9%B*bjTf?ZJ^fR2s>4?pXl7! z(YF~#`aGek)>=(y3Em%XsXs%+ryW!t$r#ODzPw21D2UV_Eo1xNI8|(v3jmuRf;qGE zm4~f6*{UagPVym89ZV892|!9Hh9#3u6O4O=L5rSnCPZKm?IS7ih?Px;0wH|rHOK$Bs|T^ciRML>i;5d zDp!jg1C!Nje^#LSGCiXE%dSU;#^!4ch*)6`uc{U9A?e`WFHg3^8kL31Mu&CKwwD8wXa71dcs6nHp{PqJf!N(KCxJ zv8u$DQshT<0{i0Z*1Va1{WIPD z-uvFy)9mjrDER&5SEG$TR21c(ROtPUqHqCM{Gp~O*A=EPHBcP7Yk?YSjuz^U9vY4j znvNM-juqydTxdIXn0NAF!6~Q;)0q+Ug+-?r_B;Jy$ti_#SfT9Cb$Jb1oPQ$DQ$T!kGy7Is3v%XENOH><Ctc$W7+IK~PO)rYE6r84Wo({rrIO@4e_Vg1>? zVXzY0^O@m1zoW+H$NBMwHm-~-XfeR{qQwhx)KYiUDOTpA7$?VvWUE0ogjUnC)t+vv z6P;ECKFEie+R$a&VK#!cGjA$vl#P9+u(1uzIVpPK!9e4I}VCmF%g^vvSpFP*YEh{k zdQ5&-tL9Vv^=LJ1-?+--*t^No;mc8@DMBxM?E;Tino-Qt+(I@^YHz8kYTCcR>)gM~-)J=& zTvYAUx_IUCTEnueLwA&j|+2) z@66X0=Td8NZsFaz1+1!krCIlacSJL3)|bT<1AwE$OrLAnJ z>nc;$wYEB|+&H51cPB6VtKw{1dsk7Fw%((g%XCaxL=QNSURyg_Z_;90(moYh zO2tbmFsn!^%|<1&ef$-zs#49Rh7X@g`; z(rUszA-vU8=Mk%#;s`a-{3JC3FD8k%i7J$j6mbH#uiu+qZialCE#JO#_T==`N^2?b zH@oW~MPY za^QGsWi=giG392!6E1yKPX0Jv8PlA!pWCXT+G;^cy4#wqjzC(fmFYLdNi^JHTpbE> z18Lk-c-S&7j9Ok-6E%T>nc7x2jLc-?3QR-DB@J`OlqN80YvXsK#ph6Sk$T*MXe$qthsrvZE4{ajvieXF z1BsS-F)g;O#$zbMhvC&a{92{$V4XW{Q(`hZv638Wus!6{8;AjBvD}yN_TQK&(JSUkNdG3L6!MbbLp<%Y{kK<>qineV2f?6lmXH)Sg#(9#30^I;SeWs zyJ5i7&}3G8iJmArdW^R(n+*B4+YrsrB|voRfe+yN5t_ynj5a)%{)Y5wO&w5;O+$xG zH#ODT6tAJl4wI5OyC(fT3jZII!sksGnIP>rvm!k!uhTu((Vu3v)T6v^5XiAS8GhYt zo2+nK5pO0|q$as_t8FEAl81Bj^*BedZMKcJ&ie10aE?+JENmksuKn~=@n8JK!YKHLLi<{9`C@S5&M-lY+kI-}+$P{O(@CpeE4e>gO z3lPdks$MAu2AYppzwrL_oGCVsd|XSc@h+X)!c5ExIk5MczRK4)q$z8yW3Na z?Dmu$+0l);z&d}50pjN%Y`xcIM${2a+Z@x2Y6*8uFRNPTZ~a@mh30i!JAULo7jVT? z%M}M$;2{1%k^p=lSq3vfvJ7T%lWE)n>9e8F$Xt%usLMlNXuttj0i`~s!=!!b;6)@U z`1TbZ-AtAjGG1Z@vLue;U9~#6cK1imbkWAd0}ySst+<)QlopjoYK>yu%|=KI*!j@& zBR{$cwGs26A>Kx}-J5B;c2iqTrP+4OPDelLD`z*0hqiJH zeD1a;>_pv=FbO&U9S8xXdWxJO37_b8OGywp8|oP>&{c>UFzr5pqF$3A_ef0*5Ec*F z_9})Jdm+-{o!I3iZrDWr)vAq1W`a@EJ|=G zf5#SNopzuMAu&-Rx%vq_Bv|_c*yk3lSs$a_&>qSZQPpZ|H&!?om3q(w6jwl1B3>sV zS^3CE;%|YdfLXw7s0zVm6J7~3+F4m@venA5t(dReTdxouiJ!0Vk5@1TM!UCOts3GW zrjS}0Llsw0ko)#X&30t>K1jsn&Bia$FfKx55m8dLP2-!VJHl3%YB9w&QYLp@cpOZ? zS^+&5UH4AQ3$hwI;JR2dw=g}ZM%^QEeu?s28v5O}UUm85$+ilpf>KdyU% zr2~jxkKDjTa`po*#7{7G&+f>Lp-ue)m*nmsb_POsWXFuZBWP(eyKZ|9>!1J?BW<`Y zSkG3N_S5VWO>!H!Fqn%^c$x?>ULNnqxj~L~RldKF^r4KC0T`8;AU!eziPmJ+ecEBW+uLV335x*6 z4a|}u!A3AC(rh-q5x3;qvN_v5bN-||XS-+4+arI$@)+5~h&ef8F6qZf#cJnR;l4!l zS``NrvJrX2HZhYH?$F>Z1}t@M?62|1189s>qOs(~{Mx0*+<wF=`C>^?P03D^FNOGYW7tFgIz z9bH7#GKi`6iT7zZhr|aYz7KwWhyi|$tAn2fb8#za+A=M^Y3;V@Fxm^sSXnxxxXIq~t(ov9n*0@)bR}CE zQOlMf-4lGI>;JS(Z6w&O7@(b{IN0}QGpP`*s(iG}qYi~2+A%kO35z8;X6&vUh56;08Y2oT4_zsEsK(K=#RlPDA2{BwiyiN8&9KM0`Yp1O=6K@`f*t7F=AunK+}O;n?;mMlLMnAy>!0Zr&$No!^9LfZ7Vxx PZOe>D0`2}g@UQ;?X&0>> literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_receivebuffer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc30ba0e0312a44a459631a4392f2951d37652b5 GIT binary patch literal 3197 zcmb7G&2AgX5uWbp8ImK3mS|hDy!n~U{)O4BxK0ox2G)tOiIaHaWq^2putbu26rdARtAc&lE4tW9T=r_nqe;5!1I(3-HtmH9WnGe9&@C-%{snv zPAXC;XQz6~JGI|9(v$8}%pLPiAlYN5>7QXgr`>c5@hHhnQT_ecB%>@&3-8kmonqw= zs;81Y_2H!7S2`y>f|XwcJzDm1^T6E4m;Vz)IiysF%T4J@@lQzv4QfpSY-={$Cx@wO)6rYLIN1EXTCRRN3KtHvWtiB3EhunWO92?LU8R4Ms!Nl7rnRcYoB{8c(`uk`G$_B#X12 z+BzI1`PQy(ZSARSuazd<*7(2-M%jM%ehTwN z;9w!vZZciNT$Ae+{OL6!bj^}nL(eJ{OBqE!0cVj{XW}Y#tk5N2&2?DDa^o0y>6je@ z^qQ1v@W;&>8>qPuiF-D>%Y!%LA%ho1xGIfb>srFULFTHmDe=>Aup zT!|tm6-6IF;5qFCC)~W~1S|2%bM*#oKD($#D9m4dUM-5OL=@epRhuA(8yC-;Nfcgh zG|9|@$H~%jYySWYu8ZU}Wq(7oAMqF5J;eTth?yedbOqu~x73YnrI$dSxg{#Tg?{0V zCg!ql5JWoe84EI6SLe&j=ROns5?*JbuU0w4daERxtITsGpT`(I!PqHfN`ClZ5YF0z z^6)SY`^mnNVKy0dl@3S!&{`?%>(MYY0~OAqYre1zyj!<_7f0%E6S)BTo5T2^tD>3C zQEZ~&C^sKNGOvQvg+L4h{P2xM|6I9h0UeaN>9ZF5Ejq?JV~0t8%Q@ypaLf)raixp< zayX4kvCH*qM$q_i={64*;nLr5j$ByAo4VFAmBZi7FL-Vlx_m#;xd|!L{V+`WVPe80 z4|}5_5}kq3lI%(o+0=PP`O`vwB{=&Ut$jvu(DVy;81HKf6tZI>kp5&DPGr)iu)ygw z%G4U=Ce{XNO{)FQ(ir_DPNPKb7cR&}({C&qah|6?$HqCiY1ONU}G<(~88(NxIVrUQz#0wE85`ZCz%dGe9-S7=O>WF#X09^?=H{nUx%1QT~09h8F-_4Ni2`t+I9e*WCb* za1~=d<9~UR2OKHx^>2cn-E#qUWDd$6Hum2}=dfA=3!vk>&gTG{zyo>EU=IDh02CiP zUm}{yLgtKY{OeijDuRa;P7kym=__Baca!|38fVnqOGcACJwO!h#c3i@cs!Y?yextK zfsJ#DW{&$JfiwQ~;oZf%{U5tQLkh5V^9I!pSv*uxR0I(+sGOjnrdm(GM#N@qmwF))a+#*Qq^UyDKO^!Yo!cH2GPb5{ zp_9{|RlMf6y}GEob5rM~VvN w&?Hqw?c+}$ee&?p!}bIH-uXFKDNs~DC{6Hl0zyv3P8G%74Lq3jcN*^h0Gm77;{X5v literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_state.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..973ca09a1911d3baf561dd62c3843a4a0b22ba8b GIT binary patch literal 5591 zcma)A%WoUU8Q-0Ka7j_5M7=H9p&Z4I>{^QBKH^jjoJy>t)}aiNj?o2*1;ZU$Ym-ZQ zc4^lt1r%{m6h(s^dg!5t+U=n*&_fSB^bhE@_hQjoPr3Bc2inw)`}=0em8{58mYCOX zX1@LA`{sKrJENl+1<#*8o@xH$lA`>T2K%2046dLAe`bnuLva;XZ7FTlR@=;GZOzu& zx~;bj+i07%*-qIhRdJcCwX7PodMn+|*qQc-J)$bN6xaBbYG6hnFPxL8*#J1vI&+4HtObp_8Iq;s`1Mw# zRe2a0wO+TyBfa*Z%Om54kEu^o+NDP7xn&j=u5}vq)^*VdJB?1OBt%CG+bor9ky$NO-YZoieRJblDH^So${S9lRK31cu9l*-9DZ|ay@qA*80}9Xgmf=8+(vZs#LZr4LaQZhuFS? z^7kw%uGp%p*vwTS2qs1Wm7i#lI?ml*y%oZmM5S0w_Wr`tTNH(K=|c;WfP zEcW0`IW%Q4hkB3UxOa*$n*IrOUK);$rI^RcBPi1J#|cFm9ZPZSXo@ubvxFjzj-@z$ zG)0>Jc|ws!$5JdDO_8R5kx-=3u@ou193e-V{$)auM#oZ|Jend+|2m;aqhl$~98Hm? zf0Iz8(XkY#j;2V{zfCC8=va!=M^mKf-z5}jbR5MfKlCp*u3xRZy-_+sON*fQ`-D1; zzBu*ut#Y}vUOR&NY0&#aLY+p@eCa)SQm0ngyn3}%fy1j+-Y!=+Yn$+)(R{V`cCB>y z z-D4P;u0pY)TtkG++~K_I)LY&?9%%vM;%t}uuIJx!g8N?B*mk<2)9nQHRv;aae8K37a$m;#RHd!gfeicw&qG7U>Fu$|ch=UEvpjC9dy@dm@v;X{25 zMV^Z8d5F{8R{QE2+DGiMg7g$;d7_q=H9@v2&Y_AHou(&v9CVyec(-nG!Cmy~K4KFD z86b*$iI%TWl|(%uIUmK58$1XcPC*|Tuo94DGip}dIeC!z=hl8sBgDVtoxEqP5%8@J z`GyX@1y0Tq6R%Nqo~i@v%nx6&rzywvg8KU{?jjA3nKOyG^DkoVkeyL>pkIy%9==%U z6mlVQFx^)ltLk%N7ps_r;Fr-vTHST!A%>#8bjVpw4bReOd3f!?JC+|FCrig!dC_qW z-yCJ+QJjzxx`}{`dt3}(5Fe7XID8Crs7USn6rDcX)%%*O^i;9XS3{+z1leyZAEmO1BsvrTBy0qC7?scDdc@g~fVtV5&t(Rodus zMw+Hnh#0}4BD2{M?K+a*3JF_wW*@R$7Mf6T zs?Tm)P~CvaW9=al>JQj`s4>RYq|<@%?tHmX_s@pK?Yi%_@Lff$73uzwvhHtlzepbK z8yH|gQTj^^mebNpiI>4@WPOJ}kRKO+L zLv@$r$ix(CHG~$VkxYd~JSI1On*~eBtN}Aw3Q5jbEoaT(P3S1qWE;x&a=Qp$aR1Px zq;om6;_;et_xzBCY*X}|y{m=kN149nDUZoevGdUg3{rYA3LZLy=K&kI4ht5`x6X}1tG&0g0S2e49hS^567x9g zcfz9Q!&3>~lMyR6f))6*R&ynm&pwNwk5wVXErm=TEH(fcA*DuS{&85C90N7T+~?m9 zoyLPki#JJ-M5llopHcN^86%?>)ScqNyMAyZ0vO4^9AAoYX?iV6RbQd%Evm>C#2Qr=Rh0ZlV~m4*iH3VYUiRdN>noV}4@yAyz(T??J(|&{b!O>L zO~yVmHTJ&@S*(%yFFQfVDIiSGJk5;fUKO;vynHq?;ee38#r}l+WXulPXv~S^ofxxI zvFi?O!|8=yEA}{aswm|kCu})RYynamQu1R&g+4B0HAyp|udX=xl14&lnpmWYT)h;C zJs~|>Ey=&=PZ#lZOxt67+E{OO0`A)SMm?BrGb{)>|Y zH0eh3;Md1(tIO=paqNjIS=xa&lEF$j9VY(BT8sY|Aq!N3AEP?cwHV@(HkqH)Ck>Rn z-(bXa6SvD$&&B=}k&LCuI4$|p5#JEu{>?HJ>2%d%(4HxKm}gJ3h=cT#tNxb#CtEy& QdzwvW8POR0{#D5RAGB7A^8f$< literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_util.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86f9e6247a682778c6fbce8aedefe43466f6216f GIT binary patch literal 3860 zcmai1-Etg96`tSy(`qft|BeeLB#^AJcdaB8AW|tq2muOIE?c3fy%~?D&+d*jJG1WY zl`Pe|sES;bD*}(;P~7BU$OH5(S9t{k3E%0_O0wjFS@ltO@AT>KobQ~|z2)+9%fa)H zzg!t!z2G?iMIE02sd{o?!cXR18?FF{7EnfCgC8Q)CRRleNdk?1`XF4 zIl}v!J7|9F2ww!x91&3Kz#lAO9EuvoHCn>Bjd5KxFmBlKaWDU- z6U*d^4taErIz#W8Gi-@-V&z#lSfRQ&FIL5cKYN4o&~#C(Lena(Lh}W2i5k?Qi*$)D z)45>?eI2Y1#AR{iSunUFu0C+O*T05MPPbwFpBH;3_+^%A)7U8Qlb*@K)bAx)6FTAM zY?_k^Hut7v>MZ||NE3ciWM$C}&GJ22>M||!kEAT6S^Zs^Ci%;A7w*%f)b#RXV<*Wo zk!UiFtvyXD8}6ly=j2nz;4Yea8-kpHE1ZER+<`Be!lwX!4cVi^n)PEisEHcvYDwla z`F-FxA3aHFssS|03X!FW&Wcf#L_1lTqmSuw80j%Zzuw%u*I(M?J zFQAbEltf2+y3F$F_TW$80Be*KrQxPC$c}}AwzXhNosy2Lu&lfvd zMTZVq?8;t{mZoS*Bwvl70(g4&N?nDZ7d;?~)+G(s9})+|?J*$bK>sirmNF8glPp(< z?)?qiDnw?PfU%6BDCH!{4{bQ24~r>5SQ31m>1Yf}%7P+9sLZxzn$|12dc6}<>yZTz zD~**Zh6i=^)`Hhjwgc;vNX>`XP%Q(o0{cXY7XY1xF^?4c zZNyZ_c9TN01#r}~L@1z}0JPeoak9g)&)mX=LtgWiq=lAjf)t-nahM;KwXX*J%0RYw zQ)I~&MLO9g@OsL#XCccf&??}7$MI)TSCM}c2yZgd@!A>)hfnjo+{Je`KgtDiBpyJ| z=osuKqDas%ndO>O(_sE z9mn_+H8SVVgqEox{ZThJQXj=<@o*ny$oUXW-GtE2+&OTyJ9A`9qm&)EpSs$A9?YG& z`-SH^b8qg%p>R;fyp8=I9@l|PQmXSk6bl3}tLVS@q(4T{>5K992`vo>Vv#~Jkwd;o9@ZWyeXP$ zK(yV4+jd*-{^gg<=q(_2U3re*uQTc*nNS>?Rvb@CG0VB%j^oF(BtQJ79>=0gG3}#D z8y~rDceCc45Z9p5I;hPsY7h-4aBtkOb18-|JfvHd~ z;RU%0ks?Hn9`1W+mVG{xnElwDJD<8=x*J_jG78g-V|$v!@t3Z=f|*lz&FirwnPiIM zM4`(^X}k#5*aqVJSfx15YW1MC|K8aY?fqXB8?b`Sl&`V4!GaaaH&}2`oDkNFZ1T_0 z?7j_W)wNDI<3skrU4D&iJ@z5Tw>5vG>!05DRlD)(d#r{*F=ux1iw@2TRF( z=c%W?xySiB51#v9AVXz@1>L|jQKEC~k&aER+ReJcG)Jyne@a^~UuKWQDn{98Q zXF|K^v}5_oxrt^y*75^4K$bM{k^GHWiZ|m2wo+4W8jD`nHQ`n{E5sQB*mL}-KSCT6 zK)65QR_NgdrJ$$)Q{BE-Ehq^9lHs440c4BMYMLsv9J^I3b)!c2(pZ;2&@|I%lu zZi6<+Y|GnFZ~Qb@Cg7X|9Nd#s&op_YP!Mp1+};(3BruJOhtrUW;D}Q1K+HXj9k)GI z|1DBQy9drAl*PG=;^+^9%$Wy&cRzQZhI4#ke;yuDQGp263}w)uBowrZTK76sc5AYa zfAS8CH5R;)d>6vFJ4if!sba!L_m42l(QK*e)UUfW(6GOwyM7EE}u>mz8*`CTKOFoyrsmC7)NqQ zOI9S=4*3%ZvwT=)Qp$5|c${QE=2xuIOyM?~Vs#D2gVEl%p67kj^1c7G0`K2m=>5y9 zbzWR<8&{pNop-gie}K-3gRU`$7mz%T_76O{iWCb3r&u)?V(v9v6E?LpisONcc=9() zn5Z<%_TQi4Xk?;|GQUB4QDMbRF#*lziqkX zIIf7W6yZ`_I literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_version.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea79d73075d4ab74cd301c6309240c16394ddc46 GIT binary patch literal 203 zcmd1j<>g`kg0ubNY3rC67#@Q-$bb>ZaRB0C4j_@j5XF$f7|fu_RK;eXXK12l;HSxW zi#tBPEVZaOGe0jrekDT@&=d&qD?&dbKQ~oBB_q4g(nw#gpfo8bvp7RPEi*4MFF94O zDnGMWFS|%zuPimMOg|?xNxz`7BqKl1SkKTvzc{lbRkt89IXf{uwOBvH&`=*{iC#hF WEe@O9{FKt1R6CIKia|DV@B;w*FEpnB literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/__pycache__/_writers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7e8f878dcf93484b8c6d8db3daddefd2382b65a GIT binary patch literal 4519 zcmb7IOLH5?5#HGs79aqEAPI^TB|(xY1#(1?b}F$Q#gRoK79AQ=kyPw#CD~eG2E;805vP*Jo_%lJ-E(f#rY%pif1@rcNP_Zj= z&GZ+7bN0Dl(O!gkW}nzgOl9Zy2_tQFQL&e)#Y!~GmT8VowN09*g>QBH0xhz_1a+F0 zfO?V6unfzyBJP}6Ez?<8z4W<4=ji;m3Y|Yv?JCSFbOB}yta_x`mtlU6F2a0K&ac3H ziJph~c{#tzH2Ai`Ot!eFq&=Q8G0FhPdoZsqDsn{~--Rvjt8jbdS6N{^YilX5y~4_D zwym;@tRml+;5`rXOKgr^VVBuey8L&|)9q_)gh{BkO%np0fW$;yNNU9N$xyxM2cw94txv{;~XzmGpYje9H zvb&AurgP`s<{w2t4tE;6_wO}#8^YXe?EImzQ&UBGJ8HT9eI6xIEAkthM_gFDa0M@9 zzQ}yFv$faQ*%g^idWJB*;a(7n8PRV1HSNepieXVb_)rxXNi1NfZg-_!*PVg-PMZ+Cb0TbxWScj83QJlmU z3|8V#sw;6J_X;mo$km8F<+QuL@4&5txMuQ2pz|f@M3%eXq-0^?Fmwa3lkAPBuHR)Z z6@D2QfBd@Mi2_!qoySi;{-C~k(0%B8ai`w)LN{!&)n4SqtB-ko6)g9(?t2gG2Zu=~ z3O`(3U#rJ(?#%$?vc|IsX!(e|AgD8-s?fBd#uFW8MxPw1BVE4IVE6j! z`j2y4)hP52t1$~{_3qx@{W?(N60EMopx+S*G;E4|CrJ*RrvO1fD@Q4W88A=*6=ve{ zeU`|}OV!s@{vI$$3rOvz-4)z4(8fSSWRoV%fiC7i8~g?`S$yCO$5ep#9;sjxCMQ*p zNa2sjcRJO+Cjd)A^*+)@5KK&%WhNA2H2DgAi(kWo4L5Fip47omA*cxiTg~Fvkxz=Q z#R(TvapET3*l9%+oP~wyn=>~C4WT7dWoZ0;93vd<{9wz&!-U0es-~O*#SIUgq5MCG zO)+McoQ7B_XF)^jFl|9Q_Mltdh88!WV~S0vVyl!ejj9ZEL3N1g1~nl<8#Ker393c2 zK+Vt`vnHrhG!N7))xrG=B6laEhhJe(;KE=Syi(hqhr^mJw9D{0W~19cO%%{INk~`W z(|zSTu*f5=uYNy(<6u>X)r+tSKz(G6SHDnRke8$hu~$zZvT{^}$Rb=FicwX^o?~hi zmZY*M80cK+G4tE}Ls&Z%hL+<%Nc0`&x4xfV{uo9eEe6yctTVR@*B`z zAucgi@n66|8uq2eKgKccJM9V_o%nNTGK%S>H#c$WNJc5nnaA>9|fxP-#~Xv%%S>fIRUD{_~{!K7}Uz-cl;0Vl8QsdN!)@(#KIvwYE-mY5+=gYO(>Ufojr8L`$qo z>JZVIMD*-N6efVU(R?6YmB(V2glgZ))Fm!(pQ|Z#W6!W>23&q((Vml zosb_zN7Z_vmpIM?{0@FFM|#VrTm@j4GLGSM0tBN_xCYZmUy8XR1O$Ql+fryPVPL;9@sZCDkJ{GjxJSKXp1_Qd z6NQaVH+;%Q1(&`WrwZtdTp`IDkD_UCntvoB__%dv+ z5q=k5XJW4ni_!|ZrbEV*=vz2;+10n;PJ=H|^b=I=sLx4!m{ zMjSaLM*pF)jwih{&C-P}GT=cls7#*vHfxLy#iRm0ZzfRnj(lEi_O7*D^inkH*mIL; zSiP=QTfPT@9_)nnN!#&~W^z#qnA^gB||*u``Y=!D3kt z$?`|$V_raxB6iczL9!YA{field_name})" + 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/.venv/lib/python3.10/site-packages/h11/_connection.py b/.venv/lib/python3.10/site-packages/h11/_connection.py new file mode 100644 index 0000000..d175270 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/_connection.py @@ -0,0 +1,633 @@ +# This contains the main Connection class. Everything in h11 revolves around +# this. +from typing import Any, Callable, cast, Dict, List, Optional, 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("expected CLIENT or SERVER, not {!r}".format(our_role)) + 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() # type: ignore[attr-defined] + 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 + + 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/.venv/lib/python3.10/site-packages/h11/_events.py b/.venv/lib/python3.10/site-packages/h11/_events.py new file mode 100644 index 0000000..075bf8a --- /dev/null +++ b/.venv/lib/python3.10/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, field +from typing import Any, cast, Dict, 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/.venv/lib/python3.10/site-packages/h11/_headers.py b/.venv/lib/python3.10/site-packages/h11/_headers.py new file mode 100644 index 0000000..b97d020 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/_headers.py @@ -0,0 +1,278 @@ +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 + + +# 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 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/.venv/lib/python3.10/site-packages/h11/_readers.py b/.venv/lib/python3.10/site-packages/h11/_readers.py new file mode 100644 index 0000000..08a9574 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/_readers.py @@ -0,0 +1,247 @@ +# 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; if + # this is >0 then we discard that many bytes before resuming regular + # de-chunkification. + self._bytes_to_discard = 0 + 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 > 0: + data = buf.maybe_extract_at_most(self._bytes_to_discard) + if data is None: + return None + self._bytes_to_discard -= len(data) + if self._bytes_to_discard > 0: + return None + # else, fall through and read some more + assert self._bytes_to_discard == 0 + 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 = 2 + 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/.venv/lib/python3.10/site-packages/h11/_receivebuffer.py b/.venv/lib/python3.10/site-packages/h11/_receivebuffer.py new file mode 100644 index 0000000..e5c4e08 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/h11/_state.py b/.venv/lib/python3.10/site-packages/h11/_state.py new file mode 100644 index 0000000..3593430 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/_state.py @@ -0,0 +1,367 @@ +################################################################ +# 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 {} event without a pending proposal".format( + server_switch_event + ) + ) + _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( + "not in a reusable state. self.states={}".format(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/.venv/lib/python3.10/site-packages/h11/_util.py b/.venv/lib/python3.10/site-packages/h11/_util.py new file mode 100644 index 0000000..6718445 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/h11/_version.py b/.venv/lib/python3.10/site-packages/h11/_version.py new file mode 100644 index 0000000..4c89113 --- /dev/null +++ b/.venv/lib/python3.10/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.14.0" diff --git a/.venv/lib/python3.10/site-packages/h11/_writers.py b/.venv/lib/python3.10/site-packages/h11/_writers.py new file mode 100644 index 0000000..939cdb9 --- /dev/null +++ b/.venv/lib/python3.10/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/.venv/lib/python3.10/site-packages/h11/py.typed b/.venv/lib/python3.10/site-packages/h11/py.typed new file mode 100644 index 0000000..f5642f7 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/py.typed @@ -0,0 +1 @@ +Marker diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__init__.py b/.venv/lib/python3.10/site-packages/h11/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2c601f21464f6c15f07f60ccd90bbe258e5b1fc GIT binary patch literal 187 zcmd1j<>g`kg0ubNX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10QKO;XkRX-&o zyU@}|U$3AvDJQcyLq9DuFEKAURj(>Pvsf>?NMElkHLpxRCo@UEpt2+*KhIdt&_KU9 zvm{lwATc>RF+H_dKf};aza+J|q*y;bJ~J<~BtBlRpz;=nO>TZlX-=vg$lhWmAi=@_ E05+#Ck^lez literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/helpers.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..060d9b333bc6e06149d55c70b237c659d1a268ba GIT binary patch literal 2804 zcmZt|U31&U@$PT{L6D*-iIPIui4{9-&9)Kaq#x5x#b*I~lMAu|oGWs%l$~?9Y|16zZ2p$WWx4W<$dxlD-j}T%(pi0pKI*uJ4+mLp_`L|> z?#VuHO!G+?e}`y;r8v_+s6Ci_QRdtcBf*R zuLbVJ<4j4zw+H#a)O)GCKl)r{*-Ek(O4$~R5yqpsBAJ$Gi53d)FJGf z8~=g?R(f~t-R<>v@p~V(0=4)1JrjKXaA!BPB;)P$9z5zj=uqSDfc7X=G2oSZQLgkL zhGT;1#?vZ4(&-Q~Vg5LP;kW}M`yGHiGNn~gkaO~!Oj*HlnzIo*Cb|h!xY81F2WuX9(N}v`TjWlWb4L9-3%P^;bbs8fJkKB{TnyBIXD|I6~q47*5t%A z_Ea7Y;<&UrTZ1jLcK~q8s88zvxf{F+N{q69>8rprTtcLWc(98H@wsQ0VS+v_sPz{u z$Qk%jUjlN6nYva(6&PJYuj^Hu?Q1wIjh+uqlkxTjtGB@YI zdUQ3#N{pk^G6FN#{TPI1k;k~V=yiyF1AGj#Z|WYW`X?YUgz?6MNqh@N76VX3P)P)X zF6BrL-N;c~QspWSx*C(N^q%oEDk{~AY(Q`GRkcl^g9WOl>TROxBL?%}^;|8;3ao?> zfR@I{mo-^`=88qhzT1knjkk)%$|!5q9q0Q>zo3R^DjvPKa|9r|WOp zx^*G-J#(>;thv}b3i5=U)8})8$~rOLv2E9S3vJq*0~=izn_p%%psIkKw%*#>3K$of z@o?X8J&u*BWsqyLL@=KEY66Xah(&hsU^m0L)%$lqup)AL#xlQPdvwYqopQ;h&?2F} zR;M0V4mH#!=T6~0r_)MNkytxdq%(C78wD>aza&$Rn7(0U3D!)TzzVnESR;k2Z@$fu zWkV^o&sUt$sb4_C9WdQ5*c8H9IM%jDg#)%Z1#k~o_NU*IKhuIk>bU)X;=w-K)t|rz z?y?}tq7-TmI;!E&U-L535a3km4?#wMfZ!@hS9KThpCR};f?puG2Ecejdl8D@wL68M zs;6bAdk^I{=K!One+>Zdp$wBV@I1=l^=T7^M+3(B8qC+A8h!W%K&!*|bmgsx;&#wO zZT@#?d8np=OiTxf3PTfwVKSCSG2-g8(lwjW>kGj$se*okMLR&7SP1fZc?VVQccCTQlCG%;&E>#{S!I*f%ZCUNN`v zAB~dz&Q;^Vtr(?y<$Y=QvisYu(J)gBF?Gv-lG4igB`Yek?6tS5?UWjR5NGBtBGyE( zgnB$|v+%26i+cshEd;9wu*`)U9_3M7o*a*AYIl>#Sm!;h$673vc7|}*t2Bcjn#?9f y=?}b+Y^Sux`hT7={-;rna3fC=bLWrA`eY?gt7B(u&t^WbF(r>u{ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_against_stdlib_http.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_against_stdlib_http.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..026d99b61ebec0fab3518cec3ae2236857936021 GIT binary patch literal 3839 zcmZ`+&2tpT6`$_;*bl8%DMGQ`s`LHEg$}m1bvF z-LnvhRh1oar8p$F+(6M&%yEPxSmZRaFKckyb{nq!dJWHh{f3V(kAhCF zk?Z6ec}DVXROl2NMO*ixkxr>m>WnrG}aXB?52 zqo_{^CfKq&<1BlkAd1ht9o9G|`P$^*xTRC_#4ZyfySy98s3V9k=nmI4;IS<(bzw4bHfj0B3^s z1Kt_%j)_U|&I-2ZRHt5%#ulpF3iC3SDohg^lIy7`>B`vTRx{C>36xBGDsJI24jvaZ zx~3M2z6bKPlR5*as_*RbZI<#ix6jr*!G+sq!h6oQx$yhE>2H<$d=Tv7@O}0L=mUHQ zIcf`M@u2?1sRlUPR$=zi<=REOvx-(XqunHmnr$3YJr1Llr;~r1|JT;DPjH+d4b_TF zO|bq16}?o=o03ji>oV1lmC6*BZrxiPR?}4_LqR$VmTc9GTB+u8q9h3iB9xsZHonHR zsmbfrUMi9&an)6HYU8h_X;)xTJNl)gPN4UHaeX!E$hufv-?(zAUhDQAMQy!WUv9@? z+>*7eq^)b~s$P367O!B599|Z_B45CirJncn)SgRL9vJa7{^bYleTsF_Hm)68z8m-r8}ITj%=oUps$f2fQip!oCaciOX2wpudFv zcFZdQ$& z_HifCsVPKBD~wiAed(H@BY`TRNZs&a0J>Cq=@o^XSAPeop0r@FccjQ-OpxKojJMzx zU{CO)v23MnIDm47t!5~Ml3E)V$TY=U2Lg@Y)^9$WTUatVEn@+XN){UnlN(~el;&db z+vU3$3t*eVqs>%?N`;%I7{gUJ;cep7_+2Ov$5@z~yWPBfbLpljDcO?k$FfO?H6B`z zjhAkArODryx|_sWnh`jsw5PFMA&qz23R-cWR?&yiMBPt<^rDinIfyeg}a28x~nIq*0B(9gi@SU)pF?9vOP(R7>Z!As zT%99A*R1Xnd9#;;4XIy&LFXODwKB6kE%Y2bIn)jy_fIs2aqVZ@FrGD@8INECWP^Q< z%+O7})Tbx`P)-u`C>InQ5#tQO2W{kn+x}r=wrTT)!>0TW_u64@nn%R+2StJmKo+DU z{lLb*KzK;&{r$Ms4@7`A#kq&Hw#cKWfS%%v^VrcVwvS@Y$imhXrCe9*^{3lcpKjMR zvOMH!NN&jZECe#+pd`c^$5!!;kO`1dBW<$=vsLUNqFg{Mh|_8*3q+)5RRb{rjG_~! z)^Zi8*5r`Wk}**T2!&dpK0iuAp)*UojE-t9bL<`kKxADBGFBIB8n$eqpneCTLlZ$Idau;V%gtpHnY6nZ}4sV6#OPWq?SeH@iqA6{SgvoRBGJN~`U|m$YFqY$iSp zwR|fUQ0|*4llBkTCT;w|h_Ri{|8G3ol*b* literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_connection.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_connection.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7acdab07942867cc6a43f6538a9bc6c7f6830101 GIT binary patch literal 33072 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_events.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_events.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30b6a6d3e69855f50eb1cd2b9173cae1c617f901 GIT binary patch literal 2935 zcmaJDO>Y}TbZ2(GUa!}V}WvsBv%Qf?|R zT{B3#>A-TWAme5N+qHwNn^in!+X-@R4)%FwvCKDyn}?mvvalP2ox^glD=>OpD~;`e zU9Ci<{n3pZSFguj+!afEG@+$y{w+U@MJX){7o#xr>v1azFSaA$GihA%Voy4YA-l5j znJjp|)a zkGM3sA9s0JN7n|w3~cbZ2#@#^jxE+6keEIs_r{49>x?isss>>OOYIn2+D$k>1OD4O z(L$@LiJ9AQsQCXJo*{lS;qPgy21~C|QNFBwO#n+V3$VBPn8`8?0{FXqJk4ytE+ID1 z#j*`LunzJd!JGyKuA7Q$;BE21dXD7|C64*KKH~4Qr2F0dSpslq2SB2wEZ}&ZTe~{@xcEHlW_kNyw zI>g=26FHuze@1NmdPMrfbEGp>?LHB?Vfol*6Uy4j9lB-ojMXfgSfjx8lFFk2S(?PW z0_F8SCC#Q3er_adV-SbUrU$x?_?=k3JYv~lGYt(+^wf^NmFlIy@{H2^rLvP+H5;13 zSNgcRQQ${-%&x;G4mFKrIEFG>Bw#T$=Fr9>t1 zBw2o}SIgC1Lz;mfHzOv^*y9a9mg%PNF`o8ay9Hb5H^{vpu&siYM+8<-q*hPC zW%UktO4K!)SFXpKS^q09=(PQEJqm!;0Fh=SVv&W-$SY}l1aw{i`esVY*-lpKA4HL> zdxDiHpF_F{dqVFB)S}Jb`FAr9Zp>HavAb3vjy(o+h%75qtF6@|2w_su_$(~^6o9^q z)xBQ;+4~K^uFmISQJj1Vc2ch{Bw^x;*1+%z^izXDTiz@lZP%}rN=0dQHe%?%uF1WY z@CA2JCC(>4f#4(p^d+&7Sq5&8b8kbMUZ>-SjAH{%9KplkCW12v(g;!jq{00TFJ+|8 z{dLz`_E@dn^mwvEh02OcTO2t>M-t}heiTSrukUKS3@RRbm1Y$971mr^KYy-L?sS*i zEzzv3v_dbe`{m83CCY2OQifS`tI}>QS0Jor6uwceE>uJ-_Rn^_`WlQQQE67I6^vLY z*q>(Q&W6k)wU5JC*2GT$973s0to_-iMKe$Hq(Jh7>XcAo;`5}Kb`+N2)|1(N$HKRV zxRn7N>JO3xIp|$#4>-&xmSqu}Adj*GZyht?Hx&Qee%>mOB3O24fdHl#U_Zbdz~=T7 zXv5wF9+OTIz5vdT3`@NBm<=^7mtYfXF3$@h*{stHdUtf_&5J z{Nb%1c7xhbE!>5-!U9l$0H+BA_ckEMg2S7qg2Qr(Rap3;1oJ4xOq~BQ&Tt4s&GZxK zIO5Ej(O3q8R>3JshS_RLtKg9GK!2#QY=3qy9E6-(;(4&e#{fXFpN8eIb40uWHEkaj z-KM?f`<=61y9I3tFBm_8Ku3Vd0S#E~kA{1UQX;S%>j&Rjj}SdnRidiYRU3LosZsog zcKLav8mg$J-u6RP&oaZk+cl_+K=3z#;b=CBDjP{Vt<^oz3LD=6o4{U_T+e<1m_@jp zR&v3g@(XB-@*FHnrEzIs8|HWo_^SY<#<4A_u8?#J)g&;tNgq*-2M@qa)w*%3owOso q%PQwe{g9{F8o0VV)`cKq-M0T8o}|Eb>}VEs=qtp@*t#9&Gyeg#+J=Jw literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_headers.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_headers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05d7ccfca600052594472d024336cdb23d3bc46f GIT binary patch literal 3687 zcmaJ^&u=3|7VfHUyW5WKNkS&WKo|@o0WA_co>^%@Aha-wc7!0X>`1G%7Oak|W1HCB zp{kw9Sc8NJ5?l~_=750PTsZB8KLT!CTHKJ3khq|T%Lvwdui6f7k9%zSx!#ZO)vM}P zuU?1ca?!x&n@=w6|9svsejsM{V}kh`e(Eg{VF=bYnug%Q?6U!HazlX&aW)b7Eu!Zx1)m*};Ac`23Fj^8NjLL%j({L+4VGd*WCl2be z*nY!*XXvZQ&Bekl%RfH!+fl2ry$xj$^@5=v+t;;$ir0fs z4!nMEUjKFCa z%Do9GegBPLl*U*Ym}`qM@6tTE49uIe7?F>x+s50u6Lw^%g9Xvr8D8F-^)eT&lY#m4 zKA1uV=6{PZdWFRd%(t@`u{5*7?-#7Fl;P!x@h}mM?-j8>MREzoBO8M9o;Mmf82m?K+Xs4L>MM{nw#G_kiEWHa zTvLnaD#n^iGzm>>U~y?oNYG?FLmi8=(ww#eOV0C*k1byOzhfpAoaI@53?J}*X`JAu zI+9Q%Q=4^5UPj2-t;}c8Mh1!-qvD1#z;2_7IpL6)Us7YUq6-Cw)Dk(7M}aV5Wqxi& zIW#rPD8Px%PIL=en?|~Hz_X)0C#8(gXbMrn;P*B~vZS@Io|To-u4|&O6mg6KG=04= zh;!|JsC<_`YE(~1r z6rG%*oyjsrk{pM@|nR8)3m zrib_`Nc4gAW|=*?3Hj)p=+OVN}BF!xj}`dVO%sI8O-_ ziZ~y65*s0}Aarc@U-6gNA_KMU$ZXWMT}wU#jeM2}nZ~7V6dksZj0!mlAmx@ciBJKX zA$r5l>kX%unc26P_hG5X8^;-@FSh)5XUy#i14WIPkvUV2GwZj~SUv|BrllO;bu0SO zH|-WqM-V9;N9;_CU6LU>z&y;8tf7Qy=32w3*VoyiONV~E+V#u=^m_CvoaYCj820@a WQ11;z$Hy^Be1nzjqFMY$fgc5Zztdv7L{qmkP)kA?1Kg(k~&Qs#53yB!X0KzC=!T6I=0DcQ=*NBk8r` zckoZR@CSV5lru<3aDbUj5Jh4wzu9?yJKA~UveRi2Sf4*Um~|~ezF=~H0Y}c^Rc8R4 zaGH^vMl@#;%dN=D?a0oZ$jKW~BX=X063)1ldAT3?u=jX_ySH}Ka;9|S*ZlC?U%8R>-I&#-_G6$rQ*4$or`Nx==$JQF)L*rqdLwmg{sOziQ2ss zS4*LE?fs!P6syzvpg?(+-iR@Ws$+p=RNat5FJ&>Bg6f~uhHMD0x&_cgQ_VPCQ_k+F zrra{o;`W?y=Z*o>*nM$LwAXL~8r`b>U2I~U`)jPwGTi+NZNqF&c8t#@3}bgY+ZJS{ockcgNIsf^^%;E};&gC_=06&l|km~eQc zaHz*8r#(mF@Fk|TKUrxJOBt`EholYgk;sR*NBA)blQI_}PZn3t2VqbxCt0eJaF!Nv zF%`j0nW|tR!vNgA4zqL;Rx6#9#bMBY7OGT>r&T;%z+6?B^!uTP(J6!DL}V3o5LBzW zi}d)v^XtGJ)Dr+k+sva)>cL|h^eFqzet8|_kYPXD-((l0JtkWaM!i<#?tTM_PMD5O shtk2cf#4!w>*%Su(bgR-^w);%?h(qo7kSB-nK;8)DXj6BwEaEnH_^V&4gdfE literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_io.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_io.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4699a9f911abf19f7f087961dabbd6a3a63895e2 GIT binary patch literal 12308 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 CDWx$0 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_receivebuffer.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_receivebuffer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea5823eb64c9d0ce3fa9eaa2a01d9580508c1b6e GIT binary patch literal 2302 zcmZ`)&2Jk;6rY*>h_mq~u9GHB`La|bYKeO5q#rawRYiM1fC8eCkXA+3+B1%qtasg+ zO{gokLbT!r^u!S*+~CL`z>ymlj(dbt;Ft^Q0rB4Krda&ayv9#GHXl)cj?>$uxp)XU zkj*B|tgYQqBn}y{z_}lao(T8ETf6bV43cPIs7E&^*&T1AYbh3E{?7jaRRf@FwVAE8z{`y%YS^+%;cz~YON zhbr)26&_HJ{5K^%M);bZx^k3zFr zU=6+kCx1rUpUY)Ws61cTtvKoTwN8t+v+gzk9;BtBH)76soOP3v2RW#Dg z8F=i(xdPB22*CWAqg?H%D(I)wFKcT61{;m8>-3XkqZ>%qah+5KVHC#OO+(HANSQzo zq>w9cI`}bAVQye~$PqpVsgPLOtn ziAw#IX>knt4&)`W#c2h~RFh@2n^}7OJ&|>Y@pRw~lA-YUVCU|&HLo?=?M9&*c>ORA z;+|;TPeRq&kzQ+0#Cu*8cD>O!9VGF3t9{W^VJa?+g5FNBEtEHCw>`)-Rho8W-k`d= zLA6HXtd7cQG2WxP1H`5kT7zGO<#UbIORE}1u4301U|>{mKBgwFHE*MB9kHxVmzYB< zW}PlmxrAqF@*oYGmO2H@+gn>7cEP82}#2bxXlqdmmtXQzdZQO=aY;+So_7^`5(?O>vqke~rC>+8eN$A)t z0N6=_bD_VV`4z_ zp}P5;DcS&qzZh&*jb}~3*lZeV0lb|!26YBQ{m&ifYx~zB=&isD#6%^!l-MhpraX;n zJnGEEVwZU7y4-Vu*O{IFcR6*Gv;5WGd;6E+21do`v<=ZA&39~ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_state.cpython-310.pyc b/.venv/lib/python3.10/site-packages/h11/tests/__pycache__/test_state.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf764082501305e7de472fae28ff8c41146294e6 GIT binary patch literal 5371 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 List[Event]: + got_events = [] + while True: + event = conn.next_event() + if event in (NEED_DATA, PAUSED): + break + event = cast(Event, event) + got_events.append(event) + if type(event) is ConnectionClosed: + break + return got_events + + +def receive_and_get(conn: Connection, data: bytes) -> List[Event]: + conn.receive_data(data) + return get_all_events(conn) + + +# Merges adjacent Data events, converts payloads to bytestrings, and removes +# chunk boundaries. +def normalize_data_events(in_events: List[Event]) -> List[Event]: + out_events: List[Event] = [] + for event in in_events: + if type(event) is Data: + event = Data(data=bytes(event.data), chunk_start=False, chunk_end=False) + if out_events and type(out_events[-1]) is type(event) is Data: + out_events[-1] = Data( + data=out_events[-1].data + event.data, + chunk_start=out_events[-1].chunk_start, + chunk_end=out_events[-1].chunk_end, + ) + else: + out_events.append(event) + return out_events + + +# Given that we want to write tests that push some events through a Connection +# and check that its state updates appropriately... we might as make a habit +# of pushing them through two Connections with a fake network link in +# between. +class ConnectionPair: + def __init__(self) -> None: + self.conn = {CLIENT: Connection(CLIENT), SERVER: Connection(SERVER)} + self.other = {CLIENT: SERVER, SERVER: CLIENT} + + @property + def conns(self) -> ValuesView[Connection]: + return self.conn.values() + + # expect="match" if expect=send_events; expect=[...] to say what expected + def send( + self, + role: Type[Sentinel], + send_events: Union[List[Event], Event], + expect: Union[List[Event], Event, Literal["match"]] = "match", + ) -> bytes: + if not isinstance(send_events, list): + send_events = [send_events] + data = b"" + closed = False + for send_event in send_events: + new_data = self.conn[role].send(send_event) + if new_data is None: + closed = True + else: + data += new_data + # send uses b"" to mean b"", and None to mean closed + # receive uses b"" to mean closed, and None to mean "try again" + # so we have to translate between the two conventions + if data: + self.conn[self.other[role]].receive_data(data) + if closed: + self.conn[self.other[role]].receive_data(b"") + got_events = get_all_events(self.conn[self.other[role]]) + if expect == "match": + expect = send_events + if not isinstance(expect, list): + expect = [expect] + assert got_events == expect + return data diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_against_stdlib_http.py b/.venv/lib/python3.10/site-packages/h11/tests/test_against_stdlib_http.py new file mode 100644 index 0000000..d2ee131 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_against_stdlib_http.py @@ -0,0 +1,115 @@ +import json +import os.path +import socket +import socketserver +import threading +from contextlib import closing, contextmanager +from http.server import SimpleHTTPRequestHandler +from typing import Callable, Generator +from urllib.request import urlopen + +import h11 + + +@contextmanager +def socket_server( + handler: Callable[..., socketserver.BaseRequestHandler] +) -> Generator[socketserver.TCPServer, None, None]: + httpd = socketserver.TCPServer(("127.0.0.1", 0), handler) + thread = threading.Thread( + target=httpd.serve_forever, kwargs={"poll_interval": 0.01} + ) + thread.daemon = True + try: + thread.start() + yield httpd + finally: + httpd.shutdown() + + +test_file_path = os.path.join(os.path.dirname(__file__), "data/test-file") +with open(test_file_path, "rb") as f: + test_file_data = f.read() + + +class SingleMindedRequestHandler(SimpleHTTPRequestHandler): + def translate_path(self, path: str) -> str: + return test_file_path + + +def test_h11_as_client() -> None: + with socket_server(SingleMindedRequestHandler) as httpd: + with closing(socket.create_connection(httpd.server_address)) as s: + c = h11.Connection(h11.CLIENT) + + s.sendall( + c.send( # type: ignore[arg-type] + h11.Request( + method="GET", target="/foo", headers=[("Host", "localhost")] + ) + ) + ) + s.sendall(c.send(h11.EndOfMessage())) # type: ignore[arg-type] + + data = bytearray() + while True: + event = c.next_event() + print(event) + if event is h11.NEED_DATA: + # Use a small read buffer to make things more challenging + # and exercise more paths :-) + c.receive_data(s.recv(10)) + continue + if type(event) is h11.Response: + assert event.status_code == 200 + if type(event) is h11.Data: + data += event.data + if type(event) is h11.EndOfMessage: + break + assert bytes(data) == test_file_data + + +class H11RequestHandler(socketserver.BaseRequestHandler): + def handle(self) -> None: + with closing(self.request) as s: + c = h11.Connection(h11.SERVER) + request = None + while True: + event = c.next_event() + if event is h11.NEED_DATA: + # Use a small read buffer to make things more challenging + # and exercise more paths :-) + c.receive_data(s.recv(10)) + continue + if type(event) is h11.Request: + request = event + if type(event) is h11.EndOfMessage: + break + assert request is not None + info = json.dumps( + { + "method": request.method.decode("ascii"), + "target": request.target.decode("ascii"), + "headers": { + name.decode("ascii"): value.decode("ascii") + for (name, value) in request.headers + }, + } + ) + s.sendall(c.send(h11.Response(status_code=200, headers=[]))) # type: ignore[arg-type] + s.sendall(c.send(h11.Data(data=info.encode("ascii")))) + s.sendall(c.send(h11.EndOfMessage())) + + +def test_h11_as_server() -> None: + with socket_server(H11RequestHandler) as httpd: + host, port = httpd.server_address + url = "http://{}:{}/some-path".format(host, port) + with closing(urlopen(url)) as f: + assert f.getcode() == 200 + data = f.read() + info = json.loads(data.decode("ascii")) + print(info) + assert info["method"] == "GET" + assert info["target"] == "/some-path" + assert "urllib" in info["headers"]["user-agent"] diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_connection.py b/.venv/lib/python3.10/site-packages/h11/tests/test_connection.py new file mode 100644 index 0000000..73a27b9 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_connection.py @@ -0,0 +1,1122 @@ +from typing import Any, cast, Dict, List, Optional, Tuple, Type + +import pytest + +from .._connection import _body_framing, _keep_alive, Connection, NEED_DATA, PAUSED +from .._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from .._state import ( + CLIENT, + CLOSED, + DONE, + ERROR, + IDLE, + MIGHT_SWITCH_PROTOCOL, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, + SWITCHED_PROTOCOL, +) +from .._util import LocalProtocolError, RemoteProtocolError, Sentinel +from .helpers import ConnectionPair, get_all_events, receive_and_get + + +def test__keep_alive() -> None: + assert _keep_alive( + Request(method="GET", target="/", headers=[("Host", "Example.com")]) + ) + assert not _keep_alive( + Request( + method="GET", + target="/", + headers=[("Host", "Example.com"), ("Connection", "close")], + ) + ) + assert not _keep_alive( + Request( + method="GET", + target="/", + headers=[("Host", "Example.com"), ("Connection", "a, b, cLOse, foo")], + ) + ) + assert not _keep_alive( + Request(method="GET", target="/", headers=[], http_version="1.0") # type: ignore[arg-type] + ) + + assert _keep_alive(Response(status_code=200, headers=[])) # type: ignore[arg-type] + assert not _keep_alive(Response(status_code=200, headers=[("Connection", "close")])) + assert not _keep_alive( + Response(status_code=200, headers=[("Connection", "a, b, cLOse, foo")]) + ) + assert not _keep_alive(Response(status_code=200, headers=[], http_version="1.0")) # type: ignore[arg-type] + + +def test__body_framing() -> None: + def headers(cl: Optional[int], te: bool) -> List[Tuple[str, str]]: + headers = [] + if cl is not None: + headers.append(("Content-Length", str(cl))) + if te: + headers.append(("Transfer-Encoding", "chunked")) + return headers + + def resp( + status_code: int = 200, cl: Optional[int] = None, te: bool = False + ) -> Response: + return Response(status_code=status_code, headers=headers(cl, te)) + + def req(cl: Optional[int] = None, te: bool = False) -> Request: + h = headers(cl, te) + h += [("Host", "example.com")] + return Request(method="GET", target="/", headers=h) + + # Special cases where the headers are ignored: + for kwargs in [{}, {"cl": 100}, {"te": True}, {"cl": 100, "te": True}]: + kwargs = cast(Dict[str, Any], kwargs) + for meth, r in [ + (b"HEAD", resp(**kwargs)), + (b"GET", resp(status_code=204, **kwargs)), + (b"GET", resp(status_code=304, **kwargs)), + ]: + assert _body_framing(meth, r) == ("content-length", (0,)) + + # Transfer-encoding + for kwargs in [{"te": True}, {"cl": 100, "te": True}]: + kwargs = cast(Dict[str, Any], kwargs) + for meth, r in [(None, req(**kwargs)), (b"GET", resp(**kwargs))]: # type: ignore + assert _body_framing(meth, r) == ("chunked", ()) + + # Content-Length + for meth, r in [(None, req(cl=100)), (b"GET", resp(cl=100))]: # type: ignore + assert _body_framing(meth, r) == ("content-length", (100,)) + + # No headers + assert _body_framing(None, req()) == ("content-length", (0,)) # type: ignore + assert _body_framing(b"GET", resp()) == ("http/1.0", ()) + + +def test_Connection_basics_and_content_length() -> None: + with pytest.raises(ValueError): + Connection("CLIENT") # type: ignore + + p = ConnectionPair() + assert p.conn[CLIENT].our_role is CLIENT + assert p.conn[CLIENT].their_role is SERVER + assert p.conn[SERVER].our_role is SERVER + assert p.conn[SERVER].their_role is CLIENT + + data = p.send( + CLIENT, + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Content-Length", "10")], + ), + ) + assert data == ( + b"GET / HTTP/1.1\r\n" b"Host: example.com\r\n" b"Content-Length: 10\r\n\r\n" + ) + + for conn in p.conns: + assert conn.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + assert p.conn[CLIENT].our_state is SEND_BODY + assert p.conn[CLIENT].their_state is SEND_RESPONSE + assert p.conn[SERVER].our_state is SEND_RESPONSE + assert p.conn[SERVER].their_state is SEND_BODY + + assert p.conn[CLIENT].their_http_version is None + assert p.conn[SERVER].their_http_version == b"1.1" + + data = p.send(SERVER, InformationalResponse(status_code=100, headers=[])) # type: ignore[arg-type] + assert data == b"HTTP/1.1 100 \r\n\r\n" + + data = p.send(SERVER, Response(status_code=200, headers=[("Content-Length", "11")])) + assert data == b"HTTP/1.1 200 \r\nContent-Length: 11\r\n\r\n" + + for conn in p.conns: + assert conn.states == {CLIENT: SEND_BODY, SERVER: SEND_BODY} + + assert p.conn[CLIENT].their_http_version == b"1.1" + assert p.conn[SERVER].their_http_version == b"1.1" + + data = p.send(CLIENT, Data(data=b"12345")) + assert data == b"12345" + data = p.send( + CLIENT, Data(data=b"67890"), expect=[Data(data=b"67890"), EndOfMessage()] + ) + assert data == b"67890" + data = p.send(CLIENT, EndOfMessage(), expect=[]) + assert data == b"" + + for conn in p.conns: + assert conn.states == {CLIENT: DONE, SERVER: SEND_BODY} + + data = p.send(SERVER, Data(data=b"1234567890")) + assert data == b"1234567890" + data = p.send(SERVER, Data(data=b"1"), expect=[Data(data=b"1"), EndOfMessage()]) + assert data == b"1" + data = p.send(SERVER, EndOfMessage(), expect=[]) + assert data == b"" + + for conn in p.conns: + assert conn.states == {CLIENT: DONE, SERVER: DONE} + + +def test_chunked() -> None: + p = ConnectionPair() + + p.send( + CLIENT, + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Transfer-Encoding", "chunked")], + ), + ) + data = p.send(CLIENT, Data(data=b"1234567890", chunk_start=True, chunk_end=True)) + assert data == b"a\r\n1234567890\r\n" + data = p.send(CLIENT, Data(data=b"abcde", chunk_start=True, chunk_end=True)) + assert data == b"5\r\nabcde\r\n" + data = p.send(CLIENT, Data(data=b""), expect=[]) + assert data == b"" + data = p.send(CLIENT, EndOfMessage(headers=[("hello", "there")])) + assert data == b"0\r\nhello: there\r\n\r\n" + + p.send( + SERVER, Response(status_code=200, headers=[("Transfer-Encoding", "chunked")]) + ) + p.send(SERVER, Data(data=b"54321", chunk_start=True, chunk_end=True)) + p.send(SERVER, Data(data=b"12345", chunk_start=True, chunk_end=True)) + p.send(SERVER, EndOfMessage()) + + for conn in p.conns: + assert conn.states == {CLIENT: DONE, SERVER: DONE} + + +def test_chunk_boundaries() -> None: + conn = Connection(our_role=SERVER) + + request = ( + b"POST / HTTP/1.1\r\n" + b"Host: example.com\r\n" + b"Transfer-Encoding: chunked\r\n" + b"\r\n" + ) + conn.receive_data(request) + assert conn.next_event() == Request( + method="POST", + target="/", + headers=[("Host", "example.com"), ("Transfer-Encoding", "chunked")], + ) + assert conn.next_event() is NEED_DATA + + conn.receive_data(b"5\r\nhello\r\n") + assert conn.next_event() == Data(data=b"hello", chunk_start=True, chunk_end=True) + + conn.receive_data(b"5\r\nhel") + assert conn.next_event() == Data(data=b"hel", chunk_start=True, chunk_end=False) + + conn.receive_data(b"l") + assert conn.next_event() == Data(data=b"l", chunk_start=False, chunk_end=False) + + conn.receive_data(b"o\r\n") + assert conn.next_event() == Data(data=b"o", chunk_start=False, chunk_end=True) + + conn.receive_data(b"5\r\nhello") + assert conn.next_event() == Data(data=b"hello", chunk_start=True, chunk_end=True) + + conn.receive_data(b"\r\n") + assert conn.next_event() == NEED_DATA + + conn.receive_data(b"0\r\n\r\n") + assert conn.next_event() == EndOfMessage() + + +def test_client_talking_to_http10_server() -> None: + c = Connection(CLIENT) + c.send(Request(method="GET", target="/", headers=[("Host", "example.com")])) + c.send(EndOfMessage()) + assert c.our_state is DONE + # No content-length, so Http10 framing for body + assert receive_and_get(c, b"HTTP/1.0 200 OK\r\n\r\n") == [ + Response(status_code=200, headers=[], http_version="1.0", reason=b"OK") # type: ignore[arg-type] + ] + assert c.our_state is MUST_CLOSE + assert receive_and_get(c, b"12345") == [Data(data=b"12345")] + assert receive_and_get(c, b"67890") == [Data(data=b"67890")] + assert receive_and_get(c, b"") == [EndOfMessage(), ConnectionClosed()] + assert c.their_state is CLOSED + + +def test_server_talking_to_http10_client() -> None: + c = Connection(SERVER) + # No content-length, so no body + # NB: no host header + assert receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n") == [ + Request(method="GET", target="/", headers=[], http_version="1.0"), # type: ignore[arg-type] + EndOfMessage(), + ] + assert c.their_state is MUST_CLOSE + + # We automatically Connection: close back at them + assert ( + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + == b"HTTP/1.1 200 \r\nConnection: close\r\n\r\n" + ) + + assert c.send(Data(data=b"12345")) == b"12345" + assert c.send(EndOfMessage()) == b"" + assert c.our_state is MUST_CLOSE + + # Check that it works if they do send Content-Length + c = Connection(SERVER) + # NB: no host header + assert receive_and_get(c, b"POST / HTTP/1.0\r\nContent-Length: 10\r\n\r\n1") == [ + Request( + method="POST", + target="/", + headers=[("Content-Length", "10")], + http_version="1.0", + ), + Data(data=b"1"), + ] + assert receive_and_get(c, b"234567890") == [Data(data=b"234567890"), EndOfMessage()] + assert c.their_state is MUST_CLOSE + assert receive_and_get(c, b"") == [ConnectionClosed()] + + +def test_automatic_transfer_encoding_in_response() -> None: + # Check that in responses, the user can specify either Transfer-Encoding: + # chunked or no framing at all, and in both cases we automatically select + # the right option depending on whether the peer speaks HTTP/1.0 or + # HTTP/1.1 + for user_headers in [ + [("Transfer-Encoding", "chunked")], + [], + # In fact, this even works if Content-Length is set, + # because if both are set then Transfer-Encoding wins + [("Transfer-Encoding", "chunked"), ("Content-Length", "100")], + ]: + user_headers = cast(List[Tuple[str, str]], user_headers) + p = ConnectionPair() + p.send( + CLIENT, + [ + Request(method="GET", target="/", headers=[("Host", "example.com")]), + EndOfMessage(), + ], + ) + # When speaking to HTTP/1.1 client, all of the above cases get + # normalized to Transfer-Encoding: chunked + p.send( + SERVER, + Response(status_code=200, headers=user_headers), + expect=Response( + status_code=200, headers=[("Transfer-Encoding", "chunked")] + ), + ) + + # When speaking to HTTP/1.0 client, all of the above cases get + # normalized to no-framing-headers + c = Connection(SERVER) + receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n") + assert ( + c.send(Response(status_code=200, headers=user_headers)) + == b"HTTP/1.1 200 \r\nConnection: close\r\n\r\n" + ) + assert c.send(Data(data=b"12345")) == b"12345" + + +def test_automagic_connection_close_handling() -> None: + p = ConnectionPair() + # If the user explicitly sets Connection: close, then we notice and + # respect it + p.send( + CLIENT, + [ + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Connection", "close")], + ), + EndOfMessage(), + ], + ) + for conn in p.conns: + assert conn.states[CLIENT] is MUST_CLOSE + # And if the client sets it, the server automatically echoes it back + p.send( + SERVER, + # no header here... + [Response(status_code=204, headers=[]), EndOfMessage()], # type: ignore[arg-type] + # ...but oh look, it arrived anyway + expect=[ + Response(status_code=204, headers=[("connection", "close")]), + EndOfMessage(), + ], + ) + for conn in p.conns: + assert conn.states == {CLIENT: MUST_CLOSE, SERVER: MUST_CLOSE} + + +def test_100_continue() -> None: + def setup() -> ConnectionPair: + p = ConnectionPair() + p.send( + CLIENT, + Request( + method="GET", + target="/", + headers=[ + ("Host", "example.com"), + ("Content-Length", "100"), + ("Expect", "100-continue"), + ], + ), + ) + for conn in p.conns: + assert conn.client_is_waiting_for_100_continue + assert not p.conn[CLIENT].they_are_waiting_for_100_continue + assert p.conn[SERVER].they_are_waiting_for_100_continue + return p + + # Disabled by 100 Continue + p = setup() + p.send(SERVER, InformationalResponse(status_code=100, headers=[])) # type: ignore[arg-type] + for conn in p.conns: + assert not conn.client_is_waiting_for_100_continue + assert not conn.they_are_waiting_for_100_continue + + # Disabled by a real response + p = setup() + p.send( + SERVER, Response(status_code=200, headers=[("Transfer-Encoding", "chunked")]) + ) + for conn in p.conns: + assert not conn.client_is_waiting_for_100_continue + assert not conn.they_are_waiting_for_100_continue + + # Disabled by the client going ahead and sending stuff anyway + p = setup() + p.send(CLIENT, Data(data=b"12345")) + for conn in p.conns: + assert not conn.client_is_waiting_for_100_continue + assert not conn.they_are_waiting_for_100_continue + + +def test_max_incomplete_event_size_countermeasure() -> None: + # Infinitely long headers are definitely not okay + c = Connection(SERVER) + c.receive_data(b"GET / HTTP/1.0\r\nEndless: ") + assert c.next_event() is NEED_DATA + with pytest.raises(RemoteProtocolError): + while True: + c.receive_data(b"a" * 1024) + c.next_event() + + # Checking that the same header is accepted / rejected depending on the + # max_incomplete_event_size setting: + c = Connection(SERVER, max_incomplete_event_size=5000) + c.receive_data(b"GET / HTTP/1.0\r\nBig: ") + c.receive_data(b"a" * 4000) + c.receive_data(b"\r\n\r\n") + assert get_all_events(c) == [ + Request( + method="GET", target="/", http_version="1.0", headers=[("big", "a" * 4000)] + ), + EndOfMessage(), + ] + + c = Connection(SERVER, max_incomplete_event_size=4000) + c.receive_data(b"GET / HTTP/1.0\r\nBig: ") + c.receive_data(b"a" * 4000) + with pytest.raises(RemoteProtocolError): + c.next_event() + + # Temporarily exceeding the size limit is fine, as long as its done with + # complete events: + c = Connection(SERVER, max_incomplete_event_size=5000) + c.receive_data(b"GET / HTTP/1.0\r\nContent-Length: 10000") + c.receive_data(b"\r\n\r\n" + b"a" * 10000) + assert get_all_events(c) == [ + Request( + method="GET", + target="/", + http_version="1.0", + headers=[("Content-Length", "10000")], + ), + Data(data=b"a" * 10000), + EndOfMessage(), + ] + + c = Connection(SERVER, max_incomplete_event_size=100) + # Two pipelined requests to create a way-too-big receive buffer... but + # it's fine because we're not checking + c.receive_data( + b"GET /1 HTTP/1.1\r\nHost: a\r\n\r\n" + b"GET /2 HTTP/1.1\r\nHost: b\r\n\r\n" + b"X" * 1000 + ) + assert get_all_events(c) == [ + Request(method="GET", target="/1", headers=[("host", "a")]), + EndOfMessage(), + ] + # Even more data comes in, still no problem + c.receive_data(b"X" * 1000) + # We can respond and reuse to get the second pipelined request + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + c.start_next_cycle() + assert get_all_events(c) == [ + Request(method="GET", target="/2", headers=[("host", "b")]), + EndOfMessage(), + ] + # But once we unpause and try to read the next message, and find that it's + # incomplete and the buffer is *still* way too large, then *that's* a + # problem: + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + c.start_next_cycle() + with pytest.raises(RemoteProtocolError): + c.next_event() + + +def test_reuse_simple() -> None: + p = ConnectionPair() + p.send( + CLIENT, + [Request(method="GET", target="/", headers=[("Host", "a")]), EndOfMessage()], + ) + p.send( + SERVER, + [ + Response(status_code=200, headers=[(b"transfer-encoding", b"chunked")]), + EndOfMessage(), + ], + ) + for conn in p.conns: + assert conn.states == {CLIENT: DONE, SERVER: DONE} + conn.start_next_cycle() + + p.send( + CLIENT, + [ + Request(method="DELETE", target="/foo", headers=[("Host", "a")]), + EndOfMessage(), + ], + ) + p.send( + SERVER, + [ + Response(status_code=404, headers=[(b"transfer-encoding", b"chunked")]), + EndOfMessage(), + ], + ) + + +def test_pipelining() -> None: + # Client doesn't support pipelining, so we have to do this by hand + c = Connection(SERVER) + assert c.next_event() is NEED_DATA + # 3 requests all bunched up + c.receive_data( + b"GET /1 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n" + b"12345" + b"GET /2 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n" + b"67890" + b"GET /3 HTTP/1.1\r\nHost: a.com\r\n\r\n" + ) + assert get_all_events(c) == [ + Request( + method="GET", + target="/1", + headers=[("Host", "a.com"), ("Content-Length", "5")], + ), + Data(data=b"12345"), + EndOfMessage(), + ] + assert c.their_state is DONE + assert c.our_state is SEND_RESPONSE + + assert c.next_event() is PAUSED + + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + assert c.their_state is DONE + assert c.our_state is DONE + + c.start_next_cycle() + + assert get_all_events(c) == [ + Request( + method="GET", + target="/2", + headers=[("Host", "a.com"), ("Content-Length", "5")], + ), + Data(data=b"67890"), + EndOfMessage(), + ] + assert c.next_event() is PAUSED + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + c.start_next_cycle() + + assert get_all_events(c) == [ + Request(method="GET", target="/3", headers=[("Host", "a.com")]), + EndOfMessage(), + ] + # Doesn't pause this time, no trailing data + assert c.next_event() is NEED_DATA + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + + # Arrival of more data triggers pause + assert c.next_event() is NEED_DATA + c.receive_data(b"SADF") + assert c.next_event() is PAUSED + assert c.trailing_data == (b"SADF", False) + # If EOF arrives while paused, we don't see that either: + c.receive_data(b"") + assert c.trailing_data == (b"SADF", True) + assert c.next_event() is PAUSED + c.receive_data(b"") + assert c.next_event() is PAUSED + # Can't call receive_data with non-empty buf after closing it + with pytest.raises(RuntimeError): + c.receive_data(b"FDSA") + + +def test_protocol_switch() -> None: + for (req, deny, accept) in [ + ( + Request( + method="CONNECT", + target="example.com:443", + headers=[("Host", "foo"), ("Content-Length", "1")], + ), + Response(status_code=404, headers=[(b"transfer-encoding", b"chunked")]), + Response(status_code=200, headers=[(b"transfer-encoding", b"chunked")]), + ), + ( + Request( + method="GET", + target="/", + headers=[("Host", "foo"), ("Content-Length", "1"), ("Upgrade", "a, b")], + ), + Response(status_code=200, headers=[(b"transfer-encoding", b"chunked")]), + InformationalResponse(status_code=101, headers=[("Upgrade", "a")]), + ), + ( + Request( + method="CONNECT", + target="example.com:443", + headers=[("Host", "foo"), ("Content-Length", "1"), ("Upgrade", "a, b")], + ), + Response(status_code=404, headers=[(b"transfer-encoding", b"chunked")]), + # Accept CONNECT, not upgrade + Response(status_code=200, headers=[(b"transfer-encoding", b"chunked")]), + ), + ( + Request( + method="CONNECT", + target="example.com:443", + headers=[("Host", "foo"), ("Content-Length", "1"), ("Upgrade", "a, b")], + ), + Response(status_code=404, headers=[(b"transfer-encoding", b"chunked")]), + # Accept Upgrade, not CONNECT + InformationalResponse(status_code=101, headers=[("Upgrade", "b")]), + ), + ]: + + def setup() -> ConnectionPair: + p = ConnectionPair() + p.send(CLIENT, req) + # No switch-related state change stuff yet; the client has to + # finish the request before that kicks in + for conn in p.conns: + assert conn.states[CLIENT] is SEND_BODY + p.send(CLIENT, [Data(data=b"1"), EndOfMessage()]) + for conn in p.conns: + assert conn.states[CLIENT] is MIGHT_SWITCH_PROTOCOL + assert p.conn[SERVER].next_event() is PAUSED + return p + + # Test deny case + p = setup() + p.send(SERVER, deny) + for conn in p.conns: + assert conn.states == {CLIENT: DONE, SERVER: SEND_BODY} + p.send(SERVER, EndOfMessage()) + # Check that re-use is still allowed after a denial + for conn in p.conns: + conn.start_next_cycle() + + # Test accept case + p = setup() + p.send(SERVER, accept) + for conn in p.conns: + assert conn.states == {CLIENT: SWITCHED_PROTOCOL, SERVER: SWITCHED_PROTOCOL} + conn.receive_data(b"123") + assert conn.next_event() is PAUSED + conn.receive_data(b"456") + assert conn.next_event() is PAUSED + assert conn.trailing_data == (b"123456", False) + + # Pausing in might-switch, then recovery + # (weird artificial case where the trailing data actually is valid + # HTTP for some reason, because this makes it easier to test the state + # logic) + p = setup() + sc = p.conn[SERVER] + sc.receive_data(b"GET / HTTP/1.0\r\n\r\n") + assert sc.next_event() is PAUSED + assert sc.trailing_data == (b"GET / HTTP/1.0\r\n\r\n", False) + sc.send(deny) + assert sc.next_event() is PAUSED + sc.send(EndOfMessage()) + sc.start_next_cycle() + assert get_all_events(sc) == [ + Request(method="GET", target="/", headers=[], http_version="1.0"), # type: ignore[arg-type] + EndOfMessage(), + ] + + # When we're DONE, have no trailing data, and the connection gets + # closed, we report ConnectionClosed(). When we're in might-switch or + # switched, we don't. + p = setup() + sc = p.conn[SERVER] + sc.receive_data(b"") + assert sc.next_event() is PAUSED + assert sc.trailing_data == (b"", True) + p.send(SERVER, accept) + assert sc.next_event() is PAUSED + + p = setup() + sc = p.conn[SERVER] + sc.receive_data(b"") + assert sc.next_event() is PAUSED + sc.send(deny) + assert sc.next_event() == ConnectionClosed() + + # You can't send after switching protocols, or while waiting for a + # protocol switch + p = setup() + with pytest.raises(LocalProtocolError): + p.conn[CLIENT].send( + Request(method="GET", target="/", headers=[("Host", "a")]) + ) + p = setup() + p.send(SERVER, accept) + with pytest.raises(LocalProtocolError): + p.conn[SERVER].send(Data(data=b"123")) + + +def test_close_simple() -> None: + # Just immediately closing a new connection without anything having + # happened yet. + for (who_shot_first, who_shot_second) in [(CLIENT, SERVER), (SERVER, CLIENT)]: + + def setup() -> ConnectionPair: + p = ConnectionPair() + p.send(who_shot_first, ConnectionClosed()) + for conn in p.conns: + assert conn.states == { + who_shot_first: CLOSED, + who_shot_second: MUST_CLOSE, + } + return p + + # You can keep putting b"" into a closed connection, and you keep + # getting ConnectionClosed() out: + p = setup() + assert p.conn[who_shot_second].next_event() == ConnectionClosed() + assert p.conn[who_shot_second].next_event() == ConnectionClosed() + p.conn[who_shot_second].receive_data(b"") + assert p.conn[who_shot_second].next_event() == ConnectionClosed() + # Second party can close... + p = setup() + p.send(who_shot_second, ConnectionClosed()) + for conn in p.conns: + assert conn.our_state is CLOSED + assert conn.their_state is CLOSED + # But trying to receive new data on a closed connection is a + # RuntimeError (not ProtocolError, because the problem here isn't + # violation of HTTP, it's violation of physics) + p = setup() + with pytest.raises(RuntimeError): + p.conn[who_shot_second].receive_data(b"123") + # And receiving new data on a MUST_CLOSE connection is a ProtocolError + p = setup() + p.conn[who_shot_first].receive_data(b"GET") + with pytest.raises(RemoteProtocolError): + p.conn[who_shot_first].next_event() + + +def test_close_different_states() -> None: + req = [ + Request(method="GET", target="/foo", headers=[("Host", "a")]), + EndOfMessage(), + ] + resp = [ + Response(status_code=200, headers=[(b"transfer-encoding", b"chunked")]), + EndOfMessage(), + ] + + # Client before request + p = ConnectionPair() + p.send(CLIENT, ConnectionClosed()) + for conn in p.conns: + assert conn.states == {CLIENT: CLOSED, SERVER: MUST_CLOSE} + + # Client after request + p = ConnectionPair() + p.send(CLIENT, req) + p.send(CLIENT, ConnectionClosed()) + for conn in p.conns: + assert conn.states == {CLIENT: CLOSED, SERVER: SEND_RESPONSE} + + # Server after request -> not allowed + p = ConnectionPair() + p.send(CLIENT, req) + with pytest.raises(LocalProtocolError): + p.conn[SERVER].send(ConnectionClosed()) + p.conn[CLIENT].receive_data(b"") + with pytest.raises(RemoteProtocolError): + p.conn[CLIENT].next_event() + + # Server after response + p = ConnectionPair() + p.send(CLIENT, req) + p.send(SERVER, resp) + p.send(SERVER, ConnectionClosed()) + for conn in p.conns: + assert conn.states == {CLIENT: MUST_CLOSE, SERVER: CLOSED} + + # Both after closing (ConnectionClosed() is idempotent) + p = ConnectionPair() + p.send(CLIENT, req) + p.send(SERVER, resp) + p.send(CLIENT, ConnectionClosed()) + p.send(SERVER, ConnectionClosed()) + p.send(CLIENT, ConnectionClosed()) + p.send(SERVER, ConnectionClosed()) + + # In the middle of sending -> not allowed + p = ConnectionPair() + p.send( + CLIENT, + Request( + method="GET", target="/", headers=[("Host", "a"), ("Content-Length", "10")] + ), + ) + with pytest.raises(LocalProtocolError): + p.conn[CLIENT].send(ConnectionClosed()) + p.conn[SERVER].receive_data(b"") + with pytest.raises(RemoteProtocolError): + p.conn[SERVER].next_event() + + +# Receive several requests and then client shuts down their side of the +# connection; we can respond to each +def test_pipelined_close() -> None: + c = Connection(SERVER) + # 2 requests then a close + c.receive_data( + b"GET /1 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n" + b"12345" + b"GET /2 HTTP/1.1\r\nHost: a.com\r\nContent-Length: 5\r\n\r\n" + b"67890" + ) + c.receive_data(b"") + assert get_all_events(c) == [ + Request( + method="GET", + target="/1", + headers=[("host", "a.com"), ("content-length", "5")], + ), + Data(data=b"12345"), + EndOfMessage(), + ] + assert c.states[CLIENT] is DONE + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + assert c.states[SERVER] is DONE + c.start_next_cycle() + assert get_all_events(c) == [ + Request( + method="GET", + target="/2", + headers=[("host", "a.com"), ("content-length", "5")], + ), + Data(data=b"67890"), + EndOfMessage(), + ConnectionClosed(), + ] + assert c.states == {CLIENT: CLOSED, SERVER: SEND_RESPONSE} + c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(EndOfMessage()) + assert c.states == {CLIENT: CLOSED, SERVER: MUST_CLOSE} + c.send(ConnectionClosed()) + assert c.states == {CLIENT: CLOSED, SERVER: CLOSED} + + +def test_sendfile() -> None: + class SendfilePlaceholder: + def __len__(self) -> int: + return 10 + + placeholder = SendfilePlaceholder() + + def setup( + header: Tuple[str, str], http_version: str + ) -> Tuple[Connection, Optional[List[bytes]]]: + c = Connection(SERVER) + receive_and_get( + c, "GET / HTTP/{}\r\nHost: a\r\n\r\n".format(http_version).encode("ascii") + ) + headers = [] + if header: + headers.append(header) + c.send(Response(status_code=200, headers=headers)) + return c, c.send_with_data_passthrough(Data(data=placeholder)) # type: ignore + + c, data = setup(("Content-Length", "10"), "1.1") + assert data == [placeholder] # type: ignore + # Raises an error if the connection object doesn't think we've sent + # exactly 10 bytes + c.send(EndOfMessage()) + + _, data = setup(("Transfer-Encoding", "chunked"), "1.1") + assert placeholder in data # type: ignore + data[data.index(placeholder)] = b"x" * 10 # type: ignore + assert b"".join(data) == b"a\r\nxxxxxxxxxx\r\n" # type: ignore + + c, data = setup(None, "1.0") # type: ignore + assert data == [placeholder] # type: ignore + assert c.our_state is SEND_BODY + + +def test_errors() -> None: + # After a receive error, you can't receive + for role in [CLIENT, SERVER]: + c = Connection(our_role=role) + c.receive_data(b"gibberish\r\n\r\n") + with pytest.raises(RemoteProtocolError): + c.next_event() + # Now any attempt to receive continues to raise + assert c.their_state is ERROR + assert c.our_state is not ERROR + print(c._cstate.states) + with pytest.raises(RemoteProtocolError): + c.next_event() + # But we can still yell at the client for sending us gibberish + if role is SERVER: + assert ( + c.send(Response(status_code=400, headers=[])) # type: ignore[arg-type] + == b"HTTP/1.1 400 \r\nConnection: close\r\n\r\n" + ) + + # After an error sending, you can no longer send + # (This is especially important for things like content-length errors, + # where there's complex internal state being modified) + def conn(role: Type[Sentinel]) -> Connection: + c = Connection(our_role=role) + if role is SERVER: + # Put it into the state where it *could* send a response... + receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n") + assert c.our_state is SEND_RESPONSE + return c + + for role in [CLIENT, SERVER]: + if role is CLIENT: + # This HTTP/1.0 request won't be detected as bad until after we go + # through the state machine and hit the writing code + good = Request(method="GET", target="/", headers=[("Host", "example.com")]) + bad = Request( + method="GET", + target="/", + headers=[("Host", "example.com")], + http_version="1.0", + ) + elif role is SERVER: + good = Response(status_code=200, headers=[]) # type: ignore[arg-type,assignment] + bad = Response(status_code=200, headers=[], http_version="1.0") # type: ignore[arg-type,assignment] + # Make sure 'good' actually is good + c = conn(role) + c.send(good) + assert c.our_state is not ERROR + # Do that again, but this time sending 'bad' first + c = conn(role) + with pytest.raises(LocalProtocolError): + c.send(bad) + assert c.our_state is ERROR + assert c.their_state is not ERROR + # Now 'good' is not so good + with pytest.raises(LocalProtocolError): + c.send(good) + + # And check send_failed() too + c = conn(role) + c.send_failed() + assert c.our_state is ERROR + assert c.their_state is not ERROR + # This is idempotent + c.send_failed() + assert c.our_state is ERROR + assert c.their_state is not ERROR + + +def test_idle_receive_nothing() -> None: + # At one point this incorrectly raised an error + for role in [CLIENT, SERVER]: + c = Connection(role) + assert c.next_event() is NEED_DATA + + +def test_connection_drop() -> None: + c = Connection(SERVER) + c.receive_data(b"GET /") + assert c.next_event() is NEED_DATA + c.receive_data(b"") + with pytest.raises(RemoteProtocolError): + c.next_event() + + +def test_408_request_timeout() -> None: + # Should be able to send this spontaneously as a server without seeing + # anything from client + p = ConnectionPair() + p.send(SERVER, Response(status_code=408, headers=[(b"connection", b"close")])) + + +# This used to raise IndexError +def test_empty_request() -> None: + c = Connection(SERVER) + c.receive_data(b"\r\n") + with pytest.raises(RemoteProtocolError): + c.next_event() + + +# This used to raise IndexError +def test_empty_response() -> None: + c = Connection(CLIENT) + c.send(Request(method="GET", target="/", headers=[("Host", "a")])) + c.receive_data(b"\r\n") + with pytest.raises(RemoteProtocolError): + c.next_event() + + +@pytest.mark.parametrize( + "data", + [ + b"\x00", + b"\x20", + b"\x16\x03\x01\x00\xa5", # Typical start of a TLS Client Hello + ], +) +def test_early_detection_of_invalid_request(data: bytes) -> None: + c = Connection(SERVER) + # Early detection should occur before even receiving a `\r\n` + c.receive_data(data) + with pytest.raises(RemoteProtocolError): + c.next_event() + + +@pytest.mark.parametrize( + "data", + [ + b"\x00", + b"\x20", + b"\x16\x03\x03\x00\x31", # Typical start of a TLS Server Hello + ], +) +def test_early_detection_of_invalid_response(data: bytes) -> None: + c = Connection(CLIENT) + # Early detection should occur before even receiving a `\r\n` + c.receive_data(data) + with pytest.raises(RemoteProtocolError): + c.next_event() + + +# This used to give different headers for HEAD and GET. +# The correct way to handle HEAD is to put whatever headers we *would* have +# put if it were a GET -- even though we know that for HEAD, those headers +# will be ignored. +def test_HEAD_framing_headers() -> None: + def setup(method: bytes, http_version: bytes) -> Connection: + c = Connection(SERVER) + c.receive_data( + method + b" / HTTP/" + http_version + b"\r\n" + b"Host: example.com\r\n\r\n" + ) + assert type(c.next_event()) is Request + assert type(c.next_event()) is EndOfMessage + return c + + for method in [b"GET", b"HEAD"]: + # No Content-Length, HTTP/1.1 peer, should use chunked + c = setup(method, b"1.1") + assert ( + c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" # type: ignore[arg-type] + b"Transfer-Encoding: chunked\r\n\r\n" + ) + + # No Content-Length, HTTP/1.0 peer, frame with connection: close + c = setup(method, b"1.0") + assert ( + c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" # type: ignore[arg-type] + b"Connection: close\r\n\r\n" + ) + + # Content-Length + Transfer-Encoding, TE wins + c = setup(method, b"1.1") + assert ( + c.send( + Response( + status_code=200, + headers=[ + ("Content-Length", "100"), + ("Transfer-Encoding", "chunked"), + ], + ) + ) + == b"HTTP/1.1 200 \r\n" + b"Transfer-Encoding: chunked\r\n\r\n" + ) + + +def test_special_exceptions_for_lost_connection_in_message_body() -> None: + c = Connection(SERVER) + c.receive_data( + b"POST / HTTP/1.1\r\n" b"Host: example.com\r\n" b"Content-Length: 100\r\n\r\n" + ) + assert type(c.next_event()) is Request + assert c.next_event() is NEED_DATA + c.receive_data(b"12345") + assert c.next_event() == Data(data=b"12345") + c.receive_data(b"") + with pytest.raises(RemoteProtocolError) as excinfo: + c.next_event() + assert "received 5 bytes" in str(excinfo.value) + assert "expected 100" in str(excinfo.value) + + c = Connection(SERVER) + c.receive_data( + b"POST / HTTP/1.1\r\n" + b"Host: example.com\r\n" + b"Transfer-Encoding: chunked\r\n\r\n" + ) + assert type(c.next_event()) is Request + assert c.next_event() is NEED_DATA + c.receive_data(b"8\r\n012345") + assert c.next_event().data == b"012345" # type: ignore + c.receive_data(b"") + with pytest.raises(RemoteProtocolError) as excinfo: + c.next_event() + assert "incomplete chunked read" in str(excinfo.value) diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_events.py b/.venv/lib/python3.10/site-packages/h11/tests/test_events.py new file mode 100644 index 0000000..bc6c313 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_events.py @@ -0,0 +1,150 @@ +from http import HTTPStatus + +import pytest + +from .. import _events +from .._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from .._util import LocalProtocolError + + +def test_events() -> None: + with pytest.raises(LocalProtocolError): + # Missing Host: + req = Request( + method="GET", target="/", headers=[("a", "b")], http_version="1.1" + ) + # But this is okay (HTTP/1.0) + req = Request(method="GET", target="/", headers=[("a", "b")], http_version="1.0") + # fields are normalized + assert req.method == b"GET" + assert req.target == b"/" + assert req.headers == [(b"a", b"b")] + assert req.http_version == b"1.0" + + # This is also okay -- has a Host (with weird capitalization, which is ok) + req = Request( + method="GET", + target="/", + headers=[("a", "b"), ("hOSt", "example.com")], + http_version="1.1", + ) + # we normalize header capitalization + assert req.headers == [(b"a", b"b"), (b"host", b"example.com")] + + # Multiple host is bad too + with pytest.raises(LocalProtocolError): + req = Request( + method="GET", + target="/", + headers=[("Host", "a"), ("Host", "a")], + http_version="1.1", + ) + # Even for HTTP/1.0 + with pytest.raises(LocalProtocolError): + req = Request( + method="GET", + target="/", + headers=[("Host", "a"), ("Host", "a")], + http_version="1.0", + ) + + # Header values are validated + for bad_char in "\x00\r\n\f\v": + with pytest.raises(LocalProtocolError): + req = Request( + method="GET", + target="/", + headers=[("Host", "a"), ("Foo", "asd" + bad_char)], + http_version="1.0", + ) + + # But for compatibility we allow non-whitespace control characters, even + # though they're forbidden by the spec. + Request( + method="GET", + target="/", + headers=[("Host", "a"), ("Foo", "asd\x01\x02\x7f")], + http_version="1.0", + ) + + # Request target is validated + for bad_byte in b"\x00\x20\x7f\xee": + target = bytearray(b"/") + target.append(bad_byte) + with pytest.raises(LocalProtocolError): + Request( + method="GET", target=target, headers=[("Host", "a")], http_version="1.1" + ) + + # Request method is validated + with pytest.raises(LocalProtocolError): + Request( + method="GET / HTTP/1.1", + target=target, + headers=[("Host", "a")], + http_version="1.1", + ) + + ir = InformationalResponse(status_code=100, headers=[("Host", "a")]) + assert ir.status_code == 100 + assert ir.headers == [(b"host", b"a")] + assert ir.http_version == b"1.1" + + with pytest.raises(LocalProtocolError): + InformationalResponse(status_code=200, headers=[("Host", "a")]) + + resp = Response(status_code=204, headers=[], http_version="1.0") # type: ignore[arg-type] + assert resp.status_code == 204 + assert resp.headers == [] + assert resp.http_version == b"1.0" + + with pytest.raises(LocalProtocolError): + resp = Response(status_code=100, headers=[], http_version="1.0") # type: ignore[arg-type] + + with pytest.raises(LocalProtocolError): + Response(status_code="100", headers=[], http_version="1.0") # type: ignore[arg-type] + + with pytest.raises(LocalProtocolError): + InformationalResponse(status_code=b"100", headers=[], http_version="1.0") # type: ignore[arg-type] + + d = Data(data=b"asdf") + assert d.data == b"asdf" + + eom = EndOfMessage() + assert eom.headers == [] + + cc = ConnectionClosed() + assert repr(cc) == "ConnectionClosed()" + + +def test_intenum_status_code() -> None: + # https://github.com/python-hyper/h11/issues/72 + + r = Response(status_code=HTTPStatus.OK, headers=[], http_version="1.0") # type: ignore[arg-type] + assert r.status_code == HTTPStatus.OK + assert type(r.status_code) is not type(HTTPStatus.OK) + assert type(r.status_code) is int + + +def test_header_casing() -> None: + r = Request( + method="GET", + target="/", + headers=[("Host", "example.org"), ("Connection", "keep-alive")], + http_version="1.1", + ) + assert len(r.headers) == 2 + assert r.headers[0] == (b"host", b"example.org") + 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"), + ] diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_headers.py b/.venv/lib/python3.10/site-packages/h11/tests/test_headers.py new file mode 100644 index 0000000..ba53d08 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_headers.py @@ -0,0 +1,157 @@ +import pytest + +from .._events import Request +from .._headers import ( + get_comma_header, + has_expect_100_continue, + Headers, + normalize_and_validate, + set_comma_header, +) +from .._util import LocalProtocolError + + +def test_normalize_and_validate() -> None: + assert normalize_and_validate([("foo", "bar")]) == [(b"foo", b"bar")] + assert normalize_and_validate([(b"foo", b"bar")]) == [(b"foo", b"bar")] + + # no leading/trailing whitespace in names + with pytest.raises(LocalProtocolError): + normalize_and_validate([(b"foo ", "bar")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([(b" foo", "bar")]) + + # no weird characters in names + with pytest.raises(LocalProtocolError) as excinfo: + normalize_and_validate([(b"foo bar", b"baz")]) + assert "foo bar" in str(excinfo.value) + with pytest.raises(LocalProtocolError): + normalize_and_validate([(b"foo\x00bar", b"baz")]) + # Not even 8-bit characters: + with pytest.raises(LocalProtocolError): + normalize_and_validate([(b"foo\xffbar", b"baz")]) + # And not even the control characters we allow in values: + with pytest.raises(LocalProtocolError): + normalize_and_validate([(b"foo\x01bar", b"baz")]) + + # no return or NUL characters in values + with pytest.raises(LocalProtocolError) as excinfo: + normalize_and_validate([("foo", "bar\rbaz")]) + assert "bar\\rbaz" in str(excinfo.value) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", "bar\nbaz")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", "bar\x00baz")]) + # no leading/trailing whitespace + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", "barbaz ")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", " barbaz")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", "barbaz\t")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("foo", "\tbarbaz")]) + + # content-length + assert normalize_and_validate([("Content-Length", "1")]) == [ + (b"content-length", b"1") + ] + with pytest.raises(LocalProtocolError): + normalize_and_validate([("Content-Length", "asdf")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("Content-Length", "1x")]) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("Content-Length", "1"), ("Content-Length", "2")]) + assert normalize_and_validate( + [("Content-Length", "0"), ("Content-Length", "0")] + ) == [(b"content-length", b"0")] + assert normalize_and_validate([("Content-Length", "0 , 0")]) == [ + (b"content-length", b"0") + ] + with pytest.raises(LocalProtocolError): + normalize_and_validate( + [("Content-Length", "1"), ("Content-Length", "1"), ("Content-Length", "2")] + ) + with pytest.raises(LocalProtocolError): + normalize_and_validate([("Content-Length", "1 , 1,2")]) + + # transfer-encoding + assert normalize_and_validate([("Transfer-Encoding", "chunked")]) == [ + (b"transfer-encoding", b"chunked") + ] + assert normalize_and_validate([("Transfer-Encoding", "cHuNkEd")]) == [ + (b"transfer-encoding", b"chunked") + ] + with pytest.raises(LocalProtocolError) as excinfo: + normalize_and_validate([("Transfer-Encoding", "gzip")]) + assert excinfo.value.error_status_hint == 501 # Not Implemented + with pytest.raises(LocalProtocolError) as excinfo: + normalize_and_validate( + [("Transfer-Encoding", "chunked"), ("Transfer-Encoding", "gzip")] + ) + assert excinfo.value.error_status_hint == 501 # Not Implemented + + +def test_get_set_comma_header() -> None: + headers = normalize_and_validate( + [ + ("Connection", "close"), + ("whatever", "something"), + ("connectiON", "fOo,, , BAR"), + ] + ) + + assert get_comma_header(headers, b"connection") == [b"close", b"foo", b"bar"] + + headers = set_comma_header(headers, b"newthing", ["a", "b"]) # type: ignore + + with pytest.raises(LocalProtocolError): + set_comma_header(headers, b"newthing", [" a", "b"]) # type: ignore + + assert headers == [ + (b"connection", b"close"), + (b"whatever", b"something"), + (b"connection", b"fOo,, , BAR"), + (b"newthing", b"a"), + (b"newthing", b"b"), + ] + + headers = set_comma_header(headers, b"whatever", ["different thing"]) # type: ignore + + assert headers == [ + (b"connection", b"close"), + (b"connection", b"fOo,, , BAR"), + (b"newthing", b"a"), + (b"newthing", b"b"), + (b"whatever", b"different thing"), + ] + + +def test_has_100_continue() -> None: + assert has_expect_100_continue( + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Expect", "100-continue")], + ) + ) + assert not has_expect_100_continue( + Request(method="GET", target="/", headers=[("Host", "example.com")]) + ) + # Case insensitive + assert has_expect_100_continue( + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Expect", "100-Continue")], + ) + ) + # Doesn't work in HTTP/1.0 + assert not has_expect_100_continue( + Request( + method="GET", + target="/", + headers=[("Host", "example.com"), ("Expect", "100-continue")], + http_version="1.0", + ) + ) diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_helpers.py b/.venv/lib/python3.10/site-packages/h11/tests/test_helpers.py new file mode 100644 index 0000000..c329c76 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_helpers.py @@ -0,0 +1,32 @@ +from .._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from .helpers import normalize_data_events + + +def test_normalize_data_events() -> None: + assert normalize_data_events( + [ + Data(data=bytearray(b"1")), + Data(data=b"2"), + Response(status_code=200, headers=[]), # type: ignore[arg-type] + Data(data=b"3"), + Data(data=b"4"), + EndOfMessage(), + Data(data=b"5"), + Data(data=b"6"), + Data(data=b"7"), + ] + ) == [ + Data(data=b"12"), + Response(status_code=200, headers=[]), # type: ignore[arg-type] + Data(data=b"34"), + EndOfMessage(), + Data(data=b"567"), + ] diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_io.py b/.venv/lib/python3.10/site-packages/h11/tests/test_io.py new file mode 100644 index 0000000..2b47c0e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_io.py @@ -0,0 +1,572 @@ +from typing import Any, Callable, Generator, List + +import pytest + +from .._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from .._headers import Headers, normalize_and_validate +from .._readers import ( + _obsolete_line_fold, + ChunkedReader, + ContentLengthReader, + Http10Reader, + READERS, +) +from .._receivebuffer import ReceiveBuffer +from .._state import ( + CLIENT, + CLOSED, + DONE, + IDLE, + MIGHT_SWITCH_PROTOCOL, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, + SWITCHED_PROTOCOL, +) +from .._util import LocalProtocolError +from .._writers import ( + ChunkedWriter, + ContentLengthWriter, + Http10Writer, + write_any_response, + write_headers, + write_request, + WRITERS, +) +from .helpers import normalize_data_events + +SIMPLE_CASES = [ + ( + (CLIENT, IDLE), + Request( + method="GET", + target="/a", + headers=[("Host", "foo"), ("Connection", "close")], + ), + b"GET /a HTTP/1.1\r\nHost: foo\r\nConnection: close\r\n\r\n", + ), + ( + (SERVER, SEND_RESPONSE), + Response(status_code=200, headers=[("Connection", "close")], reason=b"OK"), + b"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", + ), + ( + (SERVER, SEND_RESPONSE), + Response(status_code=200, headers=[], reason=b"OK"), # type: ignore[arg-type] + b"HTTP/1.1 200 OK\r\n\r\n", + ), + ( + (SERVER, SEND_RESPONSE), + InformationalResponse( + status_code=101, headers=[("Upgrade", "websocket")], reason=b"Upgrade" + ), + b"HTTP/1.1 101 Upgrade\r\nUpgrade: websocket\r\n\r\n", + ), + ( + (SERVER, SEND_RESPONSE), + InformationalResponse(status_code=101, headers=[], reason=b"Upgrade"), # type: ignore[arg-type] + b"HTTP/1.1 101 Upgrade\r\n\r\n", + ), +] + + +def dowrite(writer: Callable[..., None], obj: Any) -> bytes: + got_list: List[bytes] = [] + writer(obj, got_list.append) + return b"".join(got_list) + + +def tw(writer: Any, obj: Any, expected: Any) -> None: + got = dowrite(writer, obj) + assert got == expected + + +def makebuf(data: bytes) -> ReceiveBuffer: + buf = ReceiveBuffer() + buf += data + return buf + + +def tr(reader: Any, data: bytes, expected: Any) -> None: + def check(got: Any) -> None: + assert got == expected + # Headers should always be returned as bytes, not e.g. bytearray + # https://github.com/python-hyper/wsproto/pull/54#issuecomment-377709478 + for name, value in getattr(got, "headers", []): + assert type(name) is bytes + assert type(value) is bytes + + # Simple: consume whole thing + buf = makebuf(data) + check(reader(buf)) + assert not buf + + # Incrementally growing buffer + buf = ReceiveBuffer() + for i in range(len(data)): + assert reader(buf) is None + buf += data[i : i + 1] + check(reader(buf)) + + # Trailing data + buf = makebuf(data) + buf += b"trailing" + check(reader(buf)) + assert bytes(buf) == b"trailing" + + +def test_writers_simple() -> None: + for ((role, state), event, binary) in SIMPLE_CASES: + tw(WRITERS[role, state], event, binary) + + +def test_readers_simple() -> None: + for ((role, state), event, binary) in SIMPLE_CASES: + tr(READERS[role, state], binary, event) + + +def test_writers_unusual() -> None: + # Simple test of the write_headers utility routine + tw( + write_headers, + normalize_and_validate([("foo", "bar"), ("baz", "quux")]), + b"foo: bar\r\nbaz: quux\r\n\r\n", + ) + tw(write_headers, Headers([]), b"\r\n") + + # We understand HTTP/1.0, but we don't speak it + with pytest.raises(LocalProtocolError): + tw( + write_request, + Request( + method="GET", + target="/", + headers=[("Host", "foo"), ("Connection", "close")], + http_version="1.0", + ), + None, + ) + with pytest.raises(LocalProtocolError): + tw( + write_any_response, + Response( + status_code=200, headers=[("Connection", "close")], http_version="1.0" + ), + None, + ) + + +def test_readers_unusual() -> None: + # Reading HTTP/1.0 + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.0\r\nSome: header\r\n\r\n", + Request( + method="HEAD", + target="/foo", + headers=[("Some", "header")], + http_version="1.0", + ), + ) + + # check no-headers, since it's only legal with HTTP/1.0 + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.0\r\n\r\n", + Request(method="HEAD", target="/foo", headers=[], http_version="1.0"), # type: ignore[arg-type] + ) + + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.0 200 OK\r\nSome: header\r\n\r\n", + Response( + status_code=200, + headers=[("Some", "header")], + http_version="1.0", + reason=b"OK", + ), + ) + + # single-character header values (actually disallowed by the ABNF in RFC + # 7230 -- this is a bug in the standard that we originally copied...) + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.0 200 OK\r\n" b"Foo: a a a a a \r\n\r\n", + Response( + status_code=200, + headers=[("Foo", "a a a a a")], + http_version="1.0", + reason=b"OK", + ), + ) + + # Empty headers -- also legal + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.0 200 OK\r\n" b"Foo:\r\n\r\n", + Response( + status_code=200, headers=[("Foo", "")], http_version="1.0", reason=b"OK" + ), + ) + + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.0 200 OK\r\n" b"Foo: \t \t \r\n\r\n", + Response( + status_code=200, headers=[("Foo", "")], http_version="1.0", reason=b"OK" + ), + ) + + # Tolerate broken servers that leave off the response code + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.0 200\r\n" b"Foo: bar\r\n\r\n", + Response( + status_code=200, headers=[("Foo", "bar")], http_version="1.0", reason=b"" + ), + ) + + # Tolerate headers line endings (\r\n and \n) + # \n\r\b between headers and body + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.1 200 OK\r\nSomeHeader: val\n\r\n", + Response( + status_code=200, + headers=[("SomeHeader", "val")], + http_version="1.1", + reason="OK", + ), + ) + + # delimited only with \n + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.1 200 OK\nSomeHeader1: val1\nSomeHeader2: val2\n\n", + Response( + status_code=200, + headers=[("SomeHeader1", "val1"), ("SomeHeader2", "val2")], + http_version="1.1", + reason="OK", + ), + ) + + # mixed \r\n and \n + tr( + READERS[SERVER, SEND_RESPONSE], + b"HTTP/1.1 200 OK\r\nSomeHeader1: val1\nSomeHeader2: val2\n\r\n", + Response( + status_code=200, + headers=[("SomeHeader1", "val1"), ("SomeHeader2", "val2")], + http_version="1.1", + reason="OK", + ), + ) + + # obsolete line folding + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" + b"Host: example.com\r\n" + b"Some: multi-line\r\n" + b" header\r\n" + b"\tnonsense\r\n" + b" \t \t\tI guess\r\n" + b"Connection: close\r\n" + b"More-nonsense: in the\r\n" + b" last header \r\n\r\n", + Request( + method="HEAD", + target="/foo", + headers=[ + ("Host", "example.com"), + ("Some", "multi-line header nonsense I guess"), + ("Connection", "close"), + ("More-nonsense", "in the last header"), + ], + ), + ) + + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" b" folded: line\r\n\r\n", + None, + ) + + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" b"foo : line\r\n\r\n", + None, + ) + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" b"foo\t: line\r\n\r\n", + None, + ) + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" b"foo\t: line\r\n\r\n", + None, + ) + with pytest.raises(LocalProtocolError): + tr(READERS[CLIENT, IDLE], b"HEAD /foo HTTP/1.1\r\n" b": line\r\n\r\n", None) + + +def test__obsolete_line_fold_bytes() -> None: + # _obsolete_line_fold has a defensive cast to bytearray, which is + # necessary to protect against O(n^2) behavior in case anyone ever passes + # in regular bytestrings... but right now we never pass in regular + # bytestrings. so this test just exists to get some coverage on that + # defensive cast. + assert list(_obsolete_line_fold([b"aaa", b"bbb", b" ccc", b"ddd"])) == [ + b"aaa", + bytearray(b"bbb ccc"), + b"ddd", + ] + + +def _run_reader_iter( + reader: Any, buf: bytes, do_eof: bool +) -> Generator[Any, None, None]: + while True: + event = reader(buf) + if event is None: + break + yield event + # body readers have undefined behavior after returning EndOfMessage, + # because this changes the state so they don't get called again + if type(event) is EndOfMessage: + break + if do_eof: + assert not buf + yield reader.read_eof() + + +def _run_reader(*args: Any) -> List[Event]: + events = list(_run_reader_iter(*args)) + return normalize_data_events(events) + + +def t_body_reader(thunk: Any, data: bytes, expected: Any, do_eof: bool = False) -> None: + # Simple: consume whole thing + print("Test 1") + buf = makebuf(data) + assert _run_reader(thunk(), buf, do_eof) == expected + + # Incrementally growing buffer + print("Test 2") + reader = thunk() + buf = ReceiveBuffer() + events = [] + for i in range(len(data)): + events += _run_reader(reader, buf, False) + buf += data[i : i + 1] + events += _run_reader(reader, buf, do_eof) + assert normalize_data_events(events) == expected + + is_complete = any(type(event) is EndOfMessage for event in expected) + if is_complete and not do_eof: + buf = makebuf(data + b"trailing") + assert _run_reader(thunk(), buf, False) == expected + + +def test_ContentLengthReader() -> None: + t_body_reader(lambda: ContentLengthReader(0), b"", [EndOfMessage()]) + + t_body_reader( + lambda: ContentLengthReader(10), + b"0123456789", + [Data(data=b"0123456789"), EndOfMessage()], + ) + + +def test_Http10Reader() -> None: + t_body_reader(Http10Reader, b"", [EndOfMessage()], do_eof=True) + t_body_reader(Http10Reader, b"asdf", [Data(data=b"asdf")], do_eof=False) + t_body_reader( + Http10Reader, b"asdf", [Data(data=b"asdf"), EndOfMessage()], do_eof=True + ) + + +def test_ChunkedReader() -> None: + t_body_reader(ChunkedReader, b"0\r\n\r\n", [EndOfMessage()]) + + t_body_reader( + ChunkedReader, + b"0\r\nSome: header\r\n\r\n", + [EndOfMessage(headers=[("Some", "header")])], + ) + + t_body_reader( + ChunkedReader, + b"5\r\n01234\r\n" + + b"10\r\n0123456789abcdef\r\n" + + b"0\r\n" + + b"Some: header\r\n\r\n", + [ + Data(data=b"012340123456789abcdef"), + EndOfMessage(headers=[("Some", "header")]), + ], + ) + + t_body_reader( + ChunkedReader, + b"5\r\n01234\r\n" + b"10\r\n0123456789abcdef\r\n" + b"0\r\n\r\n", + [Data(data=b"012340123456789abcdef"), EndOfMessage()], + ) + + # handles upper and lowercase hex + t_body_reader( + ChunkedReader, + b"aA\r\n" + b"x" * 0xAA + b"\r\n" + b"0\r\n\r\n", + [Data(data=b"x" * 0xAA), EndOfMessage()], + ) + + # refuses arbitrarily long chunk integers + with pytest.raises(LocalProtocolError): + # Technically this is legal HTTP/1.1, but we refuse to process chunk + # sizes that don't fit into 20 characters of hex + t_body_reader(ChunkedReader, b"9" * 100 + b"\r\nxxx", [Data(data=b"xxx")]) + + # refuses garbage in the chunk count + with pytest.raises(LocalProtocolError): + t_body_reader(ChunkedReader, b"10\x00\r\nxxx", None) + + # handles (and discards) "chunk extensions" omg wtf + t_body_reader( + ChunkedReader, + b"5; hello=there\r\n" + + b"xxxxx" + + b"\r\n" + + b'0; random="junk"; some=more; canbe=lonnnnngg\r\n\r\n', + [Data(data=b"xxxxx"), EndOfMessage()], + ) + + t_body_reader( + ChunkedReader, + b"5 \r\n01234\r\n" + b"0\r\n\r\n", + [Data(data=b"01234"), EndOfMessage()], + ) + + +def test_ContentLengthWriter() -> None: + w = ContentLengthWriter(5) + assert dowrite(w, Data(data=b"123")) == b"123" + assert dowrite(w, Data(data=b"45")) == b"45" + assert dowrite(w, EndOfMessage()) == b"" + + w = ContentLengthWriter(5) + with pytest.raises(LocalProtocolError): + dowrite(w, Data(data=b"123456")) + + w = ContentLengthWriter(5) + dowrite(w, Data(data=b"123")) + with pytest.raises(LocalProtocolError): + dowrite(w, Data(data=b"456")) + + w = ContentLengthWriter(5) + dowrite(w, Data(data=b"123")) + with pytest.raises(LocalProtocolError): + dowrite(w, EndOfMessage()) + + w = ContentLengthWriter(5) + dowrite(w, Data(data=b"123")) == b"123" + dowrite(w, Data(data=b"45")) == b"45" + with pytest.raises(LocalProtocolError): + dowrite(w, EndOfMessage(headers=[("Etag", "asdf")])) + + +def test_ChunkedWriter() -> None: + w = ChunkedWriter() + assert dowrite(w, Data(data=b"aaa")) == b"3\r\naaa\r\n" + assert dowrite(w, Data(data=b"a" * 20)) == b"14\r\n" + b"a" * 20 + b"\r\n" + + assert dowrite(w, Data(data=b"")) == b"" + + assert dowrite(w, EndOfMessage()) == b"0\r\n\r\n" + + assert ( + dowrite(w, EndOfMessage(headers=[("Etag", "asdf"), ("a", "b")])) + == b"0\r\nEtag: asdf\r\na: b\r\n\r\n" + ) + + +def test_Http10Writer() -> None: + w = Http10Writer() + assert dowrite(w, Data(data=b"1234")) == b"1234" + assert dowrite(w, EndOfMessage()) == b"" + + with pytest.raises(LocalProtocolError): + dowrite(w, EndOfMessage(headers=[("Etag", "asdf")])) + + +def test_reject_garbage_after_request_line() -> None: + with pytest.raises(LocalProtocolError): + tr(READERS[SERVER, SEND_RESPONSE], b"HTTP/1.0 200 OK\x00xxxx\r\n\r\n", None) + + +def test_reject_garbage_after_response_line() -> None: + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1 xxxxxx\r\n" b"Host: a\r\n\r\n", + None, + ) + + +def test_reject_garbage_in_header_line() -> None: + with pytest.raises(LocalProtocolError): + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" b"Host: foo\x00bar\r\n\r\n", + None, + ) + + +def test_reject_non_vchar_in_path() -> None: + for bad_char in b"\x00\x20\x7f\xee": + message = bytearray(b"HEAD /") + message.append(bad_char) + message.extend(b" HTTP/1.1\r\nHost: foobar\r\n\r\n") + with pytest.raises(LocalProtocolError): + tr(READERS[CLIENT, IDLE], message, None) + + +# https://github.com/python-hyper/h11/issues/57 +def test_allow_some_garbage_in_cookies() -> None: + tr( + READERS[CLIENT, IDLE], + b"HEAD /foo HTTP/1.1\r\n" + b"Host: foo\r\n" + b"Set-Cookie: ___utmvafIumyLc=kUd\x01UpAt; path=/; Max-Age=900\r\n" + b"\r\n", + Request( + method="HEAD", + target="/foo", + headers=[ + ("Host", "foo"), + ("Set-Cookie", "___utmvafIumyLc=kUd\x01UpAt; path=/; Max-Age=900"), + ], + ), + ) + + +def test_host_comes_first() -> None: + tw( + write_headers, + normalize_and_validate([("foo", "bar"), ("Host", "example.com")]), + b"Host: example.com\r\nfoo: bar\r\n\r\n", + ) diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_receivebuffer.py b/.venv/lib/python3.10/site-packages/h11/tests/test_receivebuffer.py new file mode 100644 index 0000000..21a3870 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_receivebuffer.py @@ -0,0 +1,135 @@ +import re +from typing import Tuple + +import pytest + +from .._receivebuffer import ReceiveBuffer + + +def test_receivebuffer() -> None: + b = ReceiveBuffer() + assert not b + assert len(b) == 0 + assert bytes(b) == b"" + + b += b"123" + assert b + assert len(b) == 3 + assert bytes(b) == b"123" + + assert bytes(b) == b"123" + + assert b.maybe_extract_at_most(2) == b"12" + assert b + assert len(b) == 1 + assert bytes(b) == b"3" + + assert bytes(b) == b"3" + + assert b.maybe_extract_at_most(10) == b"3" + assert bytes(b) == b"" + + assert b.maybe_extract_at_most(10) is None + assert not b + + ################################################################ + # maybe_extract_until_next + ################################################################ + + b += b"123\n456\r\n789\r\n" + + assert b.maybe_extract_next_line() == b"123\n456\r\n" + assert bytes(b) == b"789\r\n" + + assert b.maybe_extract_next_line() == b"789\r\n" + assert bytes(b) == b"" + + b += b"12\r" + assert b.maybe_extract_next_line() is None + assert bytes(b) == b"12\r" + + b += b"345\n\r" + assert b.maybe_extract_next_line() is None + assert bytes(b) == b"12\r345\n\r" + + # here we stopped at the middle of b"\r\n" delimiter + + b += b"\n6789aaa123\r\n" + assert b.maybe_extract_next_line() == b"12\r345\n\r\n" + assert b.maybe_extract_next_line() == b"6789aaa123\r\n" + assert b.maybe_extract_next_line() is None + assert bytes(b) == b"" + + ################################################################ + # maybe_extract_lines + ################################################################ + + b += b"123\r\na: b\r\nfoo:bar\r\n\r\ntrailing" + lines = b.maybe_extract_lines() + assert lines == [b"123", b"a: b", b"foo:bar"] + assert bytes(b) == b"trailing" + + assert b.maybe_extract_lines() is None + + b += b"\r\n\r" + assert b.maybe_extract_lines() is None + + assert b.maybe_extract_at_most(100) == b"trailing\r\n\r" + assert not b + + # Empty body case (as happens at the end of chunked encoding if there are + # no trailing headers, e.g.) + b += b"\r\ntrailing" + assert b.maybe_extract_lines() == [] + assert bytes(b) == b"trailing" + + +@pytest.mark.parametrize( + "data", + [ + pytest.param( + ( + b"HTTP/1.1 200 OK\r\n", + b"Content-type: text/plain\r\n", + b"Connection: close\r\n", + b"\r\n", + b"Some body", + ), + id="with_crlf_delimiter", + ), + pytest.param( + ( + b"HTTP/1.1 200 OK\n", + b"Content-type: text/plain\n", + b"Connection: close\n", + b"\n", + b"Some body", + ), + id="with_lf_only_delimiter", + ), + pytest.param( + ( + b"HTTP/1.1 200 OK\n", + b"Content-type: text/plain\r\n", + b"Connection: close\n", + b"\n", + b"Some body", + ), + id="with_mixed_crlf_and_lf", + ), + ], +) +def test_receivebuffer_for_invalid_delimiter(data: Tuple[bytes]) -> None: + b = ReceiveBuffer() + + for line in data: + b += line + + lines = b.maybe_extract_lines() + + assert lines == [ + b"HTTP/1.1 200 OK", + b"Content-type: text/plain", + b"Connection: close", + ] + assert bytes(b) == b"Some body" diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_state.py b/.venv/lib/python3.10/site-packages/h11/tests/test_state.py new file mode 100644 index 0000000..bc974e6 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_state.py @@ -0,0 +1,271 @@ +import pytest + +from .._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from .._state import ( + _SWITCH_CONNECT, + _SWITCH_UPGRADE, + CLIENT, + CLOSED, + ConnectionState, + DONE, + IDLE, + MIGHT_SWITCH_PROTOCOL, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, + SWITCHED_PROTOCOL, +) +from .._util import LocalProtocolError + + +def test_ConnectionState() -> None: + cs = ConnectionState() + + # Basic event-triggered transitions + + assert cs.states == {CLIENT: IDLE, SERVER: IDLE} + + cs.process_event(CLIENT, Request) + # The SERVER-Request special case: + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + # Illegal transitions raise an error and nothing happens + with pytest.raises(LocalProtocolError): + cs.process_event(CLIENT, Request) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + cs.process_event(SERVER, InformationalResponse) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + cs.process_event(SERVER, Response) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_BODY} + + cs.process_event(CLIENT, EndOfMessage) + cs.process_event(SERVER, EndOfMessage) + assert cs.states == {CLIENT: DONE, SERVER: DONE} + + # State-triggered transition + + cs.process_event(SERVER, ConnectionClosed) + assert cs.states == {CLIENT: MUST_CLOSE, SERVER: CLOSED} + + +def test_ConnectionState_keep_alive() -> None: + # keep_alive = False + cs = ConnectionState() + cs.process_event(CLIENT, Request) + cs.process_keep_alive_disabled() + cs.process_event(CLIENT, EndOfMessage) + assert cs.states == {CLIENT: MUST_CLOSE, SERVER: SEND_RESPONSE} + + cs.process_event(SERVER, Response) + cs.process_event(SERVER, EndOfMessage) + assert cs.states == {CLIENT: MUST_CLOSE, SERVER: MUST_CLOSE} + + +def test_ConnectionState_keep_alive_in_DONE() -> None: + # Check that if keep_alive is disabled when the CLIENT is already in DONE, + # then this is sufficient to immediately trigger the DONE -> MUST_CLOSE + # transition + cs = ConnectionState() + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + assert cs.states[CLIENT] is DONE + cs.process_keep_alive_disabled() + assert cs.states[CLIENT] is MUST_CLOSE + + +def test_ConnectionState_switch_denied() -> None: + for switch_type in (_SWITCH_CONNECT, _SWITCH_UPGRADE): + for deny_early in (True, False): + cs = ConnectionState() + cs.process_client_switch_proposal(switch_type) + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, Data) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + assert switch_type in cs.pending_switch_proposals + + if deny_early: + # before client reaches DONE + cs.process_event(SERVER, Response) + assert not cs.pending_switch_proposals + + cs.process_event(CLIENT, EndOfMessage) + + if deny_early: + assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} + else: + assert cs.states == { + CLIENT: MIGHT_SWITCH_PROTOCOL, + SERVER: SEND_RESPONSE, + } + + cs.process_event(SERVER, InformationalResponse) + assert cs.states == { + CLIENT: MIGHT_SWITCH_PROTOCOL, + SERVER: SEND_RESPONSE, + } + + cs.process_event(SERVER, Response) + assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} + assert not cs.pending_switch_proposals + + +_response_type_for_switch = { + _SWITCH_UPGRADE: InformationalResponse, + _SWITCH_CONNECT: Response, + None: Response, +} + + +def test_ConnectionState_protocol_switch_accepted() -> None: + for switch_event in [_SWITCH_UPGRADE, _SWITCH_CONNECT]: + cs = ConnectionState() + cs.process_client_switch_proposal(switch_event) + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, Data) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + cs.process_event(CLIENT, EndOfMessage) + assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} + + cs.process_event(SERVER, InformationalResponse) + assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} + + cs.process_event(SERVER, _response_type_for_switch[switch_event], switch_event) + assert cs.states == {CLIENT: SWITCHED_PROTOCOL, SERVER: SWITCHED_PROTOCOL} + + +def test_ConnectionState_double_protocol_switch() -> None: + # CONNECT + Upgrade is legal! Very silly, but legal. So we support + # it. Because sometimes doing the silly thing is easier than not. + for server_switch in [None, _SWITCH_UPGRADE, _SWITCH_CONNECT]: + cs = ConnectionState() + cs.process_client_switch_proposal(_SWITCH_UPGRADE) + cs.process_client_switch_proposal(_SWITCH_CONNECT) + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} + cs.process_event( + SERVER, _response_type_for_switch[server_switch], server_switch + ) + if server_switch is None: + assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} + else: + assert cs.states == {CLIENT: SWITCHED_PROTOCOL, SERVER: SWITCHED_PROTOCOL} + + +def test_ConnectionState_inconsistent_protocol_switch() -> None: + for client_switches, server_switch in [ + ([], _SWITCH_CONNECT), + ([], _SWITCH_UPGRADE), + ([_SWITCH_UPGRADE], _SWITCH_CONNECT), + ([_SWITCH_CONNECT], _SWITCH_UPGRADE), + ]: + cs = ConnectionState() + for client_switch in client_switches: # type: ignore[attr-defined] + cs.process_client_switch_proposal(client_switch) + cs.process_event(CLIENT, Request) + with pytest.raises(LocalProtocolError): + cs.process_event(SERVER, Response, server_switch) + + +def test_ConnectionState_keepalive_protocol_switch_interaction() -> None: + # keep_alive=False + pending_switch_proposals + cs = ConnectionState() + cs.process_client_switch_proposal(_SWITCH_UPGRADE) + cs.process_event(CLIENT, Request) + cs.process_keep_alive_disabled() + cs.process_event(CLIENT, Data) + assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} + + # the protocol switch "wins" + cs.process_event(CLIENT, EndOfMessage) + assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} + + # but when the server denies the request, keep_alive comes back into play + cs.process_event(SERVER, Response) + assert cs.states == {CLIENT: MUST_CLOSE, SERVER: SEND_BODY} + + +def test_ConnectionState_reuse() -> None: + cs = ConnectionState() + + with pytest.raises(LocalProtocolError): + cs.start_next_cycle() + + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + + with pytest.raises(LocalProtocolError): + cs.start_next_cycle() + + cs.process_event(SERVER, Response) + cs.process_event(SERVER, EndOfMessage) + + cs.start_next_cycle() + assert cs.states == {CLIENT: IDLE, SERVER: IDLE} + + # No keepalive + + cs.process_event(CLIENT, Request) + cs.process_keep_alive_disabled() + cs.process_event(CLIENT, EndOfMessage) + cs.process_event(SERVER, Response) + cs.process_event(SERVER, EndOfMessage) + + with pytest.raises(LocalProtocolError): + cs.start_next_cycle() + + # One side closed + + cs = ConnectionState() + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + cs.process_event(CLIENT, ConnectionClosed) + cs.process_event(SERVER, Response) + cs.process_event(SERVER, EndOfMessage) + + with pytest.raises(LocalProtocolError): + cs.start_next_cycle() + + # Succesful protocol switch + + cs = ConnectionState() + cs.process_client_switch_proposal(_SWITCH_UPGRADE) + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + cs.process_event(SERVER, InformationalResponse, _SWITCH_UPGRADE) + + with pytest.raises(LocalProtocolError): + cs.start_next_cycle() + + # Failed protocol switch + + cs = ConnectionState() + cs.process_client_switch_proposal(_SWITCH_UPGRADE) + cs.process_event(CLIENT, Request) + cs.process_event(CLIENT, EndOfMessage) + cs.process_event(SERVER, Response) + cs.process_event(SERVER, EndOfMessage) + + cs.start_next_cycle() + assert cs.states == {CLIENT: IDLE, SERVER: IDLE} + + +def test_server_request_is_illegal() -> None: + # There used to be a bug in how we handled the Request special case that + # made this allowed... + cs = ConnectionState() + with pytest.raises(LocalProtocolError): + cs.process_event(SERVER, Request) diff --git a/.venv/lib/python3.10/site-packages/h11/tests/test_util.py b/.venv/lib/python3.10/site-packages/h11/tests/test_util.py new file mode 100644 index 0000000..79bc095 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/h11/tests/test_util.py @@ -0,0 +1,112 @@ +import re +import sys +import traceback +from typing import NoReturn + +import pytest + +from .._util import ( + bytesify, + LocalProtocolError, + ProtocolError, + RemoteProtocolError, + Sentinel, + validate, +) + + +def test_ProtocolError() -> None: + with pytest.raises(TypeError): + ProtocolError("abstract base class") + + +def test_LocalProtocolError() -> None: + try: + raise LocalProtocolError("foo") + except LocalProtocolError as e: + assert str(e) == "foo" + assert e.error_status_hint == 400 + + try: + raise LocalProtocolError("foo", error_status_hint=418) + except LocalProtocolError as e: + assert str(e) == "foo" + assert e.error_status_hint == 418 + + def thunk() -> NoReturn: + raise LocalProtocolError("a", error_status_hint=420) + + try: + try: + thunk() + except LocalProtocolError as exc1: + orig_traceback = "".join(traceback.format_tb(sys.exc_info()[2])) + exc1._reraise_as_remote_protocol_error() + except RemoteProtocolError as exc2: + assert type(exc2) is RemoteProtocolError + assert exc2.args == ("a",) + assert exc2.error_status_hint == 420 + new_traceback = "".join(traceback.format_tb(sys.exc_info()[2])) + assert new_traceback.endswith(orig_traceback) + + +def test_validate() -> None: + my_re = re.compile(rb"(?P[0-9]+)\.(?P[0-9]+)") + with pytest.raises(LocalProtocolError): + validate(my_re, b"0.") + + groups = validate(my_re, b"0.1") + assert groups == {"group1": b"0", "group2": b"1"} + + # successful partial matches are an error - must match whole string + with pytest.raises(LocalProtocolError): + validate(my_re, b"0.1xx") + with pytest.raises(LocalProtocolError): + validate(my_re, b"0.1\n") + + +def test_validate_formatting() -> None: + my_re = re.compile(rb"foo") + + with pytest.raises(LocalProtocolError) as excinfo: + validate(my_re, b"", "oops") + assert "oops" in str(excinfo.value) + + with pytest.raises(LocalProtocolError) as excinfo: + validate(my_re, b"", "oops {}") + assert "oops {}" in str(excinfo.value) + + with pytest.raises(LocalProtocolError) as excinfo: + validate(my_re, b"", "oops {} xx", 10) + assert "oops 10 xx" in str(excinfo.value) + + +def test_make_sentinel() -> None: + class S(Sentinel, metaclass=Sentinel): + pass + + assert repr(S) == "S" + assert S == S + assert type(S).__name__ == "S" + assert S in {S} + assert type(S) is S + + class S2(Sentinel, metaclass=Sentinel): + pass + + assert repr(S2) == "S2" + assert S != S2 + assert S not in {S2} + assert type(S) is not type(S2) + + +def test_bytesify() -> None: + assert bytesify(b"123") == b"123" + assert bytesify(bytearray(b"123")) == b"123" + assert bytesify("123") == b"123" + + with pytest.raises(UnicodeEncodeError): + bytesify("\u1234") + + with pytest.raises(TypeError): + bytesify(10) diff --git a/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/INSTALLER b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/LICENSE.md b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/LICENSE.md new file mode 100644 index 0000000..19b6b45 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/LICENSE.md @@ -0,0 +1,31 @@ +BSD 3-Clause License + +Copyright (c) 2013-2024, 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/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/METADATA b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/METADATA new file mode 100644 index 0000000..b28f6ec --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/METADATA @@ -0,0 +1,243 @@ +Metadata-Version: 2.1 +Name: idna +Version: 3.7 +Summary: Internationalized Domain Names in Applications (IDNA) +Author-email: Kim Davies +Requires-Python: >=3.5 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: BSD License +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.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +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 +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 + +Internationalized Domain Names in Applications (IDNA) +===================================================== + +Support for the Internationalized Domain Names in +Applications (IDNA) protocol as specified in `RFC 5891 +`_. This is the latest version of +the protocol and is sometimes referred to as “IDNA 2008”. + +This library also provides support for Unicode Technical +Standard 46, `Unicode IDNA Compatibility Processing +`_. + +This acts as a suitable replacement for the “encodings.idna” +module that comes with the Python standard library, but which +only supports the older superseded IDNA specification (`RFC 3490 +`_). + +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: + +.. 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 A-labels or U-labels +respectively. + +.. code-block:: pycon + + >>> import idna + >>> idna.encode('ドメイン.テスト') + b'xn--eckwd4c7c.xn--zckzah' + >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) + ドメイン.テスト + +You may use the codec encoding and decoding methods using the +``idna.codec`` module: + +.. code-block:: pycon + + >>> import idna.codec + >>> print('домен.испытание'.encode('idna2008')) + b'xn--d1acufc.xn--80akhbyknj4f' + >>> print(b'xn--d1acufc.xn--80akhbyknj4f'.decode('idna2008')) + домен.испытание + +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) ++++++++++++++++++++++++++++++++ + +As described in `RFC 5895 `_, the +IDNA specification does not normalize input from different potential +ways a user may input a domain name. This functionality, known as +a “mapping”, is considered by the specification to be a local +user-interface issue distinct from IDNA conversion functionality. + +This library provides one such mapping that was developed by the +Unicode Consortium. Known as `Unicode IDNA Compatibility Processing +`_, it provides for both a regular +mapping for typical applications, as well as a transitional mapping to +help migrate from older IDNA 2003 applications. + +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 + +Transitional processing provides conversions to help transition from +the older 2003 standard to the current standard. For example, in the +original IDNA specification, the *LATIN SMALL LETTER SHARP S* (ß) was +converted into two *LATIN SMALL LETTER S* (ss), whereas in the current +IDNA specification this conversion is not performed. + +.. code-block:: pycon + + >>> idna.encode('Königsgäßchen', uts46=True, transitional=True) + 'xn--knigsgsschen-lcb0w' + +Implementers should use transitional processing with caution, only in +rare cases where conversion from legacy labels to current labels must be +performed (i.e. IDNA implementations that pre-date 2008). For typical +applications that just need to convert labels, transitional processing +is unlikely to be beneficial and could produce unexpected incompatible +results. + +``encodings.idna`` Compatibility +++++++++++++++++++++++++++++++++ + +Function calls from the Python built-in ``encodings.idna`` module are +mapped to their IDNA 2008 equivalents using the ``idna.compat`` module. +Simply substitute the ``import`` clause in your code to refer to the new +module name. + +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 positional context (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. These tables are +computed 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.5 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. + Removing support for older versions should be well justified in that the + maintenance burden has become too high. + +* **Python 2**. Python 2 is supported by version 2.x of this library. + While active development of the version 2.x series has ended, notable + issues being corrected may be backported to 2.x. Use "idna<3" in your + requirements file if you need this library for a Python 2 application. + +* **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. + diff --git a/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/RECORD b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/RECORD new file mode 100644 index 0000000..fac5229 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/RECORD @@ -0,0 +1,22 @@ +idna-3.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +idna-3.7.dist-info/LICENSE.md,sha256=pZ8LDvNjWHQQmkRhykT_enDVBpboFHZ7-vch1Mmw2w8,1541 +idna-3.7.dist-info/METADATA,sha256=OixCk-dKLZkPy-MfviOmiPvwJ1O2K_8rqCrFjC_uxy4,9888 +idna-3.7.dist-info/RECORD,, +idna-3.7.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +idna/__init__.py,sha256=KJQN1eQBr8iIK5SKrJ47lXvxG0BJ7Lm38W4zT0v_8lk,849 +idna/__pycache__/__init__.cpython-310.pyc,, +idna/__pycache__/codec.cpython-310.pyc,, +idna/__pycache__/compat.cpython-310.pyc,, +idna/__pycache__/core.cpython-310.pyc,, +idna/__pycache__/idnadata.cpython-310.pyc,, +idna/__pycache__/intranges.cpython-310.pyc,, +idna/__pycache__/package_data.cpython-310.pyc,, +idna/__pycache__/uts46data.cpython-310.pyc,, +idna/codec.py,sha256=PS6m-XmdST7Wj7J7ulRMakPDt5EBJyYrT3CPtjh-7t4,3426 +idna/compat.py,sha256=0_sOEUMT4CVw9doD3vyRhX80X19PwqFoUBs7gWsFME4,321 +idna/core.py,sha256=lyhpoe2vulEaB_65xhXmoKgO-xUqFDvcwxu5hpNNO4E,12663 +idna/idnadata.py,sha256=dqRwytzkjIHMBa2R1lYvHDwACenZPt8eGVu1Y8UBE-E,78320 +idna/intranges.py,sha256=YBr4fRYuWH7kTKS2tXlFjM24ZF1Pdvcir-aywniInqg,1881 +idna/package_data.py,sha256=Tkt0KnIeyIlnHddOaz9WSkkislNgokJAuE-p5GorMqo,21 +idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +idna/uts46data.py,sha256=1KuksWqLuccPXm2uyRVkhfiFLNIhM_H2m4azCcnOqEU,206503 diff --git a/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/WHEEL b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna-3.7.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.venv/lib/python3.10/site-packages/idna/__init__.py b/.venv/lib/python3.10/site-packages/idna/__init__.py new file mode 100644 index 0000000..a40eeaf --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/__init__.py @@ -0,0 +1,44 @@ +from .package_data import __version__ +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 + +__all__ = [ + "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/.venv/lib/python3.10/site-packages/idna/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe2ef5898dd7a0072213e20315cf1220a8a12832 GIT binary patch literal 841 zcmbu7&5qMB5XX~#q)n6bdt1aC^gzM_LPA0aSUBuu1>%G+mK%E;Q-1^}ttcdGGK$v*1K00nY@26BjoGDM*qp^=PGBx4lI1SN8e#&Uuta*C#MhGue( z=5m1+a*39WURRvS6)VkFt!nnEwgC}j%Y+@}1*VaDwTn|(FopHr zuG#=syyisUT+1z2%-E=nw+dnFsO#JYl;tk94VY@*hxU``P*;y0W5XmV?YJq?i8Y0M zxaDg*Z}*!&v0!Rf7k1Ics@ib1y9v63nYk7XQ9D*Oa)hhR!nk32rU&Q)0>A(;1cU&X zyomrYAOVa4XMhP{3YY=rfCXUbaJ9K(mz0V3QSw@Tf$0rZ6v^;DDuZrxNE246ie%8E7_a;k^OdT`9w^@0r w3#}fe=l8RU*X-U+UscAbA{oXoc#PBXWQR|srU${E!IiAwBxCQ5A1~w1Zz+-El>h($ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/__pycache__/codec.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/codec.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90cba8b645a2ae80dfc53a0cb291c0a43643c195 GIT binary patch literal 3267 zcmb7`&u<(>7RS4~tAEURJa!xh$G|R52)oPzGf4me3qghip{!O$;>WJk2#wlPHE}0B zJ(H>)Rt{|m;aqq3U$Bq9?H{mvL*m9CP*+YlaqwxmEZ_Kahrusy2RRqyrGk5`}f zs)qCPbqCLP|6J*B&O6Qz)R=vIG}ck{_YlGnEOQ1dW&<~N2VU$Ac+3ZW>@!EW!pnj< zuN8;BIr*i<{6yq6SS3ngwVU zp{a{GXy%|f2h9>R4KWYRylg^uewWARp=*i-=oYMQ8MP472qbFG|@++A|2*QHg3TBdHaX2zxnas|M>Ag`(O0v^Vz3{#yX1rGlX&F`#T{%Ys)fqRJ092G*exC-zxL4T+Q zNugY7c$v%(Jj1oj`U(^}stIx6sEc_0^q0=oa3DKk>)!phu6Np_@n)9ltxiA9le{O} z4~D63-&39Tmoopdlck%T(RQ&l%wKI^yV}udAzv9Ky?e&PCVqHbremM9AnD>Yy~a{xWHD17Tm~!%K>Hx zN+Pp#JMSquka>}0AJ|A!(_J<`ZDghv&~uMyJbGwM%05J={ujiP=-dOD`)mhu+3`!R zUMjipR~>y>1k@J(4JWUap0@fM4t+tEJI)R=(N0+MTh133cA_%aI~A4OQgI^g61$Y z*D2P|!|*K1A^9nCe#aDP{x7IGvaJuO1LWf;Lw(C08#7Sb4R`|5-(pTrLb^n{-F5XU zC0)UH-5pl&J%56^Z!v!zXa~UjWk5`r2NTS#-eUebSuEz!3Cx2coWcB0z`QoWJUYhw zZ4vI(PGBCDk7Hh+#rzqp%J_-yrKzGlP%n^z&7xkPLA{>pG}i?sa=X*&_w=6^Nwi2% z0;sa*A5c3RboCN_^fHN8NKlSa9f-I-!J1OzH2+cRn?hYB+jpVUuR%l)5Xf-=Nxbx>K%Sh2aJnualtGDW)lxtfL&#!8}dWNW-pa zd{QWx4F0NcCaR4C@9{`GYsk0IO+x)up~RUY%`XnC-h_2J)W^gTnE0Mtq;9W$*{X3mO z-bNhJ;eY+=)i+zAvQDI%hdmn2QaU}KsvM_I=&CJLrU8!Nz`t1s9<`vs8gWPm_F|z; z&0ZgF=eXd|S!%Bt)e-zWHEG+d6YX+w#@oqEeQ)Vp&@xfIt!{su_vmVw;!m3H50qs& zb6J3&JNX6wRkvVjts34NDmgPCZCVvVbik|kA&iUTBq+8=I1iLX(1J&YtqFU>!6?mS z6@)Z-^Yr^R^-FO&b=#zR<_D7ycx$HD%x+YTcPO5?8S!9^#o$8+RE^WLf_dJWm WM{F5Ux#TV_FI`%`vdk~?=KRmW*sf3j literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/__pycache__/compat.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63817d78c3543539775468af0ad9b93a4058302f GIT binary patch literal 741 zcmZ{iy^a$x5XbHP$|kuSa3By=+b)9La5NwxM08N3NpnF+={D=hWtClfnRQOu6BS3# zbL2^Q2e(vL(@`*hUY9kz99-0bHktCP{3lxxD(kL|FbNVG=7;ap)>)4-lELy-rHeghvpg0KOq^- zzOie5&USo8^#YK&60qYKkhWuZMDFjGbge2##d`Dg?P;3S+htia>vUDfOy-bWsiH|X zm?oDXFVnJErgf{=O1@5Bjnk&k@UqVGO?ClIS_qk?xvJ_+Cv|Ijb2T|Xn@)X8W3fVx z$K>urMvIJnG8R^Vg~g%GS5nO(h@ zewZnGgRjx`RdN@;hTGb^~AT@|jhzetlC;!SuHe2-{bJTzXe5R7lxa}(&cF60H;ABMI~#%(kjf7xnix?Y*SjWfio?Ouqs f%t1R2u6$Q1u`S`f{REB8ht%-<{KR?YK6d{Bya%Lp literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/__pycache__/core.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/core.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2d595aaaa942efb2ec49b7f7d76cd326f5d11a6 GIT binary patch literal 9472 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 T_|*8Z(xc=1#}7?9lSlp+z*Ct^ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/__pycache__/idnadata.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/idnadata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50ddecf1aba3080935b88ae3aa4a7668fb0855db GIT binary patch literal 194442 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%0D{b%leb^plS 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 aajqUyJ()!;0c*}I@z1;)*KhiFf`0+J3HNFM literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/__pycache__/package_data.cpython-310.pyc b/.venv/lib/python3.10/site-packages/idna/__pycache__/package_data.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4143a2ce1f6d40759474875c64b1c7c299f3a12 GIT binary patch literal 205 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/idna/codec.py b/.venv/lib/python3.10/site-packages/idna/codec.py new file mode 100644 index 0000000..c855a4d --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/codec.py @@ -0,0 +1,118 @@ +from .core import encode, decode, alabel, ulabel, IDNAError +import codecs +import re +from typing import Any, Tuple, Optional + +_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]') + +class Codec(codecs.Codec): + + def encode(self, data: str, errors: str = 'strict') -> 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/.venv/lib/python3.10/site-packages/idna/compat.py b/.venv/lib/python3.10/site-packages/idna/compat.py new file mode 100644 index 0000000..786e6bd --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/compat.py @@ -0,0 +1,13 @@ +from .core import * +from .codec import * +from typing import Any, Union + +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/.venv/lib/python3.10/site-packages/idna/core.py b/.venv/lib/python3.10/site-packages/idna/core.py new file mode 100644 index 0000000..0dae61a --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/core.py @@ -0,0 +1,395 @@ +from . import idnadata +import bisect +import unicodedata +import re +from typing import Union, Optional +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 = None # type: Optional[str] + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if not direction 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 not direction 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']): + if not valid_contextj(label, pos): + raise InvalidCodepointContext('Joiner {} not allowed 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 = None # type: Optional[str] + 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/.venv/lib/python3.10/site-packages/idna/idnadata.py b/.venv/lib/python3.10/site-packages/idna/idnadata.py new file mode 100644 index 0000000..c61dcf9 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/idnadata.py @@ -0,0 +1,4245 @@ +# 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/.venv/lib/python3.10/site-packages/idna/intranges.py b/.venv/lib/python3.10/site-packages/idna/intranges.py new file mode 100644 index 0000000..6a43b04 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/intranges.py @@ -0,0 +1,54 @@ +""" +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/.venv/lib/python3.10/site-packages/idna/package_data.py b/.venv/lib/python3.10/site-packages/idna/package_data.py new file mode 100644 index 0000000..ed81113 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/package_data.py @@ -0,0 +1,2 @@ +__version__ = '3.7' + diff --git a/.venv/lib/python3.10/site-packages/idna/py.typed b/.venv/lib/python3.10/site-packages/idna/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.venv/lib/python3.10/site-packages/idna/uts46data.py b/.venv/lib/python3.10/site-packages/idna/uts46data.py new file mode 100644 index 0000000..6a1eddb --- /dev/null +++ b/.venv/lib/python3.10/site-packages/idna/uts46data.py @@ -0,0 +1,8598 @@ +# 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/.venv/lib/python3.10/site-packages/jinja2/__init__.py b/.venv/lib/python3.10/site-packages/jinja2/__init__.py new file mode 100644 index 0000000..af5d428 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/__init__.py @@ -0,0 +1,37 @@ +"""Jinja is a template engine written in pure Python. It provides a +non-XML syntax that supports inline expressions and an optional +sandboxed environment. +""" +from .bccache import BytecodeCache as BytecodeCache +from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache +from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache +from .environment import Environment as Environment +from .environment import Template as Template +from .exceptions import TemplateAssertionError as TemplateAssertionError +from .exceptions import TemplateError as TemplateError +from .exceptions import TemplateNotFound as TemplateNotFound +from .exceptions import TemplateRuntimeError as TemplateRuntimeError +from .exceptions import TemplatesNotFound as TemplatesNotFound +from .exceptions import TemplateSyntaxError as TemplateSyntaxError +from .exceptions import UndefinedError as UndefinedError +from .loaders import BaseLoader as BaseLoader +from .loaders import ChoiceLoader as ChoiceLoader +from .loaders import DictLoader as DictLoader +from .loaders import FileSystemLoader as FileSystemLoader +from .loaders import FunctionLoader as FunctionLoader +from .loaders import ModuleLoader as ModuleLoader +from .loaders import PackageLoader as PackageLoader +from .loaders import PrefixLoader as PrefixLoader +from .runtime import ChainableUndefined as ChainableUndefined +from .runtime import DebugUndefined as DebugUndefined +from .runtime import make_logging_undefined as make_logging_undefined +from .runtime import StrictUndefined as StrictUndefined +from .runtime import Undefined as Undefined +from .utils import clear_caches as clear_caches +from .utils import is_undefined as is_undefined +from .utils import pass_context as pass_context +from .utils import pass_environment as pass_environment +from .utils import pass_eval_context as pass_eval_context +from .utils import select_autoescape as select_autoescape + +__version__ = "3.1.3" diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8022f67e5b3430042ca45a11dc60e69745743326 GIT binary patch literal 1612 zcmbW1%WmT~6o%!*j%``KJ9h3-lDQy@vD%qcfud-WnE)*&K`?27f?Wu-#IZS{NDWE3 zc2?c>6}s!XujFl4eTA-i$W*pF%gXSNk3SE|L+Xg4UUwaMZhjxU|F!Hmf11YnvjL5- z;jexvI8N*!CoaSrtdMM=je_A#;7zn?xd>cDMav~tO199JW8t%N1Z3 zxt6QIHB__g0(;1_Tm!D7x@8Zzff|6h%+sSif~FEO0R~W4`1D!KVOu? zFcwi5qVg!ROG|Sn$xS0gkVS261z9roma$zji-;{+CE;dsWW`9;h`I7)&4_2D4zegS z`}UM<7^`WdWu$GSW29@OXJi`$mE~gr$-c1$Ms|$s8rcI`lrl}3lKaLuFmh<*$jGq~ zA7oJr!zq#GQwzgC9QoXI82S6BU?LI{#FP7vU%U*4X*Ob1O#&!8%p)><5L6BCWiXt= z_5(&oL25sDIJeINMKyVmJ{F7$KA0=xWe|pxQyqrGbiSy3nb`9B%6zrz0;K48MX&Jx If0d1Y0N2#NtN;K2 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..709094dfc00370f8adca84aaf9eda0ba8bb257f0 GIT binary patch literal 2087 zcmYk7&2Qtz8OG(^7Fh(ywf!4{Vyref1O63}zoLk{cgI?cW#pE?&2$gP+5VNVtCoA;UbeK_+DM}oHA zd+*&4J|9l^J_$ua>dN}PiY?1rQV->xOud)XD^RaSJ&pRF1M}1hGBss7;S#n@? zWO81TQy`~Cjz%t)bQ9!G$o0sDdyu37+=DC);2y{{DAJ%t1C54p8YXD8PoqOdqZc$P z(C7rJN~1oF92)m%>@pf((-q#s)z@_0qiZCtujqP0*B(u>j3zR9C*+mL8<005?~1$` zd2^cf7|oJ2OVcbvGZ~X2&2YyvkLGDEnT$&_9xE^&EAdzbLFKU;LY>E22o{g^5L_OQ zGai?D{E){_p~_q?GcH&8`4QviFZg*M!R6&6UOwjKJ}*1G;xb-6=G8J+bBwDpucde` z&1*WZtBlu8Uhg7Ic)Q4W`;6-^8P_XZM@{#*KIaC?#*}v?#yd&g!D?2LTWHvF_$88; zaejG$U~#+2xb5(6o$>C7J9);PBksIFXmiKn4tjH3?u-zw_y~`V5GDxog*0Epq($t- zB9Ui{#Q7p|u}Czax{Kt=B6+!RY_@QEi@|&`QrTiOzmp7hC)s!L(p~&ilx$IQnJ7)g zX+@k?#aUOJ^@JK1YFel{p=wO1Em4z1EhcI(YAKxejs#N=o2RNsW7_2=rdus!Wao-ER2~j=E95#(`3T5g*g!B zP}tbnHiX>~wzce3mSc%6$A`=90U&>B)|lC zV1|U81R0P8xga5fBB%ikG=pRZ1bxZqB0qpo(1ud+m7^egj8zLZL}37e6BW@<@f?(W zzsT=SjcZ#>JG|LlBtt4jA}l0~O;838M-w0%7}=;CoY%(jXg%697*|x&Rue z16)`|GW?2`htLXsrICba?Ej$R8});lu|NIU`}g16+ljn+=i%1V?dS%?_S)WFWM@+k z?fe-3t^XVT{fF@5t*4Rj`r{{m`sD}V)$M1WZA5n;haW{Z*ESzUR{ydU-CcdM6JGr? zviW6rBl=l*`>VajTbm!Q{^IB1-RNF~ZLd9ivi5moH~d9(^NY0)!hejeM>hAOkD`&C i)$Om|Joweqt@URckzcQ1%iRYU9)x~$|K7@j|NIyG+xb=i literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5a2bf93fc5083b2c5bbf826e55a1fef011e4a89 GIT binary patch literal 2701 zcma)7UvCpf5Z~Q9+vl^L|Ad6JDx&`|1sj5dS{0$D|EXGw5*j2Udb)Vm$vO6&v$qb! zawH;BB|OloU!YB-zVH?L+KO{*}0jyo!|auHYyZc0>8@d zC+ojt3Hb*XgFn!bPhiA)GY zr|M85*nXC04rtZo4$tn8YEI-uL5zq|F($^vgqY;?AzgKeM~yx8tW2tYGDMH~ctWkSidMw?Xv8hTrsRQK-ay zrRh=)4Uc{d1nY3bV<7C3I^~qJ9cPR7@bgw>$RPzbX&93*;@@CWWS{O?2NcaY>5xaP zM-^$X4w18*Dyw00rc#iT#qAyY5e?lTZ7R|7^cGWTl~K+^x}WW_13+`jQtqDBvv}q) z1Bvt)V*l9MCA)N&?OG7i<+&a309$*H$!}DyXQRyXJ==o;+b>kK?aP%|r=?IG84e|b zNMJ&Xn9RgsGK%$pEVHCx9k506gjJ+L*49*MyXMC*FGo>RJ3;LE@n%?iLZt(~Pl!YS zpZ!=~jas72SJ&1*nlG2yo#kc_ua@gU=!Z2?>PA6aT9f6{h6p#x&0x9Q-c+kmc)4`x zVmS_!xX|`%YyOIe%Z(sx`157+5wD|yW?X7-$`Sa8K_AaK8 z4sl4Pag=b!GcaP@@f0mu+V#9v#5+ylc|ce%^jj$9J#W3^Hd!H7SEX^-{@P=Nt0@_3${`~-!#1tgLufJ!7FJ^Baz85j-} z8(0DNNhY;E-L4Za^I< zwr_D@8{crZy|xTmfeJQ6+^;>I3BtH7YD(vV*gtXyyx)b8N!oqRxqe4Qp0WBE6TrmT zgFK+?vI&}J@&iynGgCt1CZ3&Br60l|3h%(qu)AG9d;z;Ve_E9WmUo{`4B9}a0h=M@ zkZhRdXCTC1g0RgHIk+mBoK1Hn*lx`EeMwSRA>-j67Sp@6P$=%ekb`Eub zp3Zt6z$T>Ub%%Cwh@+)5tA339?862PI{ue0Qp5(YjlW?S`ft+}aOygPNc_sytt*%@ ztsL@Ov(iOP@4vGBt8mFE;7t44Eewc!We-jfs2e3=v<;y00=i<^$P#Mjh7+n9~Ec~DalTfTe`r}y!*DZ^f!JuWLlaFe69 yzXdn5^?^+LrQ%#oE~RUDtT86x5QpaR&yL~_{3^M3(3l5}nW literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8533fd8136f9acb5cf622ee713863204709fc7f3 GIT binary patch literal 13958 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/environment.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/environment.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fcf13eb922491d5136d3ee54ca9dfea22ae344a3 GIT binary patch literal 53398 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 nTaEO63#eO>`Z4`kDJJ=1SqXc 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/filters.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/filters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..372c60b687b4197ccc6016a3ca4134bf1e63e441 GIT binary patch literal 51382 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66517c57961425c84cd2441213d6e6ab77a7b459 GIT binary patch literal 11099 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 EKh2S48~^|S literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59ec36c45cdbff0e799dcee5609687cddaef96ba GIT binary patch literal 20449 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 NO)Yiycei)P{tpEZKS2Nh literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58b9b525b87389276f21833eda357f053309cc97 GIT binary patch literal 20505 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/meta.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/meta.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9cb1506eed5bfe5356bf6b914a308f4a0ea0ca9 GIT binary patch literal 3828 zcmcgvTXP#p6`q?emSyLD1-3dN!4Vi~$u19@+N4+#Cm1M0C0@1=ER)uB%Nlt!qja}? zi(D1TsoI}G^093x1oPW`e`KyW_zrd~kj)!o%j&OySxLr^9B1rsE&<$J%bS0^bs@ZcO+=gLub}*)e+@!9T^IiM zgxmGS@)u6u6;)At-RuUUE-NAs75HvJG+=EN{;U-%mXAEz?AE_<0;jtGKb*-gZ7LpZ z!-#hjJ7|98m;p`_j!9!VpYahvApbe?IFBvXShF!S;)f?snSaNiT`@ zpwo|2o<_2Lkj1*atvc-;7}rVSUT3^-23h(+`)BWWbZq2L$8a6rlDadD(;>gx8A-$2 z<9)S=!%#wwrnsGTo9@ATr@Fa)VuQQ)9Y0a(JUkX6T=K_3^HG+r7`Cf$dV53B87)sO zJy@UDuhqLvQH6 z3En!7oX;=+**o-b`-j2Q7w)#FZcc-#Gpr1&J1%HvSbI~S2DI-*(-xtBaO82BFN?<*v@Mxvn<(>8?6OJ5Jky`+6%3=c}?$+dRe0LN|JGb7hE&aHr{z{E6I91 z(Q1jd`CN!rrSKN{BzMES%5A;ol`)6y>I{}={!>@*^D1uL#G~n5^)4co-mBp2gBz#& zaZa&TV0Ey?pcb%yqt&3KP2plBZ6gdvnV2L*H^cD7geT>fS{RBf3PYPkNN%IlMQm3T z3ae4RR3>pGlLUOTpj-7R@~VahrG+Mk)t$gy_Ra_I`F0(SfKXB?q8vNEC_^aBHs`K` zFsQ_#d*mLXKHqp#rwqA|Omz8Wus*dFt{G>jK$i7w6nD6ac`pH8#;FC5Po8ZS5W5>A z$UVuDEZdfXO~$ORvQdNKDnJHN-7^eetR|@6k!&;eOBr!OAuLAOXdEX1Bz$49Sy#GSp6@X zfG?~7HYwT-%lY8J18WE?K!C-gai$ELgY#8Jz;MD0G-3DWzu#${d_!dL4IFJGq?UJ9 zUf#CO?PnR*KfKFsAHICadR(!e0ERPmc(^j#Y~cs!CBj)Lg(nWV1KBNh|2})Ug8eIp z_RLK+k%bxUHsfNH0aDTX?%iYSXnUy6)YxWN@E}s_RC+1Ob-xVSJDnlc%(|NzA}K-+ zpXtI*bZOheA#QVkE%@8YGQmt{!-*Uzf__TtDcY~%G3CUukb813y7zpuY}B7cXHNy=l(*>gFbAo7EUFJYfML+6U(N?C;wg(JO2HK{x;VNV86r6@ zCI!uQQHzCDD155E0)Z+!F*=3C9{}}_u->gvH$^j@t6K}!*ZybZZeW|HrrNmBaI3Dm z1M;2HC4?q;h;ZwF;PF?K?iw8C@`uP+i z8sYe%k8gg#r`{)exL_LK=n(Y>2l)L1;TG={NN=es$t(FD5p}ZaLee63^OB=!mh5?) zxNu&hJdaKYr@r0y>5J;I+@kUE9?{oye(8Fez z#et$`8BcAX(IV{p#j>5U_mIQ^SAt?Q6NstM$W+smxC%Inl8L1uMig>vscW3H-e+PT z03Ju+8%XqL8X=gS3(IYk=2RT3?D7Eq1I0%6M86b^n2SIRw3pv2-ngVt=9rv+96H1p(JA8t`M(Cm+;&g;hp<_#2ds%?0ck5cPa z9wI$VUfG;Lw>Q4WEF-d*yvy zuLS>8A7Eqay80nrc@+i&FLT%Ajx{i^mz`HB!Wlb<{QX+^@KvWNy+S z=*#PyWku%xGij^`ENFFWYgAA|cN>pUsc13ilzFvys}4zT(f-P(DQd1;51-2ZCj6h* z*UO5{>%X&*%M+{goP+EXWP!B)aWPpvpy@`_{1!NMzv(qGyjAf$>tDZc@#=N=mj5mD Cb~5e& literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8df3e165d4c7beab9cb9d6b1abeeb58e943be70e GIT binary patch literal 5023 zcmb_g&668P6`!6NX-8T~-d(TlwG*g`As-4so7fN%;}|=RofybEWL*TN3dUn~%Nlt! zqjdLry(+mX$@)sF;2%J);^M!C1Gl+yA!lwWD(3fkBw1Q-Tof={{q(wDf4qMEJ~yk^ zs}{bkKcDEx70dcNb>_bkIv3H@KLEJJSz-kYzjk8xoxou<<^XpC*Whka>X(DE!AroG zf+d5O6R%$hD!`YxmsI=9!Lq?CNv&TG>ISa@Zv+j4F9Sak95Hw;S?R9^s|K$FUklcN zHw5b)MO!~<@gw*>R^T0%ukh6eZgBj4i?8vc4=jFE)c2j>1p4dz82ZP=D*7AfALl2~ zKOxr8KPgU%jqns_+g5YqE8N!FYO=hR#9GKG3B}zgLBBMJq!NU*yHT71DaR^_+cZ>v zU!<6;GkIfgAiiSQf+nUJ7mCQ2fy|~5<*JPOW??r{p^7>plwu%3S-z6qjb)bhMXJ&D zZixOMiL}Ve;9^Ipyex&@k!hRGn0^irdd$mc>Q4aL(rkn$+qd`GeKulhncLfzwnuEA zap#ULzcXUoJ!##ywKKA{yKk%KN0^bWqi^ZbzAazY>;~v4=dW!m66RoUikw~`NZ0`TuWE=vaWTUy$_g0e7%M-jDn= z((zs4f3&B&S?X&@&F{#p@9VDclUQj#>-g=gKZp~-eIv(~f2~vX@zE41)J~%PSYay_ zr?(SfCcWmzTKPs&L@Pukc+0yhS6X6AMF-9w z){avDmhg=laDO+}U9-=*&Q97scQaDDHLo!@%}LYQ&tz$KtK#4V&a1^4I5g@P7gOi_ zYowUBaAyc9+tGs^Tv})I_h^}AU)j)wEx80JNndhnL2ZcYqHUx7a~J8>GN zZP6NLv1;9so2|Pdy}Oyjw>Agnz0bDZczsjBynZ-{+IOPcLT&cqv=^P(EYyP3LA3^Z zdG$Q$0_nkp7l}#Yc-A-5Nkp1g zW2lYN#HKt(_bC$~Y2fpj zu84T<$Y}S8nB+;K)EAhB$F5Qy1ewj-Dd%;7$Y8y!gV^L0ven$TxOM5 z#B#63tD?@AMWc6Qvex4@UI%^UX*zFoJbr|)fV%oE)K$I)>Kbpru^!EjZW)_j@P)(Z z64aIp|Mt{@`n%n@-G%9DJ`f!Sp>DqXo_Bb1WS0tw#>sdnQUU{;3KYvTy!G1o{)4riHG7RwAxsb zJ$&(y8@8TWk(X|R*Fl>WO+Ug(ISnrxKs3Dfm~ops@Vcz9Of!<(V8fUGGaho6ymnsdQ25Nf=^M1^^`;+*(Lpn!d=tosjS+}? z6t-N1Kp28*XlLv`w7y`vG-BH6l@aickKAo*C-@M8nEAsbc9ra#Mdmz7Oi-lz#9b45I9TVfS8WY#MF%w z9_p+(`vRt_8bHnQ;3;bG7*%`t>NAD5u))@Xh)7&B5q%e(k<+udwZmk6WQ`g19x^0a zP$+6f6mb8JlI^^-E8(~wxrbiqz-?9+Z!?hM7jzMFwN+<@xsSiaVy3EMu7FkF&iwQ9 z%-4u{j(2{-deh$enlNj?Me#EAc^5RJ28%evh(H1^(Mion88UI=qpQ6SLQem8$@-4k`;+3~%@s_9gj4 zXILFsJ$sC#f9#H&hZvhA@}<4glN8?SmB&jDtyv<^qIVHBKQ{5%q{q`op%io=q4sUz zAC}-x^Jx>6k;nf(l6czYe@ohCiKKIeN8W4PQ@-ccrEVf z+~sjw=c{wNKT%M6yL?4v8O34BibAS5^2(KaZ86YsmgdWIi}ICjlyZ0;F(prZHL0V# zMw>Yl#142u)RnaNEzlJur|V0$U1lCDKdw0qIECS{MfGbH^B3}vsmlG8Ht7O?)z zu=0sT=U%Le zNqOz#om9vDq9&0)2T@XBmA@oF>LNcRutne_0u<8@FqYRQ%4E)!n4l;vv_C_^fj{^0 zx=RYM@k9Zhdj{W!_+9di1xJ?%dzZjAflmlL(LRHj;PgHSA==ExK5zRgl17`)Mh8bcBudm!CaJ?C$p8l3GsF-B z4689Dr#)0;QL$xjuj9Ov9Yu19J`z2+vNMQIac4s zj%-=`|F8N0FaRheLw2EGS9Kk)UcGwn)vM~p@Nh1Hzp0O3JNr-XO(gz;KMLeacSP1{QMDIV0g% z^Mk4&ZwyTjBPLTDSy(f@Mq)2JW5$Mq(A_#?^bZAjDd-kj0#&WOBoBhqij z^=4c)mc6y>cFXptW4(skr+?TM|+t=XDYn)vdlhbbjyurQ} z@U_lvz&8QjXm0|%>7qGZur~t-Y}X#Auqk10aSF3(`+9rpbJq0DNO^-jfRqEyO?Li; zJ@(CjZx;9tz_-|Y0q+%fAK+W<+W_At@OJ@ztNk{> zZxi@Vz;Cy22YkE0cLBb`-UoP}z;^@wF8fZvcM5zD;JfU*0pBg~e!%zG`vLD4coOiW zeJ|j91-=*X0sA1}g90A_e8@fw_^`D9AmID#`vKqY97OvM0X||s0Qdoc4+DPCJ_`7# z!1n=u$esc`CGh=#kJ%3cepuimfZt&s2YlQ)g8Uu;e8N5n_@uxO0)E7P6!4=09|ioF z{W##q1%3$dJMC$}(*kb>{Dl1^;3u71k>3>Hr|fqDewV<<02l2N;F6U8u)P_S@(#NU zN||Y)8EgJ1poef>kC8x%#~rV5bbzKRwhfv(jvO6(7CFvJjwb-m*{1-Xa!#NICjnRO zdBF1mKLYr)T?1T`^p65wuw#XKV#n3H(mLuH6LO6nGl&l6@BN zS%IGbe9k@(_`J0ENx;jt2iS8Cp*~Lmez&~>ctzlM0lr{A4ftt+i-5n|eg^O}0+#^4 z$9@*@vjUd^U$mbC{G7lufWOCnFW~nITmk$(`+3063v2^^zx@Hg9}w69{BP{<1^m6v zVbo_9@C)__0e?{7Il$j%e?Q>w7x)z5AFw|J_(RgZD&QZqe+cjo2|N$@Mf)YdFA01a z@DJNR0{BM+t^xj0`^NzPn7|8wKWu*l@J9r$1OBM}F~A=axB>X%_9eiV1YQJu+5QCJ zPsoTk1Nf8nrvQISUrSdU+z%eApRKA!eZi?W{akSh&APX-RJVPLx6EXQ z;6%nZcD-WkdBxm=YZq?c{EG3GSB#tdk>X6X-dHR)8%5TCBIzgVjiy?IqSPn?f4I0* zj^isPo`rwB=XC&=n?V%96ud^&Eu2<+3TK`A**&%D%$~*N=BY;g*1|0}?{TY5=cdJS z<#c(@arewu>+|Kkd!!o+i_3oY&RTh4#xCFe78Ld}E0s;C&G>m86*f*J)cUZFYD07< z_1;8~8SUoHbqFT1zUiFt&AQ{8bIoaMu1TndyPDip>wXF-#Lq~vvar~KJG|WX$Nt=p z>t!O^NkE!OP?DKW3Z*9f+!4I)y49JQ_Wbr zSEL!2BwZF_EKFUoKrzL7dBG_bK_bP4hP_nd{ZO%ZW~p2YVlu^|-KZ3cad+uELBMuY z@MhN3LXb^l4aFxFTy1~E`+i*RMg;8*vXjpxAf8zmf+;^s;yk&$=y;!=%r7|2a-{}} zmSHD7iYAtu`BNA(HH=aY%-O1grg9LKn@v@nS!z1DJpQWnQ;w=Og?#clmD`>S*{a5Z zWP;I+VUpK{;a+kmFEtwrz*LO*@aF$$~4Vsx`Y%VY|aW2%(7#E+PAu zaAO+>6Ho2CV9g~iq*hXw5=~>pRBKjD8zNxcXqqdQoxGU5Y#0f~t|Tud`Q)<6CrxX` zya++{wBe3F05SEV@vMPo_-$HEeQaYR&3m&1uD^kQGqUIOo{jnp%0e zu>{OD>a(?KrRitOGj3CX!VXX5{Iqkv>44>A=FpSq9Y5WenRk#Xi3fhN=G6V9i@Q{F z35EDM+}qA<8HM^*6GY&H^y<#JVsRqvCl@NNZ;>Ryxyr8N`UZFzbDhq(&4$9@Zy`{j z&D+t2J8-#U2(pG{Y&FJ=^~M%s#27M04R16gwn9+M)I>_{Kw7nv!8n5n2F$1>^LY4^ zr`(3iWzT05mN8^0K3hfqq>BBx+*1fz>3_hqN9?3+*(pp>DJKn4DQ%mWrqFlKrKU4> z8qc#1!vQTGQ3=5Wma_-jW8^){9PwwrhGXbE)P zsOOtiOjp%9IfOhYia3a|0g%4sgCdL@at@Q?Sr4&ZXhPe84SBFBp{k5PazV_Y&< zFfQ=atXq7_JDYIQ=EP!79iFh%J$Tj6a>SOw8$sI`!;V`igO;*q8>j;&ZOmkr>(pi? zvD%L}TKblRL#|k@SDVG+1AtsAndxK>RFgGxhPS>2r63%gu)>iO{_&m+Pa4CwR}%Ay zOU7kXQ>GIPK9pc%xPaGMmB!-o6+<0Hy3Tr7ZuzWp5)m?Qq3qGtvKi?o(WR?qvIvu$ zp2EVxV^|Gy#UOVf&U9sx>VBm1Q7f#thsukK)%u*DoUAXa2U+;T3?e~6-^u8{ z8xerp1l7~LmoX{{ZD+5GS+}aP^ZAhCqD0^7W;K87L(Uk}h?f^4W4#*rhOV zJhrQ|vq%nsh?8*p>$8m|m0u{&Qx9U~zMQ;u6C|#EQh|M?6U~KYXShRDqb1FT0S$=ay<^B{@NiuWB}k9Osq^09dTHf22FV(7br`{;#$B7yOEj`ai#KweRpwz;NN_rkYi3DwrzjO!yHn^u{SZLb(=3ZgbxIKsqy5@K^w-Nifih9*U7u=M%Vhar@I z6ru)%?AB+=@SP8Xn}zpw3OU?vr$3zdsEFluCcJB=nJ>yRA^7K>G%qACSj`NCZ;0g= zlSbmq0mNq!H*_H-&r>TVg!7c0xNJ)NJD?z(M$NO$Tyu~Lz(wQ3LA^L-Lv;6U3`Oh^ zr=T~gdQ}iv8IuPkA8#z*ET6{UzB#5EZzy^OI`jsj7{yuKH-I{CY^i>_-Z&?dlvbwl z6GN)N_yMYAdRn>_uymMuJMVTdI_Xsx{S4@WlA~hJ`AMj_n0qlP`WAF_HIddrg(%ES zq4r5K5Wc#LVEgPQBEfg#xw{KN+MonKW~3p(o5n`S9M)@??@fm5tr1Lj8xW7{HE(zd zlpTp?e#SXpsVzYOup0H+a+}!6h7aK4)acG5c#qHy`loOKy=WT{1V*5);n&?Nu%R}f zFO9PXU_Lk0Uclzrgxc%nR+11{(bpHvS@Y3^k$5a|#0Ap@hIF*bqFyDNsG!8zo zTXUm{QYkMw6`A+L$ShE+S~F#SS`w$I0=+rPs@mKM878nVkcZW(3y}7u7J$UY71RvY zF>U+euqO*B5yzz{D{us8Y-ktETFfcv3Z2K2FbjDrcwQn4(J!Fl_k#UKIk~6ArU9l5 z8Uu=u9hFAh%?36A>V|<9LWE2~q!LP_I^mB@h6;_4FjNH*xMvZk<`|F^I|$GpWRDbe zQ-1*QB5In?i!20e!dOW)K~ieVN{U2vX6y`D8&dJvjulIuWi&~7e|BUQ4cS!% zm0O!D0*(=|YqDgZSx7LXy$Ii(G#Hbd^s}Dy0>-}#RuWn%^Z6rsGLRH;cC(N?1e2UT z$}*V>HM0Bl+yHG-NR0EWWEfJXo+oslTB-`%`MD}+hwQF`Va*pr6bczk)T_P$1q)4E z@Qr$B=Z;EGi4~_P75EG?4tjX~Ko0CC2WDeFV}2)>OUwxn&!dWm_B@uQIExd5vq09+&VNTXGqPjI9K5#~0i(2G$&NgKz zAq{Y*Ksk>2h~OXGf{MSNftXTrW}AAp5H))bo-6i#I8X2?Y?2MTp_TD=Nk!zIBFqb4 zMKX63K`w0t3}nQxzHOzvAsH@c0+Su~vt+LdOGa&T1m}l{2p#|s5kYb#scu9^lL#O_ ztXM(>oAHY!0SG78f=D)lBrK3b5+q?oB#{hABIy-Q1k})?3&`|I3WHwuh?W-W^|LKxvyH5w?1laOJYAIl-$;IRwp733N~yybQ*{d7b%D4 znwUtapeRmqGo7xsB`x3Ko&%ugM_W8s-=D~}wMP5Kv zpU2&Nk}B4UfiU$^3rs9M^@_PWzbaFj(y4&BI}mVod1~YW%*1#N7h?;YYv~>zn$taJXSu++^^ zWFj?2$F<=B%w1?fkW0zc1|7@;kqE^?1th}?^}fXW3|Nq`yzt!6`xA4C_Zz?uP))C= zOV;y1zMxr;)=6a3RtS5K*E(G8?;{|=H8FX+BhSMc-%K*A(3Z?6s6?ntC!kF0b*;pF z+TAX(0#k{l;yaHuD~JTQL+a%eXQRGf(?uUNN4U z$m!{yb~ZmvlM)xu*&(s!E4}RxI54Y;`X)rCPU8*m5b{AkS+&pmDG`4Cl!(P@0ncIW zNEPj+g+)I(vosr%q56JAehZgNb2Qf-IMUJ(N2&i>_|^Y70(m!N_cJnb>T9Z#8Vk>H* zE;9w8Rdq<>;eK2%Z$}WKsdHUJ)+mx(qX63Aco3SBy?NGDSCj)CGBixss4CP0S;UOQ zRj%p496{+RHawG=$jc(1QtOblpx6=|_zg+)6@%1hFRM?ZqElA}t}5Ys^r5+7nG~Z#3CSpedu5emGV5>0?XH#igeA(xfIXE&0o`a^x$} zV%E=}J5`0IO6vg7REMny!x;(~@D-Ywfg=3Zeo+v5L<}QJOOmz}ldTB&j0w!=QHSKQ zU|H7L0ip1)0ipR8*BI32(e9~)D#SXC0Yo> z2Qt-^CU)mbd>5usWGcD9QqJ-?2BkD@my*n&DhnmaU=|7%8ihW~THeH0uucP=v*grV zr&t1q5W`jU9vg&$Br{1<%FjS>JdFai5r^;TQ4|<)U}MGnLskK{f`wu*oaVCRTF`4) zz!$7Ta3)h2L%McM7A>QNt{S5C!b%L=56sEU(r&F7pM#%RzSSDU0j-g%Y!VOIke`zF zK-tBc{s3%;OIXx_w)#b;h?1#)OYmnI{5u3w6N9~JlB`G*CTD&<++<4sFu`s!>=zJm z7YIY^h~#3~EcEFS`3JIPd~dS7AF+MNHYV4Ac)2v(jd<-0$P_+(M`pd-&}ABzLX>LB z0Wn2ngSArlY|@M_eHu_i0mcJCP>9y*Y_SDxe5!t)0Z}D5s^=z;}})@0!#2PPD;Kx5M3!~;WL>loLWbswuiZP~AS zK0yysyMmt?YUF3bLS>)?F=RIC7m-La=zq^UcI^~&haCiVG8ktt!9ck5N#4mE9*+p= z@K=cDUt-X;gZhlP*V{M0 zjLc`-`Uci#`W$S(m^*SMPC=-J{Eqd5qjB^96dZp(hec5h28 zK+=mQfG8!C|Gg|90kc9U$CqkV-I-4ydsl;Lt*EEm7a$Ez?&0}H`2NJRn z?eY@Nx$Q6I&w;3_vC#{P250B|4D}?u%lpy^_~L;xNx58JBIW9tw@?U6D%;*hxdUkxohn zB*&QE-Na>uZruddO>r(}{_LN{b9O8OyR@1c0F0%b>_);9F{u7#~{xgEU!bnfn+fx|% z4P^PgwlSXO7|(KCFs?VksZOs(c+7vnYl&ibm$jfcbEGcr3f|5hNG8&%It@hQIl2x~ zE%1j(@u4H2KZ11Fzn?bm{lGG9lOvY%QX^ zfyo2B1m>OmxHeL-slhrYO*X3OPM{*%Jb{b?9TVOzcz;1A-p~-C=bZ}XWAUTW;%6wV z;8zq!n!8%u<)wY_j8bK^4N|Ij2-BJbudRA8=@8G6PANS?w?r;x!uT1wzd+V4*Q(qQ zA=2(S^s0kdi`+G23@PbOJ?`V7@Lxfd@@xtoUONbMlTgjEom~*K>IMHex^1 zHbo6)jcw$Zj9E2Ql6bfu*UQ}vD51q6wAInJBWBLY$yh8vXVJFE30SDHT{EVpZdb7r zK*7SouGX#&1$f@mMlV5MekilCV56Ii{=3NI7s(EOhM5uS*+yBn>c!`j>0^md_&lHYZX>m( zer@c~JhTRh{q~RrvygQM{6XDbEpBXy8m~<#WLt5wle*boLXjUE*_ih9sS|YoBPTb^0?8h#k)O;3>;83mM zCO!Z-hXp(wJOHQfL9y@;O4oW@S9^TNb|4oPbU&;21@zkUfZA(k6HZgj#Kpw3#)MI> z{gEQa05+^8-E|?{hKFZf%gp};a zO2e3d&+(r5KFat3%5l%APM8d-Lj{ ziJjEkDG-k!IGC7lT!hz=pHkJiQ%&{9Y|ft`fNv0%FUxRT!ZMhU!z7-zxq?`Dzy=?{ z<<=2!Wu9(zbcC44-Z;32i5oiZEjo)eQykygIek;&g6YAj87VTCvfK@Zy8(T7(R>W+ z^H!pnTgFL&1gQ)5&wjxxkrZP&O6mT}uNl=GU3Vc{r2&DXKF) zCh}RuS;W}W+sIv^aS_xPfz> zWxh6Irm-#0G`Ou3I>5F!;K`mEu=y&BO+=Z93`vkAL+%G98PZ5JpBqd6NX-!RP$w9?!~BcQYaI>+~?v|LPS>d#nPp|Q2CG`573 z3IY;a7qv%7?0*papA0&BjIje?rd>#BEGDI~2%YW3r2e8kOUYa);V%(kFy9f}#FQX( zz_?X(ki^6NxL&>uK_5B@*b-y{ZVRJ?V1Y4-xFkl-@*wE%C^Rl;9EU%W4n= z$Iv5~>+aMDw30w2qXeHsESPC4m{`ApX_pgi@OZYtE#I6Pw27-_<5x*akS$;IwrnYg z6CsO|$&q`+O7spzO8#JifxzA#E$;t}r+GQZSM15!q_5jVF(TRtfn7$y=^8D22c$g6 z!xTgH#>x0jxG69d{qdfY>H%CbkANS-q3WzSj!p4oDJ%fchZ>$GSoq;?QrxFz;R1%A z!}4QcdzS-ULW=1!Pb$t}J5Y)`iW~Si694h^*mvz;IFj(D{&V3kA!phHVzZzunvI!4 z9Tmj3{UrhI$EE%X0VM9!)QRKHtT%yxoBt}%MJZ*oe_Wid;RNKP=X&l_3-NmwGm(bN zU03`P$HcGt?<~xmI@wdA5KP^|X5dP|b9Pkf)ru_jf0$D|oa3?gcZk^4h5|850R@a% zg#y-UKd#VOC393(g=^lm?VPiwA5*MWmzcg=*?*6SJ5aWEOd+(YJkHtsakZTS&?VuVNJHrrord+i2x8m2CM-K$9=)8048-TufujUgme%`z!eg+6jp|x!^Sks z33P55^-~b1A*^pednd6d6N&D6BnK9qRv+(R3qd3Sin+su*{G(6a+m|06}S@t#qEH)D5C7hwOxAf*83U zM88PTOXxz^MpCs)ra(3kc-E?aP{OSMJj93wFmYTKPXlzl zY#34s1iweY8Vf(6NbMEJf8!yBT=ZZ5J;>IpO#Yc1K(^r-$X9*9^8|E*-D z=ITC-FskF*`@j(wC}Lp6VBFbfw;xKXax9n_voGtUwn3A5 z2wjsfq~X_vg$TH_(HBd76D9T=MoGjA1@Fd9yBw(o1L}o8IP?|^gAAMuCobSObYo9z zdGHWk)>_3u-Z4`tx#u{viP9k?=J=QDLX(pm5}fx zH5BR;=II4j3w*DjL2}nZh=n#S8eI`N(Z9S604WhW5zP0)%UyOVV6Vb+@I{|Dxl@5u zIFW4Mc^+nQE8c#2GXmLf;|Y~Jb`(Jya2|YXYk`2=kefcxYP6^WB)w> zmyxd+Zp>#kCcHO^`&vYqv3Ga0{Q!pkY3A})2Ga0&D&m|a4&74nxiIG(worQ`?KxK{ z4~2hhS~O0#0^oE9uloUMoN*Z=3EK#OlQY4gWK)MvLL!vX{|L!(PrX(=-CKr(w2|@e zMgbyibEhTtSH1?T(WtIZEEj9D(c0d6yNo@t)pls`@pvRK@9zAqPnAj_AwfEW7Fu6L>g-HjE;}!$3$+p0U^c+?{L;XYac|02IraMjJrhNAa{9bw{Z|O4H0wn%Rr8 zpJ%U8RLbFi0B^W0Q%y$0Z;Xs$3VM`SS2mP^*<8Q z-+c=_S3o!W^0!?ml>*6MxMs8h8TqjaR}ESA!{sWRvBYMs*{w=~Tlf~AOULvhJ$4I8 zPkjqPKOU;S%~YIvdy67{ZHwrK-D`R$IHsATzME~?wq*CUr){an&x2 zr;rYj?nUH!l`bT%KEf{CfV7$m(E8ifiA>YG6KNRg(}|%Km>eM+Od)X5BsV}f)W#2R zbU9>|K|k}LJ~_y{yL%_1>)H<%3Up>Xr-ED#1$#Bfu6<+uy9Lc@?_Ua1*pQ0_hweQq zohseit7pGJ1Zy5YhQsiJ)^&7n9|bLz*`=%BcrOnF51(TtM2m>5{JTuWm{olnsbH^f zfQlLxZKM!ee>hmP9ITP8A9fz}?~tE`u4;>^e|nN?nH?S_6)!a9$E$VO?+xiXemVip zKVB-m``yChVXmR@JyTZNe|@Ix@u zlQ`95$n@5RIP4&!K0Yx$`NX49m0|`T^QI9X>gQO8NVbHpFg*#eK*TsGFl&q2P4^`B zUL24E64b9U&#xh96X-};lsAZ6mr2^hILPTdI3mzuxc#?9i^0K0V6i~4q2BJ{h$);F zK$e@Ly29PEk0t7(SOHAS3LvaXSOLsn1<;ZeK*!YmBb`Zmz~eH=0Lj> z2f5^fV~%K@>Y7iGZX&f>uL=cDg?FzaTB;P1{0>m7(zx;7L~ng8O6x`Q7JVs_C|7AZ zWGc7fdc6Y3@3Js0fb=RX5KGmb8;P~5_=~LO7;*CFyc7D0lstd9tvX*NxiQQ2kZ5wIiEZWKB55vZLQu|HBd>x8 zv1po2s%wyGZyxqEvT2{6931axn}Gvs=t0bFBC^{}xEVKwXeU<+8#)f&#N=iHBrZSj zZOKB49kD5pV#IBZ>Vzyv$!>Z-18;on3TXQ4;KJ8X z*lU8_-{HES(5;_F5;$$@&gXcV9?~8-I!DFPg`J>clOQ{t&fvU_;zAiG)G?#!Ed5_O zBwI)-9$+ySXV!nqVf8lLz<>y=G5rs+<`BX$Kv|p(#v^Fc$q}3n#;y6>!f)bfIP|>D ztJr+UY{~{U1=5V3j`S`& zxYBT9Vw$cz0k0(7g9ti#f>sa6n@LaRxTx)FgfSH+RSmRI%oB_hs>*49#`!GXH z4?>n1P+vw?-akz)E^<3(xTl3HkgfiXg?y>R1<6vk?PFS&5wg=q?`n&soVx&F7AwLNAKFYQ zKcg{KIG>3xRd5Os9p>~pd$3ai>m7L^+N;S>Ng{kJ0*wEJNJv>6#zD6pj98vIX&W!- zC2KLfVC$OjL77le?h<^8w6yefWPyFs1I3~&NQCG5iy}(mz77S+`WCI@BXH%?B1s2@ zb{CIgi8_{%?na(5A>ykMy4;FWtA%CD=*p97r4}TGwXB6^$(Ava88?MMDu`+O!#j!n zxWW}&i;`1$4<3hNCXH?=4jHx`?Qoe;{_f2w||ZOQldU0hPI@ zK$qGdQ3$ivn5$M=c6EV>Kuf|k3wgG!WjRiq`Dhyt4>resWb)@=TXJc?aI}Dugxye*^^ITB((@!6_ALK^8K_fg!ma|_$# zG1GyWg1U~@e!@-VdRr;C$WSWKaiR2}p~zua(0PFGI)&xO{LEUhPzPCXRp)S3I7CJmzAe%z3Z;@vF3D`WI$L)r*TIvvaA@SKsk zg2}iqOE|EDD(W?ntD~3FfiGu9-(3!U zIkU?+zTyH!KZ_H_iYdaK`Ls#l4u|-_4;71Rn1UZ?MLAz+fliBV*jd2V#B!CA_E4O< z5}Y0RHNNua4C3CEj^%W6A3IhA3@*5uCM2ZwM*6jpq*gn;(E#7=^UIY!#`>7RVlgN- zx01>9Hr8(kA>P9pMLM`R2xTeiFz#PWXn}bS=hVx#Nip7BozO^IUj2;_n)u9#ZLaKA zs@0o#UXJjXnPturTn_Cd#)yD}0Uwa1IBQ9l3t2|s>mo~Hxer+mcO%Odg51@cAk~}E z4c&=RpR6UdC1vR|qe+NrocyH=@fF$CV@N?+hQzly7Q#t*L`^&4sfqTiVlIU`Cmv}d z9Wmbs=`gN0>CkxHZQg5J!smu)z44o~UkqXP6Jp{MdV^)LBP3kP5AA@d6ZrOy;}wsG zt~;3j@-CkRPCl3bPtu!TcA1f6c*2MXu#kkq34vmVkWx6cod~zz1&7DN`6eY>>G1uO zCXe=p2hF0|O@x8NK(|HEk9x?ofxv`IQ#ZA1z1WUpwOjfvqZp}4OQ559t zI+(I>PCDofhsJ3q;@~%nWqCR`rKa#9l$m)oiHs|#MfAse7P$_WaG@0~I>S$nrbfL; zA3AYy<#NJMlpZ_RE>jSr+~#>?C89Cix^WiT^@8_^fMQFNqy`bovPFkb%%KB3vUfUg zhY2H6Pu0z=g-~B)+!4066xJbUY&W;2ypi@g=tYk1(zz&+9kqE0wb8obEi6#RRXmVl z>VFGjPqXNVabk&z|KPyFxC-)V`(tPC$JMsysngdH)**e+0iBTIg>lZx+S@T$5cksu z8ud!K={>H0oqD+8R4t0F%L-kT(P_eD#Zth~$=m z{HuNfb=BuZ_1JV_B0)sKoF!W+_>y)Qk)tg^rzQ=sa=M~5CCBfz5oMSY4UVGGiPuOD z2Vufx?-I^vybNcP4$l#+fy-m^ZPU2wLY}J}N1kJb zpJ(uO23^SR`7rC8vDxs}bYy+irL|ZTjA!q7&W>Bwjr8_{yq;n46pBPV1nGh7_`EmS z-H*iGm~O0W#3$MWOD)#n4`B;bH6YLOTE?{lg+i)9N>t}*A>aBo!v0C~VMDn8tpv90GEwfsX2rneP z8$hf{c=c?AsnQCUU~%R=A!t}M6=GKrjGOLGt_;xMXC-wZd1mcnkRt>8{+*c2VRsMg z`)QFb(@&>mr_jA99#%KugKU9jFs!}WhA7``EQ)1L#7-PX5c5BUXuYodcD8(g-+>c< z<(`t}OQeylc#R*V!Uv$R#)Bg=A>XA<^PjE3(9rFT20a)JjH^;_OtUc^$J9%P-kWjW zirT-xnhmjLTr!jsVjyoaW)=M+Wnw?B9=n8NWf^n~K|vOJ)9P)=%G<6#?*_#r+(0Ih zV4I@CO~S;dkW+lu_cR06|CIwkPqD@73r~0{V}Q&zk>Q}d56YfOYzxNTalc!ZSMvIG4=ujXe;*C z^e>%KHKXHmDk5sCvvIHZ7 zou8aKSn!jW;7a#%+l0x)!t>qCzCY)`7y17w3X-E(_1P`9`mb?P9>?1`zrjW9KMtW#A!#235q-TM&nzxm=}rXaMc#dy{}9ZWTv z-i9e>4uZXm-B^Aqs4*n&GlY&Hvwvi9m)R+VUPp1xoOk_0IBcb(uza0Wz61sY+4>w%z_HLzWOD;a3FMd7Vkcg29bycLY06Tg45_`BzxT^UlF?B&2 z!I#~zlnE2G&aLGMvg7m?nr)(bgv**@`jN#0=^}k(E<^_?!1yL1*fOLWb_s2V$Vdc< zecY(Duk^I6`|mBFCks)&1-1m*jQ(mFdaboFfsxU~Cz_%<>$U!4z_sp0^$>5n_0kj~ z*07f%T@OnE=qEn!*-t8<<{_Rr!egMgzofhauV6tpIsrs>4MHT+r(tmwS+Ld$13h}@ zBXELd5oLmma)qBWgc^4ka^TT#oAt&Av8w}>`6#NmvDg{r6fE9|EV)KYxY7&~s{tK>+AM&Juk zbqDD%)bw^;wp45$^5qI_;0sR43OdU`X9-$}74;4vZmM?|J&forZ38Kd4&u|E9V9yy zLm{Ho2Bej7cnRp;>^P28gomLckXsc#4J;i=(0tf@pz58CC2lq4 z`7*lCnE;20u^08KDZW&W&luI<>4=S~d^_0k8kmcK}6BQnoPaqX$mE#m+%8o{X z@HbtqE)45<&biicOP-Dzpr$e&<2-baVXZ0r4r@diQXMS5$hq?(@Jr{S^1-n-vUv(4 z7xvucc6`XIDq@^!lH9Y+3I(htC~h6VB_c`_>OH@I$qySpc%WS086i?mS_o0kaqx&f zq%B|Sg$^=>0KGh7tB5jMJ~9ytWA`CqFNrCQ8~wdv@0!-$k3QoF#Z}tS?=<KEj z8O(7sduJzu88H=~ucF^j2zGBrc75o#eG4V+^V)hj7;K@;K2%nxPhcafw~u$yQ~C?F zc8lGTUMX_=-ZK#bytqoh$E<5)-Nv^|)65CIt@ScX}N6_3mSnfZwj)YcqQ?#ju z)}!9tgiZ799Yv=Cx*3Mf^SaaYrum$|K5XKV*~#cD^4@#?#T`hlBcoE*U*K;YeVd;1 zE(UfP=l4SH>^wVF&Wn-*XWyy^^`pRnbXG4aAVPT^z~$bCAf^Hy57g?(h^1rLsrdn( z`IOp-1A_3yS(x~uofjFcRvkhndSy5!l7oE4V%nB1BtD+mBaLecU8vU%;C2niYg}AJ zp$x8vMk|&(h^miAe@~+NP*}UGC~1!YnFm?7^>{(db2!{J+_f>ntv5_jL1fz>o@qh) zM%-Xs3^qk^T#OFSC_e<=+A96w7=8Uo?U0>A0HdoTC;9d>5@c^}w=WuSCfgkze^4sv zFYQ6p!09bAIq2Q?(dlhMEn%^ta2N`7umc`MY+C zBCvBJ{(vJB<1bjM9q+{QIQ(sPvgn-?6MEd}xfMQoWw%P17Kd)(bYX~8ke?|JMchUF&?|DlT&0XfRg7dve=Uco zXhB7Kn^nNlD+_{r2L6sX$wYtjGg^wJUCvUk$^67&x9;aW65Ju>#2;*KGSWlN6 zt{><-bdl7gPeIuGkXVWeB6QV)Quji*JM9h2&+91S31qq)6+viK5y_BSeUjWN<)`GJ zb8kJQY8;Hq?=MxkOO!`z7u1iFhCYp;&oS{&qLd3LGghWeoPEisJ$bJ>vQ)SH8Dx(d^UIldrmHKK5^&ML%n%9J9D_BCCI<|FXM=^BleAH& zLs;4=*iDfg^@hkJ0z(h-u4>pzaG#)lQN#DEkxg06RAE}iF@7O;!;u9z&RB9QgH&h2 zD&d3?6we)!IMa?VK=N;aWLO03Rv)HZs_3~OP!RcH@9;}7fi?(Tl^mfZmo|QVD9}ll z-13~$%4k~=I3AR87j+<h}DLtkoj|@zsO85oaHAM_`D|ts!t+2 zQ2)9^m<~9GK{qhki&dqZ!UMNLUqXX|@r^yAK)(-E| zw(%hMyPgPYGrlv<1T!yC;Wo!l@-(Cg^euZEC%I&Tw^R|B>HBq>cuiE?JY}V@Tc^DX z8U1h@)5xOB`1Gn>wn;dE-KBBfS9tVblVCz$DI7|VD zd>T9OdV@`;FxAlWcpGY|?(;gvadiSOQPtlH<`=8_6&#BM_Qkr&XSH2*QqslQw+u*1 z_x@0Ewp^v{un2?4PqS_;B5SBJU-a}>Z?0nvxrBlbPAxAYvHlw6UheA`zE@Weyj2|N&9Kt6DPW^5xFyfS z(%J+`oW}q*i+tJjlUOuR>sag-2G=v7BZ6;Y@%09|!K>T&Slku2^X}~o-oilEl0+Yt zH7wzJA7{iT7<`Js=NSAHgD)`nIR?ML;FlTv8iQYF@EZ)i!r-e6ew)GXGWdN4f51Q( zt!tV|bdy-L<2eMmLVG9bJR8Hz2%bbP(al z=#aUA+st@v!*@jS{AQ#Y9vvOU=STq!k8Z*HEJ267%i&*G<}mUZ!?gk7z^H|PnbCEl L!l5Z}E!pU)RNg_5?=BG@-%shpwZ1qq>+D3l7xAQ}nv_;cFauH$pgyYB8f zsU!C(m3V@$K#O?k6W`}vdFofFRA6QuC*-Uh&+YEb%x~s5qkFxSz%%^)+Q`I&{EaXF ze_)T?fn@~_PNO`c1oT$jn#Ordi3}!fa|3qbI+=Fz4xF}SG)YAw zIwD1F6pIbfeH!H(_lW3;&8I|c%J?MAyCQf%`j_}$l#t!AWP0YRX>}|ObEcA(In7F~ ztmDeDk*)=kk7q_&TfrvdO0cOG)o8&Se0%r7Zdxfet9dDz)v(7Ms~odqJ%=y%BpY$- z(6naqkk@nWWR|91$db>kT$^A*gI}c`I(8fk^1Akiw$!sq?Xyaaw3%`TG58R`cUtP{ ztg6BGnERkd6~yKP&~tZ_9Z6Plg+_%wvv-Qs8?taEJpz;&`%)V~$)~eg-ek4bGd5R7 z*EPDv*whD(9cgm_fL4L8j-~LIZF=O>$IJP&m@3O-pGZEhv|UpzIp1EM`d> z*xJ}phn3N43UM?MUTikx`Ic#ci6%DE&5bGpG<*7l@Q-ZVhGpLc;mDGn&?kYT&jJ@t zqGj-`wIt8!b7T=c{u$9>+2mu##ucE3tYhJ!zJNiqnKT#`l#KzWTve_K=Zlasc=kBn zh0-GAwXOZ?P^zpSH=S?R1Z^l_DS=Q1qiiCC-LwuXTe*ISeML+gMBX{0^b2A(VdvG4 zgR!28Lmp19qY~&OBtZMU$-G-U44X0+EDU)Vu*o3G2d>oW9vRph%Ka==MN#MN7oc ztD*1WmPlkgX^W1RA#`(Vl>9{D;BA2gAb^~k^YG_J%YxZfm2QK`xm#SM6~Xe*`1 zm(jl;CE5DeSEY%#*|$x6aD@LCBJs(BuhFQjK{#?kCUi;n=`#3(en%>@4F9CR(I?ae zONsFrA;O;r}2V@(Q7^MkRJrwrVI(U`Zkaa`t` zBcrFqTsbp`ktgzm+XBc8Y`qG&yyZN-Kb>h9rF*sPN9Ho_d)jWHb_K)>+H{Jdthu#C zah`AUHk`c&%U%a@J?usSjp-JR;FrAKYy~t5g4a=aeC@mh7h(r**c#?d6rK?M6pN_% zR2D^(76nXo7&4%Di{jCo*Q*nQl=fgv7d0eH6W&z|A5qggjkT0@y^a?f&LAxe7S$6J zgSME31ZWb35e@!5Tfx;W1&;ldx0U;*?Q5WoLCQ3}-G|@q6x(0z vY=3=!cyEObXWA-C?7UTH_+ZY(io2h!uzrrUw|F-qNv9ihX$^M#$_j^9#IEiJ&FScmW z7I+}v_g8n%fd%FF0&)sn)zx+U_22bZp*=pHPvOtpS9dSH>r1KB|6peDPX?L$@C$x` zs+(AI#HS6o6VBS`)*?gev?~HWv7&kAvcBJB`DeD?_N%+!e6(} zSd~5UJTA|d;{9d#U5?)s_+5$LRrp=4ieL6BW%PNCzZdDXD7)^`)RKK^%72@hxF_{s zN|n@(7gB1+8M|`5vY$*%Pj=sRq^1ME+-V>4TS0kAw^z%Z6~El{Px-oBZ*|(`R$KXa z)7J80vAw!hZ~A)Xdw^JK?t2!}X)8=iEj;X+_gB}NwT^#(5cs-NZ?_I>-PU-sGk){r z=~kz9DlRUf^+jDj>Q`k9tT)Zo z>SMJ<-9A`rHm3`rgVBa|eJM;IZMGMWRWkmmj^9#2m|oMEQ&^=l2tc3a6dZ&%?)zh^M@t#ZyjA zEM)~N(v`7+b|+DzfZsU2+er*U-TwFHt0{HK3vQ)|k$nG=VAOkZd)239Ovwz@wf+wIF0SvX>(txO+NDWrm!YN02@SM!z1oL%uE4vU zjVqDAK}{onmE^BR{zmn7sQt)aC;7J_e~Y>m`RgUW5Bb~F z?a1Gt-r-NHcgo170nfOlSf>v(D zTHAooz3M$ExlL-^jvDu=`;mW#1L`31cS!zDb)4-L+W99|89)%5%uT`X>hE2rN(2qy;%Rf>a3}Uy4$VmTm*Tp*n9AMH-6(w z4&aeLs3%c+zs%r1%y3>kg&97Oy2*MgGAgzo2T!zc}-4x>$9OgjMArtV&5TL0b>C_`bab3+hF*@vMyTIgIJ!>J#|-Ln19d7kVNsb@#>jm3mOd|CE)B z5Ja#v;NLxPYtZ6?ml^}nE4&*AuUoaz0%!OlqUnc4-gh%KF?RCBAhiO=lO zR?AabJ`O$Ych+@l(L>$%55HsnAbvp;Nzdw~sz^7jp51eLZZEy%qJ+<>D)XtTt5_#p zPa*YCGqaUClzOhX;q|;m7EjrY44!hmRKx3K?nxcL=J*xLM&0}}zZjFWpi)ploVi&o zO2oL{i@w90(F5vTA9LwwzqYEcL%Dt%UwVtpHXsz{`_QXQ)H}Y0k^l)WkP6*SZJDB; zicMImVl_I|x&qkhOLbpERlxfyz_EA?Z=n{L4o%5)Hgp5Oxg=xJ*RtcJcYVE#FX<_C z(9p{%{SFkLdwTy$d)42sR*oIN>$d$fYwJgw^4i} z){pLAJKb4nw{D-g^_KksW^nTw##3ANgZ&L6&Tac;_#cgHTD=_|1y>;P zvXho4|JjcFX2Ho@Maw?#*`AfRx)TORXX3A*dIZa%*Q~evRy%b3Q;XfPjz2Tke!`%F ziw5IAe1`U6P=OQgK?7M&X)a`{VKwXxA_37N)c`Uy+%xXStZBQud9dBW%<4YoT3+=r zGhp#bty9*uIw+vLfL<5MRH=kwR)N%*>rD|!2r`o$r*z4RG-%d%3((>+_4m9^=jG%asz1;%~G=KBq=Wvdh@4vHd{=tku%TN{~H zM!7xfOSVdXMe;pQ&q)nSAI8GDCsO!3v*{^N>X%Zi#hzL@DFe;+%dor|{hX9%`OKb8 zyZoY;+RUolrrXPGSv_aVhT%hM&d+sSF5UOe<4^bUr&?fP{$dAA4S*@Pm&#yZVjj$N z_Z)65w%1!AUc6mz9c#5uw#uNWa%jzTpMAQ$US8AfqqU>W)8*Bg!UC6De$XLZ4E%t`|(2Gjbu7&aFBGT?_okj46`u^!!+eVP}z~psv35;4bHYESkO7*AIB9@qY&k#@3rJ#jf1ZXKmc0&y0C)|r1Byfl zL6JC!5|E(tx(+@9V6*Fl(1oMa$}8)u_yDp(0bL+AX>o!L36n8vg@&7|yy7?4*hVA` zPABciAb@R6e|3;&*!sPggT4jHv@@_c!XQR?L&?Cz;4wwa^Y|*TkxXT}y9angHNth) zfgp?JPcQ_?Ax1odMmhjx1FnD#uwSrbOBZ|2rron5T67?fogon4^=SPV&{>whKPaIJ z(!dBgmLY@IYc$t`nYn2y$MU30E_?dnHY5tzu+b$0D(v$Wr2;so_P|ur5pfb%DmYG zaJGP9$_19CyI0aDfJZ~hH}n=-g@-%xZOiW z)|bgcPr}RNgQX=J5yj~NQCbfyeAs9oGvcC{d5GM(Rcp>cz%I;au19Du)nB$``KL3Q zm>GKQqYd!*FjK9f^=egf%#QL4`b$%;lK?V{jAuZF#z&+5%*p{jD z;5KzU)Ty9OA*%EANS#z;e6wiA1TDc;8KAnR{(Z)heve;JKfNiVP+2Hysm%#~i=WI; zzW8+i3zY$(;D_=5OuzJG>SSs<*S%C=41A$Q1C}b*15J+^(V4nCD5yp6ilx(h#RJU* zel>I#!Q4X+N*J&Q6jbU{kbVN|BErrnSt9$$V8Zl?T65hGcTx>EMo#sZfBGbxXF-@* z_EFf;p|jRr3rnUOc2X6J4JS>B>Clwvx3f_PAL@tj1nrONU6>XhV@m+iUezx+Jr1H5&+L2|5zH34FW%juWlo) z9N^iNzz5*B)Ufq+oebZep(f{$Mbw@EbsrI5Fua$YIyhv1(P8S+6I_Eb4iyMGTfJFs zLsh3f7co}jKu!cI6d{P?#T8#sc1OnYuyM;TkG9omwvs>^k{_LQ%C%--%;Ylu2#_HB zBh|4CrK(2N0SXj=1r82#hP@<;1o~Y(2A_3ZW4K1gNJbVZPf!Ek@utF7D=)U2?Uq>K z!Lj<9^lv_b_&^2B)HILkP${MDq`BBHZuCNm7+Ukuhz+FB)&Q^;P{&xD!2()O8tQ}V z2&^CFFV(ON0^ZtUr+y-G(PJT`%vi?5k}YY9kR^F=@O*~TnJXazP^OLPJjA8Ld;H&O zcgiPgVD+lJFo1mvNqdoR0&a0CPYd&U-CvMtvT;s1fu;6W+b6K*$){mjfUA!HVL@u` zB`CSZ4kM_maM62)frMFj&IN2DY7L`!j9%a?em>rNRZIbOPnK1$i#{mY+<-S8c@8HeHJnp&oI;!%qe{p zNG-jU+Hg7^*soa3$~_A*LwQ!EL7EgLIpyKo%vpOQje2?1gQEp<+dWI|CELC1h)^RG zTlkIY%dI|<%*n@_V#wFji@k2pnLbrFv5a)W4Nu>QrWzEfSWDTo>7XVea|!*y0ly> zV-bg@auK?u{n6FSnYJDm(h6#6;*giTU+ zAe%F6GFdU~=|wBXH*Um0vA2R1;d(d_pCarx(<+Dcyq>HR>lv5jv4UxoWz-m+ybjG{ zuu`mO0gU#ZdTZL!qGx^tbDBkYQOdOseinc|OxxkOV8mj(r3h`QJr{qzq@Txk)AqRp zEztV8oWYT1;8#3gigc*Ypdv^dso>Id!Qe}a1zc2pg2_oHf+-Qju}|Zx6r3=aR%I;* zN$AXCHj#lVt^5Q_UHa~zRzsl`DIZtI#6DlL{ zCWpPg{8_taSM%tVI{a9qGSD)HK*1_Q1gtMYANv>vEh{xY3p)QOa??(-vh^kX0!q&1 z%}Tcv3eNHamI9?d!)LDbbkVGn{m|0rddpJ3#EK+#S)2+Mr@mCxpJIXV6xv5(Dn^_d zY?~VYaTb$pj;>?YkZ*nI4ZM_Pyv(*i;01AO=EYourX&k#lUv88WBlFFDpK7~R*_Us zcz4803A%){8uV^~E^Yj%7Ky#2Y?uM>f%*&8sNrBO#T7;#Ewt`#<|5u;Z{~Y3mtZ|` zaH>rx74<&iA4!|RC7^VxTA-)2I*zuB6S8L+1hO@ha z(Sv;#;sqm78*+pqEu`dr07WC5d_ZUlp^`?!447kev2)6p@GnY{VaP$~iM}25mo!q5 z_2*DclMwV@VL~z;UAw$l1CDG0rd3czohczeYQ`i$u3v$g@{hc%2U5iP88#QQZGJnn zg0wBUib98n@UYzqb|6=2)PR2m( zZ|g^(9TU)2E`4&bz2>XK01iCb9Vi};wLvo2HW-0-n0drlC)$9uy(YesJ~+d)H1%@i zA`qyKxCkP~*&j=pz@z}1vZesE!l;VUuQ>!dB1MAy-@XXw1jPY7uryc!0yYQA2v8n5 zy7!p_k|PJS27!z<3Sz_F1aOa&&54a%BqFO^jLMC?eggL81pL>#;f5&nY%CkXOZ20i zNeMv!^J-vc=nOnp`hC(;fh`?B5cLQK*vRZoN$Xs&Vzgk_VH%MN6UdTu$7Sube|)_T zhq1n#71l)K5IdA6O5_h-sfo5sw=CANuF6Mbt7X9BVYb{>Yo|r`1uyN?@b${+wH53k z-Na2eve|VAQjOke1%TVayEp?JGUI@>6pi1Y&(LxZleruLe>WoeDCEX-r40+3qt$`? z;f!5Kt(7owXVcwE6;khq+u%4{`A?=^wy;kT=Ib!Jp}=A<#Sna9KC*lc!SD%Pnm>qL z2}JLM+_z_Lsf@MPJ8N+B3ez3Iv)nz)KK=0e-g}5(1q{i4-c8v~@lDX_o87mG0uocE zOl#&IsB*Bu?wv`#?cVuB1bgEH4`j=--GXmD1|azucPF_4aB>BrT}IeV%gRmfG?Pio znvIZ?7N#ZI0#{xXi;8DfKFlVIE<&d7LP*4s{wh8Sy~hOx2*iPFE^^nB?kYK|n%jaV z(sE_a*AqDGowP?IznG?(@18HEJvhU`;GFCm`LzA~qz!g9c_Gj)zycDc@Uy*m*p8op zAYdneGecK>E{A&C%%p5jROQWz7jsqv8*+|h}M%_^kJ#IKO_!kX;S+5z#>+OcW-Y+;Lv`Augl71=-K4zy#@h&|;Vqtp{; z1LZ212xcns5soPke0r{Hv`|WfNb2zs_7JvH)A;*rh4)n|OMcaOJ(g6$|Xqr~{ z@*y}5e|Z5ikR=E*9L2+rK?d^Q4EQm)wZ1_(We&g|2tF3U7yD;)>&<_UtZH_8JVLi9mTo(A(|-pwjgBFp{yMUiqG_}m zHK)J9I^SgS7AP5o+=Y0#1)~JSyKaLBIs^`)7Ih~ME-0b}1CEyLVs&y$ z_9s%Gun_SA`{sqhhLyvcMpoYx)fTrnpBu1bRTg&ciJo-^8|JN9lop`j=ESD9>9SU^ zkoBV|pHQ%R8*Znh3fzs5wsxp-yj>jl%3)8Nlc)(hh><{42U?kasZkHkq=F7xkP&2{ zyRWyht#~%DoghW8?d*IB@r`Hf;6*ionN7XKP3h7wDM*y3-UnbU;y3h%5ZsAh@Bk9@ z1uoYBm%|po)yzdaj%0atC(RPT7v6+pb_7>ggyeDDe^P1m?9JUv8WY}C$wYij|6*J; zKO4Ej3~7n{BWVrrv%k-*P!^>+)JaM-<6#joFL4PGyN?*&8gZzIY7k+L{l+9cUS#_> z46!SQy!OSs!L6u)dHvJuL?rP)##3ljyYHY759otJP%rk;IhRC9lDG|e3F%6N+GTLr zS1>RojN%`$InHEu`VvDz`B`-TmmwoW7PDizi`vZrD@U9V9ATK3F$Elu*;ybthz22c zPncP$1>8N50mOd9f5tlEf=EL}tOZ6I{8N?+L?aW2Kxz=2+>SRS=~+{@o%h7N@xZu@ z?|~*NHqPHDqzl*A&F|Jcfj3O<9#MK?YK>W6g=OD~Rp9BLAiM|FX2=FuPgI=h0zxQG|vA5mz!>-*oLJ=ONSDAJh1@Zo#C{;zQ&;(ar zd19l%%;@U^`a2jxcO0gG3CZCe!Jw;w`N$sLVaPOh5JlT6?EQuKw`f!+Fcy2*=;JOw zHYE8R>u4r)?G5T;l^lEBPC3`)&Ogu9*oB8F;~PSVTNXM3GzD3W5g)!ZCCdEJGLQu) z%RuMjMV2A0Qi{G|k{!Hz@Wa9T2O?rVD}am?1p40#!gdguN9G488hAoN74( z#<5u`+ZK?gF&_OPCJB7D)1S0Lm2VOn#z9ar^EdmnvF#T5*MAHIDBCUy0nXpJ2*ke` zZ5YzW(uV~UCy{N&>nPMdXc)`k3N!z_nSWXiXN>Ag2@BVPLT@?!ct1kg{w0DTk6F-C zqo)`Ab=V%0Y8S_WXDmBhWC1 zUh-lTnGKy^!bjZ_woMtM)<1i z68tI$DAeah+gUND4(&M2>i`WbQU=C<_#F4H|1&ZJJx9E~-}4;bvx)7-@N3B!vO_(P zjM$4v+<%3Ko~!p^>9HlW1(}B!5j)BwN`xCe9ohbo9dj{vrPS*%@FtCIK5q4;XEsABr<(m5@RA?r(tiP9;~;1t(`qfA409XO7~#Haige(UKlfi`031MfgU+X#ixDi`PRiD7z*`hOYG($_B5sZ27dyZA$Fb?) zyX}+QaHs4uj+-bpy^KGCC~$_!F7eWO3!Bi`B&U)m0uwv*h{I(I*f#DrfzV6tAu{G2 z+t|rAa3cJN`ilA}LwzufDt3oxE%pL6Qq=>A=UYK1Ck9$Odb$kHwy2>CeWYHH&FNWq ztq`ju8{FcY>W@vr2aOtw9+R=fTi<*mcHTnVKRW4ec%w;17$A~)C}6F>OAfH01&|Z> z)UnNUvZfVagB^2jlM6UymeihOc*;1Fk(kNI2)U)p@BnPD69fPZLbs?0^Ti;%>BI!6 zWK9P5-5u5L7!CgY!0ix`da(cJ;VsMu(9W@WQ->3kgwrhn+WQc3Axp#IPVX?x>FaoF z_Thyu3D=@V6Q<{$e8OMSVy=*bA-W4glP$q8GDX00R%`mSrh-<eE=lST0-ynyZ=&?UuRYKzfa!Vy4QR`=TpVfA-A4W{?CSdc~kC8%ovx9dyEQWGW2 zo&gSyn01HoB^$R3T+BWu#Ykuno4!_6Cn?tYQLv-^(Fz+y2&{Zj%IMmXe!^%A4*Rmv zCdEfF^HCQ1BFY@VM*N3vnjuXiN>{)4A%RQY>ft9aZQ_C4P>vA5j-eqfAro{NLfh5v zh{_~p31u{~<1h+W;@n*cra+7LvmUz=N7v zfx5}?M(#G-@$vli@8NTt4?1VUAvhlLGPuY4KH$Lt1MLR}?A(v~e}MXisRMIWh(D^c*YpRs0~8(2@K*_jMV<`69DenJ-%_;YeATo zK)NcU%tx{Ik5TD%uI`O^AWfMNRBpBJ!CLQ$oahAy&UA#g**|b6T+rNzGd&vp1vn6s z+$#;VZq~#^OZ6EwS6@7#x0~G^<}Z~PH`X_5vD9{X5J8yqHmoRaCBRm(PzEsiGW03? zxfdbt$UzQ%xmfEMg`~_+NHZ@F0`h;NAaoX+f&O27KSCdWg0hDJ!B?j6KnQY=&-@LS z&TFnWVl~OK4?&9SO9m~}vK^#w04rv_fE5gg>*Ad-ajC_aOPT@93@nb>!43rDB3?)w zKr@Kq$H`~G;2d2#hzBI3(sKx2t~aqGO`aqtCJngqZ-KS98E6S}A%=zyPJL0;FgeDM=oV;n2xvsD7`^llkpVk|7xoG~ z=_{FB#pG%xZ^_-)+9yZWUjI2i8X50vD63+;`bT)!W<_rs8XQ+M9$fGtWZnw*v7R>% ztfx_824g%gitkwC7~dJge$vczR3nLP`}Gzz=O-{4!&``Up>qVE{Q=8HCj17<8vO<0 zq7bPiT=I1{Jt6?mc{nCElkpV|slkLqg5Ts^2{dA?b`U)U*#}5m)i;M@$w!_IGZy}{ z4Y#!i^|1G=ZyTyduZe8LCG{vX;74I>rHQh_lcgU(Zj26S${WFcVGy$dIAIuZSYqFK zA}B1VE_~RT^OyB`OoE^b^l$MgHcoJmZ>fGN++mP5@|sb*i`70*XiEPXJ~0uGpX1XA z+}U)8a3}jBVPqYi2p~g7DiOxqcNsxJS=%8L9Hfun1@voxo}5&%^<4}VQ8t9`WgU3@ zCFh)gjY1zkfNcZVtUI=`V-Te!Tx>JTvw;QZtV}f39B> zV;NIp*iej^ExaVyP#l;^5%pgN0>Nhjb{x-d0;S(VX)!6q`509~%o1Xg#E*iW#g9UE zyJJp_=V_dT>%cV@rkChf2wnQg!nD|8kX&h^3GV-iSeMP9N8AsC!%j?_?V6G^?6CMl z#NP70nU24VfY&sxg@Gvh4lswVJx06N$MikQTv8K_}b{`=%jbXE#~dUMKgi}_dh z-W|)o$~_hY@@Deqpx&hOuOoH#FwkN+U?uh~{8tXA1n3X>^>QdBO%VtIA&hNgV+(m7J@@tjwpymJG52|`#o*#5@e%LaUP8(FBn8GQrWhL7}K9Ud6*wizejLf_vd4mERpC2352gyLC)zf=LT;twD6+r*B)Ry%Q>47+HO zwuYR32MCe_7cSDkL>}-LYm7BCuGX^RU0b*^!Gzgiie`~C27{5&(TCk7hB?-7ZfbcQ zOTl$ZdWX+ce3RuBuo*emgF|F=K+>ZMXB_Z`UMIHEhdU-W%hSN8YH$kneWI9&97Vu} z|N0v5*^0+_)bE`1ac*h>HOv{Hg?dZetvr_`u3JuMrQg)TsKb;)i=A2v&+H@Y57b-x zo?BQL01dvnkR{6cksS}78<$`N92)Du6#?EF;dCnj%MjYpEfzCaSyzk&|HlW@mg>vc z0WKrw~nPP`j#x*L<47Fx zeW`y4gB@I+M|pUkl0P=@D7nKlc-v|e=^|oVpgV=G{)o`sg*rS&V`BJmp$wjiuN6Ev z5r$*;sVEEqj^Z})B7GT|w*=gMKL&8u0BA0hG~)_R&Syy(u1eYDX}Ju14Dd4mWa+b` zz`qc@Vn<6|s&?4JpCoua0k3a>dkmu|T= zGwVlrbK_c~H8T9-<$=I!V?m9~-@*LT7`HeS%=sS78ppOs$@Z(Gx}GuBE?M7dkxJ2}+PZ|a8jA$t5$ZX5 zFK;gB*X_|?kvOWPr8^-mJY^yr!2+W`>=Txr>3muGMOx{pQHr#+#rDNjHsBVH{w8?C z?NLiY^8;^feS7QqB%j0j%=N&9c>h`Z0dODu&5a0zW@99Lf_3c?Z(7eLUy*nC`0C=d z-PYlx_84k^kvRr-V}v~5{l&qrqnfzyP-^9jFDmL6Yrl!(z>NY9eP?^w29ARpb)_|x zjC;$Bq`lR{u`t<2u{QJOdt#=V*pS(PcM5!hYo#A-YYC_1ReVr|mgpo!nEQ9I6tlXA z)Yu{iSag)!Q5-M80U=JZ@3*EKVuB?((WfXq;s z1JGF%f5Bu+`hPi!DIg0nf{)rJZhL42FtJvMlayF;Ez0@s^+RG#!Z;ZM+>cK;pY>ym z&HllgZ2USV9VXvmLN$3Fr%-8+7&I=I`Mttk*o4EZIO$?YVIbLN z@jHlLa0?Q{^vFIp?XA?a?goVDMjCe;0PP^yrNyHj^Y zmq9=liGm%JlisLDJ_s;^?*NPd;YJ3YKtyqGr166^LR>#eL^42Q!j&Jq5&|AYUI=nF zvjNIZq*yX`jGxjY3$HXmCMf@#n4`Xz$#<9#?`IKa+Fy~r1Q9Y2JWN(8^kz+*@*tYa zLJ_j&$i8&*msm3Dy+6w(y8#cAFv^LSbn&)>i z^p+FEC62-=XuXQ>BYANjGDB zbwPI@Z|6i%AKjIUD?B@$xSVP7z;VmdL9mmEltYTIu!@)1Vjm|3PX#fb6SJ#=rb4LHALY`794xqV+ORBev#PAv5~`4 zGvZZUG5+%GClz4mM_KzXiaF{~{1K-OK5uiu0pT#ja)q6t2hJy0L7&U1Px43MD<^%R zy;ypOU?Yrik^SS5o&=1Bp5$~ti?_D^YfNFuVQUmR0d3g>cuFIN&KB1Q_Xu6%?htK= zr~46J04?`9`GWfsPx3}PQwj}&5y-rt!q5cDW4o+%NWP%X^m*QP2i>aw9q*mB^eHnM z=s4DAQu@?OyzS1sIf*wGcj2O2@yy;^x&vFSQ^FkqpMdhQ19wYvWYBRoVFij#WBSL{ zIw*H>k3iv!^)Xrqc5tN`L(;?7`aSTVU)1k6`=xT59qts^2cR$Fm;3?z#bOp^=pJNV zvh)=%S<1Q;QelI7Bd!l=I4FUo_#$q;#r=N>>f)HvpX#pqrtJp$Y!o3nA{zNIrFE!VLl`3EUF7c84kG%8>V4nL%_u5EDf;KKz zR$n>lf2X(NzADA!Zp)+oa=kS#-evu`^e+cQs!}djkaTx(XOcHP(m^g8DsqP^^g2Rr z4rljeI@A3?Do;G#Pa@|N z5BTF?zuefD{UHSxj3Jmv-XCT!GrRcNH|55@IBYQn|Bxv}CxDCJLHvTfNO-;m%pAIu zc=&}a!vhBsLQtG6+UedRD=ND(Cs*3oT8Pi|W0MDQ*fm_W79H|mknJ~f1E*oCX<>|E zHm;#L|H=e5R&e2H^6#W*js>eI-10b{N3|`w-#v_6w5>^)gV=2?M2IF>hK-52IXQeW zZO`FevDs;RW@g%*pT)(F*8H?P%R5r5Iz&6TS-pyVI9%get%ika_4sn^Ru`P)qX zE|VOSZ!-A@O#UI0Z!`HPO#V5Of6auXYfd%&J3cKk`HxH#lV4-<>r8|-{3kqx9)kWD zCy>Scd76;}`n#-fg2{hlvWI|pkx#$PKI$C9(I{dzWSzn1mvb9N^GBl|MEeVuQ!(OWy6f6Xpt<<13D zUrMIk^E_Ld#Sfc3Z`xz{?v2UlJKN2_ZWrA1lhNBN@_RG(RjypR$*=PG;)*LvW2K#? z$sCAKp2yagjE^(hwcFlj=FZ&It+EQ!`}AF0s{5GS&19SjNr(TA!lEBtT}1w6 z2r(`H`jc$qnQP0(=bt`uxO(uthYvpT(A8pItvHYIpHVu*e@1B*w|r%NJ%RRl0~kxnzb?*OgDf52Qy&x z3`vZ^T}hO^a=enC*EzkBO?o$WWGAtc*v>jme8)-b#ExUV#p zzVEN@o*rPZ@@8Kg4>^VEs_Hua`s=U%s+!jDa6W<0%=c`c|M=^P#BcK<{u#r=NqoJ1 z$wb0QloO8Om<^+B$X~N;%HL$!!rx>gwVW=e4VJMQndNLbEAdn#x12BMC7wons5~U` z4B~}y0r9MpYYZWjq&Ae)yk@z;m_m=k>3D>%| z&zZPxl=r*V(mrQ9LfhGa@RoUVXTsU}mRUZ4r(4zc2_$YS-zI-=FW-St?P?rcK2$zr zB%Vk(yPZ96B%D3&9ZQo}ljXw;31{#38s$6jcOU*9arV3W9oyYMZ#lO(2i~yCN1aVqi2irLjm65UGtz+)J&ha4UK6yLLxhqJ$zb_Sa&yP4KoV(vhl^?*E?{V(M znD4!6mLGKPa}Qt?2QZ5Jod?j@DL1`z|I&w0>OtoyN*%pwUNy=O;d#pW5S~ATw;smR zL(ao^dKgcS;OP*nBI*+rT&S{M0 z3}TPDrv#QkY(DKg;XH}HPUGFDoDbvO54)#O^W%7a+Ia@g&&cy>JU{Eq;CV)#&$y>% zpKu??_cXp|W}k4(vx&*)yB|8Y=-R5&Y}c1vd%n}Gwd<{>XIGn!?X|0I*Y0?(W6!PH zwbt@Vy@7b!U0!J*$18n-%Wh`U@RQZK8vdkei`9A)k+kd8sw*yI&sNp>&I)2#uQlJU zcy09s18==+`1xw5-KtdUZC4>Xc)EmVJdKjTY0|fd8gC@;^|teS*tR&P)ELMRvWdJ!=7fA>z-F{ zvQTcOy6k!@)f&@BT60TotzBuauDBKDuCU3`6;xPp(MkpNu^HcZ(KpVNke8YZ`a5*G zd9kiq&1JXQt`So4PYw?!@%4@)a1$U-iL#k9oE(rKxn#L1OnTBuIF_4sQf_8G>!h6w zrakLqF>QIj_)M#{@`8(zt23B1MVR^-<<^Uj}K1bEaqqC-NdBjTb|pPSG$p__AuDXzz%~OcnJCytd? zI&+P>w|ES*QEk@TQnyw2O6S$F(nYs<@mQlicWh;~z1V8rUApV|F%Mlm3Lu}aF1X&Y zrFwIzdg54siKUfQOk1T^Z8R#CThW|nBCyik?fv5}g=K(+0)xpM-)mz2DiuFpsVujg zPJ{76rE;NDZ3H<++s{4)NLA+=u9`sAeiG>5CxM=d&Gm+;V+WYF3jre@U&toRl=Vkh z(|q4dnqM(3^N-9_@yk+Xvgi-7n*j#;qY>h|^DZW(=K85;t2JP6iq#evaMMx*zCW}q zE2gs4syDG{+A4_E9pF*Dy{d*-bSsPIBFtB#c%Dr9Bd5I8W-ZpZBBCj7n7(mY?Ze+1 z=Q{i_9?t!HY<>-MKWTKIc|q{Rv+Hfp0=3W~5|`|ccIsrdVVd%XH0{8p|6|lSsGtK(Pt1@NL(@6 ziMFwpxN2T8*UZNguk5&zTr;kjYsu?|k!UB^l8$lJRJXJ(2SoZ>s-0dl*37Hsb;HDn z&n7P9+L<-us)6AqyN_b3Ko#6(mDCR-skUuR!Z5OVyXn?k&#S6cA&Xe?7cqFxZnr=p z6^36T&Mmf=fvbLEGV3Rot1F8A_0!dr6|6!(vsm@2Z6FtC+_yNlDv78XK`?2ldzqY^ z>&*LEF5qgrr9f2G!g_F(Q0{4bJ-%m|c_VA&@o$G=-prbcxqWcs)Dm_Aw<02hS=%Jk zWaLKo?z44JbC+`*8xV*+$LJ9l+zIg515ar(Dcx2Nph9&R0p^wiSl`)WNP7`qncJeN z_7SXC}SxzK3MRU1e^G5oD% zP)GP7qVrh>yn+bPpp#JPdIIQSsiC#xl}t0=POPO?wm9azQAdf-8E+d`GHYp7LW#Y| z%UqS`YsPip<|~D7G_Pc@M8N~eb3SdM+cHUj}Q`nz6XrDzS;EMByn(n1=*ZLR|JQ9U$ z-ZCsBZH$}vo6H&`K&-4`zG?xv(l-^CTn*p84-xAmzTQI!!Y#}(%1LKfHY*DpcGgXC z3tP&7hsrs5@K9Mir@-Y5IR!lB9Kx)qj-ZO}4zeP%+;C=voV5$R&S#Vw|2N&0HwdrhXvMmdZ5<_ zTr=KGTo;+sNwxv0dFzvjc}ST~>Wu>E3&`*_tDRaiu9FW>&uG|0gX*iDWSli`W$k1a z-o!jyOI*iXoK1uXp1~|uz%Qwfq5xq1jrbD-b84QMpJWZ}Y{BgAuf#^f%+f=eqCQfR zvXf~)CjvpM1!|kRq^c{PfKicb_*Sio-ETXhSU%EN1##WtpJ9yP^hee=@-0a9xHo2v zT}C0PYKZdN_u*D`5?}8ZG4wcTftYwF_+kJNqEX6CBg}{}$XM1*gKN%2IXNdGVq>1^ zk=U4(lGf5t?``Dfg*>Io1t$%TdkAGVyzLZ_I_wOiblNF8TR^^w=*2%M{>ud2bQzVnZTPPQ7%d2c4r6DMx}<>s6ZxnI=hfFHXw(>xmDikjyrp$ zxBH|Oiu}4K!?9Mgj_us?h6Q1D8+uIPpHPUk1h^HP1bT9-a~t|T;cj<#EbT=3of6xH z*e;3fMr^mhsNn8F`P-d4(2Ko&qdDjtLfSs`IgJrOsK?WO5jT$r0k8fJkeRd|^hqR1 z@)z9c?8R2Y0ULrWZ25IE=bqh~x2sXfl5IcL2G`Y6$O#!v+2%Z(G8x6wmQ)bcP5uRJ zf=(rE)(u4Y?&XyhxH-+LPRsV(T)_SV=@*e&poL0x9NDX0!W8xrtec%u@?jm{+Z3d%@XzlV34zDt1XbLLQQe8H~3)cF%|Q5g<*vfi&P{C z5bHD$q*^0GFExem!^AsBrMo@Y#>S%YGe7{(W@#CmO&V&qu-OHmJ~WFy&K{ALXTgPe zvq$V%jiHPQe-}hBTAfXnzpsc2is@Qnn>pXqYzt&BuTq(v1awb1PMz~C$VNnUiL_OF ziW}9`ES5^EanYTX%Jklakpn56mg_YSw(a?9yWe#@GtISKUA+?eL7oGsOzmKWSBzD)-Rlbv@e)EmQnsqHl zj$YF8)N)KFXZki;HchtnEWX|j1Z?<~ECc`pQYP5^1>-x-3)ryrHfN*6yGh?H9rum% zzHzaasyDy&E~dy`w052v7E|sa{~icOj?|s^N!BQWjqh%i{!h$AtSOFASOe8emMO zX?x;|g(UT!4|#gro-L z+GSDnK))$VMyAQnL0hTSkphCrRE$?&#+&lG@))zDfV`5rfZ+4^dgBO8D-U=V@Gp&T z{-$}eXmy7}s7sI3hf&VYptWkJ(e48?K^}pbm3LDB3V{3)fCOMBR!0J0Mu3CX=U1UP zI&XJY0IP8S<&MKm^N5WdPg4Wr22D~o!hH;g28tsTf(jsPDxe1dL$FOTZ3@7zF0M1B&K z`xg)q*5AzJ0e8s2H@ib2)RC_-nhQDn5Y+rmS)BoE`^SVgcJB>@H-dIRfHwt2RPd>Jd$rX8GXu2d9_T=?10Dc7_?){~y;yH4 zOfs}S3Yx~~rT#sn(o&Ux%3~+uJVX8G*?LncMH5R-hx6H4iRuwSLM#hloAmah--=b! zYPw$+#wZ2oL--sEcDz_`wSHAdUx$SP0a_N2sWuR9DAHxm{1=>4uA_WDYZeX5>~0Bh zAt=!&=o2mY6;z-~LyPtop@0pE9HyV*zJauH{^goH3*rWpFuoR)uxDq(iI}xLkTuvp z8WFTV7#W@mCOSTW>##!4V1yj8mD$f%90?f>VSI#x46r87xR70z#-dJ!So3&`ObF?1 zUuT>;tQl>vkD4FjYW~`Z2qv17p|?`%*h5v15CNN65^(*iRRq6{udM%k9*R{cSTX0j z*3Eegull$LENGzwN!CFcE&@MUkL;V!@R0E!%hA2_32?DhEW}Hidlc4-bTr(|BkJgt z`Whf^aRc4T272tt6<`q?ATGt&6X+H>c8u7?A2rW_x`Eh;7xDN-Ce;yi4~65zL{`GS z4CGA=)!tk^$A)FkjXJ(Gs$Ou)n942ixz_I;yE&ePK}~sBkw5m}FuqGPNP zw~u6z;UDd#I7>?gPb|Uw34JKy9CWqA&5J_!8P|i|CKpfO& zRngpDMh4kd1rgpU7vg4gwZu2MPy5N0)`~ye*M^e4J6$gJuv^U2SNPJ$8GHgkd8|@t zD;V$RU|X&%VrD9pa#r*R0P%XJ4{FRt!vg8??!mie&N8x=d2_@}o1p$?K3RkXgnT$d za)br5V3_6zVrj!Pvf#_Rg^;qbDzU@#EwLo(jd=0L@jxv)c78~)6fdtOuZxEgjFB0z zjEN;{&8*!3XQl1N2d1Kz3!Er>9UR4H)J3Mr~K`Pv>B_y`Rnjfp52*bamtT0p^} z#87dt)a?N_o{iu&4EdFzQ0fM_V6B`tUxe&;!KBz8s=O^Y8?=>!H`dQ;?jdTWF0ZIZ zrZ~0SRm@lSCAtT~sS3an+ugz!CbMGh(lWQGDoAxTVxB_GPj^-vsJle64jIWaEHc1+ zq+UhFUF<>u5i>PmSU0oDJ+QU)Xm-$*KAhoB&+jz8!b*gk8%%a)`nb~VDJ*`6i}*1))&IZ)0^3iqbj{7dL!I5Fh&e2eO|btocc zpvMUZ;qR@inI*5cHAIjY@4A6Wq3S?@aT_A*tzy^A>j^3*uxe=?v);)7B&iv74rSFx z5Ogi-e-$m`uw}i(WY(hu%>?0ke3i`%&Yu{po(re#HY2Wp(RMMtDC~8nFjeNu2NC$z z<4{Ja!+aJ4PWCw=*VTrfoeuWCz$u2_2gPT#F8NvLg~6=9bqzM8qiV8(4u4ok1 zkY8g=hCo*ob(O)Z3~CI>(fAg&P;eny(<#fxx8`76Qg5=zSq7V$&U6wgyV%3>9!*9_n zynn}$e1Yy0V>Iy%v7>#TJf2SC>%ER3ZiRx67B~*ELZz0{ZVDC`3znu7tt#5m1ba%_ z%{dt-8(5aCa^4++Z7Q`?aE4e0_LgC>$PBwh+N_WwHYM0swnQl-&Zv|b5wEW?Q7Cl} zJlAx!5(^q=yJs5#8ydJ5l{5v2%%sp@wXqj!=PfSanHt52@WZ%??=-&eiG7+%Q>}V6 zM6qhFSx8CtXs;zLz&IXk27VfzeP{xI#nG%!>m~j8PE@|mdrTuXInNh?*za*2rZePd zVPW6iZ}E;)rK*Wi8x|zFSoYrIa>v5MqTDXtK}*;<&ZpE4F2*HTyu@ssj_VB}d}okL zDMKrkgSP|i;mBF){)C;2=?zs2?Wh$7RN869LstDo#QkK$ZK}V()IZN4(mCikd4Xwz z);H^!`A`v_9#%q$Gg9CW<^AB<37QJ|rGq1PjU5RdK-C!$Ky0eKJU~H$3UY^Wo zM=^=YXnq^HtNdv0dja*%)?h-n9+0k;LnQ zj+_lZ8MClts+{KafN)q$OVGzI!7R<(tAM@CMq(+ml*Mddj}K=F%m) zsC_*EICk~j47jS*_b{-dfY294{31t5mL!jDZvu?2jB(?lBS%}QOpXrRRSvT@y|p|; zM(k63ev82*11@Yo3*iV02yTnt&NNvqvO!$qVSv;Ju9hI> zaJ4kQY?9a)CJZw>Vwm}HLx^Jy#rr;VmOP2CXPG@3{t+w>xG9-%P)e3z1z*az*_{c{ zYwMwen=ivNV5xwolspXwPic8722UAz+7dj$9W0m3<=_?$UxTF)cNFxWwZLwV7;DHl zMZ~taS!cvaVow-##$acs^}hE8JPDSz@m<)}w>slO`C*BNZ9R+KLHq`=JM0Lawa)aPD^QLC&OmxDSSR;_Z8#`(#u{@YbCefp*_N>LfwlKBVph zK6KqvHa%KM+-ZIl$)A3$&MGVt^&0f6c$%H19(%<*qPf<36KS;Tx0=GIR^jTcMSYeM z&8O7G0$SSn!cBZ;;E#k&VS)bFmFhfN&VI1(FNi&lzI#{# zSVLh4MgA2Fgt&Tll;?`Wv7eSr_qdqeHf-$?H9CaKC_P|nhj$W96o|t}!L41kc}uqW zl*3)Xte!;U5j!5JUc;VD!3`q-8iY*(vM1dIMI#-;)Bx*+E%pows#Goz?vU1?6m4q% z398WeSy3+R60jzq-Q~bVgXuvNP!JOa+BOtg7+5Lne2}VS*Or-?YdNbFYI{z~tc4%R zrU^s)9_SjOm)I~I4PlHM&h{?7p&>L&jjVy%yy#V`taatKJwqp|N(ePLq2t7ZJdwo? zG8oNQB5(mWf^n(8jtL7nsUJXG&;JiH#;h3S6rxFj`yC{jc|_7%sG$Ha188~9>OOh|P%jD|4TA`=+QN4FU;i&N$>PYUMcr&w| z?_}G#4wymK@p4edC17{=yPlC18M@+xQxvl{z+OfTNSLF2DgtL0YKHM2`RWqoR=QG% zTna;4T#EJTU6@YmPz!pt3)de7cOdG!plAX908^o`wX0CQbYmDthsM7Oh^W8J;BO%C zbLZessg2BUF!6^N5b)ZN{C$kkyb*Fa1Lg_-(lX*7!9S2QxvRa3v|o6OS=KU zQX=bV5MRC*js6U}{2sfJPj*M+T^6FSX@}L1;}vxC=(MKw8kM*?gjmTI?MB zA0mRzb0<7>$a19($g@t|#P}G{tH2kzo(AJ6gV(As!FlQlo6>*T7-Rqn+O&Wf45K56v z?NN$8jOv-{r)f3P9+uIJV7se27wJ`ty%0NL$v*4$Ob3Ali>2H2I4>=zR%c~yRRbMo zGdohBfUF6yq5dA!&H>gz1-;kA*VL|FY}Li781!Ch>AeLq^bd*s+&Kr5A&X=EU4oWS zDrCDOaiB7D13054z%718RuLC6k5p0p^f#h5E39*BZAaGIM@V!1dLwcKMfct zM_G>suFf$u{y==Zu`NDzAsCk5O~%kv=5Bym$Ir4nr;VJvkb-P3s~uSS1c0!Z7)&?J z9#wHv*2}4|HN#6&l_-`SveY~~h^L7JotD7ad@dl|^cSROUc@vkK!k#B8r}w=udB6& z#$GJwg++U=N`qq{LQ_z}py7!o&Z8l@)q6iUhG>cdk&jhQfttg$T-nQzn{~^eG_ZN1 zA^I3eGqDA+3%;EM444|c6n00th!ydp7_E|hn(X#uU_$#iQ|%}?fEbRqvw;zUm#e}` zXJI+$=f0$b;t9bbed&J(=F@e|sbc<{*ok#eEm-dz z<9@6_Snx&13(s_x6Q|^P(0(58%b+%>uA^;U{X9n@BAwvj_w!N6^T2hEqn=H_nCA#Ix2{#@f95_M<*v`b8R~Q(3C4EDj{|)oNlG^%3KM!kvSB)S25SBg{oSnrtabN>N1qSDDKqeMB z_j%E&PL>9m2?VD_pK*{Szl{M61pbyvrP_oOv39P*X-(n7WLeNat$OQ#^vD_Z{j%^tq$`^Je&B88YY*?nEhQ|6n z+^|mK>-`Rb(3bs?gxocfT!Kd)PB9v=X=LR7ku1`4ZXT&goRh>~>h_(al;)Eq$5?ru zu;30Oy$BsU?+I zZGl!3eTs31wvd!3q^9jsDzppe6P7!i?I2h?)d>t(6W1SLjM%zic@fR0nftdH>}QZ= z@FNWDC^*0v(d%ivAZsIQb@#5na-$Si^7b{wW>_zg&Z8mnHKDRNvt-aZ_yJnahqTr+ zvg}$tYc8#a*LaqgdyN%oK+~cD&9t)vG@xI_%B#K$U5o9ipW&k&1p$F{UHxm;FUa>Zo3-?_ z$lyk<{tY7Cotw6@p^*sfK8zRj5QUiu(GHT?l1W#@aNvC^cWd>wK;=#Ziz(8jyD(Ao zcp1(kEE}Ng!ld|P^x%|!K1GWWCAxtyBn@7`$i&+XQwmPTG{=p!Rrm_H8q@qrclU>*f!&eaAOiHZ4Na5r)n|c-K;Z{32-7Gn-+>20y4P|f z2am3ogJ;w~L231i48Dhf9R&v%<8E}3(8(iWz6wrHOLiMEAQbO5U;z6$&AR>=JTvD{ zGtHkM41NW#4M6FrP+wbpFqpxcF>E82@#Y@Eq9zSJF`Oe2`(OrI{c}{=$2|+>__rL{ z2XoJga)xxcchsYQWnjv2#@k3Id-5B6{8tQQ_%>s`-~b=l z*C#pN!-(V)U>Zy_xGt#hzL~=FFuq_hMv~?bV|$Ezc3)E7tKpTt4`Fr^U+r?%uTwydFRph76brUNnHeU>|aDe#qlHgfFi}z%y8h5!@D2gewHx)yybA7npblq7{YNxBISku$ z?A(B#l569{0tr4n95USfaQB|}Wc&AcP5l;w|Gv|-KgUZI&s;ep96tF-wN?b zf{(*SU`*z;)3QMOH(Ay53JWLv7<}&YhrNymichSNb=D zL%w1F!mx2%Ny0R3I8+&=m=5KD1s6Na!$20nQmsy zyp~V*KRqPx0ucva&o*Nu{5GSA*}Zp2dZ?XB%`dh1`s+3a^PUQr`#Q$HxR0gu7U3#6pp z3GH^s)bp15nOHqT$N^+f3+^R(2Z#7s&$S7-rzGXNoMC-Ol4w%S2>NMj0o zc!KlS3e(q3>vi4zsLhit_2$JEFPYFvhfA$ceHd!SycJxb$dg;TrV#OI+tEg~+JpiU=WQ%{dYdvQ9y90|Aruy zL}%#`kOj2!X3*W?pu0gw4djO(LNtZ1bo4kP?5L2FjAJw@cjB3vP>0u=A%+tW)J$<1 zTXIWSYNnj4He1crW!R*8MZrqgc~lTFnTBvKMgUq zo=GdSu7eCd#ehta`d$W~X7FtcNb|LJXB%UpiMo|Bfhys)xw3~0#kUg$$YYD!>X7wC zI<6LiJ3_PKxN6=oGv=4T!~bD6m;a)<*EIGS`<~gC9UBssq=uLKK0|mqiLdwFn2k8! zrCnHY$6gZL4U{r2{D<8fxFcK{yOakX7CvVX1Am2_thk@@F1}QmM-NaQY8SbUPn0*{ z$K>6jgjr_`c(Cvo!l*kU#~QNCLwjSm=n6z0>YGt3QQnI0IKJC(eH5R!-+}MJ@*#PiMEr0W?xOg61b0l2>z=tK z^g#1|$NJJV$9Ehfy9*=J9N&pxochwNyMsJ&hb`ZOr_9p5tW_LX_tPb|e4nJ=AEoLW zt{*^Z3AJjM*az`M=;=$aro_GUph$()Ma&dc%mKd>J5kA-@xoJhk<*{eRBSp;s+w0| z?4>$A^oFD)CjMg7wI7jFrf_${ZKUFV7G7p_sg48mayAn$+EX}=8M~)PU+FWY&1sK3 z@(3(pE&Jh~W%UrR;duBUQV&jwlAdKC;T}SYPB?flO4s*$wB(sKswjh%-f7=+BFG7j zVA_Xd&xGb&d?i4!#cVV=CB*6GTk?B}BSo(P$$UwNI`lAx2?Md`ZVhY!&$=@bL&CE8v_o zGz)U<%yrBDYEC{_O?r~+mOu)W|rsRdC^wfzok3eH-X&|TxdquNjvoU>5hddys@l~ zGu5sQdH?q?V)efm2*>jtW52^dXgIYzgY-E5SZtbuq1+EBdb{uf576hqaNtNUSP`%r zHw$U~x4S1c8PRxg@uR?^$0ywwYP+SGmbTdT%@${hUy&fV$6_y+S-K8h7Cve23;Mj{ zCM#9@3&pM#qsuEjB_qd#1XG}7 z74Z1RbxNhlnJ=(4-^AGy(=VP15kY&v-awWbz!muV+Eb!UrSc-XoJPqJaAELD-WKaN zFGtm-{FKnp&AU5-8niRC?j#+fG^c0?i}G&ZFL0B6vZFu%nyysb3%D3M1Rkzm9f|jX znVYv9A&qg}D8yQYM3zvrfDdS{iKFi4(VUpM3+tL=W*?6BQ4}^8+^CJY2nT8UX5G=e z*hizm$uMPvy!N{4Ey5y=MpY6O_LDK4xuH=uJdN*rG&s_}4Iu({dgTKgEH` zqM6@D=H~7FGIB4WJx@fHSBpkJCRR8SbCz;EN8ZHWH*fF^#y zM7JB@rf*bYeL28hQE}L1<1`DHukx;E>t=Ur9HN2#x334Bw{Y$RrcfW9*>s4!I+@3N zaRqS%*S<|oXMSJ{!ccA6iZJ7^4Q@b-0yyz=8wY(m15wp-_oR)&YqZ+9L{aZ3!^{@Z zK*RvqR)qQgb!KpRXwl%ajFF&fAwh`I`*@^-JMPrN74R6h(lKIfXD&$6F(fT_023)C zu`-gJ`bAz+ffpr4O4bHvr5_4N?t7Yt2SiYC7V}2Pz)Mas0a||0a?X$)Yuu)Mu=4!TbV_ zY;=qK3lFx^GxCf>>+oRfBivlW6pYcsg!hdI-h_4#+}H#(gGK{4+&}{d{_MK(t;U!G2^a|~P%jXRBSuTA=m!neXz?2`#Rn-0#9zky%W%74d}NKq>q-f|dhm1;rx#|Rwnbq zX?-}VFM4ZIOHHMc4WWxaiGa23I#W~jiP8f)EAUO!bxvu=I6W)y9ipFd0I4=$r>_b+ zV#9Y&-`g0BI%-b$MMC;I^Frc~e-7GVKXogN^^VfLj1)V z-s$_0RpiIJjG$k~0&5gCEDUk+_9E6w0`)${mW*=>CG=6Z<6KS02XFE_RQ9&?uf+hxeLZ_PF|e=)d|Bg1(KF6e^D| z8 zeol1}5i_|%2siY^ubS_7pZ;0_R@z+7=>r+jny5vzeoxRED18-RBH*rxpc3kgFQACt z-#&^M_^vyNv-lCU7~)F)4`UF*_40RHx(|HqUDsUjru|e$*d`|#qM!6iwpsQ{9qsQ9 zGkyf!Q6;2zAN;@Q$^ae}RYfq{*q0&pU{GI}@%gW-FPfLcFNv&U_3%@D0aquyoM57` zcEXLkMYsrrKFt`rfvfX07S>!bE!fDwgvwkJD?yNCa)lP*I7t5{^f@Bw4!ol8Ea-6` zBkzyr_E>u?#mk`Z6G54PQ2V)PkCU$BchDT?No=#QWAXMgkpJcIF^S8#@H04V9Bo#@ zpGI$$cM^kCXU% z4O;zAtw0?v(lrwV=7m?pK`{zN37y}e z8>NyIyAIyWbDJHgDh*tYd#cin9sg=N)6!g3eeB>|wR`ZD4eC>9Nn_c6(h5@<@*rO3 zuDeRdB~#-Mw~>KlW*QkiKS?YHSx&O5ZDvV8#8dYn_*G(=i3r@%cW;CtRGs>FvlM=7 zQ#{*HRDbvq(zK5C9z?W`)n<&RhIB*nD6LTj`*pOYwFCPGwiV&c47?83QHnAv7IGm2 zV&@g>)E86PjP(L(@j>+Br#LF@F(D$3ZNlXS;uKejW18jn~ zCZJ8(Y?`2d1_8JmT*xf^Y2q`9cW}3VbAr68=+CzzhWkyM!!Tj;2#3~~Yv+1i=0;@; z9BrXRPm88JGt=EEY%za-GEj&IK%cU^qtI)6o!Vlk+@8YEBYo_K@k%!dcy^Qal`Ak8 z{2uzWUb8)pH0$S+c6n(ZxwUHqF@R+HXT0=tLhfqI>uQ!EYJ+k8#v@{sr48GZN zE_ll037#(H0?d-ghr5?pBK$4b1aWa)ZxxW7Y}_wEaOG^TMtSZEJ-L;4tzN=*&c9?7 z+<@}qH%$5ShVlb34f{L}oykwLP`v>Og*W|Da>HqT**oaifwO14L!E{?r^O2&qLaho zPy*|Rwk7E!!Q5nUELnaYCh$ptILK74)!86v7QX}I;dV?RzP$}+-LOA+jh+kdJpF%e zaAPO?jevhrroIq7{~xT3vhrpow`{(6sH756MYEJWeHUbggc5Do5M!bZdy|Fj{y>)X zBPeo%i!9nzwib;shzp82lh(|cnVHEa^}UX>eE&Wq`)L@EfmqrLb*R>YAC&$jU&WQ^ z=g6zev1<9*$#R}Yq&h2J6{iQu+v(fFC` zW%|j}(@#G&^MvrWZBgV^G%HEQP#MVFJ+%st#%7zmrIe#+3<4ja#0T{ zd{)Q#iumEmR$t=dF$SXf{j-dTWFSJp+j#Ud;We1tK-3WiBzZoraah3BXJE)5W7-Q0 z?qqO+!BGZ+6~E3HIcs4Jgk;KeYKFsRZZ9Aj_}Pb`zQs@1a?%st=MY%nq4xg?V!qe5rKlF*7@q9U05)%Iq47l%`+eEtx!cv=55Y@!(3e@w9nkTs%|qe^}f* uR!rk+wZtcir;EoEpBOn)d;;-|bpbcn^4;Ku&5@~*-6OWO7b;ow?f(G#c0`l_ literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53e13ab772ec34c9c8a987276957468ba3c4c093 GIT binary patch literal 11980 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/utils.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d93e32b0d606554bb6fd2638044a4177cf1eb4dc GIT binary patch literal 24521 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 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc b/.venv/lib/python3.10/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d25dfc188704eafa4f3697c2aabd537f6f9d6b71 GIT binary patch literal 3987 zcma)9TW{OQ6(%WCr0L7X=^}B0&0^Xvkf;}_P4{JiZ4o2gZi5!uAU0A|-7Q6HMiy;~ zRAwkUR%M`o+t>bqqG(d|W&2awf56v1?b|;0rTxyKb+Z$o1b9Tw49}eF_l@$+&CtTt z{_E}j*PE90Z+cn2T)aHOZ8{Lr>R8g2PHJ}?S(9#B8@e6Wwv=<^>Gyc1-tj-Rq$lft zuw-5NN5Ms{vxX601{eu0oKA?hH5uY9R3T>9rL$)>)+f(*pFR=&T#G`-CrXygErg$FO#qoL(1z{?}t=6evz>ez79k+!NyN4ZCytg&=S_5*g#?bM|Yvx9Q;d18{{ zah#^{L8?lZOfB75ADXg$d|Lf#Rg87kbD({8QC!KU&u|-hk=CB|rQQD0YPh9qRNB`b zMs=NpPlEEq;y<0%ARnrh92~#+=wYil8Xu&I8MOLI7H2)xoaBjV9_v=~L}e$fG&yLE z&Wb^v{iylFAGBbr`u-^H9mj{tw2qSOD1O*FAs2Gp9G#Ux6!qXs6m4KTLl(RC9FGJXBFshEX)kRGvrbBq_65nC_a`olE@&HpW6xEI=?PAFux`@k>Ra! zooa?7kn8v!Lh`FPJvLl@@qt0L_6lLnvLb$o(p8EoQBVxUWmrXjoN+N4E^me6J_`jd zDisWkGuaekAEkc%gJFCos_GFZaXMB;oDP!SK%6Gff1p?mdIohS7d_EsJzarz804}U z@~Wrk5vls|I4#)p>w9tU!3r|Vh*&Gp?cV2Q(fw{$e3#Yq(%2Y5i4}RD7146ozn6MP|--*6lf1J4HWNdheB#Ti~iZxCmPm4i9L zrxOWuU^Rpg-9uGGm;Q9;dqLNeK8&~)RiR!crl^t;vz4sr!E&5Mx1DFI+h7l&KT|sC zReN;j3SsEjz^WuOg^CeqN@~@%gea3cMf0-}p-`Ou=J_&8e6a!r)MV7_k8ztFh{Boz zW(#|2U)V>^pRK<*(z&Ri7HgA#JYy(%V+Jem9Kb3rEJUwzLL|#!U?a)Ur6?4$k0@pt zl*a`kZxnBH>3rq&Jh~z=b4}NSK>EvimELxvR{F?LTok%=i?fl^TX3@BXzKPVTyt#G z1O?^#QbOOu0OQb(H@V$jbYgR9%>pG?0!u+9RAG#Lgomm1%9`4*?Q?hPN_%YUcc<>u zKD4LK-|S~rVohs*xBq1CVcijee|@~+Oe(lXsdL%4;l*tzE;m<7q~R_3Hb?N%?k_;R za@6AxeH$7KRZQpv&MkY#nQSjR%4@DUM$WNg-@(Jwer3J3erkQO1=q-U_p0%>^#U%V zhMdVqL{?O`To&r(C{21vF|XLXK?tdqDmfc>7XuA<|)#!JyTHk;u{V0-oFN&C6I1754CU24;n|O<*ZMn#p zYQBM4(qU*Q0K?r}7ybupn#Oy$SFSa@J;H6CL0l&sR;l3j8zBV?Adn#(BA*;Ewq zG5C|CvP=nc9MIJ2EB#C*M$_ES|HQ+*pMU$gbMBsd-~z93E*!mkXr0%m9yBa9V%mP5sw45Mdk7^~LkllQ@R{(fJry!8?-f z1J>@X=bvd$OZ#d5HaW1}hrLn+CO9zFO6t8d* z;U2<@G+zrV1>U7p8*tMhaghs*uqVIUMYk;=0$sm28BzodP9ehJZ$VXfbUZ~PRVP5M zP@?3^(-iYHT32Pj8?u*B51??SuawV>1$n71G z{yluiEVtu^PTh8$$=$2rTP(hg_xc{~UL&!9c}iR9{*o$)V!E{Z0_@+%#6#S?H-Y{8 z;e%V6MjIQfw5;P$g7YNnEj=m^!yA>G`@eqrN%Z*VpFIA>llG^b?P^`b6>11=OQ%p} v@KonT-pf<|!@?xO>fdBd8GKy*N%{%>`7=a9t`*caoVpX(H=Ql--EaL5>i-f0 literal 0 HcmV?d00001 diff --git a/.venv/lib/python3.10/site-packages/jinja2/_identifier.py b/.venv/lib/python3.10/site-packages/jinja2/_identifier.py new file mode 100644 index 0000000..928c150 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/_identifier.py @@ -0,0 +1,6 @@ +import re + +# generated by scripts/generate_identifier_pattern.py +pattern = re.compile( + r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 +) diff --git a/.venv/lib/python3.10/site-packages/jinja2/async_utils.py b/.venv/lib/python3.10/site-packages/jinja2/async_utils.py new file mode 100644 index 0000000..715d701 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/async_utils.py @@ -0,0 +1,84 @@ +import inspect +import typing as t +from functools import WRAPPER_ASSIGNMENTS +from functools import wraps + +from .utils import _PassArg +from .utils import pass_eval_context + +V = t.TypeVar("V") + + +def async_variant(normal_func): # type: ignore + def decorator(async_func): # type: ignore + pass_arg = _PassArg.from_obj(normal_func) + need_eval_context = pass_arg is None + + if pass_arg is _PassArg.environment: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].is_async) + + else: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].environment.is_async) + + # Take the doc and annotations from the sync function, but the + # name from the async function. Pallets-Sphinx-Themes + # build_function_directive expects __wrapped__ to point to the + # sync function. + async_func_attrs = ("__module__", "__name__", "__qualname__") + normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) + + @wraps(normal_func, assigned=normal_func_attrs) + @wraps(async_func, assigned=async_func_attrs, updated=()) + def wrapper(*args, **kwargs): # type: ignore + b = is_async(args) + + if need_eval_context: + args = args[1:] + + if b: + return async_func(*args, **kwargs) + + return normal_func(*args, **kwargs) + + if need_eval_context: + wrapper = pass_eval_context(wrapper) + + wrapper.jinja_async_variant = True + return wrapper + + return decorator + + +_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} + + +async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": + # Avoid a costly call to isawaitable + if type(value) in _common_primitives: + return t.cast("V", value) + + if inspect.isawaitable(value): + return await t.cast("t.Awaitable[V]", value) + + return t.cast("V", value) + + +async def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + async for item in t.cast("t.AsyncIterable[V]", iterable): + yield item + else: + for item in iterable: + yield item + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/.venv/lib/python3.10/site-packages/jinja2/bccache.py b/.venv/lib/python3.10/site-packages/jinja2/bccache.py new file mode 100644 index 0000000..d0ddf56 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/bccache.py @@ -0,0 +1,406 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: + ... + + def set(self, key: str, value: bytes, timeout: t.Optional[int] = None) -> None: + ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib `_ + - `python-memcached `_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/.venv/lib/python3.10/site-packages/jinja2/compiler.py b/.venv/lib/python3.10/site-packages/jinja2/compiler.py new file mode 100644 index 0000000..ff95c80 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/compiler.py @@ -0,0 +1,1956 @@ +"""Compiles nodes from the parser into Python code.""" +import typing as t +from contextlib import contextmanager +from functools import update_wrapper +from io import StringIO +from itertools import chain +from keyword import iskeyword as is_python_keyword + +from markupsafe import escape +from markupsafe import Markup + +from . import nodes +from .exceptions import TemplateAssertionError +from .idtracking import Symbols +from .idtracking import VAR_LOAD_ALIAS +from .idtracking import VAR_LOAD_PARAMETER +from .idtracking import VAR_LOAD_RESOLVE +from .idtracking import VAR_LOAD_UNDEFINED +from .nodes import EvalContext +from .optimizer import Optimizer +from .utils import _PassArg +from .utils import concat +from .visitor import NodeVisitor + +if t.TYPE_CHECKING: + import typing_extensions as te + from .environment import Environment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +operators = { + "eq": "==", + "ne": "!=", + "gt": ">", + "gteq": ">=", + "lt": "<", + "lteq": "<=", + "in": "in", + "notin": "not in", +} + + +def optimizeconst(f: F) -> F: + def new_func( + self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any + ) -> t.Any: + # Only optimize if the frame is not volatile + if self.optimizer is not None and not frame.eval_ctx.volatile: + new_node = self.optimizer.visit(node, frame.eval_ctx) + + if new_node != node: + return self.visit(new_node, frame) + + return f(self, node, frame, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_binops # type: ignore + ): + self.write(f"environment.call_binop(context, {op!r}, ") + self.visit(node.left, frame) + self.write(", ") + self.visit(node.right, frame) + else: + self.write("(") + self.visit(node.left, frame) + self.write(f" {op} ") + self.visit(node.right, frame) + + self.write(")") + + return visitor + + +def _make_unop( + op: str, +) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed + and op in self.environment.intercepted_unops # type: ignore + ): + self.write(f"environment.call_unop(context, {op!r}, ") + self.visit(node.node, frame) + else: + self.write("(" + op) + self.visit(node.node, frame) + + self.write(")") + + return visitor + + +def generate( + node: nodes.Template, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, +) -> t.Optional[str]: + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError("Can't compile non template nodes") + + generator = environment.code_generator_class( + environment, name, filename, stream, defer_init, optimized + ) + generator.visit(node) + + if stream is None: + return generator.stream.getvalue() # type: ignore + + return None + + +def has_safe_repr(value: t.Any) -> bool: + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + + if type(value) in {bool, int, float, complex, range, str, Markup}: + return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + + return False + + +def find_undeclared( + nodes: t.Iterable[nodes.Node], names: t.Iterable[str] +) -> t.Set[str]: + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class MacroRef: + def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: + self.node = node + self.accesses_caller = False + self.accesses_kwargs = False + self.accesses_varargs = False + + +class Frame: + """Holds compile time information for us.""" + + def __init__( + self, + eval_ctx: EvalContext, + parent: t.Optional["Frame"] = None, + level: t.Optional[int] = None, + ) -> None: + self.eval_ctx = eval_ctx + + # the parent of this frame + self.parent = parent + + if parent is None: + self.symbols = Symbols(level=level) + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = False + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer: t.Optional[str] = None + + # the name of the block we're in, otherwise None. + self.block: t.Optional[str] = None + + else: + self.symbols = Symbols(parent.symbols, level=level) + self.require_output_check = parent.require_output_check + self.buffer = parent.buffer + self.block = parent.block + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # variables set inside of loops and blocks should not affect outer frames, + # but they still needs to be kept track of as part of the active context. + self.loop_frame = False + self.block_frame = False + + # track whether the frame is being used in an if-statement or conditional + # expression as it determines which errors should be raised during runtime + # or compile time. + self.soft_frame = False + + def copy(self) -> "Frame": + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.symbols = self.symbols.copy() + return rv + + def inner(self, isolated: bool = False) -> "Frame": + """Return an inner frame.""" + if isolated: + return Frame(self.eval_ctx, level=self.symbols.level + 1) + return Frame(self.eval_ctx, self) + + def soft(self) -> "Frame": + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + + This is only used to implement if-statements and conditional + expressions. + """ + rv = self.copy() + rv.rootlevel = False + rv.soft_frame = True + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self) -> None: + self.filters: t.Set[str] = set() + self.tests: t.Set[str] = set() + + def visit_Filter(self, node: nodes.Filter) -> None: + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node: nodes.Test) -> None: + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names: t.Iterable[str]) -> None: + self.names = set(names) + self.undeclared: t.Set[str] = set() + + def visit_Name(self, node: nodes.Name) -> None: + if node.ctx == "load" and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting a blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + def __init__( + self, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, + ) -> None: + if stream is None: + stream = StringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + self.optimizer: t.Optional[Optimizer] = None + + if optimized: + self.optimizer = Optimizer(environment) + + # aliases for imports + self.import_aliases: t.Dict[str, str] = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks: t.Dict[str, nodes.Block] = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests: t.Dict[str, str] = {} + self.filters: t.Dict[str, str] = {} + + # the debug information + self.debug_info: t.List[t.Tuple[int, int]] = [] + self._write_debug_info: t.Optional[int] = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # Tracks toplevel assignments + self._assign_stack: t.List[t.Set[str]] = [] + + # Tracks parameter definition blocks + self._param_def_block: t.List[t.Set[str]] = [] + + # Tracks the current context. + self._context_reference_stack = ["context"] + + @property + def optimized(self) -> bool: + return self.optimizer is not None + + # -- Various compilation helpers + + def fail(self, msg: str, lineno: int) -> "te.NoReturn": + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self) -> str: + """Get a new unique identifier.""" + self._last_identifier += 1 + return f"t_{self._last_identifier}" + + def buffer(self, frame: Frame) -> None: + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline(f"{frame.buffer} = []") + + def return_buffer_contents( + self, frame: Frame, force_unescaped: bool = False + ) -> None: + """Return the buffer contents of the frame.""" + if not force_unescaped: + if frame.eval_ctx.volatile: + self.writeline("if context.eval_ctx.autoescape:") + self.indent() + self.writeline(f"return Markup(concat({frame.buffer}))") + self.outdent() + self.writeline("else:") + self.indent() + self.writeline(f"return concat({frame.buffer})") + self.outdent() + return + elif frame.eval_ctx.autoescape: + self.writeline(f"return Markup(concat({frame.buffer}))") + return + self.writeline(f"return concat({frame.buffer})") + + def indent(self) -> None: + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step: int = 1) -> None: + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline("yield ", node) + else: + self.writeline(f"{frame.buffer}.append(", node) + + def end_write(self, frame: Frame) -> None: + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(")") + + def simple_write( + self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None + ) -> None: + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically. + """ + try: + self.writeline("pass") + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x: str) -> None: + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write("\n" * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(" " * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline( + self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 + ) -> None: + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature( + self, + node: t.Union[nodes.Call, nodes.Filter, nodes.Test], + frame: Frame, + extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> None: + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occur. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = any( + is_python_keyword(t.cast(str, k)) + for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) + ) + + for arg in node.args: + self.write(", ") + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(", ") + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f", {key}={value}") + if node.dyn_args: + self.write(", *") + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(", **dict({") + else: + self.write(", **{") + for kwarg in node.kwargs: + self.write(f"{kwarg.key!r}: ") + self.visit(kwarg.value, frame) + self.write(", ") + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f"{key!r}: {value}, ") + if node.dyn_kwargs is not None: + self.write("}, **") + self.visit(node.dyn_kwargs, frame) + self.write(")") + else: + self.write("}") + + elif node.dyn_kwargs is not None: + self.write(", **") + self.visit(node.dyn_kwargs, frame) + + def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: + """Find all filter and test names used in the template and + assign them to variables in the compiled namespace. Checking + that the names are registered with the environment is done when + compiling the Filter and Test nodes. If the node is in an If or + CondExpr node, the check is done at runtime instead. + + .. versionchanged:: 3.0 + Filters and tests in If and CondExpr nodes are checked at + runtime instead of compile time. + """ + visitor = DependencyFinderVisitor() + + for node in nodes: + visitor.visit(node) + + for id_map, names, dependency in (self.filters, visitor.filters, "filters"), ( + self.tests, + visitor.tests, + "tests", + ): + for name in sorted(names): + if name not in id_map: + id_map[name] = self.temporary_identifier() + + # add check during runtime that dependencies used inside of executed + # blocks are defined, as this step may be skipped during compile time + self.writeline("try:") + self.indent() + self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") + self.outdent() + self.writeline("except KeyError:") + self.indent() + self.writeline("@internalcode") + self.writeline(f"def {id_map[name]}(*unused):") + self.indent() + self.writeline( + f'raise TemplateRuntimeError("No {dependency[:-1]}' + f' named {name!r} found.")' + ) + self.outdent() + self.outdent() + + def enter_frame(self, frame: Frame) -> None: + undefs = [] + for target, (action, param) in frame.symbols.loads.items(): + if action == VAR_LOAD_PARAMETER: + pass + elif action == VAR_LOAD_RESOLVE: + self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") + elif action == VAR_LOAD_ALIAS: + self.writeline(f"{target} = {param}") + elif action == VAR_LOAD_UNDEFINED: + undefs.append(target) + else: + raise NotImplementedError("unknown load instruction") + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: + if not with_python_scope: + undefs = [] + for target in frame.symbols.loads: + undefs.append(target) + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: + return async_value if self.environment.is_async else sync_value + + def func(self, name: str) -> str: + return f"{self.choose_async()}def {name}" + + def macro_body( + self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame + ) -> t.Tuple[Frame, MacroRef]: + """Dump the function def of a macro or call block.""" + frame = frame.inner() + frame.symbols.analyze_node(node) + macro_ref = MacroRef(node) + + explicit_caller = None + skip_special_params = set() + args = [] + + for idx, arg in enumerate(node.args): + if arg.name == "caller": + explicit_caller = idx + if arg.name in ("kwargs", "varargs"): + skip_special_params.add(arg.name) + args.append(frame.symbols.ref(arg.name)) + + undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) + + if "caller" in undeclared: + # In older Jinja versions there was a bug that allowed caller + # to retain the special behavior even if it was mentioned in + # the argument list. However thankfully this was only really + # working if it was the last argument. So we are explicitly + # checking this now and error out if it is anywhere else in + # the argument list. + if explicit_caller is not None: + try: + node.defaults[explicit_caller - len(node.args)] + except IndexError: + self.fail( + "When defining macros or call blocks the " + 'special "caller" argument must be omitted ' + "or be given a default.", + node.lineno, + ) + else: + args.append(frame.symbols.declare_parameter("caller")) + macro_ref.accesses_caller = True + if "kwargs" in undeclared and "kwargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("kwargs")) + macro_ref.accesses_kwargs = True + if "varargs" in undeclared and "varargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("varargs")) + macro_ref.accesses_varargs = True + + # macros are delayed, they never require output checks + frame.require_output_check = False + frame.symbols.analyze_node(node) + self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) + self.indent() + + self.buffer(frame) + self.enter_frame(frame) + + self.push_parameter_definitions(frame) + for idx, arg in enumerate(node.args): + ref = frame.symbols.ref(arg.name) + self.writeline(f"if {ref} is missing:") + self.indent() + try: + default = node.defaults[idx - len(node.args)] + except IndexError: + self.writeline( + f'{ref} = undefined("parameter {arg.name!r} was not provided",' + f" name={arg.name!r})" + ) + else: + self.writeline(f"{ref} = ") + self.visit(default, frame) + self.mark_parameter_stored(ref) + self.outdent() + self.pop_parameter_definitions() + + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame, force_unescaped=True) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + return frame, macro_ref + + def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) + name = getattr(macro_ref.node, "name", None) + if len(macro_ref.node.args) == 1: + arg_tuple += "," + self.write( + f"Macro(environment, macro, {name!r}, ({arg_tuple})," + f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," + f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" + ) + + def position(self, node: nodes.Node) -> str: + """Return a human readable position for the node.""" + rv = f"line {node.lineno}" + if self.name is not None: + rv = f"{rv} in {self.name!r}" + return rv + + def dump_local_context(self, frame: Frame) -> str: + items_kv = ", ".join( + f"{name!r}: {target}" + for name, target in frame.symbols.dump_stores().items() + ) + return f"{{{items_kv}}}" + + def write_commons(self) -> None: + """Writes a common preamble that is used by root and block functions. + Primarily this sets up common local helpers and enforces a generator + through a dead branch. + """ + self.writeline("resolve = context.resolve_or_missing") + self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") + # always use the standard Undefined class for the implicit else of + # conditional expressions + self.writeline("cond_expr_undefined = Undefined") + self.writeline("if 0: yield None") + + def push_parameter_definitions(self, frame: Frame) -> None: + """Pushes all parameter targets from the given frame into a local + stack that permits tracking of yet to be assigned parameters. In + particular this enables the optimization from `visit_Name` to skip + undefined expressions for parameters in macros as macros can reference + otherwise unbound parameters. + """ + self._param_def_block.append(frame.symbols.dump_param_targets()) + + def pop_parameter_definitions(self) -> None: + """Pops the current parameter definitions set.""" + self._param_def_block.pop() + + def mark_parameter_stored(self, target: str) -> None: + """Marks a parameter in the current parameter definitions as stored. + This will skip the enforced undefined checks. + """ + if self._param_def_block: + self._param_def_block[-1].discard(target) + + def push_context_reference(self, target: str) -> None: + self._context_reference_stack.append(target) + + def pop_context_reference(self) -> None: + self._context_reference_stack.pop() + + def get_context_ref(self) -> str: + return self._context_reference_stack[-1] + + def get_resolve_func(self) -> str: + target = self._context_reference_stack[-1] + if target == "context": + return "resolve" + return f"{target}.resolve" + + def derive_context(self, frame: Frame) -> str: + return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" + + def parameter_is_undeclared(self, target: str) -> bool: + """Checks if a given target is an undeclared parameter.""" + if not self._param_def_block: + return False + return target in self._param_def_block[-1] + + def push_assign_tracking(self) -> None: + """Pushes a new layer for assignment tracking.""" + self._assign_stack.append(set()) + + def pop_assign_tracking(self, frame: Frame) -> None: + """Pops the topmost level for assignment tracking and updates the + context variables if necessary. + """ + vars = self._assign_stack.pop() + if ( + not frame.block_frame + and not frame.loop_frame + and not frame.toplevel + or not vars + ): + return + public_names = [x for x in vars if x[:1] != "_"] + if len(vars) == 1: + name = next(iter(vars)) + ref = frame.symbols.ref(name) + if frame.loop_frame: + self.writeline(f"_loop_vars[{name!r}] = {ref}") + return + if frame.block_frame: + self.writeline(f"_block_vars[{name!r}] = {ref}") + return + self.writeline(f"context.vars[{name!r}] = {ref}") + else: + if frame.loop_frame: + self.writeline("_loop_vars.update({") + elif frame.block_frame: + self.writeline("_block_vars.update({") + else: + self.writeline("context.vars.update({") + for idx, name in enumerate(vars): + if idx: + self.write(", ") + ref = frame.symbols.ref(name) + self.write(f"{name!r}: {ref}") + self.write("})") + if not frame.block_frame and not frame.loop_frame and public_names: + if len(public_names) == 1: + self.writeline(f"context.exported_vars.add({public_names[0]!r})") + else: + names_str = ", ".join(map(repr, public_names)) + self.writeline(f"context.exported_vars.update(({names_str}))") + + # -- Statement Visitors + + def visit_Template( + self, node: nodes.Template, frame: t.Optional[Frame] = None + ) -> None: + assert frame is None, "no root frame allowed" + eval_ctx = EvalContext(self.environment, self.name) + + from .runtime import exported, async_exported + + if self.environment.is_async: + exported_names = sorted(exported + async_exported) + else: + exported_names = sorted(exported) + + self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = "" if self.defer_init else ", environment=environment" + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail(f"block {block.name!r} defined twice", block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if "." in imp: + module, obj = imp.rsplit(".", 1) + self.writeline(f"from {module} import {obj} as {alias}") + else: + self.writeline(f"import {imp} as {alias}") + + # add the load name + self.writeline(f"name = {self.name!r}") + + # generate the root render function. + self.writeline( + f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 + ) + self.indent() + self.write_commons() + + # process the root + frame = Frame(eval_ctx) + if "self" in find_undeclared(node.body, ("self",)): + ref = frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + frame.symbols.analyze_node(node) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + if have_extends: + self.writeline("parent_template = None") + self.enter_frame(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline("if parent_template is not None:") + self.indent() + if not self.environment.is_async: + self.writeline("yield from parent_template.root_render_func(context)") + else: + self.writeline( + "async for event in parent_template.root_render_func(context):" + ) + self.indent() + self.writeline("yield event") + self.outdent() + self.outdent(1 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in self.blocks.items(): + self.writeline( + f"{self.func('block_' + name)}(context, missing=missing{envenv}):", + block, + 1, + ) + self.indent() + self.write_commons() + # It's important that we do not make this frame a child of the + # toplevel template. This would cause a variety of + # interesting issues with identifier tracking. + block_frame = Frame(eval_ctx) + block_frame.block_frame = True + undeclared = find_undeclared(block.body, ("self", "super")) + if "self" in undeclared: + ref = block_frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + if "super" in undeclared: + ref = block_frame.symbols.declare_parameter("super") + self.writeline(f"{ref} = context.super({name!r}, block_{name})") + block_frame.symbols.analyze_node(block) + block_frame.block = name + self.writeline("_block_vars = {}") + self.enter_frame(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.leave_frame(block_frame, with_python_scope=True) + self.outdent() + + blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) + self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) + debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) + self.writeline(f"debug_info = {debug_kv_str!r}") + + def visit_Block(self, node: nodes.Block, frame: Frame) -> None: + """Call a block and register it for the template.""" + level = 0 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline("if parent_template is None:") + self.indent() + level += 1 + + if node.scoped: + context = self.derive_context(frame) + else: + context = self.get_context_ref() + + if node.required: + self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) + self.indent() + self.writeline( + f'raise TemplateRuntimeError("Required block {node.name!r} not found")', + node, + ) + self.outdent() + + if not self.environment.is_async and frame.buffer is None: + self.writeline( + f"yield from context.blocks[{node.name!r}][0]({context})", node + ) + else: + self.writeline( + f"{self.choose_async()}for event in" + f" context.blocks[{node.name!r}][0]({context}):", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + + self.outdent(level) + + def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: + """Calls the extender.""" + if not frame.toplevel: + self.fail("cannot use extend from a non top-level scope", node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline("if parent_template is not None:") + self.indent() + self.writeline('raise TemplateRuntimeError("extended multiple times")') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline("parent_template = environment.get_template(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + self.writeline("for name, parent_block in parent_template.blocks.items():") + self.indent() + self.writeline("context.blocks.setdefault(name, []).append(parent_block)") + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node: nodes.Include, frame: Frame) -> None: + """Handles includes.""" + if node.ignore_missing: + self.writeline("try:") + self.indent() + + func_name = "get_or_select_template" + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, str): + func_name = "get_template" + elif isinstance(node.template.value, (tuple, list)): + func_name = "select_template" + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = "select_template" + + self.writeline(f"template = environment.{func_name}(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + if node.ignore_missing: + self.outdent() + self.writeline("except TemplateNotFound:") + self.indent() + self.writeline("pass") + self.outdent() + self.writeline("else:") + self.indent() + + skip_event_yield = False + if node.with_context: + self.writeline( + f"{self.choose_async()}for event in template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)})):" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + else: + self.writeline("yield from template._get_default_module()._body_stream") + skip_event_yield = True + + if not skip_event_yield: + self.indent() + self.simple_write("event", frame) + self.outdent() + + if node.ignore_missing: + self.outdent() + + def _import_common( + self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame + ) -> None: + self.write(f"{self.choose_async('await ')}environment.get_template(") + self.visit(node.template, frame) + self.write(f", {self.name!r}).") + + if node.with_context: + f_name = f"make_module{self.choose_async('_async')}" + self.write( + f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" + ) + else: + self.write(f"_get_default_module{self.choose_async('_async')}(context)") + + def visit_Import(self, node: nodes.Import, frame: Frame) -> None: + """Visit regular imports.""" + self.writeline(f"{frame.symbols.ref(node.target)} = ", node) + if frame.toplevel: + self.write(f"context.vars[{node.target!r}] = ") + + self._import_common(node, frame) + + if frame.toplevel and not node.target.startswith("_"): + self.writeline(f"context.exported_vars.discard({node.target!r})") + + def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: + """Visit named imports.""" + self.newline(node) + self.write("included_template = ") + self._import_common(node, frame) + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline( + f"{frame.symbols.ref(alias)} =" + f" getattr(included_template, {name!r}, missing)" + ) + self.writeline(f"if {frame.symbols.ref(alias)} is missing:") + self.indent() + message = ( + "the template {included_template.__name__!r}" + f" (imported on {self.position(node)})" + f" does not export the requested name {name!r}" + ) + self.writeline( + f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" + ) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith("_"): + discarded_names.append(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") + else: + names_kv = ", ".join( + f"{name!r}: {frame.symbols.ref(name)}" for name in var_names + ) + self.writeline(f"context.vars.update({{{names_kv}}})") + if discarded_names: + if len(discarded_names) == 1: + self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") + else: + names_str = ", ".join(map(repr, discarded_names)) + self.writeline( + f"context.exported_vars.difference_update(({names_str}))" + ) + + def visit_For(self, node: nodes.For, frame: Frame) -> None: + loop_frame = frame.inner() + loop_frame.loop_frame = True + test_frame = frame.inner() + else_frame = frame.inner() + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body if the body is a scoped block. + extended_loop = ( + node.recursive + or "loop" + in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) + or any(block.scoped for block in node.find_all(nodes.Block)) + ) + + loop_ref = None + if extended_loop: + loop_ref = loop_frame.symbols.declare_parameter("loop") + + loop_frame.symbols.analyze_node(node, for_branch="body") + if node.else_: + else_frame.symbols.analyze_node(node, for_branch="else") + + if node.test: + loop_filter_func = self.temporary_identifier() + test_frame.symbols.analyze_node(node, for_branch="test") + self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) + self.indent() + self.enter_frame(test_frame) + self.writeline(self.choose_async("async for ", "for ")) + self.visit(node.target, loop_frame) + self.write(" in ") + self.write(self.choose_async("auto_aiter(fiter)", "fiter")) + self.write(":") + self.indent() + self.writeline("if ", node.test) + self.visit(node.test, test_frame) + self.write(":") + self.indent() + self.writeline("yield ") + self.visit(node.target, loop_frame) + self.outdent(3) + self.leave_frame(test_frame, with_python_scope=True) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if node.recursive: + self.writeline( + f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node + ) + self.indent() + self.buffer(loop_frame) + + # Use the same buffer for the else frame + else_frame.buffer = loop_frame.buffer + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline(f"{loop_ref} = missing") + + for name in node.find_all(nodes.Name): + if name.ctx == "store" and name.name == "loop": + self.fail( + "Can't assign to special loop variable in for-loop target", + name.lineno, + ) + + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline(f"{iteration_indicator} = 1") + + self.writeline(self.choose_async("async for ", "for "), node) + self.visit(node.target, loop_frame) + if extended_loop: + self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") + else: + self.write(" in ") + + if node.test: + self.write(f"{loop_filter_func}(") + if node.recursive: + self.write("reciter") + else: + if self.environment.is_async and not extended_loop: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async and not extended_loop: + self.write(")") + if node.test: + self.write(")") + + if node.recursive: + self.write(", undefined, loop_render_func, depth):") + else: + self.write(", undefined):" if extended_loop else ":") + + self.indent() + self.enter_frame(loop_frame) + + self.writeline("_loop_vars = {}") + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline(f"{iteration_indicator} = 0") + self.outdent() + self.leave_frame( + loop_frame, with_python_scope=node.recursive and not node.else_ + ) + + if node.else_: + self.writeline(f"if {iteration_indicator}:") + self.indent() + self.enter_frame(else_frame) + self.blockvisit(node.else_, else_frame) + self.leave_frame(else_frame) + self.outdent() + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write(f"{self.choose_async('await ')}loop(") + if self.environment.is_async: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async: + self.write(")") + self.write(", loop)") + self.end_write(frame) + + # at the end of the iteration, clear any assignments made in the + # loop from the top level + if self._assign_stack: + self._assign_stack[-1].difference_update(loop_frame.symbols.stores) + + def visit_If(self, node: nodes.If, frame: Frame) -> None: + if_frame = frame.soft() + self.writeline("if ", node) + self.visit(node.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + for elif_ in node.elif_: + self.writeline("elif ", elif_) + self.visit(elif_.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(elif_.body, if_frame) + self.outdent() + if node.else_: + self.writeline("else:") + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: + macro_frame, macro_ref = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith("_"): + self.write(f"context.exported_vars.add({node.name!r})") + self.writeline(f"context.vars[{node.name!r}] = ") + self.write(f"{frame.symbols.ref(node.name)} = ") + self.macro_def(macro_ref, macro_frame) + + def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: + call_frame, macro_ref = self.macro_body(node, frame) + self.writeline("caller = ") + self.macro_def(macro_ref, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: + filter_frame = frame.inner() + filter_frame.symbols.analyze_node(node) + self.enter_frame(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.leave_frame(filter_frame) + + def visit_With(self, node: nodes.With, frame: Frame) -> None: + with_frame = frame.inner() + with_frame.symbols.analyze_node(node) + self.enter_frame(with_frame) + for target, expr in zip(node.targets, node.values): + self.newline() + self.visit(target, with_frame) + self.write(" = ") + self.visit(expr, frame) + self.blockvisit(node.body, with_frame) + self.leave_frame(with_frame) + + def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: + self.newline(node) + self.visit(node.node, frame) + + class _FinalizeInfo(t.NamedTuple): + const: t.Optional[t.Callable[..., str]] + src: t.Optional[str] + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + """The default finalize function if the environment isn't + configured with one. Or, if the environment has one, this is + called on that function's output for constants. + """ + return str(value) + + _finalize: t.Optional[_FinalizeInfo] = None + + def _make_finalize(self) -> _FinalizeInfo: + """Build the finalize function to be used on constants and at + runtime. Cached so it's only created once for all output nodes. + + Returns a ``namedtuple`` with the following attributes: + + ``const`` + A function to finalize constant data at compile time. + + ``src`` + Source code to output around nodes to be evaluated at + runtime. + """ + if self._finalize is not None: + return self._finalize + + finalize: t.Optional[t.Callable[..., t.Any]] + finalize = default = self._default_finalize + src = None + + if self.environment.finalize: + src = "environment.finalize(" + env_finalize = self.environment.finalize + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(env_finalize) # type: ignore + ) + finalize = None + + if pass_arg is None: + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(value)) + + else: + src = f"{src}{pass_arg}, " + + if pass_arg == "environment": + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(self.environment, value)) + + self._finalize = self._FinalizeInfo(finalize, src) + return self._finalize + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + """Given a group of constant values converted from ``Output`` + child nodes, produce a string to write to the template module + source. + """ + return repr(concat(group)) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> str: + """Try to optimize a child of an ``Output`` node by trying to + convert it to constant, finalized data at compile time. + + If :exc:`Impossible` is raised, the node is not constant and + will be evaluated at runtime. Any other exception will also be + evaluated at runtime for easier debugging. + """ + const = node.as_const(frame.eval_ctx) + + if frame.eval_ctx.autoescape: + const = escape(const) + + # Template data doesn't go through finalize. + if isinstance(node, nodes.TemplateData): + return str(const) + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code before visiting a child of an + ``Output`` node. + """ + if frame.eval_ctx.volatile: + self.write("(escape if context.eval_ctx.autoescape else str)(") + elif frame.eval_ctx.autoescape: + self.write("escape(") + else: + self.write("str(") + + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code after visiting a child of an + ``Output`` node. + """ + self.write(")") + + if finalize.src is not None: + self.write(")") + + def visit_Output(self, node: nodes.Output, frame: Frame) -> None: + # If an extends is active, don't render outside a block. + if frame.require_output_check: + # A top-level extends is known to exist at compile time. + if self.has_known_extends: + return + + self.writeline("if parent_template is None:") + self.indent() + + finalize = self._make_finalize() + body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + + # Evaluate constants at compile time if possible. Each item in + # body will be either a list of static data or a node to be + # evaluated at runtime. + for child in node.nodes: + try: + if not ( + # If the finalize function requires runtime context, + # constants can't be evaluated at compile time. + finalize.const + # Unless it's basic template data that won't be + # finalized anyway. + or isinstance(child, nodes.TemplateData) + ): + raise nodes.Impossible() + + const = self._output_child_to_const(child, frame, finalize) + except (nodes.Impossible, Exception): + # The node was not constant and needs to be evaluated at + # runtime. Or another error was raised, which is easier + # to debug at runtime. + body.append(child) + continue + + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + if frame.buffer is not None: + if len(body) == 1: + self.writeline(f"{frame.buffer}.append(") + else: + self.writeline(f"{frame.buffer}.extend((") + + self.indent() + + for item in body: + if isinstance(item, list): + # A group of constant data to join and output. + val = self._output_const_repr(item) + + if frame.buffer is None: + self.writeline("yield " + val) + else: + self.writeline(val + ",") + else: + if frame.buffer is None: + self.writeline("yield ", item) + else: + self.newline(item) + + # A node to be evaluated at runtime. + self._output_child_pre(item, frame, finalize) + self.visit(item, frame) + self._output_child_post(item, frame, finalize) + + if frame.buffer is not None: + self.write(",") + + if frame.buffer is not None: + self.outdent() + self.writeline(")" if len(body) == 1 else "))") + + if frame.require_output_check: + self.outdent() + + def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: + self.push_assign_tracking() + self.newline(node) + self.visit(node.target, frame) + self.write(" = ") + self.visit(node.node, frame) + self.pop_assign_tracking(frame) + + def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: + self.push_assign_tracking() + block_frame = frame.inner() + # This is a special case. Since a set block always captures we + # will disable output checks. This way one can use set blocks + # toplevel even in extended templates. + block_frame.require_output_check = False + block_frame.symbols.analyze_node(node) + self.enter_frame(block_frame) + self.buffer(block_frame) + self.blockvisit(node.body, block_frame) + self.newline(node) + self.visit(node.target, frame) + self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") + if node.filter is not None: + self.visit_Filter(node.filter, block_frame) + else: + self.write(f"concat({block_frame.buffer})") + self.write(")") + self.pop_assign_tracking(frame) + self.leave_frame(block_frame) + + # -- Expression Visitors + + def visit_Name(self, node: nodes.Name, frame: Frame) -> None: + if node.ctx == "store" and ( + frame.toplevel or frame.loop_frame or frame.block_frame + ): + if self._assign_stack: + self._assign_stack[-1].add(node.name) + ref = frame.symbols.ref(node.name) + + # If we are looking up a variable we might have to deal with the + # case where it's undefined. We can skip that case if the load + # instruction indicates a parameter which are always defined. + if node.ctx == "load": + load = frame.symbols.find_load(ref) + if not ( + load is not None + and load[0] == VAR_LOAD_PARAMETER + and not self.parameter_is_undeclared(ref) + ): + self.write( + f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" + ) + return + + self.write(ref) + + def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: + # NSRefs can only be used to store values; since they use the normal + # `foo.bar` notation they will be parsed as a normal attribute access + # when used anywhere but in a `set` context + ref = frame.symbols.ref(node.name) + self.writeline(f"if not isinstance({ref}, Namespace):") + self.indent() + self.writeline( + "raise TemplateRuntimeError" + '("cannot assign attribute on non-namespace object")' + ) + self.outdent() + self.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/.venv/lib/python3.10/site-packages/jinja2/constants.py b/.venv/lib/python3.10/site-packages/jinja2/constants.py new file mode 100644 index 0000000..41a1c23 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/.venv/lib/python3.10/site-packages/jinja2/debug.py b/.venv/lib/python3.10/site-packages/jinja2/debug.py new file mode 100644 index 0000000..7ed7e92 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: "t.Optional[Context]" = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/.venv/lib/python3.10/site-packages/jinja2/defaults.py b/.venv/lib/python3.10/site-packages/jinja2/defaults.py new file mode 100644 index 0000000..638cad3 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/.venv/lib/python3.10/site-packages/jinja2/environment.py b/.venv/lib/python3.10/site-packages/jinja2/environment.py new file mode 100644 index 0000000..185d332 --- /dev/null +++ b/.venv/lib/python3.10/site-packages/jinja2/environment.py @@ -0,0 +1,1667 @@ +"""Classes for managing templates and their runtime and compile time +options. +""" +import os +import typing +import typing as t +import weakref +from collections import ChainMap +from functools import lru_cache +from functools import partial +from functools import reduce +from types import CodeType + +from markupsafe import Markup + +from . import nodes +from .compiler import CodeGenerator +from .compiler import generate +from .defaults import BLOCK_END_STRING +from .defaults import BLOCK_START_STRING +from .defaults import COMMENT_END_STRING +from .defaults import COMMENT_START_STRING +from .defaults import DEFAULT_FILTERS +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS +from .defaults import KEEP_TRAILING_NEWLINE +from .defaults import LINE_COMMENT_PREFIX +from .defaults import LINE_STATEMENT_PREFIX +from .defaults import LSTRIP_BLOCKS +from .defaults import NEWLINE_SEQUENCE +from .defaults import TRIM_BLOCKS +from .defaults import VARIABLE_END_STRING +from .defaults import VARIABLE_START_STRING +from .exceptions import TemplateNotFound +from .exceptions import TemplateRuntimeError +from .exceptions import TemplatesNotFound +from .exceptions import TemplateSyntaxError +from .exceptions import UndefinedError +from .lexer import get_lexer +from .lexer import Lexer +from .lexer import TokenStream +from .nodes import EvalContext +from .parser import Parser +from .runtime import Context +from .runtime import new_context +from .runtime import Undefined +from .utils import _PassArg +from .utils import concat +from .utils import consume +from .utils import import_string +from .utils import internalcode +from .utils import LRUCache +from .utils import missing + +if t.TYPE_CHECKING: + import typing_extensions as te + from .bccache import BytecodeCache + from .ext import Extension + from .loaders import BaseLoader + +_env_bound = t.TypeVar("_env_bound", bound="Environment") + + +# for direct template usage we have up to ten living environments +@lru_cache(maxsize=10) +def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: + """Return a new spontaneous environment. A spontaneous environment + is used for templates created directly rather than through an + existing environment. + + :param cls: Environment class to create. + :param args: Positional arguments passed to environment. + """ + env = cls(*args) + env.shared = True + return env + + +def create_cache( + size: int, +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Return the cache class for the given size.""" + if size == 0: + return None + + if size < 0: + return {} + + return LRUCache(size) # type: ignore + + +def copy_cache( + cache: t.Optional[t.MutableMapping], +) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: + return {} + + return LRUCache(cache.capacity) # type: ignore + + +def load_extensions( + environment: "Environment", + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], +) -> t.Dict[str, "Extension"]: + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated extensions. + """ + result = {} + + for extension in extensions: + if isinstance(extension, str): + extension = t.cast(t.Type["Extension"], import_string(extension)) + + result[extension.identifier] = extension(environment) + + return result + + +def _environment_config_check(environment: "Environment") -> "Environment": + """Perform a sanity check on the environment.""" + assert issubclass( + environment.undefined, Undefined + ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert ( + environment.block_start_string + != environment.variable_start_string + != environment.comment_start_string + ), "block, variable and comment start strings must be different." + assert environment.newline_sequence in { + "\r", + "\r\n", + "\n", + }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." + return environment + + +class Environment: + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here are the possible initialization parameters: + + `block_start_string` + The string marking the beginning of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the beginning of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the beginning of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation `. + + `optimized` + should the optimizer be enabled? Default is ``True``. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + ``None`` implicitly into an empty string here. + + `autoescape` + If set to ``True`` the XML/HTML autoescaping feature is enabled by + default. For more details about autoescaping see + :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return ``True`` or ``False`` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``400`` which means + that if more than 400 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + .. versionchanged:: 2.8 + The cache size was increased to 400 from a low 50. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + ``auto_reload`` is set to ``True`` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + + `enable_async` + If set to true this enables async template execution which + allows using async functions and generators. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to: t.Optional["Environment"] = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: the class that is used for code generation. See + #: :class:`~jinja2.compiler.CodeGenerator` for more information. + code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + + concat = "".join + + #: the context class that is used for templates. See + #: :class:`~jinja2.runtime.Context` for more information. + context_class: t.Type[Context] = Context + + template_class: t.Type["Template"] + + def __init__( + self, + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + loader: t.Optional["BaseLoader"] = None, + cache_size: int = 400, + auto_reload: bool = True, + bytecode_cache: t.Optional["BytecodeCache"] = None, + enable_async: bool = False, + ): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined: t.Type[Undefined] = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + + # load extensions + self.extensions = load_extensions(self, extensions) + + self.is_async = enable_async + _environment_config_check(self) + + def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes: t.Any) -> None: + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.items(): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay( + self, + block_start_string: str = missing, + block_end_string: str = missing, + variable_start_string: str = missing, + variable_end_string: str = missing, + comment_start_string: str = missing, + comment_end_string: str = missing, + line_statement_prefix: t.Optional[str] = missing, + line_comment_prefix: t.Optional[str] = missing, + trim_blocks: bool = missing, + lstrip_blocks: bool = missing, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, + keep_trailing_newline: bool = missing, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + optimized: bool = missing, + undefined: t.Type[Undefined] = missing, + finalize: t.Optional[t.Callable[..., t.Any]] = missing, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, + loader: t.Optional["BaseLoader"] = missing, + cache_size: int = missing, + auto_reload: bool = missing, + bytecode_cache: t.Optional["BytecodeCache"] = missing, + enable_async: bool = False, + ) -> "Environment": + """Create a new overlay environment that shares all the data with the + current environment except for cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + + .. versionchanged:: 3.1.2 + Added the ``newline_sequence``,, ``keep_trailing_newline``, + and ``enable_async`` parameters to match ``__init__``. + """ + args = dict(locals()) + del args["self"], args["cache_size"], args["extensions"], args["enable_async"] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in args.items(): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in self.extensions.items(): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + if enable_async is not missing: + rv.is_async = enable_async + + return _environment_config_check(rv) + + @property + def lexer(self) -> Lexer: + """The lexer for this environment.""" + return get_lexer(self) + + def iter_extensions(self) -> t.Iterator["Extension"]: + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (AttributeError, TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Any: + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a string. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def _filter_test_common( + self, + name: t.Union[str, Undefined], + value: t.Any, + args: t.Optional[t.Sequence[t.Any]], + kwargs: t.Optional[t.Mapping[str, t.Any]], + context: t.Optional[Context], + eval_ctx: t.Optional[EvalContext], + is_filter: bool, + ) -> t.Any: + if is_filter: + env_map = self.filters + type_name = "filter" + else: + env_map = self.tests + type_name = "test" + + func = env_map.get(name) # type: ignore + + if func is None: + msg = f"No {type_name} named {name!r}." + + if isinstance(name, Undefined): + try: + name._fail_with_undefined_error() + except Exception as e: + msg = f"{msg} ({e}; did you forget to quote the callable name?)" + + raise TemplateRuntimeError(msg) + + args = [value, *(args if args is not None else ())] + kwargs = kwargs if kwargs is not None else {} + pass_arg = _PassArg.from_obj(func) + + if pass_arg is _PassArg.context: + if context is None: + raise TemplateRuntimeError( + f"Attempted to invoke a context {type_name} without context." + ) + + args.insert(0, context) + elif pass_arg is _PassArg.eval_context: + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, self) + + return func(*args, **kwargs) + + def call_filter( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a filter on a value the same way the compiler does. + + This might return a coroutine if the filter is running from an + environment in async mode and the filter supports async + execution. It's your responsibility to await this if needed. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, True + ) + + def call_test( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a test on a value the same way the compiler does. + + This might return a coroutine if the test is running from an + environment in async mode and the test supports async execution. + It's your responsibility to await this if needed. + + .. versionchanged:: 3.0 + Tests support ``@pass_context``, etc. decorators. Added + the ``context`` and ``eval_ctx`` parameters. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, False + ) + + @internalcode + def parse( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> nodes.Template: + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja extensions ` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def _parse( + self, source: str, name: t.Optional[str], filename: t.Optional[str] + ) -> nodes.Template: + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, filename).parse() + + def lex( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development ` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = str(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def preprocess( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> str: + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce( + lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), + str(source), + ) + + def _tokenize( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) # type: ignore + + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) # type: ignore + + return stream + + def _generate( + self, + source: nodes.Template, + name: t.Optional[str], + filename: t.Optional[str], + defer_init: bool = False, + ) -> str: + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate( # type: ignore + source, + self, + name, + filename, + defer_init=defer_init, + optimized=self.optimized, + ) + + def _compile(self, source: str, filename: str) -> CodeType: + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, "exec") + + @typing.overload + def compile( # type: ignore + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[False]" = False, + defer_init: bool = False, + ) -> CodeType: + ... + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[True]" = ..., + defer_init: bool = False, + ) -> str: + ... + + @internalcode + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: bool = False, + defer_init: bool = False, + ) -> t.Union[str, CodeType]: + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, str): + source_hint = source + source = self._parse(source, name, filename) + source = self._generate(source, name, filename, defer_init=defer_init) + if raw: + return source + if filename is None: + filename = "

+ FastAPI +